diff --git a/src/resources/extensions/gsd/auto-post-unit.ts b/src/resources/extensions/gsd/auto-post-unit.ts index 847a0635a..3d820f7ca 100644 --- a/src/resources/extensions/gsd/auto-post-unit.ts +++ b/src/resources/extensions/gsd/auto-post-unit.ts @@ -48,8 +48,28 @@ import { import { hasPendingCaptures, loadPendingCaptures } from "./captures.js"; import { debugLog } from "./debug-logger.js"; import { runSafely } from "./auto-utils.js"; -import type { AutoSession } from "./auto/session.js"; +import type { AutoSession, SidecarItem } from "./auto/session.js"; + +/** Enqueue a sidecar item (hook, triage, or quick-task) for the main loop to + * drain via runUnit. Logs the enqueue event and notifies the UI. */ +function enqueueSidecar( + s: AutoSession, + ctx: ExtensionContext, + entry: SidecarItem, + debugExtra: Record, + notification?: string, +): "continue" { + s.sidecarQueue.push(entry); + debugLog("postUnitPostVerification", { + phase: "sidecar-enqueue", + kind: entry.kind, + unitId: entry.unitId, + ...debugExtra, + }); + if (notification) ctx.ui.notify(notification, "info"); + return "continue"; +} /** Unit types that only touch `.gsd/` internal state files (no code changes). * Auto-commit is skipped for these — their state files are picked up by the * next actual task commit via `smartStage()`. */ @@ -492,23 +512,11 @@ export async function postUnitPostVerification(pctx: PostUnitContext): Promise<" } persistHookState(s.basePath); - s.sidecarQueue.push({ - kind: "hook", - unitType: hookUnit.unitType, - unitId: hookUnit.unitId, - prompt: hookUnit.prompt, - model: hookUnit.model, - }); - - debugLog("postUnitPostVerification", { - phase: "sidecar-enqueue", - kind: "hook", - unitType: hookUnit.unitType, - unitId: hookUnit.unitId, - hookName: hookUnit.hookName, - }); - - return "continue"; + return enqueueSidecar( + s, ctx, + { kind: "hook", unitType: hookUnit.unitType, unitId: hookUnit.unitId, prompt: hookUnit.prompt, model: hookUnit.model }, + { hookName: hookUnit.hookName }, + ); } // Check if a hook requested a retry of the trigger unit @@ -607,26 +615,12 @@ export async function postUnitPostVerification(pctx: PostUnitContext): Promise<" } const triageUnitId = `${mid}/${sid}/triage`; - s.sidecarQueue.push({ - kind: "triage", - unitType: "triage-captures", - unitId: triageUnitId, - prompt, - }); - - debugLog("postUnitPostVerification", { - phase: "sidecar-enqueue", - kind: "triage", - unitId: triageUnitId, - pendingCount: pending.length, - }); - - ctx.ui.notify( + return enqueueSidecar( + s, ctx, + { kind: "triage", unitType: "triage-captures", unitId: triageUnitId, prompt }, + { pendingCount: pending.length }, `Triaging ${pending.length} pending capture${pending.length === 1 ? "" : "s"}...`, - "info", ); - - return "continue"; } } } @@ -655,27 +649,12 @@ export async function postUnitPostVerification(pctx: PostUnitContext): Promise<" markCaptureExecuted(s.basePath, capture.id); const qtUnitId = `${s.currentMilestoneId}/${capture.id}`; - s.sidecarQueue.push({ - kind: "quick-task", - unitType: "quick-task", - unitId: qtUnitId, - prompt, - captureId: capture.id, - }); - - debugLog("postUnitPostVerification", { - phase: "sidecar-enqueue", - kind: "quick-task", - unitId: qtUnitId, - captureId: capture.id, - }); - - ctx.ui.notify( + return enqueueSidecar( + s, ctx, + { kind: "quick-task", unitType: "quick-task", unitId: qtUnitId, prompt, captureId: capture.id }, + { captureId: capture.id }, `Executing quick-task: ${capture.id} — "${capture.text}"`, - "info", ); - - return "continue"; } catch (e) { debugLog("postUnit", { phase: "quick-task-dispatch", error: String(e) }); } diff --git a/src/resources/extensions/gsd/tests/sidecar-queue.test.ts b/src/resources/extensions/gsd/tests/sidecar-queue.test.ts index a5035058a..308fb0cce 100644 --- a/src/resources/extensions/gsd/tests/sidecar-queue.test.ts +++ b/src/resources/extensions/gsd/tests/sidecar-queue.test.ts @@ -113,12 +113,12 @@ test("postUnitPostVerification pushes to sidecarQueue for hooks", () => { assert.ok(triageSectionStart > -1, "auto-post-unit.ts must have a triage check section"); const hookSection = source.slice(hookSectionStart, triageSectionStart); assert.ok( - hookSection.includes("s.sidecarQueue.push("), - "hook section must push to s.sidecarQueue", + hookSection.includes("enqueueSidecar(") || hookSection.includes("s.sidecarQueue.push("), + "hook section must enqueue to sidecarQueue (via enqueueSidecar or direct push)", ); assert.ok( - hookSection.includes('kind: "hook"'), - "hook sidecar item must have kind: 'hook'", + hookSection.includes('"hook"'), + "hook sidecar item must reference kind 'hook'", ); }); @@ -132,12 +132,12 @@ test("postUnitPostVerification pushes to sidecarQueue for triage", () => { assert.ok(quickTaskSectionStart > -1, "auto-post-unit.ts must have a quick-task dispatch section"); const triageSection = source.slice(triageSectionStart, quickTaskSectionStart); assert.ok( - triageSection.includes("s.sidecarQueue.push("), - "triage section must push to s.sidecarQueue", + triageSection.includes("enqueueSidecar(") || triageSection.includes("s.sidecarQueue.push("), + "triage section must enqueue to sidecarQueue (via enqueueSidecar or direct push)", ); assert.ok( - triageSection.includes('kind: "triage"'), - "triage sidecar item must have kind: 'triage'", + triageSection.includes('"triage"'), + "triage sidecar item must reference kind 'triage'", ); }); @@ -149,12 +149,12 @@ test("postUnitPostVerification pushes to sidecarQueue for quick-tasks", () => { assert.ok(quickTaskSectionStart > -1, "auto-post-unit.ts must have a quick-task dispatch section"); const quickTaskSection = source.slice(quickTaskSectionStart); assert.ok( - quickTaskSection.includes("s.sidecarQueue.push("), - "quick-task section must push to s.sidecarQueue", + quickTaskSection.includes("enqueueSidecar(") || quickTaskSection.includes("s.sidecarQueue.push("), + "quick-task section must enqueue to sidecarQueue (via enqueueSidecar or direct push)", ); assert.ok( - quickTaskSection.includes('kind: "quick-task"'), - "quick-task sidecar item must have kind: 'quick-task'", + quickTaskSection.includes('"quick-task"'), + "quick-task sidecar item must reference kind 'quick-task'", ); });