@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
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
// Project/App: gsd-pi
|
|
2
2
|
// File Purpose: Resolve phase-aware tool surfaces for GSD model presentations.
|
|
3
3
|
import { RUN_UAT_BROWSER_TOOL_NAMES, RUN_UAT_READ_ONLY_TOOL_NAMES, RUN_UAT_TOOL_PRESENTATION_PLAN_ID, RUN_UAT_WORKFLOW_TOOL_NAMES, } from "./unit-tool-contracts.js";
|
|
4
|
+
import { toMcpToolName } from "./mcp-tool-name.js";
|
|
5
|
+
import { createToolSurfaceSnapshot } from "./tool-surface-snapshot.js";
|
|
4
6
|
import { uatTypeIncludesBrowser } from "./uat-policy.js";
|
|
7
|
+
import { canonicalWorkflowSurfaceToolName } from "./workflow-tool-surface.js";
|
|
5
8
|
export { RUN_UAT_BROWSER_TOOL_NAMES, RUN_UAT_READ_ONLY_TOOL_NAMES, RUN_UAT_TOOL_PRESENTATION_PLAN_ID, RUN_UAT_WORKFLOW_TOOL_NAMES, } from "./unit-tool-contracts.js";
|
|
6
9
|
export const RUN_UAT_FORBIDDEN_TOOL_NAMES = [
|
|
7
10
|
"edit",
|
|
@@ -21,43 +24,12 @@ export const RUN_UAT_CLAUDE_NATIVE_TOOL_NAMES = [
|
|
|
21
24
|
"Glob",
|
|
22
25
|
"Grep",
|
|
23
26
|
];
|
|
24
|
-
const WORKFLOW_ALIAS_TO_CANONICAL = {
|
|
25
|
-
gsd_save_decision: "gsd_decision_save",
|
|
26
|
-
gsd_update_requirement: "gsd_requirement_update",
|
|
27
|
-
gsd_save_requirement: "gsd_requirement_save",
|
|
28
|
-
gsd_save_summary: "gsd_summary_save",
|
|
29
|
-
gsd_generate_milestone_id: "gsd_milestone_generate_id",
|
|
30
|
-
gsd_milestone_plan: "gsd_plan_milestone",
|
|
31
|
-
gsd_slice_plan: "gsd_plan_slice",
|
|
32
|
-
gsd_task_plan: "gsd_plan_task",
|
|
33
|
-
gsd_slice_replan: "gsd_replan_slice",
|
|
34
|
-
gsd_complete_slice: "gsd_slice_complete",
|
|
35
|
-
gsd_milestone_complete: "gsd_complete_milestone",
|
|
36
|
-
gsd_milestone_validate: "gsd_validate_milestone",
|
|
37
|
-
gsd_roadmap_reassess: "gsd_reassess_roadmap",
|
|
38
|
-
gsd_complete_task: "gsd_task_complete",
|
|
39
|
-
gsd_reopen_task: "gsd_task_reopen",
|
|
40
|
-
gsd_reopen_slice: "gsd_slice_reopen",
|
|
41
|
-
gsd_reopen_milestone: "gsd_milestone_reopen",
|
|
42
|
-
};
|
|
43
27
|
export function canonicalWorkflowToolName(toolName) {
|
|
44
|
-
|
|
45
|
-
const baseName = mcp?.tool ?? toolName;
|
|
46
|
-
return WORKFLOW_ALIAS_TO_CANONICAL[baseName] ?? baseName;
|
|
47
|
-
}
|
|
48
|
-
export function parseMcpToolName(toolName) {
|
|
49
|
-
if (!toolName.startsWith("mcp__"))
|
|
50
|
-
return null;
|
|
51
|
-
const toolSeparator = toolName.indexOf("__", "mcp__".length);
|
|
52
|
-
if (toolSeparator < 0)
|
|
53
|
-
return null;
|
|
54
|
-
return {
|
|
55
|
-
server: toolName.slice("mcp__".length, toolSeparator),
|
|
56
|
-
tool: toolName.slice(toolSeparator + 2),
|
|
57
|
-
};
|
|
28
|
+
return canonicalWorkflowSurfaceToolName(toolName);
|
|
58
29
|
}
|
|
30
|
+
export { parseMcpToolName } from "./mcp-tool-name.js";
|
|
59
31
|
export function toWorkflowMcpToolName(serverName, toolName) {
|
|
60
|
-
return
|
|
32
|
+
return toMcpToolName(serverName, canonicalWorkflowToolName(toolName));
|
|
61
33
|
}
|
|
62
34
|
function dedupe(values) {
|
|
63
35
|
return [...new Set(values)];
|
|
@@ -134,6 +106,14 @@ export function resolveToolPresentationPlan(options) {
|
|
|
134
106
|
? toWorkflowMcpToolName(workflowServerName, name)
|
|
135
107
|
: name)
|
|
136
108
|
: allowedToolNames;
|
|
109
|
+
const toolSurface = createToolSurfaceSnapshot({
|
|
110
|
+
source: "presentation-plan",
|
|
111
|
+
phase: options.phase,
|
|
112
|
+
modelFacingToolNames: options.availableToolNames ?? requested,
|
|
113
|
+
registeredToolNames: options.availableToolNames ?? requested,
|
|
114
|
+
scopedToolNames: allowedToolNames,
|
|
115
|
+
presentedToolNames,
|
|
116
|
+
});
|
|
137
117
|
if (options.phase === "run-uat") {
|
|
138
118
|
for (const forbidden of RUN_UAT_FORBIDDEN_TOOL_NAMES) {
|
|
139
119
|
addBlockedTool(blockedToolNames, forbidden, "forbidden during run-uat");
|
|
@@ -148,5 +128,6 @@ export function resolveToolPresentationPlan(options) {
|
|
|
148
128
|
blockedToolNames,
|
|
149
129
|
aliases,
|
|
150
130
|
diagnostics: [],
|
|
131
|
+
toolSurface,
|
|
151
132
|
};
|
|
152
133
|
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
// Project/App: gsd-pi
|
|
2
|
+
// File Purpose: Typed snapshots for model-facing, registered, scoped, and presented tool surfaces.
|
|
3
|
+
function dedupeToolNames(toolNames) {
|
|
4
|
+
return [...new Set(toolNames ?? [])];
|
|
5
|
+
}
|
|
6
|
+
export function createToolSurfaceSnapshot(input) {
|
|
7
|
+
return {
|
|
8
|
+
source: input.source,
|
|
9
|
+
unitType: input.unitType,
|
|
10
|
+
phase: input.phase,
|
|
11
|
+
modelFacingToolNames: dedupeToolNames(input.modelFacingToolNames),
|
|
12
|
+
registeredToolNames: dedupeToolNames(input.registeredToolNames),
|
|
13
|
+
scopedToolNames: dedupeToolNames(input.scopedToolNames),
|
|
14
|
+
presentedToolNames: dedupeToolNames(input.presentedToolNames),
|
|
15
|
+
capturedAt: input.capturedAt ?? Date.now(),
|
|
16
|
+
};
|
|
17
|
+
}
|
|
@@ -1,15 +1,7 @@
|
|
|
1
1
|
// Project/App: gsd-pi
|
|
2
2
|
// File Purpose: Plans milestone roadmap state through DB-backed workflow tools.
|
|
3
|
-
import { clearParseCache } from "../files.js";
|
|
4
|
-
import { isClosedStatus } from "../status-guards.js";
|
|
5
3
|
import { isNonEmptyString, validateStringArray, validateTitle } from "../validation.js";
|
|
6
|
-
import {
|
|
7
|
-
import { invalidateStateCache } from "../state.js";
|
|
8
|
-
import { renderRoadmapFromDb } from "../markdown-renderer.js";
|
|
9
|
-
import { renderAllProjections } from "../workflow-projections.js";
|
|
10
|
-
import { writeManifest } from "../workflow-manifest.js";
|
|
11
|
-
import { appendEvent } from "../workflow-events.js";
|
|
12
|
-
import { logWarning } from "../workflow-logger.js";
|
|
4
|
+
import { persistMilestonePlan } from "../milestone-planning-persistence.js";
|
|
13
5
|
function validateRiskEntries(value) {
|
|
14
6
|
if (!Array.isArray(value)) {
|
|
15
7
|
throw new Error("keyRisks must be an array");
|
|
@@ -43,10 +35,16 @@ function validateProofStrategy(value) {
|
|
|
43
35
|
return { riskOrUnknown, retireIn, whatWillBeProven };
|
|
44
36
|
});
|
|
45
37
|
}
|
|
38
|
+
const SLICE_ID_RE = /^[A-Za-z0-9][A-Za-z0-9-]*$/;
|
|
46
39
|
function validateSlices(value) {
|
|
47
40
|
if (!Array.isArray(value) || value.length === 0) {
|
|
48
41
|
throw new Error("slices must be a non-empty array");
|
|
49
42
|
}
|
|
43
|
+
// Pre-collect all slice IDs so depends cross-validation can reference the full set.
|
|
44
|
+
const allSliceIds = new Set(value
|
|
45
|
+
.filter((e) => !!e && typeof e === "object")
|
|
46
|
+
.map(e => e.sliceId)
|
|
47
|
+
.filter((id) => isNonEmptyString(id)));
|
|
50
48
|
const seen = new Set();
|
|
51
49
|
return value.map((entry, index) => {
|
|
52
50
|
if (!entry || typeof entry !== "object") {
|
|
@@ -84,8 +82,13 @@ function validateSlices(value) {
|
|
|
84
82
|
throw new Error(`slices[${index}].title is invalid: ${titleIssue}`);
|
|
85
83
|
if (!isNonEmptyString(risk))
|
|
86
84
|
throw new Error(`slices[${index}].risk must be a non-empty string`);
|
|
87
|
-
if (!Array.isArray(depends) || depends.some((item) => !isNonEmptyString(item))) {
|
|
88
|
-
throw new Error(`slices[${index}].depends must be an array of
|
|
85
|
+
if (!Array.isArray(depends) || depends.some((item) => !isNonEmptyString(item) || !SLICE_ID_RE.test(item))) {
|
|
86
|
+
throw new Error(`slices[${index}].depends must be an array of valid slice IDs (e.g. "S01")`);
|
|
87
|
+
}
|
|
88
|
+
for (const dep of depends) {
|
|
89
|
+
if (!allSliceIds.has(dep)) {
|
|
90
|
+
throw new Error(`slices[${index}].depends references unknown slice "${dep}" — check that it is defined in the same milestone`);
|
|
91
|
+
}
|
|
89
92
|
}
|
|
90
93
|
if (!isNonEmptyString(demo))
|
|
91
94
|
throw new Error(`slices[${index}].demo must be a non-empty string`);
|
|
@@ -160,136 +163,5 @@ export async function handlePlanMilestone(rawParams, basePath) {
|
|
|
160
163
|
catch (err) {
|
|
161
164
|
return { error: `validation failed: ${err.message}` };
|
|
162
165
|
}
|
|
163
|
-
|
|
164
|
-
// Guards must be inside the transaction so the state they check cannot
|
|
165
|
-
// change between the read and the write (#2723).
|
|
166
|
-
let guardError = null;
|
|
167
|
-
try {
|
|
168
|
-
transaction(() => {
|
|
169
|
-
const existingMilestone = getMilestone(params.milestoneId);
|
|
170
|
-
if (existingMilestone && isClosedStatus(existingMilestone.status)) {
|
|
171
|
-
guardError = `cannot re-plan milestone ${params.milestoneId}: it is already complete`;
|
|
172
|
-
return;
|
|
173
|
-
}
|
|
174
|
-
// Guard: refuse to re-plan a milestone that would drop completed slices (#2960).
|
|
175
|
-
// Allow re-planning when all completed slices are still present in the
|
|
176
|
-
// incoming plan — their status is preserved below (#2558). Block only when
|
|
177
|
-
// the new plan omits a completed slice, which could shadow completed work.
|
|
178
|
-
const existingSlices = getMilestoneSlices(params.milestoneId);
|
|
179
|
-
const completedSlices = existingSlices.filter(s => isClosedStatus(s.status));
|
|
180
|
-
if (completedSlices.length > 0) {
|
|
181
|
-
const incomingSliceIds = new Set(params.slices.map(s => s.sliceId));
|
|
182
|
-
const droppedCompleted = completedSlices.filter(s => !incomingSliceIds.has(s.id));
|
|
183
|
-
if (droppedCompleted.length > 0) {
|
|
184
|
-
guardError = `cannot re-plan milestone ${params.milestoneId}: ${droppedCompleted.length} completed slice(s) would be dropped (${droppedCompleted.map(s => s.id).join(", ")}). Use gsd_reassess_roadmap to modify the roadmap.`;
|
|
185
|
-
return;
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
// Validate depends_on: all dependencies must exist and be complete
|
|
189
|
-
if (params.dependsOn && params.dependsOn.length > 0) {
|
|
190
|
-
for (const depId of params.dependsOn) {
|
|
191
|
-
const dep = getMilestone(depId);
|
|
192
|
-
if (!dep) {
|
|
193
|
-
guardError = `depends_on references unknown milestone: ${depId}`;
|
|
194
|
-
return;
|
|
195
|
-
}
|
|
196
|
-
if (!isClosedStatus(dep.status)) {
|
|
197
|
-
guardError = `depends_on milestone ${depId} is not yet complete (status: ${dep.status})`;
|
|
198
|
-
return;
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
insertMilestone({
|
|
203
|
-
id: params.milestoneId,
|
|
204
|
-
title: params.title,
|
|
205
|
-
status: params.status ?? "active",
|
|
206
|
-
depends_on: params.dependsOn ?? [],
|
|
207
|
-
});
|
|
208
|
-
upsertMilestonePlanning(params.milestoneId, {
|
|
209
|
-
title: params.title,
|
|
210
|
-
status: params.status ?? "active",
|
|
211
|
-
depends_on: params.dependsOn ?? [],
|
|
212
|
-
vision: params.vision,
|
|
213
|
-
successCriteria: params.successCriteria,
|
|
214
|
-
keyRisks: params.keyRisks,
|
|
215
|
-
proofStrategy: params.proofStrategy,
|
|
216
|
-
verificationContract: params.verificationContract,
|
|
217
|
-
verificationIntegration: params.verificationIntegration,
|
|
218
|
-
verificationOperational: params.verificationOperational,
|
|
219
|
-
verificationUat: params.verificationUat,
|
|
220
|
-
definitionOfDone: params.definitionOfDone,
|
|
221
|
-
requirementCoverage: params.requirementCoverage,
|
|
222
|
-
boundaryMapMarkdown: params.boundaryMapMarkdown,
|
|
223
|
-
});
|
|
224
|
-
for (let i = 0; i < params.slices.length; i++) {
|
|
225
|
-
const slice = params.slices[i];
|
|
226
|
-
// Preserve completed/done status on re-plan (#2558).
|
|
227
|
-
// Without this, a re-plan after milestone transition would reset
|
|
228
|
-
// already-completed slices back to "pending".
|
|
229
|
-
const existing = getSlice(params.milestoneId, slice.sliceId);
|
|
230
|
-
const status = existing && (existing.status === "complete" || existing.status === "done")
|
|
231
|
-
? existing.status
|
|
232
|
-
: "pending";
|
|
233
|
-
insertSlice({
|
|
234
|
-
id: slice.sliceId,
|
|
235
|
-
milestoneId: params.milestoneId,
|
|
236
|
-
title: slice.title,
|
|
237
|
-
status,
|
|
238
|
-
risk: slice.risk,
|
|
239
|
-
depends: slice.depends,
|
|
240
|
-
demo: slice.demo,
|
|
241
|
-
sequence: i + 1, // Preserve agent-ordered sequence (#3356)
|
|
242
|
-
// ADR-011: pass undefined through so ON CONFLICT preserves existing values
|
|
243
|
-
// when the caller omitted the fields on a re-plan.
|
|
244
|
-
isSketch: slice.isSketch,
|
|
245
|
-
sketchScope: slice.sketchScope,
|
|
246
|
-
});
|
|
247
|
-
upsertSlicePlanning(params.milestoneId, slice.sliceId, {
|
|
248
|
-
goal: slice.goal,
|
|
249
|
-
successCriteria: slice.successCriteria,
|
|
250
|
-
proofLevel: slice.proofLevel,
|
|
251
|
-
integrationClosure: slice.integrationClosure,
|
|
252
|
-
observabilityImpact: slice.observabilityImpact,
|
|
253
|
-
});
|
|
254
|
-
}
|
|
255
|
-
});
|
|
256
|
-
}
|
|
257
|
-
catch (err) {
|
|
258
|
-
return { error: `db write failed: ${err.message}` };
|
|
259
|
-
}
|
|
260
|
-
if (guardError) {
|
|
261
|
-
return { error: guardError };
|
|
262
|
-
}
|
|
263
|
-
let roadmapPath;
|
|
264
|
-
try {
|
|
265
|
-
const renderResult = await renderRoadmapFromDb(basePath, params.milestoneId);
|
|
266
|
-
roadmapPath = renderResult.roadmapPath;
|
|
267
|
-
}
|
|
268
|
-
catch (renderErr) {
|
|
269
|
-
logWarning("tool", `plan_milestone — render failed (DB rows preserved for debugging): ${renderErr.message}`);
|
|
270
|
-
invalidateStateCache();
|
|
271
|
-
return { error: `render failed: ${renderErr.message}` };
|
|
272
|
-
}
|
|
273
|
-
invalidateStateCache();
|
|
274
|
-
clearParseCache();
|
|
275
|
-
// ── Post-mutation hook: projections, manifest, event log ───────────────
|
|
276
|
-
try {
|
|
277
|
-
await renderAllProjections(basePath, params.milestoneId);
|
|
278
|
-
writeManifest(basePath);
|
|
279
|
-
appendEvent(basePath, {
|
|
280
|
-
cmd: "plan-milestone",
|
|
281
|
-
params: { milestoneId: params.milestoneId },
|
|
282
|
-
ts: new Date().toISOString(),
|
|
283
|
-
actor: "agent",
|
|
284
|
-
actor_name: params.actorName,
|
|
285
|
-
trigger_reason: params.triggerReason,
|
|
286
|
-
});
|
|
287
|
-
}
|
|
288
|
-
catch (hookErr) {
|
|
289
|
-
logWarning("tool", `plan-milestone post-mutation hook warning: ${hookErr.message}`);
|
|
290
|
-
}
|
|
291
|
-
return {
|
|
292
|
-
milestoneId: params.milestoneId,
|
|
293
|
-
roadmapPath,
|
|
294
|
-
};
|
|
166
|
+
return persistMilestonePlan(params, basePath);
|
|
295
167
|
}
|
|
@@ -31,6 +31,7 @@ function validateParams(params) {
|
|
|
31
31
|
if (!Array.isArray(params.sliceChanges.removed)) {
|
|
32
32
|
throw new Error("sliceChanges.removed must be an array");
|
|
33
33
|
}
|
|
34
|
+
const SLICE_ID_RE = /^[A-Za-z0-9][A-Za-z0-9-]*$/;
|
|
34
35
|
// Validate each modified slice
|
|
35
36
|
for (let i = 0; i < params.sliceChanges.modified.length; i++) {
|
|
36
37
|
const s = params.sliceChanges.modified[i];
|
|
@@ -40,6 +41,11 @@ function validateParams(params) {
|
|
|
40
41
|
throw new Error(`sliceChanges.modified[${i}].sliceId is required`);
|
|
41
42
|
if (!isNonEmptyString(s.title))
|
|
42
43
|
throw new Error(`sliceChanges.modified[${i}].title is required`);
|
|
44
|
+
if (s.depends !== undefined) {
|
|
45
|
+
if (!Array.isArray(s.depends) || s.depends.some((item) => !isNonEmptyString(item) || !SLICE_ID_RE.test(item))) {
|
|
46
|
+
throw new Error(`sliceChanges.modified[${i}].depends must be an array of valid slice IDs (e.g. "S01")`);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
43
49
|
}
|
|
44
50
|
// Validate each added slice
|
|
45
51
|
for (let i = 0; i < params.sliceChanges.added.length; i++) {
|
|
@@ -50,6 +56,11 @@ function validateParams(params) {
|
|
|
50
56
|
throw new Error(`sliceChanges.added[${i}].sliceId is required`);
|
|
51
57
|
if (!isNonEmptyString(s.title))
|
|
52
58
|
throw new Error(`sliceChanges.added[${i}].title is required`);
|
|
59
|
+
if (s.depends !== undefined) {
|
|
60
|
+
if (!Array.isArray(s.depends) || s.depends.some((item) => !isNonEmptyString(item) || !SLICE_ID_RE.test(item))) {
|
|
61
|
+
throw new Error(`sliceChanges.added[${i}].depends must be an array of valid slice IDs (e.g. "S01")`);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
53
64
|
}
|
|
54
65
|
return params;
|
|
55
66
|
}
|
|
@@ -111,6 +122,34 @@ export async function handleReassessRoadmap(rawParams, basePath) {
|
|
|
111
122
|
return;
|
|
112
123
|
}
|
|
113
124
|
}
|
|
125
|
+
// Cross-milestone depends validation — effective slice ID set after this reassessment
|
|
126
|
+
const removedIds = new Set(params.sliceChanges.removed);
|
|
127
|
+
const effectiveSliceIds = new Set(existingSlices.map(s => s.id).filter(id => !removedIds.has(id)));
|
|
128
|
+
for (const added of params.sliceChanges.added) {
|
|
129
|
+
effectiveSliceIds.add(added.sliceId);
|
|
130
|
+
}
|
|
131
|
+
for (let i = 0; i < params.sliceChanges.modified.length; i++) {
|
|
132
|
+
const mod = params.sliceChanges.modified[i];
|
|
133
|
+
if (mod.depends !== undefined) {
|
|
134
|
+
for (const dep of mod.depends) {
|
|
135
|
+
if (!effectiveSliceIds.has(dep)) {
|
|
136
|
+
guardError = `sliceChanges.modified[${i}].depends references unknown slice "${dep}" — check that it is defined in this milestone`;
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
for (let i = 0; i < params.sliceChanges.added.length; i++) {
|
|
143
|
+
const added = params.sliceChanges.added[i];
|
|
144
|
+
if (added.depends !== undefined) {
|
|
145
|
+
for (const dep of added.depends) {
|
|
146
|
+
if (!effectiveSliceIds.has(dep)) {
|
|
147
|
+
guardError = `sliceChanges.added[${i}].depends references unknown slice "${dep}" — check that it is defined in this milestone`;
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
114
153
|
// Record assessment
|
|
115
154
|
insertAssessment({
|
|
116
155
|
path: assessmentRelPath,
|
|
@@ -11,10 +11,11 @@
|
|
|
11
11
|
* despite passing validation.
|
|
12
12
|
*/
|
|
13
13
|
import { join } from "node:path";
|
|
14
|
-
import { transaction, insertAssessment, getMilestoneSlices, getMilestone,
|
|
15
|
-
import { gsdProjectionRoot, clearPathCache
|
|
14
|
+
import { transaction, insertAssessment, getMilestoneSlices, getMilestone, } from "../gsd-db.js";
|
|
15
|
+
import { gsdProjectionRoot, clearPathCache } from "../paths.js";
|
|
16
16
|
import { resolveCanonicalMilestoneRoot } from "../worktree-manager.js";
|
|
17
|
-
import {
|
|
17
|
+
import { resolveWorktreeProjectRoot } from "../worktree-root.js";
|
|
18
|
+
import { saveFile, clearParseCache } from "../files.js";
|
|
18
19
|
import { invalidateStateCache } from "../state.js";
|
|
19
20
|
import { VALIDATION_VERDICTS, isValidMilestoneVerdict } from "../verdict-parser.js";
|
|
20
21
|
import { insertMilestoneValidationGates } from "../milestone-validation-gates.js";
|
|
@@ -22,7 +23,7 @@ import { logWarning } from "../workflow-logger.js";
|
|
|
22
23
|
import { UokGateRunner } from "../uok/gate-runner.js";
|
|
23
24
|
import { loadEffectiveGSDPreferences } from "../preferences.js";
|
|
24
25
|
import { resolveUokFlags } from "../uok/flags.js";
|
|
25
|
-
import {
|
|
26
|
+
import { applyBrowserEvidenceGate, browserEvidenceGateRequiresAttention, } from "../milestone-validation-evidence.js";
|
|
26
27
|
function isVerificationNotApplicable(value) {
|
|
27
28
|
const v = (value ?? "").toLowerCase().trim().replace(/[.\s]+$/, "");
|
|
28
29
|
if (!v || v === "none")
|
|
@@ -44,80 +45,6 @@ function getRequiredVerificationClasses(milestoneId) {
|
|
|
44
45
|
required.push("UAT");
|
|
45
46
|
return required;
|
|
46
47
|
}
|
|
47
|
-
function hasRuntimeExecutableUatEvidenceText(text) {
|
|
48
|
-
if (!/\buatType:\s*runtime-executable\b/i.test(text))
|
|
49
|
-
return false;
|
|
50
|
-
if (!/\bverdict:\s*PASS\b/i.test(text))
|
|
51
|
-
return false;
|
|
52
|
-
return /^\|\s*[^|\n]+\s*\|\s*runtime\s*\|\s*PASS\s*\|[^|\n]*\bgsd_uat_exec\b/mi.test(text);
|
|
53
|
-
}
|
|
54
|
-
async function browserEvidenceGateRequiresAttention(params, basePath) {
|
|
55
|
-
if (params.verdict !== "pass")
|
|
56
|
-
return false;
|
|
57
|
-
const milestone = getMilestone(params.milestoneId);
|
|
58
|
-
const slices = getMilestoneSlices(params.milestoneId);
|
|
59
|
-
const requirementText = compactTextParts([
|
|
60
|
-
milestone?.vision,
|
|
61
|
-
milestone?.success_criteria,
|
|
62
|
-
milestone?.verification_uat,
|
|
63
|
-
params.successCriteriaChecklist,
|
|
64
|
-
params.verificationClasses,
|
|
65
|
-
...slices.flatMap((slice) => [
|
|
66
|
-
slice.demo,
|
|
67
|
-
slice.goal,
|
|
68
|
-
slice.success_criteria,
|
|
69
|
-
]),
|
|
70
|
-
]);
|
|
71
|
-
if (!hasBrowserRequiredText(requirementText))
|
|
72
|
-
return false;
|
|
73
|
-
// Collect per-slice evidence so the runtime bypass is checked independently
|
|
74
|
-
// for each slice. Concatenating all slices before checking would allow runtime
|
|
75
|
-
// evidence from one slice to cover another slice's browser requirements.
|
|
76
|
-
const sliceEvidencePairs = [];
|
|
77
|
-
for (const slice of slices) {
|
|
78
|
-
const chunks = [];
|
|
79
|
-
const artifactPath = `milestones/${params.milestoneId}/slices/${slice.id}/${slice.id}-ASSESSMENT.md`;
|
|
80
|
-
const artifact = getArtifact(artifactPath);
|
|
81
|
-
if (artifact?.full_content)
|
|
82
|
-
chunks.push(artifact.full_content);
|
|
83
|
-
const assessmentPath = resolveSliceFile(basePath, params.milestoneId, slice.id, "ASSESSMENT");
|
|
84
|
-
const assessmentContent = assessmentPath ? await loadFile(assessmentPath) : null;
|
|
85
|
-
if (assessmentContent)
|
|
86
|
-
chunks.push(assessmentContent);
|
|
87
|
-
sliceEvidencePairs.push({
|
|
88
|
-
sliceRequirementText: compactTextParts([slice.demo, slice.goal, slice.success_criteria]),
|
|
89
|
-
evidenceText: chunks.join("\n\n"),
|
|
90
|
-
});
|
|
91
|
-
}
|
|
92
|
-
const persistedEvidence = sliceEvidencePairs.map((s) => s.evidenceText).join("\n\n");
|
|
93
|
-
// Runtime bypass: each slice whose own requirement text has browser-observable
|
|
94
|
-
// criteria must have its own runtime-executable UAT evidence. When no individual
|
|
95
|
-
// slice has slice-level browser requirements (e.g., they come from milestone-level
|
|
96
|
-
// fields only), fall back to checking whether any slice has runtime evidence.
|
|
97
|
-
const browserRequiringSlices = sliceEvidencePairs.filter((s) => hasBrowserRequiredText(s.sliceRequirementText));
|
|
98
|
-
const runtimeBypasses = browserRequiringSlices.length > 0
|
|
99
|
-
? browserRequiringSlices.every((s) => hasRuntimeExecutableUatEvidenceText(s.evidenceText))
|
|
100
|
-
: sliceEvidencePairs.some((s) => hasRuntimeExecutableUatEvidenceText(s.evidenceText));
|
|
101
|
-
if (runtimeBypasses)
|
|
102
|
-
return false;
|
|
103
|
-
const validationEvidence = compactTextParts([
|
|
104
|
-
params.successCriteriaChecklist,
|
|
105
|
-
params.verificationClasses,
|
|
106
|
-
params.verdictRationale,
|
|
107
|
-
params.remediationPlan,
|
|
108
|
-
]);
|
|
109
|
-
return !hasBrowserEvidenceText(`${persistedEvidence}\n\n${validationEvidence}`);
|
|
110
|
-
}
|
|
111
|
-
function applyBrowserEvidenceGate(params) {
|
|
112
|
-
const note = "Browser evidence gate: Browser-observable acceptance criteria were detected, but no persisted ASSESSMENT or validation evidence recorded browser actions with assertions. Downgraded from pass to needs-attention.";
|
|
113
|
-
return {
|
|
114
|
-
...params,
|
|
115
|
-
verdict: "needs-attention",
|
|
116
|
-
verdictRationale: params.verdictRationale.trim()
|
|
117
|
-
? `${params.verdictRationale.trim()}\n\n${note}`
|
|
118
|
-
: note,
|
|
119
|
-
};
|
|
120
|
-
}
|
|
121
48
|
function renderValidationMarkdown(params) {
|
|
122
49
|
let md = `---
|
|
123
50
|
verdict: ${params.verdict}
|
|
@@ -214,6 +141,16 @@ export async function handleValidateMilestone(params, basePath, opts) {
|
|
|
214
141
|
let projectionStale = false;
|
|
215
142
|
try {
|
|
216
143
|
await saveFile(validationPath, validationMd);
|
|
144
|
+
const projectRoot = resolveWorktreeProjectRoot(basePath);
|
|
145
|
+
if (projectRoot !== artifactBasePath) {
|
|
146
|
+
const projectValidationPath = join(gsdProjectionRoot(projectRoot), "milestones", effectiveParams.milestoneId, `${effectiveParams.milestoneId}-VALIDATION.md`);
|
|
147
|
+
try {
|
|
148
|
+
await saveFile(projectValidationPath, validationMd);
|
|
149
|
+
}
|
|
150
|
+
catch (mirrorErr) {
|
|
151
|
+
logWarning("projection", `validate_milestone project-root VALIDATION mirror failed for ${effectiveParams.milestoneId}`, { error: mirrorErr.message });
|
|
152
|
+
}
|
|
153
|
+
}
|
|
217
154
|
}
|
|
218
155
|
catch (renderErr) {
|
|
219
156
|
projectionStale = true;
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
// File Purpose: Central UAT mode policy for dispatch, tool presentation, and result validation.
|
|
3
3
|
import { extractUatType } from "./files.js";
|
|
4
4
|
import { hasBrowserRequiredText } from "./browser-evidence.js";
|
|
5
|
+
import { parseMcpToolName } from "./mcp-tool-name.js";
|
|
5
6
|
export const UAT_TYPES = [
|
|
6
7
|
"artifact-driven",
|
|
7
8
|
"browser-executable",
|
|
@@ -80,26 +81,31 @@ export function shouldDispatchUatForContent(content, prefs) {
|
|
|
80
81
|
export function uatTypeIncludesBrowser(uatType) {
|
|
81
82
|
return isUatType(uatType) && UAT_MODE_POLICIES[uatType].browserTools;
|
|
82
83
|
}
|
|
83
|
-
function canonicalPresentedToolName(toolName) {
|
|
84
|
-
if (!toolName.startsWith("mcp__"))
|
|
85
|
-
return toolName;
|
|
86
|
-
const toolSeparator = toolName.indexOf("__", "mcp__".length);
|
|
87
|
-
return toolSeparator >= 0 ? toolName.slice(toolSeparator + 2) : toolName;
|
|
88
|
-
}
|
|
89
84
|
export function isUatBrowserToolName(toolName) {
|
|
90
|
-
|
|
85
|
+
const parsed = parseMcpToolName(toolName);
|
|
86
|
+
const canonicalName = parsed?.toolName ?? toolName;
|
|
87
|
+
if (canonicalName.startsWith("browser_"))
|
|
88
|
+
return true;
|
|
89
|
+
return parsed?.toolName === "*" && parsed.serverName.toLowerCase().includes("browser");
|
|
91
90
|
}
|
|
92
91
|
export function hasUatBrowserToolSurface(activeTools) {
|
|
93
92
|
return Array.isArray(activeTools) && activeTools.some(isUatBrowserToolName);
|
|
94
93
|
}
|
|
94
|
+
export function resolveUatBrowserToolSurface(options) {
|
|
95
|
+
const surfaces = [options.activeTools, options.registeredTools].filter(Array.isArray);
|
|
96
|
+
if (surfaces.length === 0)
|
|
97
|
+
return undefined;
|
|
98
|
+
return [...new Set(surfaces.flat())];
|
|
99
|
+
}
|
|
95
100
|
export function getUatBrowserToolSupportError(options) {
|
|
96
101
|
if (!uatTypeIncludesBrowser(options.uatType))
|
|
97
102
|
return null;
|
|
98
|
-
|
|
103
|
+
const toolSurface = resolveUatBrowserToolSurface(options);
|
|
104
|
+
if (!toolSurface)
|
|
99
105
|
return null;
|
|
100
|
-
if (hasUatBrowserToolSurface(
|
|
106
|
+
if (hasUatBrowserToolSurface(toolSurface))
|
|
101
107
|
return null;
|
|
102
|
-
return `Cannot dispatch browser-backed run-uat for ${options.milestoneId}/${options.sliceId}: UAT mode "${options.uatType}" requires browser tools, but the
|
|
108
|
+
return `Cannot dispatch browser-backed run-uat for ${options.milestoneId}/${options.sliceId}: UAT mode "${options.uatType}" requires browser tools, but the run-uat tool surface has none. Enable browser tools or change the UAT to a runtime-executable Playwright command, then rerun /gsd auto.`;
|
|
103
109
|
}
|
|
104
110
|
export function isPartialEligibleUatType(uatType) {
|
|
105
111
|
return !!uatType && UAT_MODE_POLICIES[uatType].partialEligible;
|
|
@@ -13,7 +13,7 @@ function isNonEmptyString(value) {
|
|
|
13
13
|
function mergeBlockedTools(current, canonical) {
|
|
14
14
|
const merged = new Map();
|
|
15
15
|
for (const entry of [...(current ?? []), ...canonical]) {
|
|
16
|
-
merged.set(canonicalWorkflowToolName(parseMcpToolName(entry.name)?.
|
|
16
|
+
merged.set(canonicalWorkflowToolName(parseMcpToolName(entry.name)?.toolName ?? entry.name), entry);
|
|
17
17
|
}
|
|
18
18
|
return [...merged.values()];
|
|
19
19
|
}
|
|
@@ -204,20 +204,15 @@ function quoteToolNames(toolNames) {
|
|
|
204
204
|
return toolNames.map((toolName) => `"${toolName}"`).join(", ");
|
|
205
205
|
}
|
|
206
206
|
function validateCanonicalPresentation(params) {
|
|
207
|
-
const aliasHints = {
|
|
208
|
-
gsd_save_summary: "gsd_summary_save",
|
|
209
|
-
gsd_complete_task: "gsd_task_complete",
|
|
210
|
-
gsd_complete_slice: "gsd_slice_complete",
|
|
211
|
-
gsd_milestone_complete: "gsd_complete_milestone",
|
|
212
|
-
};
|
|
213
207
|
const errors = [];
|
|
214
208
|
for (const toolName of params.presentation.presentedTools) {
|
|
215
|
-
const baseName = parseMcpToolName(toolName)?.
|
|
216
|
-
const canonical =
|
|
217
|
-
if (canonical)
|
|
209
|
+
const baseName = parseMcpToolName(toolName)?.toolName ?? toolName;
|
|
210
|
+
const canonical = canonicalWorkflowToolName(baseName);
|
|
211
|
+
if (canonical !== baseName) {
|
|
218
212
|
errors.push(`presentation tool "${toolName}" uses an alias; use canonical "${canonical}"`);
|
|
213
|
+
}
|
|
219
214
|
}
|
|
220
|
-
const presentedCanonical = new Set(params.presentation.presentedTools.map((toolName) => canonicalWorkflowToolName(parseMcpToolName(toolName)?.
|
|
215
|
+
const presentedCanonical = new Set(params.presentation.presentedTools.map((toolName) => canonicalWorkflowToolName(parseMcpToolName(toolName)?.toolName ?? toolName)));
|
|
221
216
|
const missingRequiredTools = RUN_UAT_WORKFLOW_TOOL_NAMES.filter((requiredTool) => !presentedCanonical.has(requiredTool));
|
|
222
217
|
if (missingRequiredTools.length === 1) {
|
|
223
218
|
errors.push(`presentation is missing required UAT tool "${missingRequiredTools[0]}"`);
|
|
@@ -227,10 +222,10 @@ function validateCanonicalPresentation(params) {
|
|
|
227
222
|
}
|
|
228
223
|
const forbiddenCanonical = new Set(RUN_UAT_FORBIDDEN_TOOL_NAMES
|
|
229
224
|
.filter((toolName) => !toolName.includes("*"))
|
|
230
|
-
.map((toolName) => canonicalWorkflowToolName(parseMcpToolName(toolName)?.
|
|
225
|
+
.map((toolName) => canonicalWorkflowToolName(parseMcpToolName(toolName)?.toolName ?? toolName)));
|
|
231
226
|
const forbiddenPresentedTools = [];
|
|
232
227
|
for (const toolName of params.presentation.presentedTools) {
|
|
233
|
-
const canonical = canonicalWorkflowToolName(parseMcpToolName(toolName)?.
|
|
228
|
+
const canonical = canonicalWorkflowToolName(parseMcpToolName(toolName)?.toolName ?? toolName);
|
|
234
229
|
if (toolName === "mcp__gsd-workflow__*" || forbiddenCanonical.has(canonical)) {
|
|
235
230
|
forbiddenPresentedTools.push(toolName);
|
|
236
231
|
}
|
|
@@ -241,7 +236,7 @@ function validateCanonicalPresentation(params) {
|
|
|
241
236
|
else if (forbiddenPresentedTools.length > 1) {
|
|
242
237
|
errors.push(`presentation includes forbidden run-uat tools ${quoteToolNames(forbiddenPresentedTools)}`);
|
|
243
238
|
}
|
|
244
|
-
const blockedCanonical = new Set(params.presentation.blockedTools.map((entry) => canonicalWorkflowToolName(parseMcpToolName(entry.name)?.
|
|
239
|
+
const blockedCanonical = new Set(params.presentation.blockedTools.map((entry) => canonicalWorkflowToolName(parseMcpToolName(entry.name)?.toolName ?? entry.name)));
|
|
245
240
|
const missingBlockedTools = ["gsd_exec", "gsd_summary_save", "gsd_save_gate_result"].filter((blockedTool) => !blockedCanonical.has(blockedTool));
|
|
246
241
|
if (missingBlockedTools.length === 1) {
|
|
247
242
|
errors.push(`presentation must record "${missingBlockedTools[0]}" as blocked during run-uat`);
|