gsd-pi 2.82.0 → 3.0.0
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 +51 -32
- package/dist/resources/.managed-resources-content-hash +1 -1
- package/dist/resources/GSD-WORKFLOW.md +10 -1
- package/dist/resources/extensions/browser-tools/tools/screenshot.js +1 -0
- package/dist/resources/extensions/browser-tools/tools/zoom.js +1 -0
- package/dist/resources/extensions/claude-code-cli/partial-builder.js +2 -1
- package/dist/resources/extensions/claude-code-cli/stream-adapter.js +1 -1
- package/dist/resources/extensions/cmux/index.js +5 -0
- package/dist/resources/extensions/gsd/auto/infra-errors.js +9 -3
- package/dist/resources/extensions/gsd/auto/loop.js +19 -6
- package/dist/resources/extensions/gsd/auto/orchestrator.js +124 -6
- package/dist/resources/extensions/gsd/auto/phases.js +90 -31
- package/dist/resources/extensions/gsd/auto/session.js +4 -0
- package/dist/resources/extensions/gsd/auto/workflow-kernel.js +3 -0
- package/dist/resources/extensions/gsd/auto/workflow-memory-pressure.js +12 -0
- package/dist/resources/extensions/gsd/auto-dashboard.js +66 -1
- package/dist/resources/extensions/gsd/auto-direct-dispatch.js +1 -0
- package/dist/resources/extensions/gsd/auto-dispatch.js +20 -19
- package/dist/resources/extensions/gsd/auto-model-selection.js +2 -0
- package/dist/resources/extensions/gsd/auto-post-unit.js +246 -133
- package/dist/resources/extensions/gsd/auto-prompts.js +13 -5
- package/dist/resources/extensions/gsd/auto-recovery.js +71 -14
- package/dist/resources/extensions/gsd/auto-start.js +87 -14
- package/dist/resources/extensions/gsd/auto-verification.js +45 -26
- package/dist/resources/extensions/gsd/auto-worktree.js +176 -10
- package/dist/resources/extensions/gsd/auto.js +178 -63
- package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +31 -7
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +10 -9
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +9 -2
- package/dist/resources/extensions/gsd/bootstrap/subagent-input.js +21 -9
- package/dist/resources/extensions/gsd/bootstrap/system-context.js +55 -12
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +17 -3
- package/dist/resources/extensions/gsd/clean-root-preflight.js +170 -8
- package/dist/resources/extensions/gsd/commands/catalog.js +10 -1
- package/dist/resources/extensions/gsd/commands/handlers/core.js +39 -1
- package/dist/resources/extensions/gsd/commands/handlers/ops.js +5 -0
- package/dist/resources/extensions/gsd/commands-bootstrap.js +5 -0
- package/dist/resources/extensions/gsd/commands-handlers.js +15 -2
- package/dist/resources/extensions/gsd/commands-prefs-wizard.js +7 -2
- package/dist/resources/extensions/gsd/commands-verdict.js +139 -0
- package/dist/resources/extensions/gsd/context-store.js +112 -0
- package/dist/resources/extensions/gsd/crash-recovery.js +43 -5
- package/dist/resources/extensions/gsd/db/milestone-leases.js +24 -0
- package/dist/resources/extensions/gsd/db/unit-dispatches.js +3 -2
- package/dist/resources/extensions/gsd/db-writer.js +150 -84
- package/dist/resources/extensions/gsd/dispatch-guard.js +2 -2
- package/dist/resources/extensions/gsd/docs/preferences-reference.md +1 -1
- package/dist/resources/extensions/gsd/doctor-git-checks.js +87 -7
- 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/forensics.js +3 -3
- package/dist/resources/extensions/gsd/git-service.js +45 -3
- package/dist/resources/extensions/gsd/gsd-db.js +21 -6
- package/dist/resources/extensions/gsd/guided-flow-queue.js +4 -3
- package/dist/resources/extensions/gsd/guided-flow.js +101 -116
- package/dist/resources/extensions/gsd/guided-unit-context.js +23 -0
- package/dist/resources/extensions/gsd/knowledge-backfill.js +144 -0
- package/dist/resources/extensions/gsd/knowledge-capture.js +136 -0
- package/dist/resources/extensions/gsd/knowledge-parser.js +154 -0
- package/dist/resources/extensions/gsd/knowledge-projection.js +210 -0
- package/dist/resources/extensions/gsd/markdown-renderer.js +16 -9
- package/dist/resources/extensions/gsd/md-importer.js +1 -1
- package/dist/resources/extensions/gsd/memory-backfill.js +73 -17
- package/dist/resources/extensions/gsd/memory-consolidation-scanner.js +222 -0
- package/dist/resources/extensions/gsd/migrate/command.js +5 -0
- package/dist/resources/extensions/gsd/migrate/parsers.js +10 -0
- package/dist/resources/extensions/gsd/migrate/preview.js +9 -0
- package/dist/resources/extensions/gsd/migrate/transformer.js +51 -4
- package/dist/resources/extensions/gsd/migrate/writer.js +11 -1
- 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/paths.js +4 -0
- package/dist/resources/extensions/gsd/pending-auto-start.js +52 -0
- 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/prompts/system.md +2 -2
- package/dist/resources/extensions/gsd/provider-switch-observer.js +146 -0
- package/dist/resources/extensions/gsd/queue-reorder-ui.js +30 -13
- package/dist/resources/extensions/gsd/smart-entry-routing.js +36 -0
- 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/state.js +3 -3
- package/dist/resources/extensions/gsd/status-guards.js +11 -0
- package/dist/resources/extensions/gsd/templates/knowledge.md +2 -2
- package/dist/resources/extensions/gsd/templates/plan.md +9 -5
- package/dist/resources/extensions/gsd/templates/task-plan.md +10 -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 +87 -14
- package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +119 -0
- package/dist/resources/extensions/gsd/unit-context-manifest.js +32 -10
- package/dist/resources/extensions/gsd/validation.js +23 -1
- package/dist/resources/extensions/gsd/verification-gate.js +68 -7
- package/dist/resources/extensions/gsd/verification-verdict.js +26 -0
- package/dist/resources/extensions/gsd/workflow-mcp.js +17 -1
- package/dist/resources/extensions/gsd/workflow-projections.js +6 -8
- package/dist/resources/extensions/gsd/worktree-lifecycle.js +54 -10
- package/dist/resources/extensions/gsd/worktree-manager.js +1 -1
- package/dist/resources/extensions/shared/html-shell.js +388 -0
- package/dist/resources/extensions/subagent/index.js +448 -78
- package/dist/resources/extensions/subagent/launch.js +77 -0
- package/dist/resources/extensions/subagent/run-store.js +148 -0
- package/dist/resources/extensions/ttsr/ttsr-manager.js +3 -1
- package/dist/resources/extensions/visual-brief/artifact-policy.js +29 -0
- package/dist/resources/extensions/visual-brief/extension-manifest.json +8 -0
- package/dist/resources/extensions/visual-brief/index.js +5 -0
- package/dist/resources/extensions/visual-brief/page-contract.js +124 -0
- package/dist/resources/extensions/visual-brief/prompts.js +140 -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 +9 -9
- 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/react-loadable-manifest.json +5 -5
- 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/browse-directories/route.js +1 -1
- 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 +9 -9
- 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/middleware-react-loadable-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/2973.33f26573894b6153.js +2 -0
- package/dist/web/standalone/.next/static/chunks/8359.65b24fac92188a6b.js +10 -0
- package/dist/web/standalone/.next/static/chunks/9441.ff70bb53f6835771.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/layout-b23b3f6858dc6dc8.js +1 -0
- package/dist/web/standalone/.next/static/chunks/{webpack-de742b64187e13fe.js → webpack-855d616060cb6e59.js} +1 -1
- package/dist/web/standalone/.next/static/css/746ee28c929d1880.css +1 -0
- package/package.json +6 -5
- package/packages/contracts/dist/rpc.test.js +7 -0
- package/packages/contracts/dist/rpc.test.js.map +1 -1
- package/packages/contracts/dist/workflow.d.ts +21 -0
- package/packages/contracts/dist/workflow.d.ts.map +1 -1
- package/packages/contracts/dist/workflow.js +24 -0
- package/packages/contracts/dist/workflow.js.map +1 -1
- package/packages/contracts/src/rpc.test.ts +8 -0
- package/packages/contracts/src/workflow.ts +24 -0
- package/packages/daemon/package.json +2 -2
- package/packages/mcp-server/README.md +14 -3
- package/packages/mcp-server/dist/workflow-tools.d.ts +0 -3
- package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.js +80 -0
- package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
- package/packages/mcp-server/package.json +2 -2
- package/packages/mcp-server/src/workflow-tools-parity.test.ts +244 -0
- package/packages/mcp-server/src/workflow-tools.test.ts +23 -1
- package/packages/mcp-server/src/workflow-tools.ts +168 -0
- package/packages/mcp-server/tsconfig.tsbuildinfo +1 -1
- package/packages/native/package.json +1 -1
- package/packages/native/tsconfig.json +2 -1
- package/packages/native/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-agent-core/package.json +1 -1
- package/packages/pi-agent-core/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-ai/dist/index.d.ts +2 -2
- package/packages/pi-ai/dist/index.d.ts.map +1 -1
- package/packages/pi-ai/dist/index.js +1 -1
- package/packages/pi-ai/dist/index.js.map +1 -1
- package/packages/pi-ai/dist/providers/google-gemini-cli.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/google-gemini-cli.js +5 -0
- package/packages/pi-ai/dist/providers/google-gemini-cli.js.map +1 -1
- package/packages/pi-ai/dist/providers/google-gemini-cli.test.d.ts +2 -0
- package/packages/pi-ai/dist/providers/google-gemini-cli.test.d.ts.map +1 -0
- package/packages/pi-ai/dist/providers/google-gemini-cli.test.js +41 -0
- package/packages/pi-ai/dist/providers/google-gemini-cli.test.js.map +1 -0
- 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/dist/providers/transform-messages.d.ts +11 -0
- package/packages/pi-ai/dist/providers/transform-messages.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/transform-messages.js +20 -0
- package/packages/pi-ai/dist/providers/transform-messages.js.map +1 -1
- package/packages/pi-ai/package.json +1 -1
- package/packages/pi-ai/src/index.ts +7 -2
- package/packages/pi-ai/src/providers/google-gemini-cli.test.ts +49 -0
- package/packages/pi-ai/src/providers/google-gemini-cli.ts +7 -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/src/providers/transform-messages.ts +24 -0
- 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/dist/core/chat-controller-ordering.test.js +44 -3
- package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/sdk.js +1 -1
- package/packages/pi-coding-agent/dist/core/sdk.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/system-prompt.js +4 -4
- package/packages/pi-coding-agent/dist/core/system-prompt.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js +24 -6
- package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +71 -97
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-ordering.test.js +25 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-ordering.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts +2 -0
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +24 -10
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/packages/pi-coding-agent/dist/tests/system-prompt-file-safety.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/tests/system-prompt-file-safety.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/tests/system-prompt-file-safety.test.js +17 -0
- package/packages/pi-coding-agent/dist/tests/system-prompt-file-safety.test.js.map +1 -0
- package/packages/pi-coding-agent/package.json +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/src/core/chat-controller-ordering.test.ts +53 -3
- package/packages/pi-coding-agent/src/core/sdk.ts +1 -1
- package/packages/pi-coding-agent/src/core/system-prompt.ts +4 -4
- package/packages/pi-coding-agent/src/modes/interactive/components/footer.ts +23 -7
- package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +75 -102
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode-ordering.test.ts +30 -1
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +29 -10
- package/packages/pi-coding-agent/src/tests/system-prompt-file-safety.test.ts +22 -0
- package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-tui/dist/__tests__/terminal.test.d.ts +2 -0
- package/packages/pi-tui/dist/__tests__/terminal.test.d.ts.map +1 -0
- package/packages/pi-tui/dist/__tests__/terminal.test.js +103 -0
- package/packages/pi-tui/dist/__tests__/terminal.test.js.map +1 -0
- package/packages/pi-tui/dist/terminal.d.ts +2 -0
- package/packages/pi-tui/dist/terminal.d.ts.map +1 -1
- package/packages/pi-tui/dist/terminal.js +12 -0
- package/packages/pi-tui/dist/terminal.js.map +1 -1
- package/packages/pi-tui/dist/tui.d.ts.map +1 -1
- package/packages/pi-tui/dist/tui.js +5 -0
- package/packages/pi-tui/dist/tui.js.map +1 -1
- package/packages/pi-tui/package.json +1 -1
- package/packages/pi-tui/src/__tests__/terminal.test.ts +121 -0
- package/packages/pi-tui/src/terminal.ts +11 -0
- package/packages/pi-tui/src/tui.ts +6 -0
- package/packages/pi-tui/tsconfig.tsbuildinfo +1 -1
- package/packages/rpc-client/package.json +1 -1
- package/packages/rpc-client/tsconfig.tsbuildinfo +1 -1
- package/pkg/package.json +1 -1
- package/src/resources/GSD-WORKFLOW.md +10 -1
- package/src/resources/extensions/browser-tools/tools/screenshot.ts +1 -0
- package/src/resources/extensions/browser-tools/tools/zoom.ts +1 -0
- package/src/resources/extensions/claude-code-cli/partial-builder.ts +2 -1
- package/src/resources/extensions/claude-code-cli/stream-adapter.ts +1 -1
- package/src/resources/extensions/claude-code-cli/tests/partial-builder.test.ts +19 -2
- package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +9 -0
- package/src/resources/extensions/cmux/index.ts +6 -0
- package/src/resources/extensions/gsd/auto/contracts.ts +59 -16
- package/src/resources/extensions/gsd/auto/infra-errors.ts +9 -3
- package/src/resources/extensions/gsd/auto/loop.ts +22 -6
- package/src/resources/extensions/gsd/auto/orchestrator.ts +129 -6
- package/src/resources/extensions/gsd/auto/phases.ts +104 -38
- package/src/resources/extensions/gsd/auto/session.ts +4 -0
- package/src/resources/extensions/gsd/auto/workflow-kernel.ts +5 -1
- package/src/resources/extensions/gsd/auto/workflow-memory-pressure.ts +13 -0
- package/src/resources/extensions/gsd/auto-dashboard.ts +72 -1
- package/src/resources/extensions/gsd/auto-direct-dispatch.ts +1 -0
- package/src/resources/extensions/gsd/auto-dispatch.ts +21 -19
- package/src/resources/extensions/gsd/auto-model-selection.ts +2 -1
- package/src/resources/extensions/gsd/auto-post-unit.ts +279 -144
- package/src/resources/extensions/gsd/auto-prompts.ts +13 -5
- package/src/resources/extensions/gsd/auto-recovery.ts +74 -11
- package/src/resources/extensions/gsd/auto-start.ts +94 -12
- package/src/resources/extensions/gsd/auto-verification.ts +58 -36
- package/src/resources/extensions/gsd/auto-worktree.ts +193 -10
- package/src/resources/extensions/gsd/auto.ts +187 -61
- package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +42 -7
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +10 -9
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +10 -2
- package/src/resources/extensions/gsd/bootstrap/subagent-input.ts +19 -7
- package/src/resources/extensions/gsd/bootstrap/system-context.ts +58 -15
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +20 -4
- package/src/resources/extensions/gsd/clean-root-preflight.ts +174 -8
- package/src/resources/extensions/gsd/commands/catalog.ts +10 -1
- package/src/resources/extensions/gsd/commands/handlers/core.ts +42 -1
- package/src/resources/extensions/gsd/commands/handlers/ops.ts +5 -0
- package/src/resources/extensions/gsd/commands-bootstrap.ts +10 -0
- package/src/resources/extensions/gsd/commands-handlers.ts +19 -2
- package/src/resources/extensions/gsd/commands-prefs-wizard.ts +8 -3
- package/src/resources/extensions/gsd/commands-verdict.ts +202 -0
- package/src/resources/extensions/gsd/context-store.ts +120 -1
- package/src/resources/extensions/gsd/crash-recovery.ts +44 -4
- package/src/resources/extensions/gsd/db/milestone-leases.ts +26 -0
- package/src/resources/extensions/gsd/db/unit-dispatches.ts +4 -3
- package/src/resources/extensions/gsd/db-writer.ts +167 -84
- package/src/resources/extensions/gsd/dispatch-guard.ts +2 -2
- package/src/resources/extensions/gsd/docs/preferences-reference.md +1 -1
- package/src/resources/extensions/gsd/doctor-git-checks.ts +89 -7
- package/src/resources/extensions/gsd/doctor-runtime-checks.ts +25 -13
- package/src/resources/extensions/gsd/doctor-types.ts +3 -0
- package/src/resources/extensions/gsd/doctor.ts +2 -27
- package/src/resources/extensions/gsd/export-html.ts +27 -427
- package/src/resources/extensions/gsd/forensics.ts +3 -3
- package/src/resources/extensions/gsd/git-service.ts +51 -4
- package/src/resources/extensions/gsd/gsd-db.ts +21 -6
- package/src/resources/extensions/gsd/guided-flow-queue.ts +4 -3
- package/src/resources/extensions/gsd/guided-flow.ts +134 -133
- package/src/resources/extensions/gsd/guided-unit-context.ts +30 -0
- package/src/resources/extensions/gsd/knowledge-backfill.ts +164 -0
- package/src/resources/extensions/gsd/knowledge-capture.ts +160 -0
- package/src/resources/extensions/gsd/knowledge-parser.ts +174 -0
- package/src/resources/extensions/gsd/knowledge-projection.ts +241 -0
- package/src/resources/extensions/gsd/markdown-renderer.ts +16 -9
- package/src/resources/extensions/gsd/md-importer.ts +1 -1
- package/src/resources/extensions/gsd/memory-backfill.ts +89 -17
- package/src/resources/extensions/gsd/memory-consolidation-scanner.ts +277 -0
- package/src/resources/extensions/gsd/migrate/command.ts +5 -0
- package/src/resources/extensions/gsd/migrate/parsers.ts +11 -0
- package/src/resources/extensions/gsd/migrate/preview.ts +10 -0
- package/src/resources/extensions/gsd/migrate/transformer.ts +58 -4
- package/src/resources/extensions/gsd/migrate/writer.ts +14 -1
- 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/paths.ts +5 -0
- package/src/resources/extensions/gsd/pending-auto-start.ts +79 -0
- 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/prompts/system.md +2 -2
- package/src/resources/extensions/gsd/provider-switch-observer.ts +185 -0
- package/src/resources/extensions/gsd/queue-reorder-ui.ts +31 -13
- package/src/resources/extensions/gsd/smart-entry-routing.ts +77 -0
- 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/state.ts +3 -3
- package/src/resources/extensions/gsd/status-guards.ts +13 -0
- package/src/resources/extensions/gsd/templates/knowledge.md +2 -2
- package/src/resources/extensions/gsd/templates/plan.md +9 -5
- package/src/resources/extensions/gsd/templates/task-plan.md +10 -2
- package/src/resources/extensions/gsd/tests/auto-dashboard.test.ts +71 -0
- 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 +131 -0
- package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +487 -4
- package/src/resources/extensions/gsd/tests/auto-paused-ui-cleanup.test.ts +151 -12
- package/src/resources/extensions/gsd/tests/auto-phases-lifecycle.test.ts +53 -2
- package/src/resources/extensions/gsd/tests/auto-post-unit-step-message.test.ts +18 -6
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +91 -6
- package/src/resources/extensions/gsd/tests/auto-runtime-state.test.ts +4 -4
- package/src/resources/extensions/gsd/tests/auto-start-orphan-bootstrap.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/auto-stop-notification.test.ts +20 -0
- package/src/resources/extensions/gsd/tests/auto-worktree-registry.test.ts +69 -1
- package/src/resources/extensions/gsd/tests/brief-command.test.ts +89 -0
- package/src/resources/extensions/gsd/tests/browser-tools-compatibility-declarations.test.ts +62 -0
- package/src/resources/extensions/gsd/tests/checkout-branch-stash-guard.test.ts +87 -0
- package/src/resources/extensions/gsd/tests/clean-root-preflight.test.ts +107 -2
- package/src/resources/extensions/gsd/tests/clear-stale-autostart.test.ts +11 -2
- package/src/resources/extensions/gsd/tests/closeout-git-deferral.test.ts +16 -0
- package/src/resources/extensions/gsd/tests/commands-verdict.test.ts +378 -0
- 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/context-store-decisions-from-memories.test.ts +312 -0
- package/src/resources/extensions/gsd/tests/crash-recovery-via-db.test.ts +86 -2
- package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +2 -0
- package/src/resources/extensions/gsd/tests/db-authority-regression.test.ts +208 -0
- package/src/resources/extensions/gsd/tests/db-writer.test.ts +13 -8
- package/src/resources/extensions/gsd/tests/decisions-projection-from-memories.test.ts +453 -0
- package/src/resources/extensions/gsd/tests/decisions-stop-table-writes.test.ts +348 -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 +66 -0
- package/src/resources/extensions/gsd/tests/dispatch-guard.test.ts +27 -0
- package/src/resources/extensions/gsd/tests/doctor-empty-worktree.test.ts +65 -0
- package/src/resources/extensions/gsd/tests/evidence-cross-ref.test.ts +38 -0
- package/src/resources/extensions/gsd/tests/export-html-enhancements.test.ts +8 -0
- package/src/resources/extensions/gsd/tests/freeform-decisions.test.ts +8 -4
- package/src/resources/extensions/gsd/tests/gsd-db.test.ts +11 -0
- package/src/resources/extensions/gsd/tests/gsd-tools.test.ts +11 -7
- package/src/resources/extensions/gsd/tests/gsdroot-worktree-detection.test.ts +5 -2
- package/src/resources/extensions/gsd/tests/guided-discuss-project-prompt-rendering.test.ts +2 -0
- package/src/resources/extensions/gsd/tests/guided-dispatch-root.test.ts +106 -0
- package/src/resources/extensions/gsd/tests/guided-flow-session-isolation.test.ts +59 -11
- package/src/resources/extensions/gsd/tests/guided-flow.test.ts +21 -0
- package/src/resources/extensions/gsd/tests/guided-tool-contract.test.ts +65 -0
- package/src/resources/extensions/gsd/tests/headless-milestone-parity.test.ts +7 -7
- 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-git.test.ts +44 -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 +112 -1
- package/src/resources/extensions/gsd/tests/integration/integration-lifecycle.test.ts +13 -5
- package/src/resources/extensions/gsd/tests/integration/migrate-command.test.ts +48 -3
- package/src/resources/extensions/gsd/tests/integration/state-machine-runtime-failures.test.ts +6 -1
- package/src/resources/extensions/gsd/tests/journal-integration.test.ts +46 -0
- package/src/resources/extensions/gsd/tests/knowledge-backfill-projection.test.ts +323 -0
- package/src/resources/extensions/gsd/tests/knowledge-capture.test.ts +242 -0
- package/src/resources/extensions/gsd/tests/knowledge.test.ts +47 -2
- package/src/resources/extensions/gsd/tests/load-knowledge-block-rules-only.test.ts +209 -0
- package/src/resources/extensions/gsd/tests/memory-consolidation-scanner.test.ts +316 -0
- package/src/resources/extensions/gsd/tests/merge-db-cycle.test.ts +179 -0
- package/src/resources/extensions/gsd/tests/migrate-transformer.test.ts +5 -1
- package/src/resources/extensions/gsd/tests/migrate-validator-parsers.test.ts +24 -1
- package/src/resources/extensions/gsd/tests/migrate-writer-integration.test.ts +6 -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/pending-autostart-scope.test.ts +29 -5
- package/src/resources/extensions/gsd/tests/pipeline-variant-dispatch.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/plan-milestone-sketch-render.test.ts +157 -0
- 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 +251 -2
- package/src/resources/extensions/gsd/tests/plan-task.test.ts +17 -0
- package/src/resources/extensions/gsd/tests/post-exec-retry-bypass.test.ts +79 -1
- 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/post-unit-state-rebuild.test.ts +84 -0
- package/src/resources/extensions/gsd/tests/pre-execution-checks.test.ts +53 -0
- package/src/resources/extensions/gsd/tests/prefs-wizard-coverage.test.ts +59 -0
- package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +8 -0
- package/src/resources/extensions/gsd/tests/prompt-loader.test.ts +23 -0
- package/src/resources/extensions/gsd/tests/provider-errors.test.ts +37 -1
- package/src/resources/extensions/gsd/tests/provider-switch-observer.test.ts +252 -0
- package/src/resources/extensions/gsd/tests/quality-gates.test.ts +6 -0
- package/src/resources/extensions/gsd/tests/queue-reorder-ui.test.ts +54 -0
- package/src/resources/extensions/gsd/tests/remediation-completion-guard.test.ts +89 -2
- package/src/resources/extensions/gsd/tests/run-uat-replay-cap.test.ts +2 -3
- package/src/resources/extensions/gsd/tests/session-start-footer.test.ts +16 -4
- package/src/resources/extensions/gsd/tests/session-switch-abort-misclassification.test.ts +10 -0
- package/src/resources/extensions/gsd/tests/smart-entry-routing.test.ts +113 -0
- package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +53 -2
- package/src/resources/extensions/gsd/tests/state-corruption-2945.test.ts +6 -0
- package/src/resources/extensions/gsd/tests/state-reconciliation-drift.test.ts +119 -23
- package/src/resources/extensions/gsd/tests/status-guards.test.ts +13 -1
- 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 +103 -7
- package/src/resources/extensions/gsd/tests/validate-milestone-stuck-guard.test.ts +29 -2
- package/src/resources/extensions/gsd/tests/verification-gate.test.ts +110 -1
- package/src/resources/extensions/gsd/tests/verification-verdict.test.ts +78 -0
- package/src/resources/extensions/gsd/tests/workflow-kernel.test.ts +7 -0
- package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +19 -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/worktree-lifecycle.test.ts +25 -0
- package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +54 -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 +97 -12
- package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +135 -0
- package/src/resources/extensions/gsd/types.ts +1 -1
- package/src/resources/extensions/gsd/unit-context-manifest.ts +47 -11
- package/src/resources/extensions/gsd/validation.ts +23 -1
- package/src/resources/extensions/gsd/verification-gate.ts +78 -6
- package/src/resources/extensions/gsd/verification-verdict.ts +47 -0
- package/src/resources/extensions/gsd/workflow-logger.ts +4 -0
- package/src/resources/extensions/gsd/workflow-mcp.ts +18 -1
- package/src/resources/extensions/gsd/workflow-projections.ts +6 -8
- package/src/resources/extensions/gsd/worktree-lifecycle.ts +61 -10
- package/src/resources/extensions/gsd/worktree-manager.ts +1 -1
- package/src/resources/extensions/shared/html-shell.ts +412 -0
- package/src/resources/extensions/subagent/index.ts +567 -103
- package/src/resources/extensions/subagent/launch.ts +131 -0
- package/src/resources/extensions/subagent/run-store.ts +218 -0
- package/src/resources/extensions/subagent/tests/launch.test.ts +115 -0
- package/src/resources/extensions/subagent/tests/run-store.test.ts +111 -0
- package/src/resources/extensions/ttsr/ttsr-manager.ts +5 -1
- package/src/resources/extensions/visual-brief/artifact-policy.ts +41 -0
- package/src/resources/extensions/visual-brief/extension-manifest.json +8 -0
- package/src/resources/extensions/visual-brief/index.ts +8 -0
- package/src/resources/extensions/visual-brief/page-contract.ts +136 -0
- package/src/resources/extensions/visual-brief/prompts.ts +183 -0
- package/src/resources/extensions/visual-brief/tests/visual-brief.test.ts +212 -0
- package/dist/web/standalone/.next/server/chunks/5822.js +0 -2
- package/dist/web/standalone/.next/static/chunks/2556.0527fea66e123b7f.js +0 -1
- package/dist/web/standalone/.next/static/chunks/8359.e059d86b255fce1c.js +0 -10
- package/dist/web/standalone/.next/static/chunks/9441.1081da1125d1764f.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/layout-9ecfd95f343793f0.js +0 -1
- package/dist/web/standalone/.next/static/css/54ec2745c1da488b.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/{S44UQTFCUdA44dkjfYt6S → qoMxZh-xuwuvpFW0x0k01}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{S44UQTFCUdA44dkjfYt6S → qoMxZh-xuwuvpFW0x0k01}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
// ADR-011 #5750: ROADMAP.md renders sketch slices with a `[sketch]` badge.
|
|
2
|
+
//
|
|
3
|
+
// Locks in the visual distinction so an auditor scanning the rendered roadmap
|
|
4
|
+
// can tell which slices are sketches awaiting refine-slice expansion vs which
|
|
5
|
+
// already carry a full plan. Sits alongside `plan-milestone.test.ts` which
|
|
6
|
+
// covers the full-plan render path.
|
|
7
|
+
|
|
8
|
+
import test from "node:test";
|
|
9
|
+
import assert from "node:assert/strict";
|
|
10
|
+
import { mkdtempSync, mkdirSync, rmSync, readFileSync } from "node:fs";
|
|
11
|
+
import { join } from "node:path";
|
|
12
|
+
import { tmpdir } from "node:os";
|
|
13
|
+
|
|
14
|
+
import { openDatabase, closeDatabase } from "../gsd-db.ts";
|
|
15
|
+
import { handlePlanMilestone, type PlanMilestoneParams } from "../tools/plan-milestone.ts";
|
|
16
|
+
|
|
17
|
+
function makeTmpBase(): string {
|
|
18
|
+
const base = mkdtempSync(join(tmpdir(), "gsd-plan-sketch-render-"));
|
|
19
|
+
mkdirSync(join(base, ".gsd", "milestones", "M001"), { recursive: true });
|
|
20
|
+
openDatabase(join(base, ".gsd", "gsd.db"));
|
|
21
|
+
return base;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function cleanup(base: string): void {
|
|
25
|
+
try {
|
|
26
|
+
closeDatabase();
|
|
27
|
+
} catch {
|
|
28
|
+
/* noop */
|
|
29
|
+
}
|
|
30
|
+
try {
|
|
31
|
+
rmSync(base, { recursive: true, force: true });
|
|
32
|
+
} catch {
|
|
33
|
+
/* noop */
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function planMilestoneWithSketches(): PlanMilestoneParams {
|
|
38
|
+
return {
|
|
39
|
+
milestoneId: "M001",
|
|
40
|
+
title: "Progressive Planning Demo",
|
|
41
|
+
vision: "Demonstrate sketch slices in ROADMAP rendering.",
|
|
42
|
+
successCriteria: ["S01 full, S02 sketch", "ROADMAP distinguishes them"],
|
|
43
|
+
keyRisks: [{ risk: "Visual collision", whyItMatters: "Auditors need to spot sketches." }],
|
|
44
|
+
proofStrategy: [{ riskOrUnknown: "Render correctness", retireIn: "S01", whatWillBeProven: "Roadmap shows the badge." }],
|
|
45
|
+
verificationContract: "Contract verification text",
|
|
46
|
+
verificationIntegration: "Integration verification text",
|
|
47
|
+
verificationOperational: "Operational verification text",
|
|
48
|
+
verificationUat: "UAT verification text",
|
|
49
|
+
definitionOfDone: ["Renderer emits badge", "Test asserts it"],
|
|
50
|
+
requirementCoverage: "Covers ADR-011 #5750.",
|
|
51
|
+
boundaryMapMarkdown: "| From | To | Produces | Consumes |\n|------|----|----------|----------|\n| S01 | S02 | scaffold | nothing |",
|
|
52
|
+
slices: [
|
|
53
|
+
{
|
|
54
|
+
sliceId: "S01",
|
|
55
|
+
title: "Fully planned scaffold",
|
|
56
|
+
risk: "medium" as const,
|
|
57
|
+
depends: [],
|
|
58
|
+
demo: "Scaffold is in place.",
|
|
59
|
+
goal: "Lay down the structural foundation.",
|
|
60
|
+
successCriteria: "Scaffold tests pass.",
|
|
61
|
+
proofLevel: "integration" as const,
|
|
62
|
+
integrationClosure: "Downstream slices depend on this scaffold.",
|
|
63
|
+
observabilityImpact: "No new telemetry.",
|
|
64
|
+
// No isSketch flag — defaults to full plan.
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
sliceId: "S02",
|
|
68
|
+
title: "Refinement candidate",
|
|
69
|
+
risk: "low" as const,
|
|
70
|
+
depends: ["S01"],
|
|
71
|
+
demo: "Sketched until S01 ships.",
|
|
72
|
+
goal: "Refine into a full plan after S01 lands.",
|
|
73
|
+
successCriteria: "",
|
|
74
|
+
proofLevel: "",
|
|
75
|
+
integrationClosure: "",
|
|
76
|
+
observabilityImpact: "",
|
|
77
|
+
isSketch: true,
|
|
78
|
+
sketchScope: "Pick up the scaffold from S01 and add the demo behavior. Stay inside the existing module boundaries.",
|
|
79
|
+
},
|
|
80
|
+
],
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
test("ROADMAP renders sketch slices with [sketch] badge and full slices without", async () => {
|
|
85
|
+
const base = makeTmpBase();
|
|
86
|
+
try {
|
|
87
|
+
const params = planMilestoneWithSketches();
|
|
88
|
+
const result = await handlePlanMilestone(params, base);
|
|
89
|
+
if ("error" in result) {
|
|
90
|
+
assert.fail(`handlePlanMilestone failed: ${result.error}`);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const roadmapPath = join(base, ".gsd", "milestones", "M001", "M001-ROADMAP.md");
|
|
94
|
+
const roadmap = readFileSync(roadmapPath, "utf-8");
|
|
95
|
+
|
|
96
|
+
// S01 is a full slice — no sketch badge.
|
|
97
|
+
const s01Line = roadmap.split("\n").find((line) => line.includes("**S01:"));
|
|
98
|
+
assert.ok(s01Line, "S01 slice line must exist in roadmap");
|
|
99
|
+
assert.equal(
|
|
100
|
+
s01Line.includes("`[sketch]`"),
|
|
101
|
+
false,
|
|
102
|
+
"fully-planned S01 must NOT carry the sketch badge",
|
|
103
|
+
);
|
|
104
|
+
assert.match(s01Line, /`risk:medium`/);
|
|
105
|
+
|
|
106
|
+
// S02 is a sketch — badge required, positioned before risk.
|
|
107
|
+
const s02Line = roadmap.split("\n").find((line) => line.includes("**S02:"));
|
|
108
|
+
assert.ok(s02Line, "S02 slice line must exist in roadmap");
|
|
109
|
+
assert.ok(
|
|
110
|
+
s02Line.includes("`[sketch]`"),
|
|
111
|
+
`sketch slice S02 must carry the sketch badge, got: ${s02Line}`,
|
|
112
|
+
);
|
|
113
|
+
// Badge sits before risk so it stays visible if the line truncates.
|
|
114
|
+
const sketchIdx = s02Line.indexOf("`[sketch]`");
|
|
115
|
+
const riskIdx = s02Line.indexOf("`risk:");
|
|
116
|
+
assert.ok(
|
|
117
|
+
sketchIdx >= 0 && riskIdx >= 0 && sketchIdx < riskIdx,
|
|
118
|
+
"sketch badge must appear before the risk tag",
|
|
119
|
+
);
|
|
120
|
+
} finally {
|
|
121
|
+
cleanup(base);
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
test("ROADMAP omits sketch badge when no slices are sketches", async () => {
|
|
126
|
+
const base = makeTmpBase();
|
|
127
|
+
try {
|
|
128
|
+
const params = planMilestoneWithSketches();
|
|
129
|
+
// Strip the sketch designation from S02 so both slices are fully planned.
|
|
130
|
+
params.slices[1] = {
|
|
131
|
+
...params.slices[1],
|
|
132
|
+
isSketch: false,
|
|
133
|
+
successCriteria: "Demo behavior works.",
|
|
134
|
+
proofLevel: "unit" as const,
|
|
135
|
+
integrationClosure: "S02 closes the demo behavior.",
|
|
136
|
+
observabilityImpact: "No new telemetry.",
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
const result = await handlePlanMilestone(params, base);
|
|
140
|
+
if ("error" in result) {
|
|
141
|
+
assert.fail(`handlePlanMilestone failed: ${result.error}`);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const roadmap = readFileSync(
|
|
145
|
+
join(base, ".gsd", "milestones", "M001", "M001-ROADMAP.md"),
|
|
146
|
+
"utf-8",
|
|
147
|
+
);
|
|
148
|
+
|
|
149
|
+
assert.equal(
|
|
150
|
+
roadmap.includes("`[sketch]`"),
|
|
151
|
+
false,
|
|
152
|
+
"roadmap must not carry the sketch badge when no slice is a sketch",
|
|
153
|
+
);
|
|
154
|
+
} finally {
|
|
155
|
+
cleanup(base);
|
|
156
|
+
}
|
|
157
|
+
});
|
|
@@ -116,6 +116,32 @@ test('handlePlanMilestone rejects invalid payloads', async () => {
|
|
|
116
116
|
}
|
|
117
117
|
});
|
|
118
118
|
|
|
119
|
+
test('handlePlanMilestone rejects delimiter characters in milestone and slice titles', async () => {
|
|
120
|
+
const base = makeTmpBase();
|
|
121
|
+
const dbPath = join(base, '.gsd', 'gsd.db');
|
|
122
|
+
openDatabase(dbPath);
|
|
123
|
+
|
|
124
|
+
try {
|
|
125
|
+
const milestoneResult = await handlePlanMilestone({ ...validParams(), title: 'Client/Server split' }, base);
|
|
126
|
+
assert.ok('error' in milestoneResult);
|
|
127
|
+
assert.match(milestoneResult.error, /validation failed: title is invalid: .*forward slash/);
|
|
128
|
+
assert.equal(getMilestone('M001'), null, 'invalid milestone title must not persist');
|
|
129
|
+
|
|
130
|
+
const sliceResult = await handlePlanMilestone({
|
|
131
|
+
...validParams(),
|
|
132
|
+
slices: [
|
|
133
|
+
validParams().slices[0],
|
|
134
|
+
{ ...validParams().slices[1], title: 'Client/Server migration' },
|
|
135
|
+
],
|
|
136
|
+
}, base);
|
|
137
|
+
assert.ok('error' in sliceResult);
|
|
138
|
+
assert.match(sliceResult.error, /validation failed: slices\[1\]\.title is invalid: .*forward slash/);
|
|
139
|
+
assert.equal(getMilestoneSlices('M001').length, 0, 'invalid slice title must not persist partial roadmap state');
|
|
140
|
+
} finally {
|
|
141
|
+
cleanup(base);
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
|
|
119
145
|
test('handlePlanMilestone surfaces render failures and does not clear parse-visible state on failure', async () => {
|
|
120
146
|
const base = makeTmpBase();
|
|
121
147
|
const dbPath = join(base, '.gsd', 'gsd.db');
|
|
@@ -65,7 +65,9 @@ test("plan-slice prompt: DB-backed tool names survive template substitution", ()
|
|
|
65
65
|
const result = loadPrompt("plan-slice", { ...BASE_VARS, commitInstruction: "Do not commit." });
|
|
66
66
|
assert.ok(result.includes("gsd_plan_slice"), "gsd_plan_slice should appear in rendered prompt");
|
|
67
67
|
assert.ok(result.includes("gsd_plan_task"), "gsd_plan_task should appear in rendered prompt");
|
|
68
|
+
assert.ok(result.includes("gsd_decision_save"), "structural decisions should use DB-backed decision tool");
|
|
68
69
|
assert.ok(result.includes("canonical write path"), "canonical write path language should survive substitution");
|
|
70
|
+
assert.doesNotMatch(result, /append them to `.gsd\/DECISIONS\.md`/);
|
|
69
71
|
});
|
|
70
72
|
|
|
71
73
|
test("plan-slice prompt: compact planning gates survive template substitution", () => {
|
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
import test from 'node:test';
|
|
4
4
|
import assert from 'node:assert/strict';
|
|
5
|
-
import { mkdtempSync, mkdirSync, rmSync, readFileSync, existsSync, writeFileSync } from 'node:fs';
|
|
5
|
+
import { mkdtempSync, mkdirSync, rmSync, readFileSync, existsSync, writeFileSync, realpathSync } from 'node:fs';
|
|
6
6
|
import { join } from 'node:path';
|
|
7
7
|
import { tmpdir } from 'node:os';
|
|
8
8
|
|
|
9
|
-
import { openDatabase, closeDatabase, insertMilestone, insertSlice, getSlice, getSliceTasks, getTask } from '../gsd-db.ts';
|
|
9
|
+
import { openDatabase, closeDatabase, insertMilestone, insertSlice, getSlice, getSliceTasks, getTask, getGateResults, updateTaskStatus } from '../gsd-db.ts';
|
|
10
10
|
import { handlePlanSlice } from '../tools/plan-slice.ts';
|
|
11
11
|
import { parsePlan } from '../parsers-legacy.ts';
|
|
12
12
|
import { parseTaskPlanFile } from '../files.ts';
|
|
@@ -15,6 +15,10 @@ import { deriveState, invalidateStateCache } from '../state.ts';
|
|
|
15
15
|
function makeTmpBase(): string {
|
|
16
16
|
const base = mkdtempSync(join(tmpdir(), 'gsd-plan-slice-'));
|
|
17
17
|
mkdirSync(join(base, '.gsd', 'milestones', 'M001', 'slices', 'S02', 'tasks'), { recursive: true });
|
|
18
|
+
mkdirSync(join(base, 'src', 'resources', 'extensions', 'gsd', 'tools'), { recursive: true });
|
|
19
|
+
writeFileSync(join(base, 'src', 'resources', 'extensions', 'gsd', 'tools', 'plan-milestone.ts'), '// fixture\n', 'utf-8');
|
|
20
|
+
writeFileSync(join(base, 'src', 'resources', 'extensions', 'gsd', 'tools', 'plan-task.ts'), '// fixture\n', 'utf-8');
|
|
21
|
+
writeFileSync(join(base, 'stale-input.py'), '# fixture\n', 'utf-8');
|
|
18
22
|
return base;
|
|
19
23
|
}
|
|
20
24
|
|
|
@@ -101,6 +105,31 @@ test('handlePlanSlice writes slice/task planning state and renders plan artifact
|
|
|
101
105
|
}
|
|
102
106
|
});
|
|
103
107
|
|
|
108
|
+
test('handlePlanSlice renders plan artifacts under worktree-local .gsd while using project DB', async () => {
|
|
109
|
+
const base = makeTmpBase();
|
|
110
|
+
const worktree = join(base, '.gsd', 'worktrees', 'M001');
|
|
111
|
+
mkdirSync(join(worktree, '.gsd'), { recursive: true });
|
|
112
|
+
mkdirSync(join(worktree, 'src', 'resources', 'extensions', 'gsd', 'tools'), { recursive: true });
|
|
113
|
+
writeFileSync(join(worktree, 'src', 'resources', 'extensions', 'gsd', 'tools', 'plan-milestone.ts'), '// fixture\n', 'utf-8');
|
|
114
|
+
writeFileSync(join(worktree, 'src', 'resources', 'extensions', 'gsd', 'tools', 'plan-task.ts'), '// fixture\n', 'utf-8');
|
|
115
|
+
openDatabase(join(base, '.gsd', 'gsd.db'));
|
|
116
|
+
|
|
117
|
+
try {
|
|
118
|
+
seedParentSlice();
|
|
119
|
+
|
|
120
|
+
const result = await handlePlanSlice(validParams(), worktree);
|
|
121
|
+
assert.ok(!('error' in result), `unexpected error: ${'error' in result ? result.error : ''}`);
|
|
122
|
+
|
|
123
|
+
const worktreePlan = join(worktree, '.gsd', 'milestones', 'M001', 'slices', 'S02', 'S02-PLAN.md');
|
|
124
|
+
const projectPlan = join(base, '.gsd', 'milestones', 'M001', 'slices', 'S02', 'S02-PLAN.md');
|
|
125
|
+
assert.ok(existsSync(worktreePlan), 'slice plan should be rendered to worktree-local .gsd');
|
|
126
|
+
assert.ok(!existsSync(projectPlan), 'slice plan should not be rendered to project .gsd');
|
|
127
|
+
assert.equal(result.planPath, realpathSync(worktreePlan));
|
|
128
|
+
} finally {
|
|
129
|
+
cleanup(base);
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
|
|
104
133
|
test('handlePlanSlice advances DB-derived state out of planning immediately', async () => {
|
|
105
134
|
const base = makeTmpBase();
|
|
106
135
|
openDatabase(join(base, '.gsd', 'gsd.db'));
|
|
@@ -125,6 +154,31 @@ test('handlePlanSlice advances DB-derived state out of planning immediately', as
|
|
|
125
154
|
}
|
|
126
155
|
});
|
|
127
156
|
|
|
157
|
+
test('handlePlanSlice clears sketch flag so DB-derived state leaves refining', async () => {
|
|
158
|
+
const base = makeTmpBase();
|
|
159
|
+
openDatabase(join(base, '.gsd', 'gsd.db'));
|
|
160
|
+
|
|
161
|
+
try {
|
|
162
|
+
insertMilestone({ id: 'M001', title: 'Milestone', status: 'active' });
|
|
163
|
+
insertSlice({ id: 'S02', milestoneId: 'M001', title: 'Planning slice', status: 'pending', demo: 'Rendered plans exist.', isSketch: true });
|
|
164
|
+
|
|
165
|
+
invalidateStateCache();
|
|
166
|
+
const before = await deriveState(base);
|
|
167
|
+
assert.equal(before.phase, 'refining');
|
|
168
|
+
|
|
169
|
+
const result = await handlePlanSlice(validParams(), base);
|
|
170
|
+
assert.ok(!('error' in result), `unexpected error: ${'error' in result ? result.error : ''}`);
|
|
171
|
+
assert.equal(getSlice('M001', 'S02')?.is_sketch, 0, 'planned slice must no longer be treated as a sketch');
|
|
172
|
+
|
|
173
|
+
invalidateStateCache();
|
|
174
|
+
const after = await deriveState(base);
|
|
175
|
+
assert.notEqual(after.phase, 'refining');
|
|
176
|
+
assert.equal(after.progress?.tasks?.total, 2);
|
|
177
|
+
} finally {
|
|
178
|
+
cleanup(base);
|
|
179
|
+
}
|
|
180
|
+
});
|
|
181
|
+
|
|
128
182
|
test('handlePlanSlice leaves omitted enrichment fields empty instead of rendering placeholders', async () => {
|
|
129
183
|
const base = makeTmpBase();
|
|
130
184
|
openDatabase(join(base, '.gsd', 'gsd.db'));
|
|
@@ -172,6 +226,28 @@ test('handlePlanSlice rejects invalid payloads', async () => {
|
|
|
172
226
|
}
|
|
173
227
|
});
|
|
174
228
|
|
|
229
|
+
test('handlePlanSlice explains string task IO fields must be arrays', async () => {
|
|
230
|
+
const base = makeTmpBase();
|
|
231
|
+
openDatabase(join(base, '.gsd', 'gsd.db'));
|
|
232
|
+
|
|
233
|
+
try {
|
|
234
|
+
seedParentSlice();
|
|
235
|
+
const result = await handlePlanSlice({
|
|
236
|
+
...validParams(),
|
|
237
|
+
tasks: [
|
|
238
|
+
{
|
|
239
|
+
...validParams().tasks[0],
|
|
240
|
+
inputs: 'src/index.ts' as unknown as string[],
|
|
241
|
+
},
|
|
242
|
+
],
|
|
243
|
+
}, base);
|
|
244
|
+
assert.ok('error' in result);
|
|
245
|
+
assert.match(result.error, /validation failed: tasks\[0\]\.inputs must be an array of strings, not string/);
|
|
246
|
+
} finally {
|
|
247
|
+
cleanup(base);
|
|
248
|
+
}
|
|
249
|
+
});
|
|
250
|
+
|
|
175
251
|
test('handlePlanSlice rejects absolute task IO paths outside the active worktree', async () => {
|
|
176
252
|
const base = makeTmpBase();
|
|
177
253
|
openDatabase(join(base, '.gsd', 'gsd.db'));
|
|
@@ -198,6 +274,63 @@ test('handlePlanSlice rejects absolute task IO paths outside the active worktree
|
|
|
198
274
|
}
|
|
199
275
|
});
|
|
200
276
|
|
|
277
|
+
test('handlePlanSlice rejects missing task input paths before persisting tasks', async () => {
|
|
278
|
+
const base = makeTmpBase();
|
|
279
|
+
openDatabase(join(base, '.gsd', 'gsd.db'));
|
|
280
|
+
|
|
281
|
+
try {
|
|
282
|
+
seedParentSlice();
|
|
283
|
+
const result = await handlePlanSlice({
|
|
284
|
+
...validParams(),
|
|
285
|
+
tasks: [
|
|
286
|
+
{
|
|
287
|
+
...validParams().tasks[0],
|
|
288
|
+
inputs: ['fixtures/missing-source.json'],
|
|
289
|
+
},
|
|
290
|
+
],
|
|
291
|
+
}, base);
|
|
292
|
+
|
|
293
|
+
assert.ok('error' in result);
|
|
294
|
+
assert.match(result.error, /pre-execution validation failed:/);
|
|
295
|
+
assert.match(result.error, /fixtures\/missing-source\.json/);
|
|
296
|
+
assert.equal(getSliceTasks('M001', 'S02').length, 0, 'invalid planning IO must not persist tasks');
|
|
297
|
+
} finally {
|
|
298
|
+
cleanup(base);
|
|
299
|
+
}
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
test('handlePlanSlice rejects task input paths created by later tasks before persisting tasks', async () => {
|
|
303
|
+
const base = makeTmpBase();
|
|
304
|
+
openDatabase(join(base, '.gsd', 'gsd.db'));
|
|
305
|
+
|
|
306
|
+
try {
|
|
307
|
+
seedParentSlice();
|
|
308
|
+
const params = validParams();
|
|
309
|
+
const result = await handlePlanSlice({
|
|
310
|
+
...params,
|
|
311
|
+
tasks: [
|
|
312
|
+
{
|
|
313
|
+
...params.tasks[0],
|
|
314
|
+
inputs: ['generated/report.json'],
|
|
315
|
+
expectedOutput: ['generated/summary.json'],
|
|
316
|
+
},
|
|
317
|
+
{
|
|
318
|
+
...params.tasks[1],
|
|
319
|
+
inputs: [],
|
|
320
|
+
expectedOutput: ['generated/report.json'],
|
|
321
|
+
},
|
|
322
|
+
],
|
|
323
|
+
}, base);
|
|
324
|
+
|
|
325
|
+
assert.ok('error' in result);
|
|
326
|
+
assert.match(result.error, /pre-execution validation failed:/);
|
|
327
|
+
assert.match(result.error, /sequence violation/);
|
|
328
|
+
assert.equal(getSliceTasks('M001', 'S02').length, 0, 'invalid task ordering must not persist tasks');
|
|
329
|
+
} finally {
|
|
330
|
+
cleanup(base);
|
|
331
|
+
}
|
|
332
|
+
});
|
|
333
|
+
|
|
201
334
|
test('handlePlanSlice accepts absolute task IO paths inside the active worktree', async () => {
|
|
202
335
|
const base = makeTmpBase();
|
|
203
336
|
openDatabase(join(base, '.gsd', 'gsd.db'));
|
|
@@ -304,3 +437,119 @@ test('handlePlanSlice reruns idempotently and refreshes parse-visible state', as
|
|
|
304
437
|
cleanup(base);
|
|
305
438
|
}
|
|
306
439
|
});
|
|
440
|
+
|
|
441
|
+
test('handlePlanSlice removes omitted pending tasks when replanning a smaller task set', async () => {
|
|
442
|
+
const base = makeTmpBase();
|
|
443
|
+
openDatabase(join(base, '.gsd', 'gsd.db'));
|
|
444
|
+
|
|
445
|
+
try {
|
|
446
|
+
seedParentSlice();
|
|
447
|
+
const fourTaskPlan = {
|
|
448
|
+
...validParams(),
|
|
449
|
+
tasks: [
|
|
450
|
+
...validParams().tasks,
|
|
451
|
+
{ ...validParams().tasks[0], taskId: 'T03', title: 'Third task' },
|
|
452
|
+
{ ...validParams().tasks[0], taskId: 'T04', title: 'Stale task', inputs: ['stale-input.py'] },
|
|
453
|
+
],
|
|
454
|
+
};
|
|
455
|
+
|
|
456
|
+
const first = await handlePlanSlice(fourTaskPlan, base);
|
|
457
|
+
assert.ok(!('error' in first), `unexpected error: ${'error' in first ? first.error : ''}`);
|
|
458
|
+
const staleTaskPlanPath = join(base, '.gsd', 'milestones', 'M001', 'slices', 'S02', 'tasks', 'T04-PLAN.md');
|
|
459
|
+
assert.ok(existsSync(staleTaskPlanPath), 'initial plan should render T04');
|
|
460
|
+
|
|
461
|
+
const second = await handlePlanSlice({
|
|
462
|
+
...validParams(),
|
|
463
|
+
tasks: fourTaskPlan.tasks.filter((task) => task.taskId !== 'T04'),
|
|
464
|
+
}, base);
|
|
465
|
+
assert.ok(!('error' in second), `unexpected error: ${'error' in second ? second.error : ''}`);
|
|
466
|
+
|
|
467
|
+
assert.deepEqual(getSliceTasks('M001', 'S02').map((task) => task.id), ['T01', 'T02', 'T03']);
|
|
468
|
+
assert.equal(getGateResults('M001', 'S02', 'task').some((gate) => gate.task_id === 'T04'), false);
|
|
469
|
+
assert.equal(existsSync(staleTaskPlanPath), false, 'omitted task plan artifact should be removed');
|
|
470
|
+
} finally {
|
|
471
|
+
cleanup(base);
|
|
472
|
+
}
|
|
473
|
+
});
|
|
474
|
+
|
|
475
|
+
test('handlePlanSlice rejects omitted completed tasks without changing slice or task state', async () => {
|
|
476
|
+
const base = makeTmpBase();
|
|
477
|
+
openDatabase(join(base, '.gsd', 'gsd.db'));
|
|
478
|
+
|
|
479
|
+
try {
|
|
480
|
+
seedParentSlice();
|
|
481
|
+
const fourTaskPlan = {
|
|
482
|
+
...validParams(),
|
|
483
|
+
tasks: [
|
|
484
|
+
...validParams().tasks,
|
|
485
|
+
{ ...validParams().tasks[0], taskId: 'T03', title: 'Third task' },
|
|
486
|
+
{ ...validParams().tasks[0], taskId: 'T04', title: 'Stale task', inputs: ['stale-input.py'] },
|
|
487
|
+
],
|
|
488
|
+
};
|
|
489
|
+
|
|
490
|
+
const first = await handlePlanSlice(fourTaskPlan, base);
|
|
491
|
+
assert.ok(!('error' in first), `unexpected error: ${'error' in first ? first.error : ''}`);
|
|
492
|
+
const staleTaskPlanPath = join(base, '.gsd', 'milestones', 'M001', 'slices', 'S02', 'tasks', 'T04-PLAN.md');
|
|
493
|
+
assert.ok(existsSync(staleTaskPlanPath), 'initial plan should render T04');
|
|
494
|
+
|
|
495
|
+
updateTaskStatus('M001', 'S02', 'T04', 'complete', '2026-05-12T00:00:00.000Z');
|
|
496
|
+
const tasksBefore = getSliceTasks('M001', 'S02');
|
|
497
|
+
const gatesBefore = getGateResults('M001', 'S02', 'task');
|
|
498
|
+
|
|
499
|
+
const second = await handlePlanSlice({
|
|
500
|
+
...validParams(),
|
|
501
|
+
goal: 'Rejected replan should not persist.',
|
|
502
|
+
tasks: fourTaskPlan.tasks.filter((task) => task.taskId !== 'T04'),
|
|
503
|
+
}, base);
|
|
504
|
+
assert.deepEqual(second, { error: 'cannot remove completed task T04' });
|
|
505
|
+
|
|
506
|
+
assert.equal(getSlice('M001', 'S02')?.goal, 'Persist slice planning through the DB.');
|
|
507
|
+
assert.deepEqual(getSliceTasks('M001', 'S02'), tasksBefore);
|
|
508
|
+
assert.deepEqual(getGateResults('M001', 'S02', 'task'), gatesBefore);
|
|
509
|
+
assert.ok(existsSync(staleTaskPlanPath), 'completed task plan artifact should remain after rejected replan');
|
|
510
|
+
} finally {
|
|
511
|
+
cleanup(base);
|
|
512
|
+
}
|
|
513
|
+
});
|
|
514
|
+
|
|
515
|
+
test('regression: validateTasks surfaces clean per-field errors for non-array IO inputs', async () => {
|
|
516
|
+
// Regression for the bug fixed in PR #5872: an earlier refactor on main
|
|
517
|
+
// (0b0e1a901) re-added validateStringArray() calls inside validateTasks
|
|
518
|
+
// without re-adding its import. The catch around validateParams swallowed
|
|
519
|
+
// the ReferenceError into a generic "validation failed: validateStringArray
|
|
520
|
+
// is not defined" message, so silent runtime breakage was possible.
|
|
521
|
+
//
|
|
522
|
+
// Exercise every validateStringArray call site (files, inputs, expectedOutput)
|
|
523
|
+
// so a future missing-import would surface as a per-field assertion failure
|
|
524
|
+
// here, not a deep ReferenceError that's easy to mis-diagnose.
|
|
525
|
+
const base = makeTmpBase();
|
|
526
|
+
openDatabase(join(base, '.gsd', 'gsd.db'));
|
|
527
|
+
|
|
528
|
+
try {
|
|
529
|
+
seedParentSlice();
|
|
530
|
+
|
|
531
|
+
for (const field of ['files', 'inputs', 'expectedOutput'] as const) {
|
|
532
|
+
const result = await handlePlanSlice({
|
|
533
|
+
...validParams(),
|
|
534
|
+
tasks: [{
|
|
535
|
+
...validParams().tasks[0],
|
|
536
|
+
[field]: 'not-an-array' as unknown as string[],
|
|
537
|
+
}],
|
|
538
|
+
}, base);
|
|
539
|
+
assert.ok('error' in result, `${field}: expected validation error, got success`);
|
|
540
|
+
assert.match(
|
|
541
|
+
result.error,
|
|
542
|
+
new RegExp(`tasks\\[0\\]\\.${field} must be an array`),
|
|
543
|
+
`${field}: expected per-field validation message, got: ${result.error}`,
|
|
544
|
+
);
|
|
545
|
+
assert.doesNotMatch(
|
|
546
|
+
result.error,
|
|
547
|
+
/is not defined/,
|
|
548
|
+
`${field}: validation surfaced ReferenceError — likely a missing import in plan-slice.ts`,
|
|
549
|
+
);
|
|
550
|
+
assert.equal(getSliceTasks('M001', 'S02').length, 0, `${field}: invalid input must not persist`);
|
|
551
|
+
}
|
|
552
|
+
} finally {
|
|
553
|
+
cleanup(base);
|
|
554
|
+
}
|
|
555
|
+
});
|
|
@@ -79,6 +79,23 @@ test('handlePlanTask rejects invalid payloads', async () => {
|
|
|
79
79
|
}
|
|
80
80
|
});
|
|
81
81
|
|
|
82
|
+
test('handlePlanTask explains string IO fields must be arrays', async () => {
|
|
83
|
+
const base = makeTmpBase();
|
|
84
|
+
openDatabase(join(base, '.gsd', 'gsd.db'));
|
|
85
|
+
|
|
86
|
+
try {
|
|
87
|
+
seedParent();
|
|
88
|
+
const result = await handlePlanTask({
|
|
89
|
+
...validParams(),
|
|
90
|
+
expectedOutput: 'src/output.ts' as unknown as string[],
|
|
91
|
+
}, base);
|
|
92
|
+
assert.ok('error' in result);
|
|
93
|
+
assert.match(result.error, /validation failed: expectedOutput must be an array of strings, not string/);
|
|
94
|
+
} finally {
|
|
95
|
+
cleanup(base);
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
|
|
82
99
|
test('handlePlanTask rejects absolute task IO paths outside the active worktree', async () => {
|
|
83
100
|
const base = makeTmpBase();
|
|
84
101
|
openDatabase(join(base, '.gsd', 'gsd.db'));
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
// Project/App: GSD-2
|
|
2
|
+
// File Purpose: Tests for post-execution retry bypass and verification gate failure handling.
|
|
1
3
|
/**
|
|
2
4
|
* post-exec-retry-bypass.test.ts — Tests for post-execution blocking failure retry bypass.
|
|
3
5
|
*
|
|
@@ -9,7 +11,7 @@
|
|
|
9
11
|
import { describe, test, mock, beforeEach, afterEach } from "node:test";
|
|
10
12
|
import assert from "node:assert/strict";
|
|
11
13
|
import { tmpdir } from "node:os";
|
|
12
|
-
import { mkdirSync, writeFileSync, rmSync
|
|
14
|
+
import { mkdirSync, readFileSync, writeFileSync, rmSync } from "node:fs";
|
|
13
15
|
import { join } from "node:path";
|
|
14
16
|
|
|
15
17
|
import { runPostUnitVerification, type VerificationContext } from "../auto-verification.ts";
|
|
@@ -71,6 +73,7 @@ function setupTestEnvironment(): void {
|
|
|
71
73
|
mkdirSync(milestonesDir, { recursive: true });
|
|
72
74
|
|
|
73
75
|
process.chdir(tempDir);
|
|
76
|
+
invalidateAllCaches();
|
|
74
77
|
_clearGsdRootCache();
|
|
75
78
|
|
|
76
79
|
dbPath = join(gsdDir, "gsd.db");
|
|
@@ -140,6 +143,34 @@ function createBasicTask(): void {
|
|
|
140
143
|
});
|
|
141
144
|
}
|
|
142
145
|
|
|
146
|
+
function createTaskWithoutVerify(): void {
|
|
147
|
+
insertMilestone({ id: "M001" });
|
|
148
|
+
insertSlice({
|
|
149
|
+
id: "S01",
|
|
150
|
+
milestoneId: "M001",
|
|
151
|
+
title: "Test Slice",
|
|
152
|
+
risk: "low",
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
insertTask({
|
|
156
|
+
id: "T01",
|
|
157
|
+
sliceId: "S01",
|
|
158
|
+
milestoneId: "M001",
|
|
159
|
+
title: "Task without host verification",
|
|
160
|
+
status: "pending",
|
|
161
|
+
planning: {
|
|
162
|
+
description: "Task intentionally missing runnable verification",
|
|
163
|
+
estimate: "1h",
|
|
164
|
+
files: [],
|
|
165
|
+
verify: "",
|
|
166
|
+
inputs: [],
|
|
167
|
+
expectedOutput: [],
|
|
168
|
+
observabilityImpact: "",
|
|
169
|
+
},
|
|
170
|
+
sequence: 0,
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
|
|
143
174
|
function createPostExecFailureTask(): void {
|
|
144
175
|
insertMilestone({ id: "M001" });
|
|
145
176
|
insertSlice({
|
|
@@ -327,6 +358,53 @@ describe("Post-execution blocking failure retry bypass", () => {
|
|
|
327
358
|
assert.equal(row?.outcome, "fail");
|
|
328
359
|
assert.equal(row?.failure_class, "artifact");
|
|
329
360
|
});
|
|
361
|
+
|
|
362
|
+
test("execute-task with no host-owned verification pauses fail-closed", async () => {
|
|
363
|
+
createTaskWithoutVerify();
|
|
364
|
+
|
|
365
|
+
const ctx = makeMockCtx();
|
|
366
|
+
const pi = makeMockPi();
|
|
367
|
+
const pauseAutoMock = mock.fn(async () => {});
|
|
368
|
+
const s = makeMockSession(tempDir, { type: "execute-task", id: "M001/S01/T01" });
|
|
369
|
+
|
|
370
|
+
const result = await runPostUnitVerification({ s, ctx, pi }, pauseAutoMock);
|
|
371
|
+
|
|
372
|
+
assert.equal(result, "pause");
|
|
373
|
+
assert.equal(pauseAutoMock.mock.callCount(), 1);
|
|
374
|
+
assert.equal(s.pendingVerificationRetry, null);
|
|
375
|
+
|
|
376
|
+
const evidencePath = join(tempDir, ".gsd", "milestones", "M001", "slices", "S01", "tasks", "T01-VERIFY.json");
|
|
377
|
+
const evidence = JSON.parse(readFileSync(evidencePath, "utf-8"));
|
|
378
|
+
assert.equal(evidence.passed, false);
|
|
379
|
+
assert.equal(evidence.discoverySource, "none");
|
|
380
|
+
assert.ok(!("retryAttempt" in evidence), "no-host-checks evidence must not include retryAttempt");
|
|
381
|
+
assert.ok(!("maxRetries" in evidence), "no-host-checks evidence must not include maxRetries");
|
|
382
|
+
});
|
|
383
|
+
|
|
384
|
+
test("auto-discovered package.json verification failure retries instead of continuing", async () => {
|
|
385
|
+
createTaskWithoutVerify();
|
|
386
|
+
writeFileSync(
|
|
387
|
+
join(tempDir, "package.json"),
|
|
388
|
+
JSON.stringify({ scripts: { test: "exit 1" } }),
|
|
389
|
+
"utf-8",
|
|
390
|
+
);
|
|
391
|
+
writePreferences({
|
|
392
|
+
verification_auto_fix: true,
|
|
393
|
+
verification_max_retries: 2,
|
|
394
|
+
});
|
|
395
|
+
|
|
396
|
+
const ctx = makeMockCtx();
|
|
397
|
+
const pi = makeMockPi();
|
|
398
|
+
const pauseAutoMock = mock.fn(async () => {});
|
|
399
|
+
const s = makeMockSession(tempDir, { type: "execute-task", id: "M001/S01/T01" });
|
|
400
|
+
|
|
401
|
+
const result = await runPostUnitVerification({ s, ctx, pi }, pauseAutoMock);
|
|
402
|
+
|
|
403
|
+
assert.equal(result, "retry");
|
|
404
|
+
assert.equal(pauseAutoMock.mock.callCount(), 0);
|
|
405
|
+
assert.equal(s.pendingVerificationRetry?.unitId, "M001/S01/T01");
|
|
406
|
+
assert.match(s.pendingVerificationRetry?.failureContext ?? "", /npm run test/);
|
|
407
|
+
});
|
|
330
408
|
});
|
|
331
409
|
|
|
332
410
|
describe("Post-execution retry behavior", () => {
|