diff --git a/src/cli/run/completion.ts b/src/cli/run/completion.ts index f28927f12..bcc0cebb8 100644 --- a/src/cli/run/completion.ts +++ b/src/cli/run/completion.ts @@ -20,6 +20,11 @@ export async function checkCompletionConditions(ctx: RunContext): Promise this.notifyParentSession(item.task)).catch(err => { log("[background-agent] Failed to notify on startTask error:", err) @@ -814,6 +821,21 @@ The fallback retry session is now created and can be inspected directly. return tasks } + private updateBackgroundTaskMarker(parentSessionID: string): void { + const tasks = this.getTasksByParentSession(parentSessionID) + const activeTasks = tasks.filter(t => t.status === "running" || t.status === "pending") + if (activeTasks.length > 0) { + setContinuationMarkerSource( + this.directory, parentSessionID, "background-task", "active", + `${activeTasks.length} background task(s) active`, + ) + } else { + setContinuationMarkerSource( + this.directory, parentSessionID, "background-task", "idle", + ) + } + } + getAllDescendantTasks(sessionID: string): BackgroundTask[] { const result: BackgroundTask[] = [] const directChildren = this.getTasksByParentSession(sessionID) @@ -1525,6 +1547,11 @@ The fallback retry session is now created and can be inspected directly. SessionCategoryRegistry.remove(task.sessionId) } + // Update continuation marker for CLI run mode + if (task.parentSessionID) { + this.updateBackgroundTaskMarker(task.parentSessionID) + } + this.markForNotification(task) this.enqueueNotificationForParent(task.parentSessionId, () => this.notifyParentSession(task)).catch(err => { log("[background-agent] Error in notifyParentSession for errored task:", { taskId: task.id, error: err }) @@ -1824,6 +1851,11 @@ The task was re-queued on a fallback model after a retryable failure. removeTaskToastTracking(task.id) + // Update continuation marker for CLI run mode + if (task.parentSessionID) { + this.updateBackgroundTaskMarker(task.parentSessionID) + } + if (options?.skipNotification) { this.cleanupPendingByParent(task) this.scheduleTaskRemoval(task.id) @@ -1942,6 +1974,11 @@ The task was re-queued on a fallback model after a retryable failure. SessionCategoryRegistry.remove(task.sessionId) } + // Update continuation marker for CLI run mode + if (task.parentSessionID) { + this.updateBackgroundTaskMarker(task.parentSessionID) + } + try { await this.enqueueNotificationForParent(task.parentSessionId, () => this.notifyParentSession(task)) log(`[background-agent] Task completed via ${source}:`, task.id) @@ -2178,6 +2215,10 @@ The task was re-queued on a fallback model after a retryable failure. } } this.cleanupPendingByParent(task) + // Update continuation marker for CLI run mode + if (task.parentSessionID) { + this.updateBackgroundTaskMarker(task.parentSessionID) + } this.markForNotification(task) this.enqueueNotificationForParent(task.parentSessionId, () => this.notifyParentSession(task)).catch(err => { log("[background-agent] Error in notifyParentSession for stale-pruned task:", { taskId: task.id, error: err }) @@ -2240,6 +2281,11 @@ The task was re-queued on a fallback model after a retryable failure. SessionCategoryRegistry.remove(task.sessionId) } + // Update continuation marker for CLI run mode + if (task.parentSessionID) { + this.updateBackgroundTaskMarker(task.parentSessionID) + } + this.markForNotification(task) this.enqueueNotificationForParent(task.parentSessionId, () => this.notifyParentSession(task)).catch(err => { log("[background-agent] Error in notifyParentSession for crashed task:", { taskId: task.id, error: err }) diff --git a/src/features/run-continuation-state/types.ts b/src/features/run-continuation-state/types.ts index 856f3d9ef..b851043d3 100644 --- a/src/features/run-continuation-state/types.ts +++ b/src/features/run-continuation-state/types.ts @@ -1,4 +1,4 @@ -export type ContinuationMarkerSource = "todo" | "stop" +export type ContinuationMarkerSource = "todo" | "stop" | "background-task" export type ContinuationMarkerState = "idle" | "active" | "stopped" diff --git a/src/hooks/todo-continuation-enforcer/continuation-injection.ts b/src/hooks/todo-continuation-enforcer/continuation-injection.ts index 5844bebd2..d1ca73a1f 100644 --- a/src/hooks/todo-continuation-enforcer/continuation-injection.ts +++ b/src/hooks/todo-continuation-enforcer/continuation-injection.ts @@ -79,7 +79,7 @@ export async function injectContinuation(args: { } const hasRunningBgTasks = backgroundManager - ? backgroundManager.getTasksByParentSession(sessionID).some((task: { status: string }) => task.status === "running") + ? backgroundManager.getTasksByParentSession(sessionID).some((task: { status: string }) => task.status === "running" || task.status === "pending") : false if (hasRunningBgTasks) { diff --git a/src/hooks/todo-continuation-enforcer/idle-event.ts b/src/hooks/todo-continuation-enforcer/idle-event.ts index eebd83315..0f3a6a71a 100644 --- a/src/hooks/todo-continuation-enforcer/idle-event.ts +++ b/src/hooks/todo-continuation-enforcer/idle-event.ts @@ -71,7 +71,7 @@ export async function handleSessionIdle(args: { } const hasRunningBgTasks = backgroundManager - ? backgroundManager.getTasksByParentSession(sessionID).some((task: { status: string }) => task.status === "running") + ? backgroundManager.getTasksByParentSession(sessionID).some((task: { status: string }) => task.status === "running" || task.status === "pending") : false if (hasRunningBgTasks) {