gsd-pi 2.82.0-dev.ed17d078d → 3.0.0-dev.8b8d129d7
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 +93 -18
- package/dist/cli.js +20 -9
- package/dist/headless.js +9 -2
- package/dist/resources/.managed-resources-content-hash +1 -1
- package/dist/resources/GSD-WORKFLOW.md +10 -1
- package/dist/resources/extensions/claude-code-cli/partial-builder.js +2 -1
- package/dist/resources/extensions/claude-code-cli/stream-adapter.js +44 -6
- 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 +110 -37
- package/dist/resources/extensions/gsd/auto/orchestrator.js +12 -1
- package/dist/resources/extensions/gsd/auto/phases.js +97 -38
- package/dist/resources/extensions/gsd/auto/session.js +6 -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 +278 -137
- package/dist/resources/extensions/gsd/auto-prompts.js +36 -10
- package/dist/resources/extensions/gsd/auto-recovery.js +79 -14
- package/dist/resources/extensions/gsd/auto-start.js +87 -14
- package/dist/resources/extensions/gsd/auto-timers.js +11 -3
- package/dist/resources/extensions/gsd/auto-verification.js +102 -34
- package/dist/resources/extensions/gsd/auto-worktree.js +178 -11
- package/dist/resources/extensions/gsd/auto.js +98 -54
- 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 +5 -4
- package/dist/resources/extensions/gsd/bootstrap/subagent-input.js +21 -9
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +24 -9
- 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 +38 -0
- package/dist/resources/extensions/gsd/commands/handlers/ops.js +20 -0
- package/dist/resources/extensions/gsd/commands-bootstrap.js +5 -0
- package/dist/resources/extensions/gsd/commands-handlers.js +2 -0
- package/dist/resources/extensions/gsd/commands-mcp-status.js +9 -0
- 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/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-base-schema.js +2 -0
- package/dist/resources/extensions/gsd/db-migration-steps.js +4 -0
- package/dist/resources/extensions/gsd/db-task-slice-rows.js +2 -0
- package/dist/resources/extensions/gsd/dispatch-guard.js +46 -2
- package/dist/resources/extensions/gsd/docs/preferences-reference.md +8 -0
- package/dist/resources/extensions/gsd/doctor-git-checks.js +46 -1
- 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 +8 -3
- package/dist/resources/extensions/gsd/git-service.js +138 -10
- package/dist/resources/extensions/gsd/gsd-db.js +76 -33
- package/dist/resources/extensions/gsd/guided-flow-queue.js +4 -3
- package/dist/resources/extensions/gsd/guided-flow.js +110 -117
- package/dist/resources/extensions/gsd/guided-unit-context.js +23 -0
- package/dist/resources/extensions/gsd/init-wizard.js +17 -2
- package/dist/resources/extensions/gsd/markdown-renderer.js +10 -8
- package/dist/resources/extensions/gsd/mcp-filter.js +58 -0
- 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 +57 -14
- package/dist/resources/extensions/gsd/parallel-orchestrator.js +3 -0
- 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/planning-path-scope.js +9 -3
- package/dist/resources/extensions/gsd/post-execution-checks.js +73 -9
- package/dist/resources/extensions/gsd/pre-execution-checks.js +38 -11
- package/dist/resources/extensions/gsd/preferences-mcp.js +19 -0
- package/dist/resources/extensions/gsd/preferences-types.js +2 -0
- package/dist/resources/extensions/gsd/preferences-validation.js +138 -0
- package/dist/resources/extensions/gsd/preferences.js +2 -0
- 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/forensics.md +3 -3
- 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/reactive-execute.md +1 -1
- 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/queue-reorder-ui.js +30 -13
- package/dist/resources/extensions/gsd/repository-registry.js +44 -0
- package/dist/resources/extensions/gsd/safety/evidence-collector.js +2 -0
- package/dist/resources/extensions/gsd/safety/evidence-cross-ref.js +42 -18
- package/dist/resources/extensions/gsd/slice-parallel-orchestrator.js +59 -2
- 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 +14 -4
- package/dist/resources/extensions/gsd/status-guards.js +14 -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 +151 -15
- package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +119 -0
- package/dist/resources/extensions/gsd/unit-context-manifest.js +36 -17
- package/dist/resources/extensions/gsd/validation.js +23 -1
- package/dist/resources/extensions/gsd/verification-gate.js +142 -7
- package/dist/resources/extensions/gsd/verification-verdict.js +26 -0
- package/dist/resources/extensions/gsd/workflow-manifest.js +2 -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/gsd/worktree-state-projection.js +31 -0
- package/dist/resources/extensions/shared/html-shell.js +388 -0
- package/dist/resources/extensions/shared/interview-ui.js +6 -4
- 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/resources/skills/forensics/SKILL.md +1 -1
- 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-8c10ec293ae0f1d5.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 +4 -4
- 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 +13 -4
- 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.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-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/package.json +1 -1
- 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/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/compaction/compaction.d.ts +6 -1
- package/packages/pi-coding-agent/dist/core/compaction/compaction.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/compaction/compaction.js +7 -2
- package/packages/pi-coding-agent/dist/core/compaction/compaction.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/compaction/compaction.test.js +14 -1
- package/packages/pi-coding-agent/dist/core/compaction/compaction.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/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/controllers/input-controller.js +7 -7
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.js +11 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.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/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/compaction/compaction.test.ts +23 -1
- package/packages/pi-coding-agent/src/core/compaction/compaction.ts +7 -2
- package/packages/pi-coding-agent/src/core/sdk.ts +1 -1
- 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/controllers/input-controller.test.ts +15 -1
- package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.ts +9 -9
- 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/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/__tests__/tui.test.js +45 -2
- package/packages/pi-tui/dist/__tests__/tui.test.js.map +1 -1
- 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 +106 -27
- 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/__tests__/tui.test.ts +59 -2
- package/packages/pi-tui/src/terminal.ts +11 -0
- package/packages/pi-tui/src/tui.ts +108 -27
- 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/claude-code-cli/partial-builder.ts +2 -1
- package/src/resources/extensions/claude-code-cli/stream-adapter.ts +52 -6
- 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 +49 -2
- package/src/resources/extensions/cmux/index.ts +6 -0
- package/src/resources/extensions/gsd/auto/contracts.ts +17 -6
- package/src/resources/extensions/gsd/auto/infra-errors.ts +9 -3
- package/src/resources/extensions/gsd/auto/loop.ts +111 -38
- package/src/resources/extensions/gsd/auto/orchestrator.ts +12 -1
- package/src/resources/extensions/gsd/auto/phases.ts +115 -49
- package/src/resources/extensions/gsd/auto/session.ts +16 -0
- package/src/resources/extensions/gsd/auto/types.ts +3 -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 +312 -148
- package/src/resources/extensions/gsd/auto-prompts.ts +36 -13
- package/src/resources/extensions/gsd/auto-recovery.ts +83 -11
- package/src/resources/extensions/gsd/auto-start.ts +94 -12
- package/src/resources/extensions/gsd/auto-timers.ts +10 -3
- package/src/resources/extensions/gsd/auto-verification.ts +124 -42
- package/src/resources/extensions/gsd/auto-worktree.ts +195 -11
- package/src/resources/extensions/gsd/auto.ts +91 -42
- 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 +5 -4
- package/src/resources/extensions/gsd/bootstrap/subagent-input.ts +19 -7
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +27 -10
- 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 +41 -0
- package/src/resources/extensions/gsd/commands/handlers/ops.ts +21 -0
- package/src/resources/extensions/gsd/commands-bootstrap.ts +10 -0
- package/src/resources/extensions/gsd/commands-handlers.ts +2 -0
- package/src/resources/extensions/gsd/commands-mcp-status.ts +8 -0
- 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/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-base-schema.ts +2 -0
- package/src/resources/extensions/gsd/db-migration-steps.ts +5 -0
- package/src/resources/extensions/gsd/db-task-slice-rows.ts +4 -0
- package/src/resources/extensions/gsd/dispatch-guard.ts +60 -2
- package/src/resources/extensions/gsd/docs/preferences-reference.md +8 -0
- package/src/resources/extensions/gsd/doctor-git-checks.ts +45 -1
- package/src/resources/extensions/gsd/doctor-runtime-checks.ts +25 -13
- package/src/resources/extensions/gsd/doctor-types.ts +1 -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 +7 -3
- package/src/resources/extensions/gsd/git-service.ts +166 -11
- package/src/resources/extensions/gsd/gsd-db.ts +80 -31
- package/src/resources/extensions/gsd/guided-flow-queue.ts +4 -3
- package/src/resources/extensions/gsd/guided-flow.ts +142 -134
- package/src/resources/extensions/gsd/guided-unit-context.ts +30 -0
- package/src/resources/extensions/gsd/init-wizard.ts +17 -2
- package/src/resources/extensions/gsd/journal.ts +8 -1
- package/src/resources/extensions/gsd/markdown-renderer.ts +10 -8
- package/src/resources/extensions/gsd/mcp-filter.ts +80 -0
- 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 +63 -14
- package/src/resources/extensions/gsd/parallel-orchestrator.ts +3 -0
- 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/planning-path-scope.ts +10 -2
- package/src/resources/extensions/gsd/post-execution-checks.ts +87 -12
- package/src/resources/extensions/gsd/pre-execution-checks.ts +49 -11
- package/src/resources/extensions/gsd/preferences-mcp.ts +27 -0
- package/src/resources/extensions/gsd/preferences-types.ts +33 -0
- package/src/resources/extensions/gsd/preferences-validation.ts +145 -0
- package/src/resources/extensions/gsd/preferences.ts +5 -0
- 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/forensics.md +3 -3
- 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/reactive-execute.md +1 -1
- 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/queue-reorder-ui.ts +31 -13
- package/src/resources/extensions/gsd/repository-registry.ts +77 -0
- package/src/resources/extensions/gsd/safety/evidence-collector.ts +2 -0
- package/src/resources/extensions/gsd/safety/evidence-cross-ref.ts +54 -19
- package/src/resources/extensions/gsd/slice-parallel-orchestrator.ts +52 -1
- 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 +15 -4
- package/src/resources/extensions/gsd/status-guards.ts +16 -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 +300 -1
- package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +174 -8
- 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 +129 -6
- package/src/resources/extensions/gsd/tests/auto-retry-mcp-churn-fixes.test.ts +12 -0
- 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/autocomplete-regressions-1675.test.ts +21 -0
- package/src/resources/extensions/gsd/tests/brief-command.test.ts +89 -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 +32 -4
- 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/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-task-slice-rows.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/deep-project-auto-loop.test.ts +61 -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 +68 -1
- package/src/resources/extensions/gsd/tests/doctor-empty-worktree.test.ts +65 -0
- package/src/resources/extensions/gsd/tests/doctor-forensics-db-open-regression.test.ts +50 -0
- package/src/resources/extensions/gsd/tests/evidence-cross-ref.test.ts +97 -0
- package/src/resources/extensions/gsd/tests/export-html-enhancements.test.ts +8 -0
- package/src/resources/extensions/gsd/tests/gsd-db.test.ts +28 -0
- 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/init-prefs-routing.test.ts +22 -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 +199 -2
- 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 +49 -3
- package/src/resources/extensions/gsd/tests/journal.test.ts +32 -0
- package/src/resources/extensions/gsd/tests/mcp-filter.test.ts +287 -0
- package/src/resources/extensions/gsd/tests/mcp-status.test.ts +11 -0
- package/src/resources/extensions/gsd/tests/merge-db-cycle.test.ts +179 -0
- 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 +80 -2
- package/src/resources/extensions/gsd/tests/orphaned-worktree-audit.test.ts +121 -1
- package/src/resources/extensions/gsd/tests/parallel-orchestrator-zombie-cleanup.test.ts +55 -0
- 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.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 +343 -3
- package/src/resources/extensions/gsd/tests/plan-task.test.ts +18 -1
- 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 +105 -3
- 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 +59 -0
- package/src/resources/extensions/gsd/tests/pre-execution-pause-wiring.test.ts +54 -0
- package/src/resources/extensions/gsd/tests/preferences-mcp.test.ts +128 -0
- package/src/resources/extensions/gsd/tests/preferences.test.ts +75 -0
- package/src/resources/extensions/gsd/tests/prefs-wizard-coverage.test.ts +70 -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/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/repository-registry.test.ts +52 -0
- package/src/resources/extensions/gsd/tests/run-uat-replay-cap.test.ts +2 -3
- package/src/resources/extensions/gsd/tests/session-switch-abort-misclassification.test.ts +10 -0
- package/src/resources/extensions/gsd/tests/slice-parallel-orchestrator.test.ts +72 -1
- 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 +17 -1
- package/src/resources/extensions/gsd/tests/stuck-state-via-db.test.ts +64 -1
- package/src/resources/extensions/gsd/tests/subagent-model-dispatch.test.ts +2 -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 +128 -9
- package/src/resources/extensions/gsd/tests/uok-gitops-turn-action.test.ts +111 -1
- package/src/resources/extensions/gsd/tests/validate-milestone-stuck-guard.test.ts +29 -2
- package/src/resources/extensions/gsd/tests/validate-milestone.test.ts +42 -1
- package/src/resources/extensions/gsd/tests/verification-gate.test.ts +173 -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/worktree-preferences-sync.test.ts +25 -0
- package/src/resources/extensions/gsd/tests/worktree-sync-milestones.test.ts +95 -0
- package/src/resources/extensions/gsd/tests/worktree-write-gate.test.ts +27 -0
- package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +59 -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 +172 -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 +51 -18
- package/src/resources/extensions/gsd/validation.ts +23 -1
- package/src/resources/extensions/gsd/verification-gate.ts +170 -6
- package/src/resources/extensions/gsd/verification-verdict.ts +47 -0
- package/src/resources/extensions/gsd/workflow-manifest.ts +2 -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/gsd/worktree-state-projection.ts +43 -0
- package/src/resources/extensions/shared/html-shell.ts +412 -0
- package/src/resources/extensions/shared/interview-ui.ts +6 -4
- package/src/resources/extensions/shared/tests/interview-notes-loop.test.ts +15 -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/src/resources/skills/forensics/SKILL.md +1 -1
- 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-a16c7a7ecdf0c2cf.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/{YEvjuT-fsFfYQhDSWtueS → _kljR-_Miq_YV1IW0wpRO}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{YEvjuT-fsFfYQhDSWtueS → _kljR-_Miq_YV1IW0wpRO}/_ssgManifest.js +0 -0
|
@@ -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
|
|
|
@@ -84,6 +88,8 @@ test('handlePlanSlice writes slice/task planning state and renders plan artifact
|
|
|
84
88
|
assert.equal(tasks[0]?.title, 'Write slice handler');
|
|
85
89
|
assert.equal(tasks[0]?.description, 'Implement the slice planning handler.');
|
|
86
90
|
assert.equal(tasks[1]?.estimate, '30m');
|
|
91
|
+
assert.deepEqual(slice?.target_repositories, ['project']);
|
|
92
|
+
assert.deepEqual(tasks[0]?.target_repositories, ['project']);
|
|
87
93
|
|
|
88
94
|
const planPath = join(base, '.gsd', 'milestones', 'M001', 'slices', 'S02', 'S02-PLAN.md');
|
|
89
95
|
assert.ok(existsSync(planPath), 'slice plan should be rendered to disk');
|
|
@@ -101,6 +107,120 @@ test('handlePlanSlice writes slice/task planning state and renders plan artifact
|
|
|
101
107
|
}
|
|
102
108
|
});
|
|
103
109
|
|
|
110
|
+
test('handlePlanSlice persists explicit slice/task target repositories', async () => {
|
|
111
|
+
const base = makeTmpBase();
|
|
112
|
+
openDatabase(join(base, '.gsd', 'gsd.db'));
|
|
113
|
+
|
|
114
|
+
try {
|
|
115
|
+
seedParentSlice();
|
|
116
|
+
const params = validParams();
|
|
117
|
+
const result = await handlePlanSlice({
|
|
118
|
+
...params,
|
|
119
|
+
targetRepositories: ['project'],
|
|
120
|
+
tasks: [
|
|
121
|
+
{ ...params.tasks[0], targetRepositories: ['project'] },
|
|
122
|
+
{ ...params.tasks[1], targetRepositories: ['project'] },
|
|
123
|
+
],
|
|
124
|
+
}, base);
|
|
125
|
+
assert.ok(!('error' in result), `unexpected error: ${'error' in result ? result.error : ''}`);
|
|
126
|
+
|
|
127
|
+
const slice = getSlice('M001', 'S02');
|
|
128
|
+
const task = getTask('M001', 'S02', 'T01');
|
|
129
|
+
assert.deepEqual(slice?.target_repositories, ['project']);
|
|
130
|
+
assert.deepEqual(task?.target_repositories, ['project']);
|
|
131
|
+
} finally {
|
|
132
|
+
cleanup(base);
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
test('handlePlanSlice rejects unknown target repositories', async () => {
|
|
137
|
+
const base = makeTmpBase();
|
|
138
|
+
openDatabase(join(base, '.gsd', 'gsd.db'));
|
|
139
|
+
|
|
140
|
+
try {
|
|
141
|
+
seedParentSlice();
|
|
142
|
+
const result = await handlePlanSlice({
|
|
143
|
+
...validParams(),
|
|
144
|
+
targetRepositories: ['frontend'],
|
|
145
|
+
}, base);
|
|
146
|
+
assert.ok('error' in result);
|
|
147
|
+
assert.match(result.error, /validation failed: unknown targetRepositories:/);
|
|
148
|
+
assert.equal(getSliceTasks('M001', 'S02').length, 0, 'invalid target repositories must not persist');
|
|
149
|
+
} finally {
|
|
150
|
+
cleanup(base);
|
|
151
|
+
}
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
test('handlePlanSlice enforces absolute path scope to declared target repositories', async () => {
|
|
155
|
+
const base = makeTmpBase();
|
|
156
|
+
openDatabase(join(base, '.gsd', 'gsd.db'));
|
|
157
|
+
|
|
158
|
+
try {
|
|
159
|
+
seedParentSlice();
|
|
160
|
+
mkdirSync(join(base, 'frontend'), { recursive: true });
|
|
161
|
+
mkdirSync(join(base, 'backend'), { recursive: true });
|
|
162
|
+
writeFileSync(
|
|
163
|
+
join(base, '.gsd', 'PREFERENCES.md'),
|
|
164
|
+
[
|
|
165
|
+
'---',
|
|
166
|
+
'workspace:',
|
|
167
|
+
' mode: parent',
|
|
168
|
+
' repositories:',
|
|
169
|
+
' frontend:',
|
|
170
|
+
' path: frontend',
|
|
171
|
+
' backend:',
|
|
172
|
+
' path: backend',
|
|
173
|
+
'---',
|
|
174
|
+
].join('\n'),
|
|
175
|
+
'utf-8',
|
|
176
|
+
);
|
|
177
|
+
|
|
178
|
+
const badPath = join(base, 'backend', 'src', 'server.ts');
|
|
179
|
+
const result = await handlePlanSlice({
|
|
180
|
+
...validParams(),
|
|
181
|
+
targetRepositories: ['frontend'],
|
|
182
|
+
tasks: [
|
|
183
|
+
{
|
|
184
|
+
...validParams().tasks[0],
|
|
185
|
+
files: [badPath],
|
|
186
|
+
targetRepositories: ['frontend'],
|
|
187
|
+
},
|
|
188
|
+
],
|
|
189
|
+
}, base);
|
|
190
|
+
|
|
191
|
+
assert.ok('error' in result);
|
|
192
|
+
assert.match(result.error, /outside allowed repository roots/);
|
|
193
|
+
assert.equal(getSliceTasks('M001', 'S02').length, 0, 'invalid scoped path must not persist');
|
|
194
|
+
} finally {
|
|
195
|
+
cleanup(base);
|
|
196
|
+
}
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
test('handlePlanSlice renders plan artifacts under worktree-local .gsd while using project DB', async () => {
|
|
200
|
+
const base = makeTmpBase();
|
|
201
|
+
const worktree = join(base, '.gsd', 'worktrees', 'M001');
|
|
202
|
+
mkdirSync(join(worktree, '.gsd'), { recursive: true });
|
|
203
|
+
mkdirSync(join(worktree, 'src', 'resources', 'extensions', 'gsd', 'tools'), { recursive: true });
|
|
204
|
+
writeFileSync(join(worktree, 'src', 'resources', 'extensions', 'gsd', 'tools', 'plan-milestone.ts'), '// fixture\n', 'utf-8');
|
|
205
|
+
writeFileSync(join(worktree, 'src', 'resources', 'extensions', 'gsd', 'tools', 'plan-task.ts'), '// fixture\n', 'utf-8');
|
|
206
|
+
openDatabase(join(base, '.gsd', 'gsd.db'));
|
|
207
|
+
|
|
208
|
+
try {
|
|
209
|
+
seedParentSlice();
|
|
210
|
+
|
|
211
|
+
const result = await handlePlanSlice(validParams(), worktree);
|
|
212
|
+
assert.ok(!('error' in result), `unexpected error: ${'error' in result ? result.error : ''}`);
|
|
213
|
+
|
|
214
|
+
const worktreePlan = join(worktree, '.gsd', 'milestones', 'M001', 'slices', 'S02', 'S02-PLAN.md');
|
|
215
|
+
const projectPlan = join(base, '.gsd', 'milestones', 'M001', 'slices', 'S02', 'S02-PLAN.md');
|
|
216
|
+
assert.ok(existsSync(worktreePlan), 'slice plan should be rendered to worktree-local .gsd');
|
|
217
|
+
assert.ok(!existsSync(projectPlan), 'slice plan should not be rendered to project .gsd');
|
|
218
|
+
assert.equal(result.planPath, realpathSync(worktreePlan));
|
|
219
|
+
} finally {
|
|
220
|
+
cleanup(base);
|
|
221
|
+
}
|
|
222
|
+
});
|
|
223
|
+
|
|
104
224
|
test('handlePlanSlice advances DB-derived state out of planning immediately', async () => {
|
|
105
225
|
const base = makeTmpBase();
|
|
106
226
|
openDatabase(join(base, '.gsd', 'gsd.db'));
|
|
@@ -125,6 +245,31 @@ test('handlePlanSlice advances DB-derived state out of planning immediately', as
|
|
|
125
245
|
}
|
|
126
246
|
});
|
|
127
247
|
|
|
248
|
+
test('handlePlanSlice clears sketch flag so DB-derived state leaves refining', async () => {
|
|
249
|
+
const base = makeTmpBase();
|
|
250
|
+
openDatabase(join(base, '.gsd', 'gsd.db'));
|
|
251
|
+
|
|
252
|
+
try {
|
|
253
|
+
insertMilestone({ id: 'M001', title: 'Milestone', status: 'active' });
|
|
254
|
+
insertSlice({ id: 'S02', milestoneId: 'M001', title: 'Planning slice', status: 'pending', demo: 'Rendered plans exist.', isSketch: true });
|
|
255
|
+
|
|
256
|
+
invalidateStateCache();
|
|
257
|
+
const before = await deriveState(base);
|
|
258
|
+
assert.equal(before.phase, 'refining');
|
|
259
|
+
|
|
260
|
+
const result = await handlePlanSlice(validParams(), base);
|
|
261
|
+
assert.ok(!('error' in result), `unexpected error: ${'error' in result ? result.error : ''}`);
|
|
262
|
+
assert.equal(getSlice('M001', 'S02')?.is_sketch, 0, 'planned slice must no longer be treated as a sketch');
|
|
263
|
+
|
|
264
|
+
invalidateStateCache();
|
|
265
|
+
const after = await deriveState(base);
|
|
266
|
+
assert.notEqual(after.phase, 'refining');
|
|
267
|
+
assert.equal(after.progress?.tasks?.total, 2);
|
|
268
|
+
} finally {
|
|
269
|
+
cleanup(base);
|
|
270
|
+
}
|
|
271
|
+
});
|
|
272
|
+
|
|
128
273
|
test('handlePlanSlice leaves omitted enrichment fields empty instead of rendering placeholders', async () => {
|
|
129
274
|
const base = makeTmpBase();
|
|
130
275
|
openDatabase(join(base, '.gsd', 'gsd.db'));
|
|
@@ -172,6 +317,28 @@ test('handlePlanSlice rejects invalid payloads', async () => {
|
|
|
172
317
|
}
|
|
173
318
|
});
|
|
174
319
|
|
|
320
|
+
test('handlePlanSlice explains string task IO fields must be arrays', async () => {
|
|
321
|
+
const base = makeTmpBase();
|
|
322
|
+
openDatabase(join(base, '.gsd', 'gsd.db'));
|
|
323
|
+
|
|
324
|
+
try {
|
|
325
|
+
seedParentSlice();
|
|
326
|
+
const result = await handlePlanSlice({
|
|
327
|
+
...validParams(),
|
|
328
|
+
tasks: [
|
|
329
|
+
{
|
|
330
|
+
...validParams().tasks[0],
|
|
331
|
+
inputs: 'src/index.ts' as unknown as string[],
|
|
332
|
+
},
|
|
333
|
+
],
|
|
334
|
+
}, base);
|
|
335
|
+
assert.ok('error' in result);
|
|
336
|
+
assert.match(result.error, /validation failed: tasks\[0\]\.inputs must be an array of strings, not string/);
|
|
337
|
+
} finally {
|
|
338
|
+
cleanup(base);
|
|
339
|
+
}
|
|
340
|
+
});
|
|
341
|
+
|
|
175
342
|
test('handlePlanSlice rejects absolute task IO paths outside the active worktree', async () => {
|
|
176
343
|
const base = makeTmpBase();
|
|
177
344
|
openDatabase(join(base, '.gsd', 'gsd.db'));
|
|
@@ -191,13 +358,70 @@ test('handlePlanSlice rejects absolute task IO paths outside the active worktree
|
|
|
191
358
|
}, base);
|
|
192
359
|
|
|
193
360
|
assert.ok('error' in result);
|
|
194
|
-
assert.match(result.error, /validation failed: tasks\[0\]\.inputs contains absolute path outside
|
|
361
|
+
assert.match(result.error, /validation failed: tasks\[0\]\.inputs contains absolute path outside allowed repository roots/);
|
|
195
362
|
assert.equal(getSliceTasks('M001', 'S02').length, 0, 'invalid planning IO must not persist tasks');
|
|
196
363
|
} finally {
|
|
197
364
|
cleanup(base);
|
|
198
365
|
}
|
|
199
366
|
});
|
|
200
367
|
|
|
368
|
+
test('handlePlanSlice rejects missing task input paths before persisting tasks', async () => {
|
|
369
|
+
const base = makeTmpBase();
|
|
370
|
+
openDatabase(join(base, '.gsd', 'gsd.db'));
|
|
371
|
+
|
|
372
|
+
try {
|
|
373
|
+
seedParentSlice();
|
|
374
|
+
const result = await handlePlanSlice({
|
|
375
|
+
...validParams(),
|
|
376
|
+
tasks: [
|
|
377
|
+
{
|
|
378
|
+
...validParams().tasks[0],
|
|
379
|
+
inputs: ['fixtures/missing-source.json'],
|
|
380
|
+
},
|
|
381
|
+
],
|
|
382
|
+
}, base);
|
|
383
|
+
|
|
384
|
+
assert.ok('error' in result);
|
|
385
|
+
assert.match(result.error, /pre-execution validation failed:/);
|
|
386
|
+
assert.match(result.error, /fixtures\/missing-source\.json/);
|
|
387
|
+
assert.equal(getSliceTasks('M001', 'S02').length, 0, 'invalid planning IO must not persist tasks');
|
|
388
|
+
} finally {
|
|
389
|
+
cleanup(base);
|
|
390
|
+
}
|
|
391
|
+
});
|
|
392
|
+
|
|
393
|
+
test('handlePlanSlice rejects task input paths created by later tasks before persisting tasks', async () => {
|
|
394
|
+
const base = makeTmpBase();
|
|
395
|
+
openDatabase(join(base, '.gsd', 'gsd.db'));
|
|
396
|
+
|
|
397
|
+
try {
|
|
398
|
+
seedParentSlice();
|
|
399
|
+
const params = validParams();
|
|
400
|
+
const result = await handlePlanSlice({
|
|
401
|
+
...params,
|
|
402
|
+
tasks: [
|
|
403
|
+
{
|
|
404
|
+
...params.tasks[0],
|
|
405
|
+
inputs: ['generated/report.json'],
|
|
406
|
+
expectedOutput: ['generated/summary.json'],
|
|
407
|
+
},
|
|
408
|
+
{
|
|
409
|
+
...params.tasks[1],
|
|
410
|
+
inputs: [],
|
|
411
|
+
expectedOutput: ['generated/report.json'],
|
|
412
|
+
},
|
|
413
|
+
],
|
|
414
|
+
}, base);
|
|
415
|
+
|
|
416
|
+
assert.ok('error' in result);
|
|
417
|
+
assert.match(result.error, /pre-execution validation failed:/);
|
|
418
|
+
assert.match(result.error, /sequence violation/);
|
|
419
|
+
assert.equal(getSliceTasks('M001', 'S02').length, 0, 'invalid task ordering must not persist tasks');
|
|
420
|
+
} finally {
|
|
421
|
+
cleanup(base);
|
|
422
|
+
}
|
|
423
|
+
});
|
|
424
|
+
|
|
201
425
|
test('handlePlanSlice accepts absolute task IO paths inside the active worktree', async () => {
|
|
202
426
|
const base = makeTmpBase();
|
|
203
427
|
openDatabase(join(base, '.gsd', 'gsd.db'));
|
|
@@ -304,3 +528,119 @@ test('handlePlanSlice reruns idempotently and refreshes parse-visible state', as
|
|
|
304
528
|
cleanup(base);
|
|
305
529
|
}
|
|
306
530
|
});
|
|
531
|
+
|
|
532
|
+
test('handlePlanSlice removes omitted pending tasks when replanning a smaller task set', async () => {
|
|
533
|
+
const base = makeTmpBase();
|
|
534
|
+
openDatabase(join(base, '.gsd', 'gsd.db'));
|
|
535
|
+
|
|
536
|
+
try {
|
|
537
|
+
seedParentSlice();
|
|
538
|
+
const fourTaskPlan = {
|
|
539
|
+
...validParams(),
|
|
540
|
+
tasks: [
|
|
541
|
+
...validParams().tasks,
|
|
542
|
+
{ ...validParams().tasks[0], taskId: 'T03', title: 'Third task' },
|
|
543
|
+
{ ...validParams().tasks[0], taskId: 'T04', title: 'Stale task', inputs: ['stale-input.py'] },
|
|
544
|
+
],
|
|
545
|
+
};
|
|
546
|
+
|
|
547
|
+
const first = await handlePlanSlice(fourTaskPlan, base);
|
|
548
|
+
assert.ok(!('error' in first), `unexpected error: ${'error' in first ? first.error : ''}`);
|
|
549
|
+
const staleTaskPlanPath = join(base, '.gsd', 'milestones', 'M001', 'slices', 'S02', 'tasks', 'T04-PLAN.md');
|
|
550
|
+
assert.ok(existsSync(staleTaskPlanPath), 'initial plan should render T04');
|
|
551
|
+
|
|
552
|
+
const second = await handlePlanSlice({
|
|
553
|
+
...validParams(),
|
|
554
|
+
tasks: fourTaskPlan.tasks.filter((task) => task.taskId !== 'T04'),
|
|
555
|
+
}, base);
|
|
556
|
+
assert.ok(!('error' in second), `unexpected error: ${'error' in second ? second.error : ''}`);
|
|
557
|
+
|
|
558
|
+
assert.deepEqual(getSliceTasks('M001', 'S02').map((task) => task.id), ['T01', 'T02', 'T03']);
|
|
559
|
+
assert.equal(getGateResults('M001', 'S02', 'task').some((gate) => gate.task_id === 'T04'), false);
|
|
560
|
+
assert.equal(existsSync(staleTaskPlanPath), false, 'omitted task plan artifact should be removed');
|
|
561
|
+
} finally {
|
|
562
|
+
cleanup(base);
|
|
563
|
+
}
|
|
564
|
+
});
|
|
565
|
+
|
|
566
|
+
test('handlePlanSlice rejects omitted completed tasks without changing slice or task state', async () => {
|
|
567
|
+
const base = makeTmpBase();
|
|
568
|
+
openDatabase(join(base, '.gsd', 'gsd.db'));
|
|
569
|
+
|
|
570
|
+
try {
|
|
571
|
+
seedParentSlice();
|
|
572
|
+
const fourTaskPlan = {
|
|
573
|
+
...validParams(),
|
|
574
|
+
tasks: [
|
|
575
|
+
...validParams().tasks,
|
|
576
|
+
{ ...validParams().tasks[0], taskId: 'T03', title: 'Third task' },
|
|
577
|
+
{ ...validParams().tasks[0], taskId: 'T04', title: 'Stale task', inputs: ['stale-input.py'] },
|
|
578
|
+
],
|
|
579
|
+
};
|
|
580
|
+
|
|
581
|
+
const first = await handlePlanSlice(fourTaskPlan, base);
|
|
582
|
+
assert.ok(!('error' in first), `unexpected error: ${'error' in first ? first.error : ''}`);
|
|
583
|
+
const staleTaskPlanPath = join(base, '.gsd', 'milestones', 'M001', 'slices', 'S02', 'tasks', 'T04-PLAN.md');
|
|
584
|
+
assert.ok(existsSync(staleTaskPlanPath), 'initial plan should render T04');
|
|
585
|
+
|
|
586
|
+
updateTaskStatus('M001', 'S02', 'T04', 'complete', '2026-05-12T00:00:00.000Z');
|
|
587
|
+
const tasksBefore = getSliceTasks('M001', 'S02');
|
|
588
|
+
const gatesBefore = getGateResults('M001', 'S02', 'task');
|
|
589
|
+
|
|
590
|
+
const second = await handlePlanSlice({
|
|
591
|
+
...validParams(),
|
|
592
|
+
goal: 'Rejected replan should not persist.',
|
|
593
|
+
tasks: fourTaskPlan.tasks.filter((task) => task.taskId !== 'T04'),
|
|
594
|
+
}, base);
|
|
595
|
+
assert.deepEqual(second, { error: 'cannot remove completed task T04' });
|
|
596
|
+
|
|
597
|
+
assert.equal(getSlice('M001', 'S02')?.goal, 'Persist slice planning through the DB.');
|
|
598
|
+
assert.deepEqual(getSliceTasks('M001', 'S02'), tasksBefore);
|
|
599
|
+
assert.deepEqual(getGateResults('M001', 'S02', 'task'), gatesBefore);
|
|
600
|
+
assert.ok(existsSync(staleTaskPlanPath), 'completed task plan artifact should remain after rejected replan');
|
|
601
|
+
} finally {
|
|
602
|
+
cleanup(base);
|
|
603
|
+
}
|
|
604
|
+
});
|
|
605
|
+
|
|
606
|
+
test('regression: validateTasks surfaces clean per-field errors for non-array IO inputs', async () => {
|
|
607
|
+
// Regression for the bug fixed in PR #5872: an earlier refactor on main
|
|
608
|
+
// (0b0e1a901) re-added validateStringArray() calls inside validateTasks
|
|
609
|
+
// without re-adding its import. The catch around validateParams swallowed
|
|
610
|
+
// the ReferenceError into a generic "validation failed: validateStringArray
|
|
611
|
+
// is not defined" message, so silent runtime breakage was possible.
|
|
612
|
+
//
|
|
613
|
+
// Exercise every validateStringArray call site (files, inputs, expectedOutput)
|
|
614
|
+
// so a future missing-import would surface as a per-field assertion failure
|
|
615
|
+
// here, not a deep ReferenceError that's easy to mis-diagnose.
|
|
616
|
+
const base = makeTmpBase();
|
|
617
|
+
openDatabase(join(base, '.gsd', 'gsd.db'));
|
|
618
|
+
|
|
619
|
+
try {
|
|
620
|
+
seedParentSlice();
|
|
621
|
+
|
|
622
|
+
for (const field of ['files', 'inputs', 'expectedOutput'] as const) {
|
|
623
|
+
const result = await handlePlanSlice({
|
|
624
|
+
...validParams(),
|
|
625
|
+
tasks: [{
|
|
626
|
+
...validParams().tasks[0],
|
|
627
|
+
[field]: 'not-an-array' as unknown as string[],
|
|
628
|
+
}],
|
|
629
|
+
}, base);
|
|
630
|
+
assert.ok('error' in result, `${field}: expected validation error, got success`);
|
|
631
|
+
assert.match(
|
|
632
|
+
result.error,
|
|
633
|
+
new RegExp(`tasks\\[0\\]\\.${field} must be an array`),
|
|
634
|
+
`${field}: expected per-field validation message, got: ${result.error}`,
|
|
635
|
+
);
|
|
636
|
+
assert.doesNotMatch(
|
|
637
|
+
result.error,
|
|
638
|
+
/is not defined/,
|
|
639
|
+
`${field}: validation surfaced ReferenceError — likely a missing import in plan-slice.ts`,
|
|
640
|
+
);
|
|
641
|
+
assert.equal(getSliceTasks('M001', 'S02').length, 0, `${field}: invalid input must not persist`);
|
|
642
|
+
}
|
|
643
|
+
} finally {
|
|
644
|
+
cleanup(base);
|
|
645
|
+
}
|
|
646
|
+
});
|
|
@@ -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'));
|
|
@@ -93,7 +110,7 @@ test('handlePlanTask rejects absolute task IO paths outside the active worktree'
|
|
|
93
110
|
}, base);
|
|
94
111
|
|
|
95
112
|
assert.ok('error' in result);
|
|
96
|
-
assert.match(result.error, /validation failed: inputs contains absolute path outside
|
|
113
|
+
assert.match(result.error, /validation failed: inputs contains absolute path outside allowed repository roots/);
|
|
97
114
|
assert.equal(getTask('M001', 'S02', 'T02'), null, 'invalid planning IO must not persist the task');
|
|
98
115
|
} finally {
|
|
99
116
|
cleanup(base);
|
|
@@ -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", () => {
|
|
@@ -127,6 +127,61 @@ import { b } from './b';
|
|
|
127
127
|
assert.equal(imports.length, 2);
|
|
128
128
|
});
|
|
129
129
|
|
|
130
|
+
test("ignores import-looking string literals in test fixtures", () => {
|
|
131
|
+
const source = `
|
|
132
|
+
const rewritten = source.replace(
|
|
133
|
+
'import { normalizeZagrebBusinessDeadline } from "./cutoff";',
|
|
134
|
+
'const helper = true;'
|
|
135
|
+
);
|
|
136
|
+
|
|
137
|
+
import realThing from "./real-thing";
|
|
138
|
+
`;
|
|
139
|
+
const imports = extractRelativeImports(source);
|
|
140
|
+
assert.deepEqual(imports, [
|
|
141
|
+
{ importPath: "./real-thing", lineNum: 7 },
|
|
142
|
+
]);
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
test("ignores import-looking lines inside template literals", () => {
|
|
146
|
+
const source = [
|
|
147
|
+
"const fixture = `",
|
|
148
|
+
"import missingThing from './missing-thing';",
|
|
149
|
+
"`;",
|
|
150
|
+
"",
|
|
151
|
+
"import realThing from './real-thing';",
|
|
152
|
+
].join("\n");
|
|
153
|
+
const imports = extractRelativeImports(source);
|
|
154
|
+
assert.deepEqual(imports, [
|
|
155
|
+
{ importPath: "./real-thing", lineNum: 5 },
|
|
156
|
+
]);
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
test("ignores require() inside string literals", () => {
|
|
160
|
+
const source = [
|
|
161
|
+
'const fixture = "const x = require(\'./missing\');";',
|
|
162
|
+
"const otherFixture = 'const y = require(\"./also-missing\");';",
|
|
163
|
+
"const real = require('./real');",
|
|
164
|
+
].join("\n");
|
|
165
|
+
const imports = extractRelativeImports(source);
|
|
166
|
+
assert.deepEqual(imports, [
|
|
167
|
+
{ importPath: "./real", lineNum: 3 },
|
|
168
|
+
]);
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
test("ignores require() inside template literals", () => {
|
|
172
|
+
const source = [
|
|
173
|
+
"const fixture = `",
|
|
174
|
+
"const x = require('./missing');",
|
|
175
|
+
"`;",
|
|
176
|
+
"",
|
|
177
|
+
"const real = require('./real');",
|
|
178
|
+
].join("\n");
|
|
179
|
+
const imports = extractRelativeImports(source);
|
|
180
|
+
assert.deepEqual(imports, [
|
|
181
|
+
{ importPath: "./real", lineNum: 5 },
|
|
182
|
+
]);
|
|
183
|
+
});
|
|
184
|
+
|
|
130
185
|
test("handles empty source", () => {
|
|
131
186
|
const imports = extractRelativeImports("");
|
|
132
187
|
assert.deepEqual(imports, []);
|
|
@@ -317,7 +372,23 @@ describe("resolveImportPath", () => {
|
|
|
317
372
|
assert.ok(result.resolvedPath?.endsWith("route.server.ts"));
|
|
318
373
|
});
|
|
319
374
|
|
|
320
|
-
test("
|
|
375
|
+
test("resolves dotted TS module stem like .test-utils via extension probing", (t) => {
|
|
376
|
+
const dir = mkdtempSync(join(tmpdir(), "post-exec-test-dotted-stem-"));
|
|
377
|
+
t.after(() => rmSync(dir, { recursive: true, force: true }));
|
|
378
|
+
mkdirSync(join(dir, "src", "lib"), { recursive: true });
|
|
379
|
+
writeFileSync(join(dir, "src", "lib", "test-helpers.test-utils.ts"), "export {};\n");
|
|
380
|
+
writeFileSync(join(dir, "src", "main.integration.test.ts"), "");
|
|
381
|
+
|
|
382
|
+
const result = resolveImportPath(
|
|
383
|
+
"./lib/test-helpers.test-utils",
|
|
384
|
+
"src/main.integration.test.ts",
|
|
385
|
+
dir
|
|
386
|
+
);
|
|
387
|
+
assert.ok(result.exists);
|
|
388
|
+
assert.ok(result.resolvedPath?.endsWith("test-helpers.test-utils.ts"));
|
|
389
|
+
});
|
|
390
|
+
|
|
391
|
+
test("unknown dotted stem falls through to extension probing", (t) => {
|
|
321
392
|
const dir = mkdtempSync(join(tmpdir(), "post-exec-test-unknown-shadow-"));
|
|
322
393
|
t.after(() => rmSync(dir, { recursive: true, force: true }));
|
|
323
394
|
mkdirSync(join(dir, "src"), { recursive: true });
|
|
@@ -325,8 +396,8 @@ describe("resolveImportPath", () => {
|
|
|
325
396
|
writeFileSync(join(dir, "src", "main.ts"), "");
|
|
326
397
|
|
|
327
398
|
const result = resolveImportPath("./video.mp4", "src/main.ts", dir);
|
|
328
|
-
assert.ok(
|
|
329
|
-
assert.
|
|
399
|
+
assert.ok(result.exists);
|
|
400
|
+
assert.ok(result.resolvedPath?.endsWith("video.mp4.ts"));
|
|
330
401
|
});
|
|
331
402
|
});
|
|
332
403
|
|
|
@@ -810,6 +881,37 @@ describe("runPostExecutionChecks", () => {
|
|
|
810
881
|
}
|
|
811
882
|
});
|
|
812
883
|
|
|
884
|
+
test("does not fail on import-looking strings in task key files", () => {
|
|
885
|
+
tempDir = join(tmpdir(), `post-exec-test-${Date.now()}`);
|
|
886
|
+
mkdirSync(tempDir, { recursive: true });
|
|
887
|
+
mkdirSync(join(tempDir, "tests"), { recursive: true });
|
|
888
|
+
writeFileSync(join(tempDir, "tests", "real-thing.ts"), "export default true;");
|
|
889
|
+
writeFileSync(
|
|
890
|
+
join(tempDir, "tests", "source-verifier.test.ts"),
|
|
891
|
+
`
|
|
892
|
+
const rewritten = source.replace(
|
|
893
|
+
'import { normalizeZagrebBusinessDeadline } from "./cutoff";',
|
|
894
|
+
'const helper = true;'
|
|
895
|
+
);
|
|
896
|
+
|
|
897
|
+
import realThing from "./real-thing";
|
|
898
|
+
assert.ok(realThing);
|
|
899
|
+
`
|
|
900
|
+
);
|
|
901
|
+
|
|
902
|
+
try {
|
|
903
|
+
const task = createTask({
|
|
904
|
+
id: "T03",
|
|
905
|
+
key_files: ["tests/source-verifier.test.ts"],
|
|
906
|
+
});
|
|
907
|
+
const result = runPostExecutionChecks(task, [], tempDir);
|
|
908
|
+
assert.equal(result.status, "pass");
|
|
909
|
+
assert.deepEqual(result.checks, []);
|
|
910
|
+
} finally {
|
|
911
|
+
rmSync(tempDir, { recursive: true, force: true });
|
|
912
|
+
}
|
|
913
|
+
});
|
|
914
|
+
|
|
813
915
|
test("returns fail status when blocking failure exists", () => {
|
|
814
916
|
tempDir = join(tmpdir(), `post-exec-test-${Date.now()}`);
|
|
815
917
|
mkdirSync(tempDir, { recursive: true });
|