fix(todo-continuation-enforcer): allow background task sessions to receive todo-continuation

Background task sessions registered in subagentSessions were not receiving
todo-continuation prompts, causing a deadlock: background tasks waited for
continuation that never came.

Changes:
- Allow both main session and background task sessions to receive continuation
- Add test for background task session continuation behavior
- Cleanup subagentSessions in test setup/teardown

This fixes the deadlock introduced in commit 116a90d which added todo waiting
logic to background-agent/manager.ts.

🤖 Generated with assistance of OhMyOpenCode
This commit is contained in:
YeonGyu-Kim
2025-12-29 16:21:49 +09:00
parent 3a08dcaeb1
commit 59507500ea
2 changed files with 28 additions and 4 deletions

View File

@@ -1,7 +1,7 @@
import { describe, expect, test, beforeEach, afterEach, mock } from "bun:test"
import { createTodoContinuationEnforcer } from "./todo-continuation-enforcer"
import { setMainSession } from "../features/claude-code-session-state"
import { setMainSession, subagentSessions } from "../features/claude-code-session-state"
import type { BackgroundManager } from "../features/background-agent"
describe("todo-continuation-enforcer", () => {
@@ -51,10 +51,12 @@ describe("todo-continuation-enforcer", () => {
promptCalls = []
toastCalls = []
setMainSession(undefined)
subagentSessions.clear()
})
afterEach(() => {
setMainSession(undefined)
subagentSessions.clear()
})
test("should inject continuation when idle with incomplete todos", async () => {
@@ -143,6 +145,25 @@ describe("todo-continuation-enforcer", () => {
expect(promptCalls).toHaveLength(0)
})
test("should inject for background task session (subagent)", async () => {
// #given - main session set, background task session registered
setMainSession("main-session")
const bgTaskSession = "bg-task-session"
subagentSessions.add(bgTaskSession)
const hook = createTodoContinuationEnforcer(createMockPluginInput(), {})
// #when - background task session goes idle
await hook.handler({
event: { type: "session.idle", properties: { sessionID: bgTaskSession } },
})
// #then - continuation injected for background task session
await new Promise(r => setTimeout(r, 2500))
expect(promptCalls.length).toBe(1)
expect(promptCalls[0].sessionID).toBe(bgTaskSession)
})
test("should skip injection after recent error", async () => {
// #given - session that just had an error
const sessionID = "main-error"

View File

@@ -1,7 +1,7 @@
import { existsSync, readdirSync } from "node:fs"
import { join } from "node:path"
import type { PluginInput } from "@opencode-ai/plugin"
import { getMainSessionID } from "../features/claude-code-session-state"
import { getMainSessionID, subagentSessions } from "../features/claude-code-session-state"
import {
findNearestMessageWithFields,
MESSAGE_STORAGE,
@@ -265,8 +265,11 @@ export function createTodoContinuationEnforcer(
log(`[${HOOK_NAME}] session.idle`, { sessionID })
const mainSessionID = getMainSessionID()
if (mainSessionID && sessionID !== mainSessionID) {
log(`[${HOOK_NAME}] Skipped: not main session`, { sessionID })
const isMainSession = sessionID === mainSessionID
const isBackgroundTaskSession = subagentSessions.has(sessionID)
if (mainSessionID && !isMainSession && !isBackgroundTaskSession) {
log(`[${HOOK_NAME}] Skipped: not main or background task session`, { sessionID })
return
}