@opengsd/gsd-pi 1.2.0-dev.844675c9 → 1.2.0-dev.b1abb545
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/dist/cli-web-branch.d.ts +2 -0
- package/dist/cli-web-branch.js +9 -2
- package/dist/help-text.js +5 -0
- package/dist/resources/.managed-resources-content-hash +1 -1
- package/dist/resources/extensions/ask-user-questions.js +78 -23
- package/dist/resources/extensions/claude-code-cli/stream-adapter.js +84 -228
- package/dist/resources/extensions/claude-code-cli/turn-assembler.js +224 -0
- package/dist/resources/extensions/github-sync/templates.js +3 -3
- package/dist/resources/extensions/gsd/artifact-projection.js +14 -0
- package/dist/resources/extensions/gsd/auto/loop.js +74 -56
- package/dist/resources/extensions/gsd/auto/orchestrator.js +109 -11
- package/dist/resources/extensions/gsd/auto/phases.js +28 -3
- package/dist/resources/extensions/gsd/auto/run-unit.js +2 -1
- package/dist/resources/extensions/gsd/auto/session.js +3 -0
- package/dist/resources/extensions/gsd/auto-dashboard.js +16 -4
- package/dist/resources/extensions/gsd/auto-dispatch.js +6 -5
- package/dist/resources/extensions/gsd/auto-model-selection.js +8 -0
- package/dist/resources/extensions/gsd/auto-post-unit.js +4 -3
- package/dist/resources/extensions/gsd/auto-prompts.js +81 -8
- package/dist/resources/extensions/gsd/auto-recovery.js +48 -49
- package/dist/resources/extensions/gsd/auto-runtime-state.js +14 -0
- package/dist/resources/extensions/gsd/auto-start.js +12 -23
- package/dist/resources/extensions/gsd/auto-timers.js +16 -2
- package/dist/resources/extensions/gsd/auto-tool-tracking.js +32 -0
- package/dist/resources/extensions/gsd/auto-unit-tool-scope.js +4 -29
- package/dist/resources/extensions/gsd/auto-verification.js +7 -7
- package/dist/resources/extensions/gsd/auto-worktree.js +21 -19
- package/dist/resources/extensions/gsd/auto.js +11 -7
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +28 -37
- package/dist/resources/extensions/gsd/bootstrap/dynamic-tools.js +11 -37
- package/dist/resources/extensions/gsd/bootstrap/query-tools.js +2 -2
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +100 -138
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +63 -4
- package/dist/resources/extensions/gsd/closeout-consistency-gate.js +21 -4
- package/dist/resources/extensions/gsd/codebase-generator.js +8 -4
- package/dist/resources/extensions/gsd/commands/handlers/auto.js +3 -0
- package/dist/resources/extensions/gsd/commands-handlers.js +20 -0
- package/dist/resources/extensions/gsd/commands-inspect.js +4 -8
- package/dist/resources/extensions/gsd/commands-maintenance.js +61 -41
- package/dist/resources/extensions/gsd/commands-ship.js +2 -2
- package/dist/resources/extensions/gsd/commands-verdict.js +12 -2
- package/dist/resources/extensions/gsd/db-workspace.js +103 -0
- package/dist/resources/extensions/gsd/delegation-policy.js +2 -10
- package/dist/resources/extensions/gsd/discussion-handoff.js +218 -0
- package/dist/resources/extensions/gsd/docs/preferences-reference.md +9 -0
- package/dist/resources/extensions/gsd/doctor.js +16 -9
- package/dist/resources/extensions/gsd/error-classifier.js +1 -1
- package/dist/resources/extensions/gsd/git-conflict-state.js +16 -1
- package/dist/resources/extensions/gsd/gsd-db.js +12 -0
- package/dist/resources/extensions/gsd/guided-flow.js +34 -468
- package/dist/resources/extensions/gsd/guided-unit-completion.js +225 -0
- package/dist/resources/extensions/gsd/markdown-renderer.js +2 -1
- package/dist/resources/extensions/gsd/mcp-filter.js +2 -1
- package/dist/resources/extensions/gsd/mcp-tool-name.js +26 -0
- package/dist/resources/extensions/gsd/md-importer.js +4 -3
- package/dist/resources/extensions/gsd/migrate/safety.js +2 -2
- package/dist/resources/extensions/gsd/migration-auto-check.js +3 -2
- package/dist/resources/extensions/gsd/milestone-closeout-proof.js +72 -0
- package/dist/resources/extensions/gsd/milestone-closeout.js +12 -4
- package/dist/resources/extensions/gsd/milestone-merge-transaction.js +10 -0
- package/dist/resources/extensions/gsd/milestone-planning-persistence.js +156 -0
- package/dist/resources/extensions/gsd/milestone-readiness.js +77 -0
- package/dist/resources/extensions/gsd/milestone-settlement.js +50 -0
- package/dist/resources/extensions/gsd/milestone-validation-evidence.js +73 -0
- package/dist/resources/extensions/gsd/milestone-validation-verdict.js +57 -0
- package/dist/resources/extensions/gsd/parallel-eligibility.js +3 -6
- package/dist/resources/extensions/gsd/parallel-orchestrator.js +3 -2
- package/dist/resources/extensions/gsd/preferences-diagnostics.js +67 -0
- package/dist/resources/extensions/gsd/preferences.js +147 -29
- package/dist/resources/extensions/gsd/prompts/complete-slice.md +1 -0
- package/dist/resources/extensions/gsd/prompts/execute-task.md +2 -0
- package/dist/resources/extensions/gsd/prompts/guided-discuss-project.md +3 -1
- package/dist/resources/extensions/gsd/prompts/plan-milestone.md +2 -0
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -0
- package/dist/resources/extensions/gsd/prompts/refine-slice.md +1 -0
- package/dist/resources/extensions/gsd/prompts/system.md +1 -1
- package/dist/resources/extensions/gsd/provider-payload-policy.js +83 -0
- package/dist/resources/extensions/gsd/pull-request-process.js +13 -0
- package/dist/resources/extensions/gsd/quality-gate-closure.js +109 -0
- package/dist/resources/extensions/gsd/question-transport.js +86 -0
- package/dist/resources/extensions/gsd/roadmap-slices.js +8 -2
- package/dist/resources/extensions/gsd/slice-parallel-orchestrator.js +3 -2
- package/dist/resources/extensions/gsd/state.js +13 -5
- package/dist/resources/extensions/gsd/templates/plan.md +7 -0
- package/dist/resources/extensions/gsd/templates/project.md +1 -0
- package/dist/resources/extensions/gsd/templates/roadmap.md +1 -1
- package/dist/resources/extensions/gsd/templates/uat.md +5 -1
- package/dist/resources/extensions/gsd/tool-contract.js +52 -8
- package/dist/resources/extensions/gsd/tool-presentation-plan.js +15 -34
- package/dist/resources/extensions/gsd/tool-surface-snapshot.js +17 -0
- package/dist/resources/extensions/gsd/tools/plan-milestone.js +15 -143
- package/dist/resources/extensions/gsd/tools/reassess-roadmap.js +39 -0
- package/dist/resources/extensions/gsd/tools/validate-milestone.js +15 -78
- package/dist/resources/extensions/gsd/uat-policy.js +16 -10
- package/dist/resources/extensions/gsd/uat-run.js +9 -14
- package/dist/resources/extensions/gsd/unit-context-composer.js +40 -20
- package/dist/resources/extensions/gsd/unit-runtime.js +3 -2
- package/dist/resources/extensions/gsd/unit-tool-contracts.js +2 -1
- package/dist/resources/extensions/gsd/user-input-boundary.js +23 -0
- package/dist/resources/extensions/gsd/validation-block-guard.js +2 -0
- package/dist/resources/extensions/gsd/web-app-uat.js +80 -0
- package/dist/resources/extensions/gsd/workflow-mcp.js +15 -102
- package/dist/resources/extensions/gsd/workflow-reconcile.js +4 -3
- package/dist/resources/extensions/gsd/workflow-tool-surface.js +46 -0
- package/dist/resources/extensions/gsd/workspace-git-guard.js +2 -0
- package/dist/resources/extensions/gsd/worktree-state-projection.js +33 -4
- package/dist/resources/extensions/gsd/worktree-telemetry.js +12 -0
- package/dist/resources/extensions/shared/interview-ui.js +2 -2
- package/dist/resources/shared/claude-runtime-floor.js +182 -0
- package/dist/tsconfig.extensions.tsbuildinfo +1 -1
- package/dist/update-cmd.js +20 -0
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +7 -7
- 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 +8 -8
- 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.html +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
- 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 +1 -1
- 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 +1 -1
- package/dist/web/standalone/.next/server/app/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +1 -1
- 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 +1 -1
- 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 +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +7 -7
- package/dist/web/standalone/.next/server/chunks/8357.js +1 -1
- 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/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/2659.b7b129ee6a769448.js +1 -0
- package/dist/web/standalone/.next/static/chunks/2772.bfa657f49f955239.js +1 -0
- package/dist/web/standalone/.next/static/chunks/{3616.4113d484a994e411.js → 3616.3c60753b8ffcbd2e.js} +1 -1
- package/dist/web/standalone/.next/static/chunks/4283.e4873b058df143a1.js +2 -0
- package/dist/web/standalone/.next/static/chunks/5826.a46ecdd1cfe8dabc.js +1 -0
- package/dist/web/standalone/.next/static/chunks/796.cf859a427a2cb2ac.js +10 -0
- package/dist/web/standalone/.next/static/chunks/8785.2e5a118797fb2dd2.js +1 -0
- package/dist/web/standalone/.next/static/chunks/{webpack-dda80a1ef5587410.js → webpack-fbea77b5f9953368.js} +1 -1
- package/dist/web/standalone/node_modules/node-pty/build/Makefile +1 -1
- package/dist/web-mode.d.ts +2 -0
- package/dist/web-mode.js +20 -8
- package/package.json +2 -1
- package/packages/cloud-mcp-gateway/package.json +2 -2
- package/packages/contracts/package.json +1 -1
- package/packages/daemon/package.json +4 -4
- package/packages/gsd-agent-core/dist/session/agent-session-extensions.d.ts +2 -0
- package/packages/gsd-agent-core/dist/session/agent-session-extensions.d.ts.map +1 -1
- package/packages/gsd-agent-core/dist/session/agent-session-extensions.js +14 -0
- package/packages/gsd-agent-core/dist/session/agent-session-extensions.js.map +1 -1
- package/packages/gsd-agent-core/package.json +5 -5
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js +106 -40
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-extension-widgets.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-extension-widgets.js +6 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-extension-widgets.js.map +1 -1
- package/packages/gsd-agent-modes/package.json +7 -7
- package/packages/mcp-server/dist/server.d.ts +10 -0
- package/packages/mcp-server/dist/server.d.ts.map +1 -1
- package/packages/mcp-server/dist/server.js +8 -0
- package/packages/mcp-server/dist/server.js.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.d.ts +41 -0
- package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.js +2 -1
- package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
- package/packages/mcp-server/package.json +3 -3
- package/packages/native/package.json +1 -1
- package/packages/pi-agent-core/package.json +1 -1
- package/packages/pi-ai/dist/models.generated.d.ts +8 -93
- package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
- package/packages/pi-ai/dist/models.generated.js +35 -120
- package/packages/pi-ai/dist/models.generated.js.map +1 -1
- package/packages/pi-ai/package.json +1 -1
- package/packages/pi-coding-agent/package.json +7 -7
- package/packages/pi-tui/dist/components/input.js +1 -1
- package/packages/pi-tui/dist/components/input.js.map +1 -1
- package/packages/pi-tui/dist/keys.d.ts.map +1 -1
- package/packages/pi-tui/dist/keys.js +39 -30
- package/packages/pi-tui/dist/keys.js.map +1 -1
- package/packages/pi-tui/dist/stdin-buffer.d.ts.map +1 -1
- package/packages/pi-tui/dist/stdin-buffer.js +22 -0
- package/packages/pi-tui/dist/stdin-buffer.js.map +1 -1
- package/packages/pi-tui/package.json +2 -2
- package/packages/rpc-client/package.json +2 -2
- package/pkg/package.json +1 -1
- package/src/resources/extensions/ask-user-questions.ts +87 -24
- package/src/resources/extensions/claude-code-cli/stream-adapter.ts +108 -281
- package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +240 -0
- package/src/resources/extensions/claude-code-cli/turn-assembler.ts +287 -0
- package/src/resources/extensions/github-sync/templates.ts +3 -3
- package/src/resources/extensions/github-sync/tests/templates.test.ts +2 -2
- package/src/resources/extensions/gsd/artifact-projection.ts +31 -0
- package/src/resources/extensions/gsd/auto/contracts.ts +32 -2
- package/src/resources/extensions/gsd/auto/loop-deps.ts +2 -0
- package/src/resources/extensions/gsd/auto/loop.ts +83 -61
- package/src/resources/extensions/gsd/auto/orchestrator.ts +125 -12
- package/src/resources/extensions/gsd/auto/phases.ts +35 -3
- package/src/resources/extensions/gsd/auto/run-unit.ts +2 -1
- package/src/resources/extensions/gsd/auto/session.ts +4 -0
- package/src/resources/extensions/gsd/auto-dashboard.ts +18 -4
- package/src/resources/extensions/gsd/auto-dispatch.ts +20 -7
- package/src/resources/extensions/gsd/auto-model-selection.ts +8 -0
- package/src/resources/extensions/gsd/auto-post-unit.ts +4 -3
- package/src/resources/extensions/gsd/auto-prompts.ts +107 -9
- package/src/resources/extensions/gsd/auto-recovery.ts +50 -50
- package/src/resources/extensions/gsd/auto-runtime-state.ts +26 -0
- package/src/resources/extensions/gsd/auto-start.ts +17 -20
- package/src/resources/extensions/gsd/auto-timers.ts +16 -2
- package/src/resources/extensions/gsd/auto-tool-tracking.ts +35 -0
- package/src/resources/extensions/gsd/auto-unit-tool-scope.ts +9 -30
- package/src/resources/extensions/gsd/auto-verification.ts +7 -8
- package/src/resources/extensions/gsd/auto-worktree.ts +33 -26
- package/src/resources/extensions/gsd/auto.ts +15 -8
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +29 -37
- package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +10 -37
- package/src/resources/extensions/gsd/bootstrap/query-tools.ts +2 -2
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +116 -151
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +107 -3
- package/src/resources/extensions/gsd/closeout-consistency-gate.ts +27 -5
- package/src/resources/extensions/gsd/codebase-generator.ts +9 -5
- package/src/resources/extensions/gsd/commands/handlers/auto.ts +3 -0
- package/src/resources/extensions/gsd/commands-handlers.ts +18 -0
- package/src/resources/extensions/gsd/commands-inspect.ts +7 -8
- package/src/resources/extensions/gsd/commands-maintenance.ts +74 -40
- package/src/resources/extensions/gsd/commands-ship.ts +2 -2
- package/src/resources/extensions/gsd/commands-verdict.ts +19 -2
- package/src/resources/extensions/gsd/db-workspace.ts +170 -0
- package/src/resources/extensions/gsd/delegation-policy.ts +3 -11
- package/src/resources/extensions/gsd/discussion-handoff.ts +276 -0
- package/src/resources/extensions/gsd/docs/preferences-reference.md +9 -0
- package/src/resources/extensions/gsd/doctor.ts +15 -5
- package/src/resources/extensions/gsd/error-classifier.ts +1 -1
- package/src/resources/extensions/gsd/git-conflict-state.ts +17 -1
- package/src/resources/extensions/gsd/gsd-db.ts +12 -0
- package/src/resources/extensions/gsd/guided-flow.ts +47 -558
- package/src/resources/extensions/gsd/guided-unit-completion.ts +275 -0
- package/src/resources/extensions/gsd/markdown-renderer.ts +2 -1
- package/src/resources/extensions/gsd/mcp-filter.ts +2 -1
- package/src/resources/extensions/gsd/mcp-tool-name.ts +35 -0
- package/src/resources/extensions/gsd/md-importer.ts +3 -3
- package/src/resources/extensions/gsd/migrate/safety.ts +2 -2
- package/src/resources/extensions/gsd/migration-auto-check.ts +2 -2
- package/src/resources/extensions/gsd/milestone-closeout-proof.ts +131 -0
- package/src/resources/extensions/gsd/milestone-closeout.ts +12 -4
- package/src/resources/extensions/gsd/milestone-merge-transaction.ts +47 -0
- package/src/resources/extensions/gsd/milestone-planning-persistence.ts +224 -0
- package/src/resources/extensions/gsd/milestone-readiness.ts +125 -0
- package/src/resources/extensions/gsd/milestone-settlement.ts +81 -0
- package/src/resources/extensions/gsd/milestone-validation-evidence.ts +95 -0
- package/src/resources/extensions/gsd/milestone-validation-verdict.ts +80 -0
- package/src/resources/extensions/gsd/parallel-eligibility.ts +4 -5
- package/src/resources/extensions/gsd/parallel-orchestrator.ts +6 -2
- package/src/resources/extensions/gsd/preferences-diagnostics.ts +98 -0
- package/src/resources/extensions/gsd/preferences-types.ts +16 -0
- package/src/resources/extensions/gsd/preferences.ts +173 -28
- package/src/resources/extensions/gsd/prompts/complete-slice.md +1 -0
- package/src/resources/extensions/gsd/prompts/execute-task.md +2 -0
- package/src/resources/extensions/gsd/prompts/guided-discuss-project.md +3 -1
- package/src/resources/extensions/gsd/prompts/plan-milestone.md +2 -0
- package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -0
- package/src/resources/extensions/gsd/prompts/refine-slice.md +1 -0
- package/src/resources/extensions/gsd/prompts/system.md +1 -1
- package/src/resources/extensions/gsd/provider-payload-policy.ts +140 -0
- package/src/resources/extensions/gsd/pull-request-process.ts +41 -0
- package/src/resources/extensions/gsd/quality-gate-closure.ts +140 -0
- package/src/resources/extensions/gsd/question-transport.ts +138 -0
- package/src/resources/extensions/gsd/roadmap-slices.ts +8 -2
- package/src/resources/extensions/gsd/slice-parallel-orchestrator.ts +6 -2
- package/src/resources/extensions/gsd/state.ts +15 -5
- package/src/resources/extensions/gsd/templates/plan.md +7 -0
- package/src/resources/extensions/gsd/templates/project.md +1 -0
- package/src/resources/extensions/gsd/templates/roadmap.md +1 -1
- package/src/resources/extensions/gsd/templates/uat.md +5 -1
- package/src/resources/extensions/gsd/tests/ask-user-questions-render.test.ts +92 -0
- package/src/resources/extensions/gsd/tests/auto-dashboard.test.ts +29 -1
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +321 -5
- package/src/resources/extensions/gsd/tests/auto-milestone-target.test.ts +23 -0
- package/src/resources/extensions/gsd/tests/auto-model-selection-tool-poisoning.test.ts +18 -0
- package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +133 -4
- package/src/resources/extensions/gsd/tests/auto-runtime-state.test.ts +34 -0
- package/src/resources/extensions/gsd/tests/canonical-milestone-root.test.ts +20 -0
- package/src/resources/extensions/gsd/tests/codebase-generator.test.ts +22 -0
- package/src/resources/extensions/gsd/tests/commands-dispatcher-workspace-git.test.ts +11 -0
- package/src/resources/extensions/gsd/tests/commands-verdict.test.ts +38 -1
- package/src/resources/extensions/gsd/tests/dispatch-complete-milestone-guard.test.ts +34 -3
- package/src/resources/extensions/gsd/tests/dispatch-run-uat-browser-tools.test.ts +88 -0
- package/src/resources/extensions/gsd/tests/doctor-scope-db-unavailable.test.ts +18 -0
- package/src/resources/extensions/gsd/tests/execute-task-rendering.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/fixtures/pr-body/swarm-lane-no-blockers.md +1 -5
- package/src/resources/extensions/gsd/tests/fixtures/pr-body/swarm-lane-with-blockers.md +1 -5
- package/src/resources/extensions/gsd/tests/gate-state-canonicalization.test.ts +48 -1
- package/src/resources/extensions/gsd/tests/mcp-tool-name.test.ts +34 -0
- package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +58 -0
- package/src/resources/extensions/gsd/tests/milestone-closeout-proof.test.ts +99 -0
- package/src/resources/extensions/gsd/tests/milestone-closeout.test.ts +25 -0
- package/src/resources/extensions/gsd/tests/milestone-merge-transaction.test.ts +46 -0
- package/src/resources/extensions/gsd/tests/milestone-readiness.test.ts +65 -0
- package/src/resources/extensions/gsd/tests/milestone-validation-evidence.test.ts +41 -0
- package/src/resources/extensions/gsd/tests/milestone-validation-verdict.test.ts +55 -0
- package/src/resources/extensions/gsd/tests/plan-milestone.test.ts +45 -0
- package/src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +2 -0
- package/src/resources/extensions/gsd/tests/planning-crossval.test.ts +45 -0
- package/src/resources/extensions/gsd/tests/preferences-diagnostics.test.ts +67 -0
- package/src/resources/extensions/gsd/tests/preferences.test.ts +183 -0
- package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +46 -0
- package/src/resources/extensions/gsd/tests/provider-errors.test.ts +9 -0
- package/src/resources/extensions/gsd/tests/provider-payload-policy.test.ts +165 -0
- package/src/resources/extensions/gsd/tests/pull-request-process.test.ts +47 -0
- package/src/resources/extensions/gsd/tests/register-hooks-depth-verification.test.ts +94 -0
- package/src/resources/extensions/gsd/tests/roadmap-parse-regression.test.ts +40 -0
- package/src/resources/extensions/gsd/tests/runtime-invariant-modules.test.ts +25 -1
- package/src/resources/extensions/gsd/tests/session-start-footer.test.ts +80 -0
- package/src/resources/extensions/gsd/tests/single-writer-invariant.test.ts +101 -1
- package/src/resources/extensions/gsd/tests/stale-queued-milestone.test.ts +27 -0
- package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/tool-availability-audit.test.ts +35 -0
- package/src/resources/extensions/gsd/tests/tool-naming.test.ts +35 -42
- package/src/resources/extensions/gsd/tests/uat-policy.test.ts +23 -0
- package/src/resources/extensions/gsd/tests/unit-context-composer.test.ts +47 -0
- package/src/resources/extensions/gsd/tests/user-input-boundary.test.ts +86 -1
- package/src/resources/extensions/gsd/tests/validate-milestone-stuck-guard.test.ts +39 -0
- package/src/resources/extensions/gsd/tests/web-app-uat.test.ts +150 -0
- package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +126 -9
- package/src/resources/extensions/gsd/tests/workspace-git-preflight.test.ts +15 -0
- package/src/resources/extensions/gsd/tests/worktree-manager.test.ts +21 -0
- package/src/resources/extensions/gsd/tests/worktree-projection-writers.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/worktree-telemetry.test.ts +22 -0
- package/src/resources/extensions/gsd/tests/write-gate.test.ts +79 -0
- package/src/resources/extensions/gsd/tool-contract.ts +86 -8
- package/src/resources/extensions/gsd/tool-presentation-plan.ts +16 -33
- package/src/resources/extensions/gsd/tool-surface-snapshot.ts +47 -0
- package/src/resources/extensions/gsd/tools/plan-milestone.ts +19 -160
- package/src/resources/extensions/gsd/tools/reassess-roadmap.ts +43 -0
- package/src/resources/extensions/gsd/tools/validate-milestone.ts +25 -84
- package/src/resources/extensions/gsd/uat-policy.ts +19 -10
- package/src/resources/extensions/gsd/uat-run.ts +10 -14
- package/src/resources/extensions/gsd/unit-context-composer.ts +85 -20
- package/src/resources/extensions/gsd/unit-runtime.ts +3 -2
- package/src/resources/extensions/gsd/unit-tool-contracts.ts +2 -1
- package/src/resources/extensions/gsd/user-input-boundary.ts +18 -0
- package/src/resources/extensions/gsd/validation-block-guard.ts +2 -0
- package/src/resources/extensions/gsd/web-app-uat.ts +101 -0
- package/src/resources/extensions/gsd/workflow-mcp.ts +22 -110
- package/src/resources/extensions/gsd/workflow-reconcile.ts +3 -3
- package/src/resources/extensions/gsd/workflow-tool-surface.ts +73 -0
- package/src/resources/extensions/gsd/workspace-git-guard.ts +1 -0
- package/src/resources/extensions/gsd/worktree-lifecycle.ts +7 -16
- package/src/resources/extensions/gsd/worktree-state-projection.ts +55 -7
- package/src/resources/extensions/gsd/worktree-telemetry.ts +16 -0
- package/src/resources/extensions/shared/interview-ui.ts +15 -2
- package/src/resources/shared/claude-runtime-floor.ts +248 -0
- package/dist/web/standalone/.next/static/chunks/2659.feb6499ca863ebfc.js +0 -1
- package/dist/web/standalone/.next/static/chunks/2772.151789db0edea835.js +0 -1
- package/dist/web/standalone/.next/static/chunks/4283.10a065467b5340d8.js +0 -2
- package/dist/web/standalone/.next/static/chunks/5826.960dc4634cc9b0d3.js +0 -1
- package/dist/web/standalone/.next/static/chunks/796.46f811c0fac23aab.js +0 -10
- package/dist/web/standalone/.next/static/chunks/8785.d32f7a61f55c1600.js +0 -1
- /package/dist/web/standalone/.next/static/{Qbr81pQ-pbQXP4bq2VXLv → 3PtrU9qGPEXwNLWkIyiqk}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{Qbr81pQ-pbQXP4bq2VXLv → 3PtrU9qGPEXwNLWkIyiqk}/_ssgManifest.js +0 -0
|
@@ -55,6 +55,31 @@ test("isMilestoneCloseoutSettled requires DB closed and summary artifact", async
|
|
|
55
55
|
assert.equal(settled, true);
|
|
56
56
|
});
|
|
57
57
|
|
|
58
|
+
test("isMilestoneCloseoutSettled accepts summary artifacts in a live milestone worktree", async () => {
|
|
59
|
+
const base = mkdtempSync(join(tmpdir(), "gsd-milestone-closeout-worktree-"));
|
|
60
|
+
tmpDirs.push(base);
|
|
61
|
+
mkdirSync(join(base, ".gsd"), { recursive: true });
|
|
62
|
+
openDatabase(join(base, ".gsd", "gsd.db"));
|
|
63
|
+
insertMilestone({ id: "M001", title: "Done", status: "complete" });
|
|
64
|
+
insertSlice({ id: "S01", milestoneId: "M001", title: "Done Slice", status: "complete" });
|
|
65
|
+
insertAssessment({
|
|
66
|
+
path: "milestones/M001/M001-VALIDATION.md",
|
|
67
|
+
milestoneId: "M001",
|
|
68
|
+
status: "pass",
|
|
69
|
+
scope: "milestone-validation",
|
|
70
|
+
fullContent: "verdict: pass",
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
const worktreeRoot = join(base, ".gsd", "worktrees", "M001");
|
|
74
|
+
const milestoneDir = join(worktreeRoot, ".gsd", "milestones", "M001");
|
|
75
|
+
mkdirSync(milestoneDir, { recursive: true });
|
|
76
|
+
writeFileSync(join(worktreeRoot, ".git"), `gitdir: ${join(base, ".git", "worktrees", "M001")}\n`);
|
|
77
|
+
writeFileSync(join(milestoneDir, "M001-SUMMARY.md"), "# Milestone Summary\n");
|
|
78
|
+
|
|
79
|
+
const settled = await isMilestoneCloseoutSettled("M001", base);
|
|
80
|
+
assert.equal(settled, true);
|
|
81
|
+
});
|
|
82
|
+
|
|
58
83
|
test("isMilestoneCloseoutSettled returns false when summary artifact is missing", async () => {
|
|
59
84
|
const base = mkdtempSync(join(tmpdir(), "gsd-milestone-closeout-missing-"));
|
|
60
85
|
tmpDirs.push(base);
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
// Project/App: gsd-pi
|
|
2
|
+
// File Purpose: Tests for the milestone merge transaction wrapper.
|
|
3
|
+
|
|
4
|
+
import test from "node:test";
|
|
5
|
+
import assert from "node:assert/strict";
|
|
6
|
+
|
|
7
|
+
import {
|
|
8
|
+
createMilestoneMergeTransaction,
|
|
9
|
+
runMilestoneMergeTransaction,
|
|
10
|
+
} from "../milestone-merge-transaction.js";
|
|
11
|
+
|
|
12
|
+
test("runMilestoneMergeTransaction delegates to the supplied merge runner", () => {
|
|
13
|
+
const calls: unknown[][] = [];
|
|
14
|
+
const result = runMilestoneMergeTransaction(
|
|
15
|
+
{
|
|
16
|
+
mergeMilestoneToMain: (basePath, milestoneId, roadmapContent) => {
|
|
17
|
+
calls.push([basePath, milestoneId, roadmapContent]);
|
|
18
|
+
return { pushed: true, codeFilesChanged: true, commitMessage: "merge M001" };
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
basePath: "/repo",
|
|
23
|
+
milestoneId: "M001",
|
|
24
|
+
roadmapContent: "# M001",
|
|
25
|
+
},
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
assert.deepEqual(calls, [["/repo", "M001", "# M001"]]);
|
|
29
|
+
assert.deepEqual(result, {
|
|
30
|
+
pushed: true,
|
|
31
|
+
codeFilesChanged: true,
|
|
32
|
+
commitMessage: "merge M001",
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
test("createMilestoneMergeTransaction returns a lifecycle-compatible runner", () => {
|
|
37
|
+
const runner = createMilestoneMergeTransaction(() => ({
|
|
38
|
+
pushed: false,
|
|
39
|
+
codeFilesChanged: false,
|
|
40
|
+
}));
|
|
41
|
+
|
|
42
|
+
assert.deepEqual(runner("/repo", "M002", "# M002"), {
|
|
43
|
+
pushed: false,
|
|
44
|
+
codeFilesChanged: false,
|
|
45
|
+
});
|
|
46
|
+
});
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import test from "node:test";
|
|
2
|
+
import assert from "node:assert/strict";
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
classifyMilestoneReadiness,
|
|
6
|
+
describeMilestoneReadinessPhase,
|
|
7
|
+
formatAcceptedDiscussHandoffMessage,
|
|
8
|
+
readinessNeedsDiscussion,
|
|
9
|
+
} from "../milestone-readiness.ts";
|
|
10
|
+
|
|
11
|
+
test("classifyMilestoneReadiness distinguishes queued shells from draft discussion work", () => {
|
|
12
|
+
const shell = classifyMilestoneReadiness({
|
|
13
|
+
status: "queued",
|
|
14
|
+
hasDraftContext: true,
|
|
15
|
+
sliceCount: 0,
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
assert.equal(shell.kind, "queued-shell");
|
|
19
|
+
assert.equal(readinessNeedsDiscussion(shell), true);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
test("classifyMilestoneReadiness marks context-only milestones as planning pending", () => {
|
|
23
|
+
const readiness = classifyMilestoneReadiness({
|
|
24
|
+
status: "queued",
|
|
25
|
+
hasContext: true,
|
|
26
|
+
sliceCount: 0,
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
assert.equal(readiness.kind, "planning-pending");
|
|
30
|
+
assert.equal(formatAcceptedDiscussHandoffMessage("M001", readiness), "Milestone M001 context captured. Continuing the planning pipeline.");
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
test("classifyMilestoneReadiness marks persisted slices as executable plan", () => {
|
|
34
|
+
const readiness = classifyMilestoneReadiness({
|
|
35
|
+
status: "active",
|
|
36
|
+
hasContext: true,
|
|
37
|
+
sliceCount: 1,
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
assert.equal(readiness.kind, "executable-plan");
|
|
41
|
+
assert.equal(formatAcceptedDiscussHandoffMessage("M001", readiness), "Milestone M001 ready.");
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
test("formatAcceptedDiscussHandoffMessage preserves ready copy for any executable plan", () => {
|
|
45
|
+
const readiness = classifyMilestoneReadiness({
|
|
46
|
+
status: "complete",
|
|
47
|
+
hasContext: true,
|
|
48
|
+
sliceCount: 1,
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
assert.equal(readiness.kind, "terminal");
|
|
52
|
+
assert.equal(formatAcceptedDiscussHandoffMessage("M001", readiness), "Milestone M001 ready.");
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
test("describeMilestoneReadinessPhase keeps dashboard phase copy centralized", () => {
|
|
56
|
+
assert.deepEqual(describeMilestoneReadinessPhase("needs-discussion"), {
|
|
57
|
+
label: "Discuss milestone draft",
|
|
58
|
+
description: "Milestone has a draft context — needs discussion before planning.",
|
|
59
|
+
});
|
|
60
|
+
assert.deepEqual(describeMilestoneReadinessPhase("pre-planning"), {
|
|
61
|
+
label: "Research & plan milestone",
|
|
62
|
+
description: "Scout the landscape and create the roadmap.",
|
|
63
|
+
});
|
|
64
|
+
assert.equal(describeMilestoneReadinessPhase("executing"), null);
|
|
65
|
+
});
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
// Project/App: gsd-pi
|
|
2
|
+
// File Purpose: Tests for forwarded milestone validation evidence helpers.
|
|
3
|
+
|
|
4
|
+
import test from "node:test";
|
|
5
|
+
import assert from "node:assert/strict";
|
|
6
|
+
|
|
7
|
+
import {
|
|
8
|
+
applyBrowserEvidenceGate,
|
|
9
|
+
hasRuntimeExecutableUatEvidenceText,
|
|
10
|
+
} from "../milestone-validation-evidence.js";
|
|
11
|
+
|
|
12
|
+
test("hasRuntimeExecutableUatEvidenceText requires runtime-executable PASS evidence", () => {
|
|
13
|
+
const evidence = [
|
|
14
|
+
"---",
|
|
15
|
+
"uatType: runtime-executable",
|
|
16
|
+
"verdict: PASS",
|
|
17
|
+
"---",
|
|
18
|
+
"| Check | Mode | Result | Evidence |",
|
|
19
|
+
"| DOM | runtime | PASS | gsd_uat_exec:.gsd/evidence/uat/M001/S01/dom.json |",
|
|
20
|
+
].join("\n");
|
|
21
|
+
|
|
22
|
+
assert.equal(hasRuntimeExecutableUatEvidenceText(evidence), true);
|
|
23
|
+
assert.equal(hasRuntimeExecutableUatEvidenceText(evidence.replace("runtime | PASS", "manual | PASS")), false);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
test("applyBrowserEvidenceGate records downgrade rationale", () => {
|
|
27
|
+
const params = applyBrowserEvidenceGate({
|
|
28
|
+
milestoneId: "M001",
|
|
29
|
+
verdict: "pass",
|
|
30
|
+
remediationRound: 0,
|
|
31
|
+
successCriteriaChecklist: "",
|
|
32
|
+
sliceDeliveryAudit: "",
|
|
33
|
+
crossSliceIntegration: "",
|
|
34
|
+
requirementCoverage: "",
|
|
35
|
+
verdictRationale: "Initial rationale.",
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
assert.equal(params.verdict, "needs-attention");
|
|
39
|
+
assert.match(params.verdictRationale, /Initial rationale/);
|
|
40
|
+
assert.match(params.verdictRationale, /Browser evidence gate/);
|
|
41
|
+
});
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import test from "node:test";
|
|
2
|
+
import assert from "node:assert/strict";
|
|
3
|
+
import { mkdirSync, writeFileSync, rmSync } from "node:fs";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
import { tmpdir } from "node:os";
|
|
6
|
+
|
|
7
|
+
import { resolveMilestoneValidationVerdict } from "../milestone-validation-verdict.ts";
|
|
8
|
+
import {
|
|
9
|
+
openDatabase,
|
|
10
|
+
closeDatabase,
|
|
11
|
+
insertAssessment,
|
|
12
|
+
insertMilestone,
|
|
13
|
+
} from "../gsd-db.ts";
|
|
14
|
+
import { invalidateAllCaches } from "../cache.ts";
|
|
15
|
+
import { _clearGsdRootCache } from "../paths.ts";
|
|
16
|
+
|
|
17
|
+
function setup(base: string): void {
|
|
18
|
+
mkdirSync(join(base, ".gsd", "milestones", "M001"), { recursive: true });
|
|
19
|
+
process.chdir(base);
|
|
20
|
+
_clearGsdRootCache();
|
|
21
|
+
openDatabase(join(base, ".gsd", "gsd.db"));
|
|
22
|
+
invalidateAllCaches();
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
test("resolveMilestoneValidationVerdict prefers DB pass over stale worktree needs-attention", async () => {
|
|
26
|
+
const base = join(tmpdir(), `validation-verdict-${Date.now()}`);
|
|
27
|
+
mkdirSync(base, { recursive: true });
|
|
28
|
+
const worktree = join(base, ".gsd", "worktrees", "M001");
|
|
29
|
+
mkdirSync(join(worktree, ".gsd", "milestones", "M001"), { recursive: true });
|
|
30
|
+
writeFileSync(join(worktree, ".git"), "gitdir: ../.git/worktrees/M001\n", "utf-8");
|
|
31
|
+
writeFileSync(
|
|
32
|
+
join(worktree, ".gsd", "milestones", "M001", "M001-VALIDATION.md"),
|
|
33
|
+
"---\nverdict: needs-attention\n---\n\n# Validation\nStale worktree copy.\n",
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
try {
|
|
37
|
+
setup(base);
|
|
38
|
+
insertMilestone({ id: "M001", title: "Test", status: "active" });
|
|
39
|
+
insertAssessment({
|
|
40
|
+
path: join(worktree, ".gsd", "milestones", "M001", "M001-VALIDATION.md"),
|
|
41
|
+
milestoneId: "M001",
|
|
42
|
+
sliceId: null,
|
|
43
|
+
taskId: null,
|
|
44
|
+
status: "pass",
|
|
45
|
+
scope: "milestone-validation",
|
|
46
|
+
fullContent: "---\nverdict: pass\n---\n\n# Validation\nManual override.\n",
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
const verdict = await resolveMilestoneValidationVerdict(base, "M001");
|
|
50
|
+
assert.equal(verdict, "pass");
|
|
51
|
+
} finally {
|
|
52
|
+
closeDatabase();
|
|
53
|
+
rmSync(base, { recursive: true, force: true });
|
|
54
|
+
}
|
|
55
|
+
});
|
|
@@ -347,3 +347,48 @@ test('handlePlanMilestone updates depends_on when a queued milestone row already
|
|
|
347
347
|
cleanup(base);
|
|
348
348
|
}
|
|
349
349
|
});
|
|
350
|
+
|
|
351
|
+
// Regression #566: bracket-wrapped slice ID in depends should be rejected
|
|
352
|
+
test('handlePlanMilestone rejects bracket-wrapped depends like ["[S01]"]', async () => {
|
|
353
|
+
const base = makeTmpBase();
|
|
354
|
+
const dbPath = join(base, '.gsd', 'gsd.db');
|
|
355
|
+
openDatabase(dbPath);
|
|
356
|
+
|
|
357
|
+
try {
|
|
358
|
+
const params = validParams();
|
|
359
|
+
// Simulate the LLM sending "[S01]" (the markdown fragment) instead of "S01"
|
|
360
|
+
const corruptSlices = [
|
|
361
|
+
params.slices[0],
|
|
362
|
+
{ ...params.slices[1], depends: ['[S01]'] },
|
|
363
|
+
];
|
|
364
|
+
const result = await handlePlanMilestone({ ...params, slices: corruptSlices }, base);
|
|
365
|
+
assert.ok('error' in result, 'should return an error for bracket-wrapped depends');
|
|
366
|
+
assert.match(result.error, /slices\[1\]\.depends must be an array of valid slice IDs/,
|
|
367
|
+
'error should mention invalid slice ID format');
|
|
368
|
+
assert.equal(getMilestoneSlices('M001').length, 0, 'no slices should persist on validation failure');
|
|
369
|
+
} finally {
|
|
370
|
+
cleanup(base);
|
|
371
|
+
}
|
|
372
|
+
});
|
|
373
|
+
|
|
374
|
+
// Regression #566: unknown slice ID in depends should be rejected
|
|
375
|
+
test('handlePlanMilestone rejects depends referencing a slice not in the same milestone', async () => {
|
|
376
|
+
const base = makeTmpBase();
|
|
377
|
+
const dbPath = join(base, '.gsd', 'gsd.db');
|
|
378
|
+
openDatabase(dbPath);
|
|
379
|
+
|
|
380
|
+
try {
|
|
381
|
+
const params = validParams();
|
|
382
|
+
const corruptSlices = [
|
|
383
|
+
params.slices[0],
|
|
384
|
+
{ ...params.slices[1], depends: ['S99'] },
|
|
385
|
+
];
|
|
386
|
+
const result = await handlePlanMilestone({ ...params, slices: corruptSlices }, base);
|
|
387
|
+
assert.ok('error' in result, 'should return an error for unknown depends slice');
|
|
388
|
+
assert.match(result.error, /references unknown slice "S99"/,
|
|
389
|
+
'error should name the unknown slice');
|
|
390
|
+
assert.equal(getMilestoneSlices('M001').length, 0, 'no slices should persist on validation failure');
|
|
391
|
+
} finally {
|
|
392
|
+
cleanup(base);
|
|
393
|
+
}
|
|
394
|
+
});
|
|
@@ -137,6 +137,7 @@ test("skillActivation default leaves no unresolved placeholder", () => {
|
|
|
137
137
|
carryForwardSection: "Carry forward",
|
|
138
138
|
resumeSection: "Resume",
|
|
139
139
|
priorTaskLines: "- (no prior tasks)",
|
|
140
|
+
onDemandContext: "",
|
|
140
141
|
templatesDir: join(fixtureRoot, "templates"),
|
|
141
142
|
taskSummaryPath: join(fixtureRoot, ".gsd", "milestones", "M001", "slices", "S01", "tasks", "T01-SUMMARY.md"),
|
|
142
143
|
inlinedTemplates: "Template",
|
|
@@ -163,6 +164,7 @@ test("custom skillActivation is substituted into execute-task", () => {
|
|
|
163
164
|
carryForwardSection: "Carry forward",
|
|
164
165
|
resumeSection: "Resume",
|
|
165
166
|
priorTaskLines: "- (no prior tasks)",
|
|
167
|
+
onDemandContext: "",
|
|
166
168
|
templatesDir: join(fixtureRoot, "templates"),
|
|
167
169
|
taskSummaryPath: join(fixtureRoot, ".gsd", "milestones", "M001", "slices", "S01", "tasks", "T01-SUMMARY.md"),
|
|
168
170
|
inlinedTemplates: "Template",
|
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
insertTask,
|
|
16
16
|
getMilestoneSlices,
|
|
17
17
|
getSliceTasks,
|
|
18
|
+
_getAdapter,
|
|
18
19
|
} from '../gsd-db.ts';
|
|
19
20
|
import {
|
|
20
21
|
renderRoadmapFromDb,
|
|
@@ -423,4 +424,48 @@ console.log('\n=== planning-crossval Test 6: ROADMAP descriptor projection dir =
|
|
|
423
424
|
}
|
|
424
425
|
}
|
|
425
426
|
|
|
427
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
428
|
+
// Test 7: Renderer strips bracket-wrapped depends from corrupt DB rows (#566)
|
|
429
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
430
|
+
// Simulates a DB that was corrupted before the insertSlice validation guard
|
|
431
|
+
// was added (issue #566). The renderer must recover "[S01]" → "S01" rather
|
|
432
|
+
// than silently dropping the dependency and rendering depends:[].
|
|
433
|
+
|
|
434
|
+
console.log('\n=== planning-crossval Test 7: renderer recovers bracket-wrapped depends (#566) ===');
|
|
435
|
+
{
|
|
436
|
+
const base = realpathSync(createFixtureBase());
|
|
437
|
+
const dbPath = join(base, '.gsd', 'gsd.db');
|
|
438
|
+
openDatabase(dbPath);
|
|
439
|
+
try {
|
|
440
|
+
scaffoldDirs(base, 'M001', ['S01', 'S02']);
|
|
441
|
+
|
|
442
|
+
insertMilestone({
|
|
443
|
+
id: 'M001',
|
|
444
|
+
title: 'Bracket Recovery',
|
|
445
|
+
status: 'active',
|
|
446
|
+
planning: { vision: 'Recover bracket-wrapped depends from corrupt DB.' },
|
|
447
|
+
});
|
|
448
|
+
|
|
449
|
+
insertSlice({ id: 'S01', milestoneId: 'M001', title: 'Foundation', status: 'pending', risk: 'low', depends: [], demo: 'Foundation done.', sequence: 1 });
|
|
450
|
+
insertSlice({ id: 'S02', milestoneId: 'M001', title: 'Build', status: 'pending', risk: 'medium', depends: [], demo: 'Build done.', sequence: 2 });
|
|
451
|
+
|
|
452
|
+
// Bypass insertSlice validation to simulate pre-fix corrupt DB state
|
|
453
|
+
// (insertSlice now rejects bracket-wrapped IDs, but old DBs may have them)
|
|
454
|
+
_getAdapter()?.prepare('UPDATE slices SET depends = ? WHERE id = ? AND milestone_id = ?')
|
|
455
|
+
.run('["[S01]"]', 'S02', 'M001');
|
|
456
|
+
|
|
457
|
+
const rendered = await renderRoadmapFromDb(base, 'M001');
|
|
458
|
+
const content = readFileSync(rendered.roadmapPath, 'utf-8');
|
|
459
|
+
const parsed = parseRoadmapSlices(content);
|
|
460
|
+
|
|
461
|
+
assertEq(parsed.length, 2, 'T7: 2 slices parsed');
|
|
462
|
+
assertEq(parsed[1]?.depends.length, 1, 'T7: S02 has 1 dependency after bracket recovery');
|
|
463
|
+
assertEq(parsed[1]?.depends[0], 'S01', 'T7: recovered dependency is "S01", not "[S01]"');
|
|
464
|
+
assertTrue(content.includes('`depends:[S01]`'), 'T7: S02 renders with recovered depends:[S01] not empty depends:[]');
|
|
465
|
+
} finally {
|
|
466
|
+
closeDatabase();
|
|
467
|
+
cleanup(base);
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
|
|
426
471
|
report();
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import test from "node:test";
|
|
2
|
+
import assert from "node:assert/strict";
|
|
3
|
+
import { mkdtempSync, mkdirSync, rmSync, writeFileSync } from "node:fs";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
import { tmpdir } from "node:os";
|
|
6
|
+
|
|
7
|
+
import {
|
|
8
|
+
_resetPreferenceDiagnosticNotificationsForTests,
|
|
9
|
+
notifyPreferenceDiagnostics,
|
|
10
|
+
} from "../preferences-diagnostics.ts";
|
|
11
|
+
import { _resetParseWarningFlag } from "../preferences.ts";
|
|
12
|
+
|
|
13
|
+
test("notifyPreferenceDiagnostics dedupes within a surface but re-surfaces across surfaces", (t) => {
|
|
14
|
+
const originalCwd = process.cwd();
|
|
15
|
+
const originalGsdHome = process.env.GSD_HOME;
|
|
16
|
+
const tempProject = mkdtempSync(join(tmpdir(), "gsd-prefs-notify-project-"));
|
|
17
|
+
const tempGsdHome = mkdtempSync(join(tmpdir(), "gsd-prefs-notify-home-"));
|
|
18
|
+
t.after(() => {
|
|
19
|
+
process.chdir(originalCwd);
|
|
20
|
+
if (originalGsdHome === undefined) delete process.env.GSD_HOME;
|
|
21
|
+
else process.env.GSD_HOME = originalGsdHome;
|
|
22
|
+
rmSync(tempProject, { recursive: true, force: true });
|
|
23
|
+
rmSync(tempGsdHome, { recursive: true, force: true });
|
|
24
|
+
_resetPreferenceDiagnosticNotificationsForTests();
|
|
25
|
+
_resetParseWarningFlag();
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
mkdirSync(join(tempProject, ".gsd"), { recursive: true });
|
|
29
|
+
process.env.GSD_HOME = tempGsdHome;
|
|
30
|
+
process.chdir(tempProject);
|
|
31
|
+
_resetPreferenceDiagnosticNotificationsForTests();
|
|
32
|
+
_resetParseWarningFlag();
|
|
33
|
+
|
|
34
|
+
writeFileSync(
|
|
35
|
+
join(tempProject, ".gsd", "PREFERENCES.md"),
|
|
36
|
+
"---\nversion: 3\n---\n",
|
|
37
|
+
"utf-8",
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
const notifications: Array<{ message: string; type?: string }> = [];
|
|
41
|
+
const ctx = {
|
|
42
|
+
ui: {
|
|
43
|
+
notify(message: string, type?: "info" | "warning" | "error" | "success") {
|
|
44
|
+
notifications.push({ message, type });
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
assert.equal(
|
|
50
|
+
notifyPreferenceDiagnostics(ctx, tempProject, { surface: "session-start" }),
|
|
51
|
+
1,
|
|
52
|
+
);
|
|
53
|
+
assert.equal(
|
|
54
|
+
notifyPreferenceDiagnostics(ctx, tempProject, { surface: "session-start" }),
|
|
55
|
+
0,
|
|
56
|
+
);
|
|
57
|
+
assert.equal(
|
|
58
|
+
notifyPreferenceDiagnostics(ctx, tempProject, { surface: "auto-preflight" }),
|
|
59
|
+
1,
|
|
60
|
+
);
|
|
61
|
+
assert.equal(notifications.length, 2);
|
|
62
|
+
assert.equal(notifications[0]!.type, "error");
|
|
63
|
+
assert.match(notifications[0]!.message, /GSD project preferences error/);
|
|
64
|
+
assert.match(notifications[0]!.message, /unsupported version 3/);
|
|
65
|
+
assert.match(notifications[0]!.message, /Run \/gsd doctor for details/);
|
|
66
|
+
assert.equal(notifications[1]!.message, notifications[0]!.message);
|
|
67
|
+
});
|
|
@@ -26,6 +26,7 @@ import {
|
|
|
26
26
|
renderPreferencesForSystemPrompt,
|
|
27
27
|
_resetParseWarningFlag,
|
|
28
28
|
} from "../preferences.ts";
|
|
29
|
+
import { collectPreferenceDiagnostics, formatPreferenceDiagnostic } from "../preferences-diagnostics.ts";
|
|
29
30
|
import { formatConfiguredModel, toPersistedModelId } from "../commands-prefs-wizard.ts";
|
|
30
31
|
import { _resetLogs, peekLogs } from "../workflow-logger.ts";
|
|
31
32
|
import type { GSDPreferences, GSDModelConfigV2, GSDPhaseModelConfig } from "../preferences.ts";
|
|
@@ -819,6 +820,188 @@ bad: [
|
|
|
819
820
|
_resetLogs();
|
|
820
821
|
});
|
|
821
822
|
|
|
823
|
+
test("malformed global preferences load with a structured parse diagnostic", (t) => {
|
|
824
|
+
const originalGsdHome = process.env.GSD_HOME;
|
|
825
|
+
const tempGsdHome = mkdtempSync(join(tmpdir(), "gsd-prefs-diagnostic-home-"));
|
|
826
|
+
t.after(() => {
|
|
827
|
+
if (originalGsdHome === undefined) delete process.env.GSD_HOME;
|
|
828
|
+
else process.env.GSD_HOME = originalGsdHome;
|
|
829
|
+
rmSync(tempGsdHome, { recursive: true, force: true });
|
|
830
|
+
_resetParseWarningFlag();
|
|
831
|
+
_resetLogs();
|
|
832
|
+
});
|
|
833
|
+
|
|
834
|
+
process.env.GSD_HOME = tempGsdHome;
|
|
835
|
+
_resetParseWarningFlag();
|
|
836
|
+
_resetLogs();
|
|
837
|
+
writeFileSync(
|
|
838
|
+
join(tempGsdHome, "PREFERENCES.md"),
|
|
839
|
+
[
|
|
840
|
+
"---",
|
|
841
|
+
"version: 1",
|
|
842
|
+
"models:",
|
|
843
|
+
" validation:",
|
|
844
|
+
" openrouter/deepseek/deepseek-v4-pro",
|
|
845
|
+
" thinking: high",
|
|
846
|
+
"---",
|
|
847
|
+
"",
|
|
848
|
+
].join("\n"),
|
|
849
|
+
"utf-8",
|
|
850
|
+
);
|
|
851
|
+
|
|
852
|
+
const loaded = loadGlobalGSDPreferences();
|
|
853
|
+
assert.notEqual(loaded, null);
|
|
854
|
+
assert.deepEqual(loaded!.preferences, {});
|
|
855
|
+
const diagnostic = loaded!.diagnostics?.[0];
|
|
856
|
+
assert.equal(diagnostic?.kind, "parse");
|
|
857
|
+
assert.equal(diagnostic?.severity, "error");
|
|
858
|
+
assert.equal(diagnostic?.line, 5);
|
|
859
|
+
assert.equal(diagnostic?.column, 5);
|
|
860
|
+
assert.equal(diagnostic?.ignored, true);
|
|
861
|
+
assert.match(diagnostic?.message ?? "", /Implicit keys need/);
|
|
862
|
+
|
|
863
|
+
const formatted = formatPreferenceDiagnostic(diagnostic!);
|
|
864
|
+
assert.match(formatted, /GSD global preferences error/);
|
|
865
|
+
assert.match(formatted, /line 5, column 5/);
|
|
866
|
+
assert.match(formatted, /Preferences from this file were ignored/);
|
|
867
|
+
});
|
|
868
|
+
|
|
869
|
+
test("project preference validation errors load with structured diagnostics", (t) => {
|
|
870
|
+
const originalCwd = process.cwd();
|
|
871
|
+
const originalGsdHome = process.env.GSD_HOME;
|
|
872
|
+
const tempProject = mkdtempSync(join(tmpdir(), "gsd-prefs-validation-project-"));
|
|
873
|
+
const tempGsdHome = mkdtempSync(join(tmpdir(), "gsd-prefs-validation-home-"));
|
|
874
|
+
t.after(() => {
|
|
875
|
+
process.chdir(originalCwd);
|
|
876
|
+
if (originalGsdHome === undefined) delete process.env.GSD_HOME;
|
|
877
|
+
else process.env.GSD_HOME = originalGsdHome;
|
|
878
|
+
rmSync(tempProject, { recursive: true, force: true });
|
|
879
|
+
rmSync(tempGsdHome, { recursive: true, force: true });
|
|
880
|
+
});
|
|
881
|
+
|
|
882
|
+
mkdirSync(join(tempProject, ".gsd"), { recursive: true });
|
|
883
|
+
process.env.GSD_HOME = tempGsdHome;
|
|
884
|
+
process.chdir(tempProject);
|
|
885
|
+
writeFileSync(
|
|
886
|
+
join(tempProject, ".gsd", "PREFERENCES.md"),
|
|
887
|
+
"---\nversion: 3\n---\n",
|
|
888
|
+
"utf-8",
|
|
889
|
+
);
|
|
890
|
+
|
|
891
|
+
const loaded = loadProjectGSDPreferences(tempProject);
|
|
892
|
+
assert.notEqual(loaded, null);
|
|
893
|
+
assert.equal(loaded!.preferences.version, undefined);
|
|
894
|
+
const diagnostic = loaded!.diagnostics?.find((item) => item.kind === "validation");
|
|
895
|
+
assert.equal(diagnostic?.scope, "project");
|
|
896
|
+
assert.equal(diagnostic?.severity, "error");
|
|
897
|
+
assert.equal(diagnostic?.sanitized, true);
|
|
898
|
+
assert.match(diagnostic?.message ?? "", /unsupported version 3/);
|
|
899
|
+
|
|
900
|
+
const collected = collectPreferenceDiagnostics(tempProject);
|
|
901
|
+
assert.ok(
|
|
902
|
+
collected.some((item) => item.path === loaded!.path && item.message.includes("unsupported version 3")),
|
|
903
|
+
"collector should include project validation diagnostics",
|
|
904
|
+
);
|
|
905
|
+
});
|
|
906
|
+
|
|
907
|
+
test("malformed project preferences do not override effective global wrapper", (t) => {
|
|
908
|
+
const originalCwd = process.cwd();
|
|
909
|
+
const originalGsdHome = process.env.GSD_HOME;
|
|
910
|
+
const tempProject = mkdtempSync(join(tmpdir(), "gsd-prefs-effective-project-"));
|
|
911
|
+
const tempGsdHome = mkdtempSync(join(tmpdir(), "gsd-prefs-effective-home-"));
|
|
912
|
+
t.after(() => {
|
|
913
|
+
process.chdir(originalCwd);
|
|
914
|
+
if (originalGsdHome === undefined) delete process.env.GSD_HOME;
|
|
915
|
+
else process.env.GSD_HOME = originalGsdHome;
|
|
916
|
+
rmSync(tempProject, { recursive: true, force: true });
|
|
917
|
+
rmSync(tempGsdHome, { recursive: true, force: true });
|
|
918
|
+
_resetParseWarningFlag();
|
|
919
|
+
_resetLogs();
|
|
920
|
+
});
|
|
921
|
+
|
|
922
|
+
mkdirSync(join(tempProject, ".gsd"), { recursive: true });
|
|
923
|
+
process.env.GSD_HOME = tempGsdHome;
|
|
924
|
+
process.chdir(tempProject);
|
|
925
|
+
_resetParseWarningFlag();
|
|
926
|
+
_resetLogs();
|
|
927
|
+
|
|
928
|
+
const globalPath = getGlobalGSDPreferencesPath();
|
|
929
|
+
const projectPath = getProjectGSDPreferencesPath(tempProject);
|
|
930
|
+
writeFileSync(globalPath, "---\nlanguage: Spanish\n---\n", "utf-8");
|
|
931
|
+
writeFileSync(
|
|
932
|
+
projectPath,
|
|
933
|
+
[
|
|
934
|
+
"---",
|
|
935
|
+
"version: 1",
|
|
936
|
+
"models:",
|
|
937
|
+
" validation:",
|
|
938
|
+
" openrouter/deepseek/deepseek-v4-pro",
|
|
939
|
+
" thinking: high",
|
|
940
|
+
"---",
|
|
941
|
+
"",
|
|
942
|
+
].join("\n"),
|
|
943
|
+
"utf-8",
|
|
944
|
+
);
|
|
945
|
+
|
|
946
|
+
const projectPrefs = loadProjectGSDPreferences(tempProject);
|
|
947
|
+
assert.equal(projectPrefs?.ignored, true);
|
|
948
|
+
|
|
949
|
+
const loaded = loadEffectiveGSDPreferences(tempProject);
|
|
950
|
+
assert.notEqual(loaded, null);
|
|
951
|
+
assert.equal(loaded!.path, globalPath);
|
|
952
|
+
assert.equal(loaded!.scope, "global");
|
|
953
|
+
assert.equal(loaded!.preferences.language, "Spanish");
|
|
954
|
+
assert.ok(
|
|
955
|
+
loaded!.diagnostics?.some((item) => item.path === projectPath && item.kind === "parse"),
|
|
956
|
+
"effective global preferences should carry malformed project diagnostics",
|
|
957
|
+
);
|
|
958
|
+
});
|
|
959
|
+
|
|
960
|
+
test("malformed global preferences: loadEffectiveGSDPreferences returns null without project file", (t) => {
|
|
961
|
+
const originalCwd = process.cwd();
|
|
962
|
+
const originalGsdHome = process.env.GSD_HOME;
|
|
963
|
+
const tempProject = mkdtempSync(join(tmpdir(), "gsd-prefs-effective-malformed-global-"));
|
|
964
|
+
const tempGsdHome = mkdtempSync(join(tmpdir(), "gsd-prefs-effective-malformed-home-"));
|
|
965
|
+
t.after(() => {
|
|
966
|
+
process.chdir(originalCwd);
|
|
967
|
+
if (originalGsdHome === undefined) delete process.env.GSD_HOME;
|
|
968
|
+
else process.env.GSD_HOME = originalGsdHome;
|
|
969
|
+
rmSync(tempProject, { recursive: true, force: true });
|
|
970
|
+
rmSync(tempGsdHome, { recursive: true, force: true });
|
|
971
|
+
_resetParseWarningFlag();
|
|
972
|
+
_resetLogs();
|
|
973
|
+
});
|
|
974
|
+
|
|
975
|
+
process.env.GSD_HOME = tempGsdHome;
|
|
976
|
+
process.chdir(tempProject);
|
|
977
|
+
_resetParseWarningFlag();
|
|
978
|
+
_resetLogs();
|
|
979
|
+
|
|
980
|
+
const globalPath = getGlobalGSDPreferencesPath();
|
|
981
|
+
writeFileSync(
|
|
982
|
+
globalPath,
|
|
983
|
+
[
|
|
984
|
+
"---",
|
|
985
|
+
"version: 1",
|
|
986
|
+
"models:",
|
|
987
|
+
" validation:",
|
|
988
|
+
" openrouter/deepseek/deepseek-v4-pro",
|
|
989
|
+
" thinking: high",
|
|
990
|
+
"---",
|
|
991
|
+
"",
|
|
992
|
+
].join("\n"),
|
|
993
|
+
"utf-8",
|
|
994
|
+
);
|
|
995
|
+
|
|
996
|
+
const globalPrefs = loadGlobalGSDPreferences();
|
|
997
|
+
assert.equal(globalPrefs?.ignored, true, "malformed global should be marked ignored");
|
|
998
|
+
|
|
999
|
+
// Symmetric with malformed project + no global: effective result should be null,
|
|
1000
|
+
// not an effective object with ignored:true leaking through.
|
|
1001
|
+
const loaded = loadEffectiveGSDPreferences(tempProject);
|
|
1002
|
+
assert.equal(loaded, null, "effective preferences should be null when only global file is malformed");
|
|
1003
|
+
});
|
|
1004
|
+
|
|
822
1005
|
// ── Experimental preferences ─────────────────────────────────────────────────
|
|
823
1006
|
|
|
824
1007
|
test("experimental.rtk: true is accepted and stored", () => {
|