gsd-pi 2.82.0-dev.2841a1e44 → 2.82.0-dev.98ea09b1e
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/dist/resources/.managed-resources-content-hash +1 -1
- package/dist/resources/GSD-WORKFLOW.md +7 -0
- package/dist/resources/extensions/claude-code-cli/partial-builder.js +2 -1
- package/dist/resources/extensions/gsd/auto/infra-errors.js +9 -3
- package/dist/resources/extensions/gsd/auto/loop.js +5 -5
- package/dist/resources/extensions/gsd/auto/orchestrator.js +11 -0
- package/dist/resources/extensions/gsd/auto/phases.js +8 -1
- package/dist/resources/extensions/gsd/auto/workflow-memory-pressure.js +12 -0
- package/dist/resources/extensions/gsd/auto-dispatch.js +13 -6
- package/dist/resources/extensions/gsd/auto-model-selection.js +2 -0
- package/dist/resources/extensions/gsd/auto-post-unit.js +70 -9
- package/dist/resources/extensions/gsd/auto-recovery.js +31 -1
- package/dist/resources/extensions/gsd/auto-start.js +85 -12
- package/dist/resources/extensions/gsd/auto-worktree.js +111 -1
- package/dist/resources/extensions/gsd/auto.js +30 -3
- package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +4 -1
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +9 -8
- package/dist/resources/extensions/gsd/bootstrap/subagent-input.js +5 -2
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +13 -1
- package/dist/resources/extensions/gsd/commands/handlers/core.js +17 -1
- package/dist/resources/extensions/gsd/crash-recovery.js +31 -5
- package/dist/resources/extensions/gsd/db/unit-dispatches.js +3 -2
- package/dist/resources/extensions/gsd/dispatch-guard.js +2 -2
- package/dist/resources/extensions/gsd/doctor-runtime-checks.js +28 -11
- package/dist/resources/extensions/gsd/doctor.js +2 -28
- package/dist/resources/extensions/gsd/export-html.js +27 -425
- package/dist/resources/extensions/gsd/git-service.js +39 -1
- package/dist/resources/extensions/gsd/gsd-db.js +1 -0
- package/dist/resources/extensions/gsd/guided-flow.js +13 -6
- package/dist/resources/extensions/gsd/migrate/parsers.js +10 -0
- package/dist/resources/extensions/gsd/migration-auto-check.js +12 -17
- package/dist/resources/extensions/gsd/milestone-actions.js +11 -4
- package/dist/resources/extensions/gsd/native-git-bridge.js +48 -12
- package/dist/resources/extensions/gsd/post-execution-checks.js +73 -2
- package/dist/resources/extensions/gsd/pre-execution-checks.js +28 -1
- package/dist/resources/extensions/gsd/prompt-loader.js +1 -1
- package/dist/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
- package/dist/resources/extensions/gsd/prompts/complete-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/discuss-headless.md +8 -8
- package/dist/resources/extensions/gsd/prompts/discuss.md +9 -9
- package/dist/resources/extensions/gsd/prompts/guided-discuss-project.md +4 -4
- package/dist/resources/extensions/gsd/prompts/guided-discuss-requirements.md +3 -3
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +4 -4
- package/dist/resources/extensions/gsd/prompts/queue.md +4 -4
- package/dist/resources/extensions/gsd/prompts/refine-slice.md +2 -2
- package/dist/resources/extensions/gsd/prompts/rewrite-docs.md +1 -1
- package/dist/resources/extensions/gsd/state-reconciliation/drift/merge-state.js +6 -1
- package/dist/resources/extensions/gsd/state-reconciliation/drift/project-md.js +9 -14
- package/dist/resources/extensions/gsd/state-reconciliation/drift/roadmap.js +19 -24
- package/dist/resources/extensions/gsd/status-guards.js +4 -0
- package/dist/resources/extensions/gsd/templates/plan.md +8 -5
- package/dist/resources/extensions/gsd/templates/task-plan.md +4 -2
- package/dist/resources/extensions/gsd/tools/complete-milestone.js +6 -8
- package/dist/resources/extensions/gsd/tools/complete-slice.js +6 -8
- package/dist/resources/extensions/gsd/tools/plan-milestone.js +7 -1
- package/dist/resources/extensions/gsd/tools/plan-slice.js +89 -14
- package/dist/resources/extensions/gsd/unit-context-manifest.js +7 -8
- package/dist/resources/extensions/gsd/validation.js +23 -1
- package/dist/resources/extensions/gsd/verification-gate.js +68 -7
- package/dist/resources/extensions/gsd/workflow-projections.js +6 -8
- package/dist/resources/extensions/gsd/worktree-lifecycle.js +33 -8
- package/dist/resources/extensions/shared/html-shell.js +388 -0
- package/dist/resources/extensions/visual-brief/page-contract.js +2 -0
- package/dist/resources/extensions/visual-brief/prompts.js +29 -0
- package/dist/tsconfig.extensions.tsbuildinfo +1 -1
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +13 -13
- package/dist/web/standalone/.next/build-manifest.json +3 -3
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found/page.js +2 -2
- package/dist/web/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.rsc +4 -7
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +4 -7
- package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +4 -5
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -5
- package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
- package/dist/web/standalone/.next/server/app/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +4 -7
- package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +4 -7
- package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +4 -5
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -5
- package/dist/web/standalone/.next/server/app/page.js +2 -2
- package/dist/web/standalone/.next/server/app/page.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +13 -13
- package/dist/web/standalone/.next/server/chunks/4266.js +2 -0
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/next-font-manifest.js +1 -1
- package/dist/web/standalone/.next/server/next-font-manifest.json +1 -1
- package/dist/web/standalone/.next/server/pages/404.html +1 -1
- package/dist/web/standalone/.next/server/pages/500.html +1 -1
- package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
- package/dist/web/standalone/.next/static/chunks/app/layout-8c10ec293ae0f1d5.js +1 -0
- package/dist/web/standalone/.next/static/chunks/{webpack-6a95bc41e0f7ec89.js → webpack-9a4db269f9ed63ad.js} +1 -1
- package/dist/web/standalone/.next/static/css/746ee28c929d1880.css +1 -0
- package/package.json +2 -2
- package/packages/mcp-server/src/workflow-tools.test.ts +1 -1
- package/packages/native/tsconfig.json +2 -1
- package/packages/native/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-ai/dist/providers/openai-codex-responses.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/openai-codex-responses.js +82 -1
- package/packages/pi-ai/dist/providers/openai-codex-responses.js.map +1 -1
- package/packages/pi-ai/dist/providers/openai-codex-responses.test.d.ts +2 -0
- package/packages/pi-ai/dist/providers/openai-codex-responses.test.d.ts.map +1 -0
- package/packages/pi-ai/dist/providers/openai-codex-responses.test.js +52 -0
- package/packages/pi-ai/dist/providers/openai-codex-responses.test.js.map +1 -0
- package/packages/pi-ai/dist/providers/simple-options.d.ts +2 -4
- package/packages/pi-ai/dist/providers/simple-options.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/simple-options.js +5 -6
- package/packages/pi-ai/dist/providers/simple-options.js.map +1 -1
- package/packages/pi-ai/dist/providers/simple-options.test.d.ts +2 -0
- package/packages/pi-ai/dist/providers/simple-options.test.d.ts.map +1 -0
- package/packages/pi-ai/dist/providers/simple-options.test.js +50 -0
- package/packages/pi-ai/dist/providers/simple-options.test.js.map +1 -0
- package/packages/pi-ai/src/providers/openai-codex-responses.test.ts +63 -0
- package/packages/pi-ai/src/providers/openai-codex-responses.ts +91 -1
- package/packages/pi-ai/src/providers/simple-options.test.ts +60 -0
- package/packages/pi-ai/src/providers/simple-options.ts +5 -6
- package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session-thinking-level.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/agent-session-thinking-level.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/agent-session-thinking-level.test.js +66 -0
- package/packages/pi-coding-agent/dist/core/agent-session-thinking-level.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/agent-session.js +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
- package/packages/pi-coding-agent/src/core/agent-session-thinking-level.test.ts +79 -0
- package/packages/pi-coding-agent/src/core/agent-session.ts +1 -1
- package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
- package/src/resources/GSD-WORKFLOW.md +7 -0
- package/src/resources/extensions/claude-code-cli/partial-builder.ts +2 -1
- package/src/resources/extensions/claude-code-cli/tests/partial-builder.test.ts +19 -2
- package/src/resources/extensions/gsd/auto/contracts.ts +14 -6
- package/src/resources/extensions/gsd/auto/infra-errors.ts +9 -3
- package/src/resources/extensions/gsd/auto/loop.ts +8 -5
- package/src/resources/extensions/gsd/auto/orchestrator.ts +11 -0
- package/src/resources/extensions/gsd/auto/phases.ts +7 -1
- package/src/resources/extensions/gsd/auto/workflow-memory-pressure.ts +13 -0
- package/src/resources/extensions/gsd/auto-dispatch.ts +14 -6
- package/src/resources/extensions/gsd/auto-model-selection.ts +2 -1
- package/src/resources/extensions/gsd/auto-post-unit.ts +77 -7
- package/src/resources/extensions/gsd/auto-recovery.ts +29 -0
- package/src/resources/extensions/gsd/auto-start.ts +92 -9
- package/src/resources/extensions/gsd/auto-worktree.ts +119 -1
- package/src/resources/extensions/gsd/auto.ts +32 -3
- package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +6 -1
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +9 -8
- package/src/resources/extensions/gsd/bootstrap/subagent-input.ts +3 -1
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +16 -1
- package/src/resources/extensions/gsd/commands/handlers/core.ts +17 -1
- package/src/resources/extensions/gsd/crash-recovery.ts +30 -4
- package/src/resources/extensions/gsd/db/unit-dispatches.ts +4 -3
- package/src/resources/extensions/gsd/dispatch-guard.ts +2 -2
- package/src/resources/extensions/gsd/doctor-runtime-checks.ts +25 -13
- package/src/resources/extensions/gsd/doctor.ts +2 -27
- package/src/resources/extensions/gsd/export-html.ts +27 -427
- package/src/resources/extensions/gsd/git-service.ts +45 -1
- package/src/resources/extensions/gsd/gsd-db.ts +3 -0
- package/src/resources/extensions/gsd/guided-flow.ts +14 -7
- package/src/resources/extensions/gsd/migrate/parsers.ts +11 -0
- package/src/resources/extensions/gsd/migration-auto-check.ts +15 -23
- package/src/resources/extensions/gsd/milestone-actions.ts +10 -4
- package/src/resources/extensions/gsd/native-git-bridge.ts +54 -12
- package/src/resources/extensions/gsd/post-execution-checks.ts +87 -2
- package/src/resources/extensions/gsd/pre-execution-checks.ts +32 -1
- package/src/resources/extensions/gsd/prompt-loader.ts +1 -1
- package/src/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
- package/src/resources/extensions/gsd/prompts/complete-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/discuss-headless.md +8 -8
- package/src/resources/extensions/gsd/prompts/discuss.md +9 -9
- package/src/resources/extensions/gsd/prompts/guided-discuss-project.md +4 -4
- package/src/resources/extensions/gsd/prompts/guided-discuss-requirements.md +3 -3
- package/src/resources/extensions/gsd/prompts/plan-slice.md +4 -4
- package/src/resources/extensions/gsd/prompts/queue.md +4 -4
- package/src/resources/extensions/gsd/prompts/refine-slice.md +2 -2
- package/src/resources/extensions/gsd/prompts/rewrite-docs.md +1 -1
- package/src/resources/extensions/gsd/state-reconciliation/drift/merge-state.ts +8 -1
- package/src/resources/extensions/gsd/state-reconciliation/drift/project-md.ts +12 -15
- package/src/resources/extensions/gsd/state-reconciliation/drift/roadmap.ts +17 -25
- package/src/resources/extensions/gsd/status-guards.ts +5 -0
- package/src/resources/extensions/gsd/templates/plan.md +8 -5
- package/src/resources/extensions/gsd/templates/task-plan.md +4 -2
- package/src/resources/extensions/gsd/tests/auto-deterministic-error-classification-4973.test.ts +116 -0
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +54 -0
- package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +80 -1
- package/src/resources/extensions/gsd/tests/auto-paused-ui-cleanup.test.ts +6 -6
- package/src/resources/extensions/gsd/tests/auto-post-unit-step-message.test.ts +12 -1
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +15 -1
- package/src/resources/extensions/gsd/tests/auto-start-orphan-bootstrap.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/auto-worktree-registry.test.ts +69 -1
- package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +4 -1
- package/src/resources/extensions/gsd/tests/complete-slice.test.ts +5 -9
- package/src/resources/extensions/gsd/tests/complete-task.test.ts +3 -1
- package/src/resources/extensions/gsd/tests/crash-recovery-via-db.test.ts +43 -2
- package/src/resources/extensions/gsd/tests/db-authority-regression.test.ts +208 -0
- package/src/resources/extensions/gsd/tests/deep-project-auto-loop.test.ts +59 -2
- package/src/resources/extensions/gsd/tests/dispatch-complete-milestone-guard.test.ts +39 -0
- package/src/resources/extensions/gsd/tests/dispatch-guard.test.ts +27 -0
- package/src/resources/extensions/gsd/tests/export-html-enhancements.test.ts +8 -0
- package/src/resources/extensions/gsd/tests/guided-discuss-project-prompt-rendering.test.ts +2 -0
- package/src/resources/extensions/gsd/tests/guided-flow.test.ts +21 -0
- package/src/resources/extensions/gsd/tests/headless-milestone-parity.test.ts +6 -6
- package/src/resources/extensions/gsd/tests/hook-model-resolution.test.ts +5 -0
- package/src/resources/extensions/gsd/tests/infra-error.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/infra-errors-cooldown.test.ts +9 -0
- package/src/resources/extensions/gsd/tests/integration/doctor-runtime.test.ts +20 -0
- package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +103 -1
- package/src/resources/extensions/gsd/tests/integration/state-machine-runtime-failures.test.ts +6 -1
- package/src/resources/extensions/gsd/tests/migrate-validator-parsers.test.ts +24 -1
- package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +26 -18
- package/src/resources/extensions/gsd/tests/native-git-bridge-exec-fallback.test.ts +63 -2
- package/src/resources/extensions/gsd/tests/orphaned-worktree-audit.test.ts +121 -1
- package/src/resources/extensions/gsd/tests/park-db-sync.test.ts +55 -1
- package/src/resources/extensions/gsd/tests/plan-milestone.test.ts +26 -0
- package/src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +2 -0
- package/src/resources/extensions/gsd/tests/plan-slice.test.ts +225 -1
- package/src/resources/extensions/gsd/tests/plan-task.test.ts +17 -0
- package/src/resources/extensions/gsd/tests/post-execution-checks.test.ts +86 -0
- package/src/resources/extensions/gsd/tests/post-unit-git-failure.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/pre-execution-checks.test.ts +53 -0
- package/src/resources/extensions/gsd/tests/prompt-loader.test.ts +23 -0
- package/src/resources/extensions/gsd/tests/remediation-completion-guard.test.ts +46 -2
- package/src/resources/extensions/gsd/tests/session-switch-abort-misclassification.test.ts +10 -0
- package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +31 -1
- package/src/resources/extensions/gsd/tests/state-reconciliation-drift.test.ts +119 -23
- package/src/resources/extensions/gsd/tests/stuck-state-via-db.test.ts +64 -1
- package/src/resources/extensions/gsd/tests/summary-render-parity.test.ts +7 -3
- package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +65 -7
- package/src/resources/extensions/gsd/tests/verification-gate.test.ts +110 -1
- package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/workflow-memory-pressure.test.ts +21 -1
- package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/worktree-git-pathspec.test.ts +39 -0
- package/src/resources/extensions/gsd/tests/worktree-journal-events.test.ts +64 -12
- package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +38 -0
- package/src/resources/extensions/gsd/tools/complete-milestone.ts +8 -10
- package/src/resources/extensions/gsd/tools/complete-slice.ts +6 -8
- package/src/resources/extensions/gsd/tools/plan-milestone.ts +5 -1
- package/src/resources/extensions/gsd/tools/plan-slice.ts +98 -12
- package/src/resources/extensions/gsd/types.ts +1 -1
- package/src/resources/extensions/gsd/unit-context-manifest.ts +12 -9
- package/src/resources/extensions/gsd/validation.ts +23 -1
- package/src/resources/extensions/gsd/verification-gate.ts +78 -6
- package/src/resources/extensions/gsd/workflow-projections.ts +6 -8
- package/src/resources/extensions/gsd/worktree-lifecycle.ts +41 -8
- package/src/resources/extensions/shared/html-shell.ts +412 -0
- package/src/resources/extensions/visual-brief/page-contract.ts +2 -0
- package/src/resources/extensions/visual-brief/prompts.ts +37 -1
- package/src/resources/extensions/visual-brief/tests/visual-brief.test.ts +40 -0
- package/dist/web/standalone/.next/server/chunks/5822.js +0 -2
- package/dist/web/standalone/.next/static/chunks/app/layout-a16c7a7ecdf0c2cf.js +0 -1
- package/dist/web/standalone/.next/static/css/0262768ec1b89d34.css +0 -1
- package/dist/web/standalone/.next/static/css/de70bee13400563f.css +0 -1
- package/dist/web/standalone/.next/static/media/4cf2300e9c8272f7-s.p.woff2 +0 -0
- package/dist/web/standalone/.next/static/media/747892c23ea88013-s.woff2 +0 -0
- package/dist/web/standalone/.next/static/media/8d697b304b401681-s.woff2 +0 -0
- package/dist/web/standalone/.next/static/media/93f479601ee12b01-s.p.woff2 +0 -0
- package/dist/web/standalone/.next/static/media/9610d9e46709d722-s.woff2 +0 -0
- package/dist/web/standalone/.next/static/media/ba015fad6dcf6784-s.woff2 +0 -0
- /package/dist/web/standalone/.next/static/{Qgr2B_MRhPxC0z8fwv4vT → euQ0CLP_v8V4e76Tu3odJ}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{Qgr2B_MRhPxC0z8fwv4vT → euQ0CLP_v8V4e76Tu3odJ}/_ssgManifest.js +0 -0
|
@@ -3353,6 +3353,60 @@ test("runDispatch runs stuck detection while artifact verification retry is pend
|
|
|
3353
3353
|
);
|
|
3354
3354
|
});
|
|
3355
3355
|
|
|
3356
|
+
test("runDispatch falls back to main when dispatch guard cannot read main branch (#5530)", async (t) => {
|
|
3357
|
+
_resetPendingResolve();
|
|
3358
|
+
|
|
3359
|
+
const ctx = makeMockCtx();
|
|
3360
|
+
const pi = makeMockPi();
|
|
3361
|
+
const basePath = mkdtempSync(join(tmpdir(), "gsd-5530-main-branch-fallback-"));
|
|
3362
|
+
t.after(() => rmSync(basePath, { recursive: true, force: true }));
|
|
3363
|
+
|
|
3364
|
+
let guardBranch: string | null = null;
|
|
3365
|
+
const s = makeLoopSession({ basePath });
|
|
3366
|
+
const deps = makeMockDeps({
|
|
3367
|
+
getMainBranch: () => {
|
|
3368
|
+
throw new Error("fatal: detected dubious ownership");
|
|
3369
|
+
},
|
|
3370
|
+
getPriorSliceCompletionBlocker: (_basePath, mainBranch) => {
|
|
3371
|
+
guardBranch = mainBranch;
|
|
3372
|
+
return null;
|
|
3373
|
+
},
|
|
3374
|
+
});
|
|
3375
|
+
|
|
3376
|
+
const result = await runDispatch(
|
|
3377
|
+
{
|
|
3378
|
+
ctx,
|
|
3379
|
+
pi,
|
|
3380
|
+
s,
|
|
3381
|
+
deps,
|
|
3382
|
+
prefs: undefined,
|
|
3383
|
+
iteration: 1,
|
|
3384
|
+
flowId: "test-flow",
|
|
3385
|
+
nextSeq: () => 1,
|
|
3386
|
+
},
|
|
3387
|
+
{
|
|
3388
|
+
state: {
|
|
3389
|
+
phase: "executing",
|
|
3390
|
+
activeMilestone: { id: "M001", title: "Test", status: "active" },
|
|
3391
|
+
activeSlice: { id: "S01", title: "Slice 1" },
|
|
3392
|
+
activeTask: { id: "T01" },
|
|
3393
|
+
registry: [{ id: "M001", status: "active" }],
|
|
3394
|
+
blockers: [],
|
|
3395
|
+
} as any,
|
|
3396
|
+
mid: "M001",
|
|
3397
|
+
midTitle: "Test",
|
|
3398
|
+
},
|
|
3399
|
+
{
|
|
3400
|
+
recentUnits: [],
|
|
3401
|
+
stuckRecoveryAttempts: 0,
|
|
3402
|
+
consecutiveFinalizeTimeouts: 0,
|
|
3403
|
+
},
|
|
3404
|
+
);
|
|
3405
|
+
|
|
3406
|
+
assert.equal(guardBranch, "main");
|
|
3407
|
+
assert.equal(result.action, "next");
|
|
3408
|
+
});
|
|
3409
|
+
|
|
3356
3410
|
test("dispatch Worktree Safety stops unknown unit types with missing Tool Contract", async (t) => {
|
|
3357
3411
|
_resetPendingResolve();
|
|
3358
3412
|
|
|
@@ -288,6 +288,51 @@ test("advance() stops when dispatch has no next unit", async () => {
|
|
|
288
288
|
assert.equal(orchestrator.getStatus().phase, "stopped");
|
|
289
289
|
});
|
|
290
290
|
|
|
291
|
+
test("advance() surfaces dispatch blocker reason instead of generic no remaining units", async () => {
|
|
292
|
+
const { deps, calls } = makeDeps({
|
|
293
|
+
dispatch: {
|
|
294
|
+
async decideNextUnit() {
|
|
295
|
+
return {
|
|
296
|
+
kind: "blocked",
|
|
297
|
+
reason: "Milestone M001 validation verdict is needs-remediation but all slices are complete.",
|
|
298
|
+
action: "pause",
|
|
299
|
+
};
|
|
300
|
+
},
|
|
301
|
+
},
|
|
302
|
+
});
|
|
303
|
+
const orchestrator = createAutoOrchestrator(deps);
|
|
304
|
+
|
|
305
|
+
const result = await orchestrator.advance();
|
|
306
|
+
|
|
307
|
+
assert.equal(result.kind, "blocked");
|
|
308
|
+
if (result.kind !== "blocked") return;
|
|
309
|
+
assert.equal(result.reason, "Milestone M001 validation verdict is needs-remediation but all slices are complete.");
|
|
310
|
+
assert.equal(result.action, "pause");
|
|
311
|
+
assert.ok(calls.includes("journal:advance-blocked"));
|
|
312
|
+
assert.ok(!calls.includes("journal:advance-stopped"));
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
test("resume() returns blocked when advance detects a dispatch blocker", async () => {
|
|
316
|
+
const { deps } = makeDeps({
|
|
317
|
+
dispatch: {
|
|
318
|
+
async decideNextUnit() {
|
|
319
|
+
return {
|
|
320
|
+
kind: "blocked",
|
|
321
|
+
reason: "remediation required",
|
|
322
|
+
action: "pause",
|
|
323
|
+
};
|
|
324
|
+
},
|
|
325
|
+
},
|
|
326
|
+
});
|
|
327
|
+
const orchestrator = createAutoOrchestrator(deps);
|
|
328
|
+
|
|
329
|
+
const result = await orchestrator.resume();
|
|
330
|
+
|
|
331
|
+
assert.equal(result.kind, "blocked");
|
|
332
|
+
if (result.kind !== "blocked") return;
|
|
333
|
+
assert.equal(result.reason, "remediation required");
|
|
334
|
+
});
|
|
335
|
+
|
|
291
336
|
test("advance() uses recovery on error", async () => {
|
|
292
337
|
const { deps, calls } = makeDeps({
|
|
293
338
|
runtime: {
|
|
@@ -797,7 +842,9 @@ test("wired DispatchAdapter forwards session-derived dispatch inputs identically
|
|
|
797
842
|
assert.equal(adapterCtx.midTitle, directCtx.midTitle);
|
|
798
843
|
|
|
799
844
|
// Dispatch action equality: both flows reach the same dispatch decision.
|
|
800
|
-
|
|
845
|
+
if (!adapterResult || !("unitType" in adapterResult)) {
|
|
846
|
+
assert.fail("expected adapter result to be a dispatch decision");
|
|
847
|
+
}
|
|
801
848
|
assert.equal(adapterResult.unitType, "execute-task");
|
|
802
849
|
assert.equal(adapterResult.unitId, "T01");
|
|
803
850
|
assert.equal(adapterResult.reason, "test-capture");
|
|
@@ -872,3 +919,35 @@ test("wired DispatchAdapter prefers caller-supplied dispatch inputs over ctx-der
|
|
|
872
919
|
resetRegistry();
|
|
873
920
|
}
|
|
874
921
|
});
|
|
922
|
+
|
|
923
|
+
test("wired DispatchAdapter preserves stop reason as a blocked decision", async () => {
|
|
924
|
+
const stateSnapshot = makeState();
|
|
925
|
+
const stopRule: UnifiedRule = {
|
|
926
|
+
name: "test-stop",
|
|
927
|
+
when: "dispatch",
|
|
928
|
+
evaluation: "first-match",
|
|
929
|
+
where: async () => ({
|
|
930
|
+
action: "stop" as const,
|
|
931
|
+
reason: "remediation blocker",
|
|
932
|
+
level: "warning" as const,
|
|
933
|
+
}),
|
|
934
|
+
then: (r: unknown) => r,
|
|
935
|
+
};
|
|
936
|
+
setRegistry(new RuleRegistry([stopRule]));
|
|
937
|
+
|
|
938
|
+
try {
|
|
939
|
+
const ctx = { model: {}, modelRegistry: { getAll: () => [] } } as any;
|
|
940
|
+
const pi = { getActiveTools: () => [] } as any;
|
|
941
|
+
const adapter = createWiredDispatchAdapter(ctx, pi, "/tmp/parity-fixture");
|
|
942
|
+
|
|
943
|
+
const result = await adapter.decideNextUnit({ stateSnapshot });
|
|
944
|
+
|
|
945
|
+
assert.deepEqual(result, {
|
|
946
|
+
kind: "blocked",
|
|
947
|
+
reason: "remediation blocker",
|
|
948
|
+
action: "pause",
|
|
949
|
+
});
|
|
950
|
+
} finally {
|
|
951
|
+
resetRegistry();
|
|
952
|
+
}
|
|
953
|
+
});
|
|
@@ -43,7 +43,7 @@ test("cleanupAfterLoopExit preserves paused auto badge after provider pause", as
|
|
|
43
43
|
}
|
|
44
44
|
});
|
|
45
45
|
|
|
46
|
-
test("cleanupAfterLoopExit clears status without replacing
|
|
46
|
+
test("cleanupAfterLoopExit clears status and progress widget without replacing outcome surface", async () => {
|
|
47
47
|
const statusCalls: unknown[] = [];
|
|
48
48
|
const widgetCalls: unknown[] = [];
|
|
49
49
|
|
|
@@ -64,8 +64,8 @@ test("cleanupAfterLoopExit clears status without replacing the last auto surface
|
|
|
64
64
|
assert.deepEqual(statusCalls, [["gsd-auto", undefined]]);
|
|
65
65
|
assert.equal(
|
|
66
66
|
widgetCalls.some((args) => Array.isArray(args) && args[0] === "gsd-progress" && args[1] === undefined),
|
|
67
|
-
|
|
68
|
-
"cleanup must
|
|
67
|
+
true,
|
|
68
|
+
"cleanup must clear the stale auto progress widget",
|
|
69
69
|
);
|
|
70
70
|
assert.equal(
|
|
71
71
|
widgetCalls.some((args) => Array.isArray(args) && args[0] === "gsd-outcome"),
|
|
@@ -79,7 +79,7 @@ test("cleanupAfterLoopExit clears status without replacing the last auto surface
|
|
|
79
79
|
}
|
|
80
80
|
});
|
|
81
81
|
|
|
82
|
-
test("cleanupAfterLoopExit
|
|
82
|
+
test("cleanupAfterLoopExit clears progress widget after stopAuto reset", async () => {
|
|
83
83
|
const statusCalls: unknown[] = [];
|
|
84
84
|
const widgetCalls: unknown[] = [];
|
|
85
85
|
|
|
@@ -103,8 +103,8 @@ test("cleanupAfterLoopExit preserves completion roll-up after stopAuto reset", a
|
|
|
103
103
|
assert.deepEqual(statusCalls, [["gsd-auto", undefined]]);
|
|
104
104
|
assert.equal(
|
|
105
105
|
widgetCalls.some((args) => Array.isArray(args) && args[0] === "gsd-progress" && args[1] === undefined),
|
|
106
|
-
|
|
107
|
-
"completion cleanup must
|
|
106
|
+
true,
|
|
107
|
+
"completion cleanup must clear the stale progress widget",
|
|
108
108
|
);
|
|
109
109
|
assert.equal(
|
|
110
110
|
widgetCalls.some((args) => Array.isArray(args) && args[0] === "gsd-outcome"),
|
|
@@ -3,7 +3,11 @@
|
|
|
3
3
|
import test from "node:test";
|
|
4
4
|
import assert from "node:assert/strict";
|
|
5
5
|
|
|
6
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
buildStepCompleteMessage,
|
|
8
|
+
shouldReturnStepWizardAfterUnit,
|
|
9
|
+
STEP_COMPLETE_FALLBACK_MESSAGE,
|
|
10
|
+
} from "../auto-post-unit.ts";
|
|
7
11
|
import type { GSDState } from "../types.ts";
|
|
8
12
|
|
|
9
13
|
function makeState(overrides: Partial<GSDState>): GSDState {
|
|
@@ -51,3 +55,10 @@ test("STEP_COMPLETE_FALLBACK_MESSAGE: used when deriveState throws, still points
|
|
|
51
55
|
assert.match(STEP_COMPLETE_FALLBACK_MESSAGE, /\/clear/);
|
|
52
56
|
assert.match(STEP_COMPLETE_FALLBACK_MESSAGE, /\/gsd/);
|
|
53
57
|
});
|
|
58
|
+
|
|
59
|
+
test("shouldReturnStepWizardAfterUnit: terminal milestone completion continues to merge-back path", () => {
|
|
60
|
+
assert.equal(shouldReturnStepWizardAfterUnit("complete-milestone", "complete"), false);
|
|
61
|
+
assert.equal(shouldReturnStepWizardAfterUnit("complete-milestone", null), false);
|
|
62
|
+
assert.equal(shouldReturnStepWizardAfterUnit("execute-task", "complete"), false);
|
|
63
|
+
assert.equal(shouldReturnStepWizardAfterUnit("execute-task", "executing"), true);
|
|
64
|
+
});
|
|
@@ -5,7 +5,7 @@ import { join } from "node:path";
|
|
|
5
5
|
import { tmpdir } from "node:os";
|
|
6
6
|
import { randomUUID } from "node:crypto";
|
|
7
7
|
|
|
8
|
-
import { verifyExpectedArtifact, hasImplementationArtifacts, resolveExpectedArtifactPath, diagnoseExpectedArtifact, buildLoopRemediationSteps, writeBlockerPlaceholder, refreshRecoveryDbForArtifact } from "../auto-recovery.ts";
|
|
8
|
+
import { verifyExpectedArtifact, hasImplementationArtifacts, resolveExpectedArtifactPath, diagnoseExpectedArtifact, diagnoseWorktreeIntegrityFailure, buildLoopRemediationSteps, writeBlockerPlaceholder, refreshRecoveryDbForArtifact } from "../auto-recovery.ts";
|
|
9
9
|
import { resolveMilestoneFile } from "../paths.ts";
|
|
10
10
|
import { openDatabase, closeDatabase, insertMilestone, insertSlice, insertGateRow, insertTask, getMilestoneCommitAttributionShas } from "../gsd-db.ts";
|
|
11
11
|
import { clearParseCache } from "../files.ts";
|
|
@@ -141,6 +141,20 @@ test("resolveExpectedArtifactPath returns null for unknown type", () => {
|
|
|
141
141
|
}
|
|
142
142
|
});
|
|
143
143
|
|
|
144
|
+
test("diagnoseWorktreeIntegrityFailure reports missing GSD worktree paths only", () => {
|
|
145
|
+
const missingWorktreePath = join(tmpdir(), `gsd-test-${randomUUID()}`, ".gsd", "worktrees", "M001-S01");
|
|
146
|
+
assert.equal(
|
|
147
|
+
diagnoseWorktreeIntegrityFailure(join(tmpdir(), `gsd-test-${randomUUID()}`)),
|
|
148
|
+
null,
|
|
149
|
+
"non-GSD paths should keep falling through to artifact recovery",
|
|
150
|
+
);
|
|
151
|
+
assert.equal(
|
|
152
|
+
diagnoseWorktreeIntegrityFailure(missingWorktreePath),
|
|
153
|
+
`Worktree integrity failure: ${missingWorktreePath} does not exist. Repair or recreate the worktree before retrying.`,
|
|
154
|
+
"missing GSD worktree paths should fail terminally before artifact retry",
|
|
155
|
+
);
|
|
156
|
+
});
|
|
157
|
+
|
|
144
158
|
test("resolveExpectedArtifactPath returns correct path for all milestone-level types", () => {
|
|
145
159
|
const base = makeTmpBase();
|
|
146
160
|
try {
|
|
@@ -98,6 +98,7 @@ test("bootstrap aborts before starting next milestone when completed orphan merg
|
|
|
98
98
|
{
|
|
99
99
|
shouldUseWorktreeIsolation: () => true,
|
|
100
100
|
registerSigtermHandler: () => {},
|
|
101
|
+
registerAutoWorkerForSession: () => {},
|
|
101
102
|
lockBase: () => base,
|
|
102
103
|
buildLifecycle: () => ({
|
|
103
104
|
adoptSessionRoot: (sessionBase: string, originalBase?: string) => {
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import { describe, test, beforeEach } from "node:test";
|
|
4
4
|
import assert from "node:assert/strict";
|
|
5
|
-
import { mkdtempSync, mkdirSync, writeFileSync, rmSync, realpathSync } from "node:fs";
|
|
5
|
+
import { existsSync, mkdtempSync, mkdirSync, writeFileSync, rmSync, realpathSync } from "node:fs";
|
|
6
6
|
import { join } from "node:path";
|
|
7
7
|
import { tmpdir } from "node:os";
|
|
8
8
|
import { execFileSync } from "node:child_process";
|
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
_resetAutoWorktreeOriginalBaseForTests,
|
|
14
14
|
createAutoWorktree,
|
|
15
15
|
enterAutoWorktree,
|
|
16
|
+
mergeMilestoneToMain,
|
|
16
17
|
teardownAutoWorktree,
|
|
17
18
|
} from "../auto-worktree.ts";
|
|
18
19
|
|
|
@@ -173,4 +174,71 @@ describe("auto-worktree workspace registry", () => {
|
|
|
173
174
|
teardownAutoWorktree(dir2, "M020");
|
|
174
175
|
try { process.chdir(savedCwd); } catch { /* ignore */ }
|
|
175
176
|
});
|
|
177
|
+
|
|
178
|
+
test("mergeMilestoneToMain cleans up when milestone branch was already regular-merged", (t) => {
|
|
179
|
+
const tempDir = createTempRepo(t);
|
|
180
|
+
const msDir = join(tempDir, ".gsd", "milestones", "M003");
|
|
181
|
+
mkdirSync(msDir, { recursive: true });
|
|
182
|
+
writeFileSync(join(msDir, "CONTEXT.md"), "# M003 Context\n");
|
|
183
|
+
git(["add", "."], tempDir);
|
|
184
|
+
git(["commit", "-m", "add milestone"], tempDir);
|
|
185
|
+
|
|
186
|
+
createAutoWorktree(tempDir, "M003");
|
|
187
|
+
const wtDir = join(tempDir, ".gsd", "worktrees", "M003");
|
|
188
|
+
writeFileSync(join(wtDir, "feature.txt"), "implemented\n");
|
|
189
|
+
git(["add", "feature.txt"], wtDir);
|
|
190
|
+
git(["commit", "-m", "feat: implement M003"], wtDir);
|
|
191
|
+
|
|
192
|
+
process.chdir(tempDir);
|
|
193
|
+
git(["merge", "--no-ff", "milestone/M003", "-m", "merge M003"], tempDir);
|
|
194
|
+
|
|
195
|
+
process.chdir(wtDir);
|
|
196
|
+
const result = mergeMilestoneToMain(tempDir, "M003", "# M003\n- [x] **S01: Done**\n");
|
|
197
|
+
|
|
198
|
+
assert.equal(result.codeFilesChanged, true);
|
|
199
|
+
assert.equal(result.pushed, false);
|
|
200
|
+
assert.equal(result.prCreated, false);
|
|
201
|
+
assert.equal(existsSync(wtDir), false, "worktree directory is removed");
|
|
202
|
+
assert.throws(
|
|
203
|
+
() => git(["rev-parse", "--verify", "milestone/M003"], tempDir),
|
|
204
|
+
/Command failed/,
|
|
205
|
+
"already-merged milestone branch is deleted",
|
|
206
|
+
);
|
|
207
|
+
try { process.chdir(savedCwd); } catch { /* ignore */ }
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
test("mergeMilestoneToMain cleans up already-merged milestone after main advances", (t) => {
|
|
211
|
+
const tempDir = createTempRepo(t);
|
|
212
|
+
const msDir = join(tempDir, ".gsd", "milestones", "M004");
|
|
213
|
+
mkdirSync(msDir, { recursive: true });
|
|
214
|
+
writeFileSync(join(msDir, "CONTEXT.md"), "# M004 Context\n");
|
|
215
|
+
git(["add", "."], tempDir);
|
|
216
|
+
git(["commit", "-m", "add milestone"], tempDir);
|
|
217
|
+
|
|
218
|
+
createAutoWorktree(tempDir, "M004");
|
|
219
|
+
const wtDir = join(tempDir, ".gsd", "worktrees", "M004");
|
|
220
|
+
writeFileSync(join(wtDir, "feature.txt"), "implemented\n");
|
|
221
|
+
git(["add", "feature.txt"], wtDir);
|
|
222
|
+
git(["commit", "-m", "feat: implement M004"], wtDir);
|
|
223
|
+
|
|
224
|
+
process.chdir(tempDir);
|
|
225
|
+
git(["merge", "--no-ff", "milestone/M004", "-m", "merge M004"], tempDir);
|
|
226
|
+
writeFileSync(join(tempDir, "hotfix.txt"), "later main work\n");
|
|
227
|
+
git(["add", "hotfix.txt"], tempDir);
|
|
228
|
+
git(["commit", "-m", "fix: advance main"], tempDir);
|
|
229
|
+
|
|
230
|
+
process.chdir(wtDir);
|
|
231
|
+
const result = mergeMilestoneToMain(tempDir, "M004", "# M004\n- [x] **S01: Done**\n");
|
|
232
|
+
|
|
233
|
+
assert.equal(result.codeFilesChanged, true);
|
|
234
|
+
assert.equal(result.pushed, false);
|
|
235
|
+
assert.equal(result.prCreated, false);
|
|
236
|
+
assert.equal(existsSync(wtDir), false, "worktree directory is removed");
|
|
237
|
+
assert.throws(
|
|
238
|
+
() => git(["rev-parse", "--verify", "milestone/M004"], tempDir),
|
|
239
|
+
/Command failed/,
|
|
240
|
+
"already-merged milestone branch is deleted",
|
|
241
|
+
);
|
|
242
|
+
try { process.chdir(savedCwd); } catch { /* ignore */ }
|
|
243
|
+
});
|
|
176
244
|
});
|
|
@@ -645,7 +645,7 @@ describe("complete-milestone", () => {
|
|
|
645
645
|
assert.strictEqual(sanitized.triggerReason, undefined);
|
|
646
646
|
});
|
|
647
647
|
|
|
648
|
-
test("rendered SUMMARY.md uses
|
|
648
|
+
test("rendered SUMMARY.md uses empty frontmatter lists for empty key fields", async () => {
|
|
649
649
|
const { handleCompleteMilestone } = await import("../tools/complete-milestone.ts");
|
|
650
650
|
const base = createFixtureBase();
|
|
651
651
|
const mid = "M001";
|
|
@@ -678,6 +678,9 @@ describe("complete-milestone", () => {
|
|
|
678
678
|
assert.match(summary, /## Success Criteria Results\n\nNot provided\./);
|
|
679
679
|
assert.match(summary, /## Definition of Done Results\n\nNot provided\./);
|
|
680
680
|
assert.match(summary, /## Requirement Outcomes\n\nNot provided\./);
|
|
681
|
+
assert.match(summary, /key_decisions:\s*\[\]/);
|
|
682
|
+
assert.match(summary, /key_files:\s*\[\]/);
|
|
683
|
+
assert.doesNotMatch(summary, /key_(?:decisions|files):\n - \(none\)/);
|
|
681
684
|
assert.match(summary, /## Deviations\n\nNone\./);
|
|
682
685
|
assert.match(summary, /## Follow-ups\n\nNone\./);
|
|
683
686
|
} finally {
|
|
@@ -408,10 +408,10 @@ console.log('\n=== complete-slice: handler with missing roadmap ===');
|
|
|
408
408
|
}
|
|
409
409
|
|
|
410
410
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
411
|
-
// complete-slice:
|
|
411
|
+
// complete-slice: PROJECT refresh uses DB-backed artifact tool.
|
|
412
412
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
413
413
|
|
|
414
|
-
console.log('\n=== complete-slice:
|
|
414
|
+
console.log('\n=== complete-slice: PROJECT refresh uses gsd_summary_save ===');
|
|
415
415
|
{
|
|
416
416
|
const promptPath = path.join(
|
|
417
417
|
path.dirname(new URL(import.meta.url).pathname),
|
|
@@ -419,13 +419,9 @@ console.log('\n=== complete-slice: step 13 specifies write tool for PROJECT.md (
|
|
|
419
419
|
);
|
|
420
420
|
const prompt = fs.readFileSync(promptPath, 'utf-8');
|
|
421
421
|
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
const mentionsWriteTool =
|
|
426
|
-
/PROJECT\.md.*\bwrite\b/i.test(prompt) ||
|
|
427
|
-
/\bwrite\b.*PROJECT\.md/i.test(prompt);
|
|
428
|
-
assertTrue(mentionsWriteTool, 'step 13 must name the `write` tool when updating PROJECT.md');
|
|
422
|
+
assertTrue(prompt.includes('gsd_summary_save'), 'PROJECT refresh must use gsd_summary_save');
|
|
423
|
+
assertTrue(prompt.includes('artifact_type: "PROJECT"'), 'PROJECT refresh must use artifact_type PROJECT');
|
|
424
|
+
assertTrue(!/with a full `write`/i.test(prompt), 'prompt must not instruct direct PROJECT.md writes');
|
|
429
425
|
}
|
|
430
426
|
|
|
431
427
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
@@ -491,7 +491,9 @@ console.log('\n=== complete-task: minimal params (no keyFiles, keyDecisions, ver
|
|
|
491
491
|
assertTrue(fs.existsSync(result.summaryPath), 'summary file should be written with minimal params');
|
|
492
492
|
const summaryContent = fs.readFileSync(result.summaryPath, 'utf-8');
|
|
493
493
|
assertMatch(summaryContent, /blocker_discovered:\s*false/, 'blocker_discovered should default to false');
|
|
494
|
-
assertMatch(summaryContent,
|
|
494
|
+
assertMatch(summaryContent, /key_files:\s*\[\]/, 'key_files should render as an empty frontmatter list');
|
|
495
|
+
assertMatch(summaryContent, /key_decisions:\s*\[\]/, 'key_decisions should render as an empty frontmatter list');
|
|
496
|
+
assertTrue(!summaryContent.includes(' - (none)'), 'empty frontmatter lists should not render (none) as a list item');
|
|
495
497
|
}
|
|
496
498
|
|
|
497
499
|
cleanupDir(basePath);
|
|
@@ -19,14 +19,15 @@ import {
|
|
|
19
19
|
insertMilestone,
|
|
20
20
|
_getAdapter,
|
|
21
21
|
} from "../gsd-db.ts";
|
|
22
|
-
import { registerAutoWorker } from "../db/auto-workers.ts";
|
|
22
|
+
import { getAutoWorker, registerAutoWorker } from "../db/auto-workers.ts";
|
|
23
23
|
import { claimMilestoneLease } from "../db/milestone-leases.ts";
|
|
24
|
-
import { recordDispatchClaim } from "../db/unit-dispatches.ts";
|
|
24
|
+
import { getLatestForUnit, markRunning, recordDispatchClaim } from "../db/unit-dispatches.ts";
|
|
25
25
|
import { setRuntimeKv, getRuntimeKv } from "../db/runtime-kv.ts";
|
|
26
26
|
import {
|
|
27
27
|
writeLock,
|
|
28
28
|
readCrashLock,
|
|
29
29
|
clearLock,
|
|
30
|
+
clearStaleWorkerLock,
|
|
30
31
|
isLockProcessAlive,
|
|
31
32
|
} from "../crash-recovery.ts";
|
|
32
33
|
import { normalizeRealPath } from "../paths.ts";
|
|
@@ -223,3 +224,43 @@ test("clearLock removes the session_file row for the active worker", (t) => {
|
|
|
223
224
|
assert.equal(getRuntimeKv("worker", workerId, "session_file"), null,
|
|
224
225
|
"session_file row deleted by clearLock");
|
|
225
226
|
});
|
|
227
|
+
|
|
228
|
+
test("clearStaleWorkerLock crashes stale worker and cancels latest active dispatch", (t) => {
|
|
229
|
+
const base = makeBase();
|
|
230
|
+
t.after(() => cleanup(base));
|
|
231
|
+
openDatabase(join(base, ".gsd", "gsd.db"));
|
|
232
|
+
insertMilestone({ id: "M001", title: "T", status: "active" });
|
|
233
|
+
const projectRoot = normalizeRealPath(base);
|
|
234
|
+
const workerId = registerAutoWorker({ projectRootRealpath: projectRoot });
|
|
235
|
+
const lease = claimMilestoneLease(workerId, "M001");
|
|
236
|
+
assert.equal(lease.ok, true);
|
|
237
|
+
if (!lease.ok) return;
|
|
238
|
+
const claim = recordDispatchClaim({
|
|
239
|
+
traceId: "t1",
|
|
240
|
+
workerId,
|
|
241
|
+
milestoneLeaseToken: lease.token,
|
|
242
|
+
milestoneId: "M001",
|
|
243
|
+
sliceId: "S01",
|
|
244
|
+
taskId: "T02",
|
|
245
|
+
unitType: "hook/codex-review",
|
|
246
|
+
unitId: "M001/S01/T02",
|
|
247
|
+
});
|
|
248
|
+
assert.equal(claim.ok, true);
|
|
249
|
+
if (!claim.ok) return;
|
|
250
|
+
markRunning(claim.dispatchId);
|
|
251
|
+
setRuntimeKv("worker", workerId, "session_file", "/tmp/pi-session-hook.jsonl");
|
|
252
|
+
setWorkerPid(workerId, 99999);
|
|
253
|
+
expireWorker(workerId);
|
|
254
|
+
|
|
255
|
+
assert.ok(readCrashLock(base), "stale worker is detected before cleanup");
|
|
256
|
+
|
|
257
|
+
clearStaleWorkerLock(base);
|
|
258
|
+
|
|
259
|
+
assert.equal(getAutoWorker(workerId)?.status, "crashed");
|
|
260
|
+
const dispatch = getLatestForUnit("M001/S01/T02");
|
|
261
|
+
assert.ok(dispatch);
|
|
262
|
+
assert.equal(dispatch!.status, "canceled");
|
|
263
|
+
assert.equal(dispatch!.exit_reason, "crash-recovered");
|
|
264
|
+
assert.equal(getRuntimeKv("worker", workerId, "session_file"), null);
|
|
265
|
+
assert.equal(readCrashLock(base), null);
|
|
266
|
+
});
|