@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
|
@@ -19,11 +19,11 @@ import {
|
|
|
19
19
|
insertAssessment,
|
|
20
20
|
getMilestoneSlices,
|
|
21
21
|
getMilestone,
|
|
22
|
-
getArtifact,
|
|
23
22
|
} from "../gsd-db.js";
|
|
24
|
-
import { gsdProjectionRoot, clearPathCache
|
|
23
|
+
import { gsdProjectionRoot, clearPathCache } from "../paths.js";
|
|
25
24
|
import { resolveCanonicalMilestoneRoot } from "../worktree-manager.js";
|
|
26
|
-
import {
|
|
25
|
+
import { resolveWorktreeProjectRoot } from "../worktree-root.js";
|
|
26
|
+
import { saveFile, clearParseCache } from "../files.js";
|
|
27
27
|
import { invalidateStateCache } from "../state.js";
|
|
28
28
|
import { VALIDATION_VERDICTS, isValidMilestoneVerdict } from "../verdict-parser.js";
|
|
29
29
|
import { insertMilestoneValidationGates } from "../milestone-validation-gates.js";
|
|
@@ -31,7 +31,10 @@ import { logWarning } from "../workflow-logger.js";
|
|
|
31
31
|
import { UokGateRunner } from "../uok/gate-runner.js";
|
|
32
32
|
import { loadEffectiveGSDPreferences } from "../preferences.js";
|
|
33
33
|
import { resolveUokFlags } from "../uok/flags.js";
|
|
34
|
-
import {
|
|
34
|
+
import {
|
|
35
|
+
applyBrowserEvidenceGate,
|
|
36
|
+
browserEvidenceGateRequiresAttention,
|
|
37
|
+
} from "../milestone-validation-evidence.js";
|
|
35
38
|
|
|
36
39
|
export interface ValidateMilestoneParams {
|
|
37
40
|
milestoneId: string;
|
|
@@ -78,86 +81,6 @@ function getRequiredVerificationClasses(milestoneId: string): string[] {
|
|
|
78
81
|
return required;
|
|
79
82
|
}
|
|
80
83
|
|
|
81
|
-
function hasRuntimeExecutableUatEvidenceText(text: string): boolean {
|
|
82
|
-
if (!/\buatType:\s*runtime-executable\b/i.test(text)) return false;
|
|
83
|
-
if (!/\bverdict:\s*PASS\b/i.test(text)) return false;
|
|
84
|
-
return /^\|\s*[^|\n]+\s*\|\s*runtime\s*\|\s*PASS\s*\|[^|\n]*\bgsd_uat_exec\b/mi.test(text);
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
async function browserEvidenceGateRequiresAttention(
|
|
88
|
-
params: ValidateMilestoneParams,
|
|
89
|
-
basePath: string,
|
|
90
|
-
): Promise<boolean> {
|
|
91
|
-
if (params.verdict !== "pass") return false;
|
|
92
|
-
|
|
93
|
-
const milestone = getMilestone(params.milestoneId);
|
|
94
|
-
const slices = getMilestoneSlices(params.milestoneId);
|
|
95
|
-
const requirementText = compactTextParts([
|
|
96
|
-
milestone?.vision,
|
|
97
|
-
milestone?.success_criteria,
|
|
98
|
-
milestone?.verification_uat,
|
|
99
|
-
params.successCriteriaChecklist,
|
|
100
|
-
params.verificationClasses,
|
|
101
|
-
...slices.flatMap((slice) => [
|
|
102
|
-
slice.demo,
|
|
103
|
-
slice.goal,
|
|
104
|
-
slice.success_criteria,
|
|
105
|
-
]),
|
|
106
|
-
]);
|
|
107
|
-
if (!hasBrowserRequiredText(requirementText)) return false;
|
|
108
|
-
|
|
109
|
-
// Collect per-slice evidence so the runtime bypass is checked independently
|
|
110
|
-
// for each slice. Concatenating all slices before checking would allow runtime
|
|
111
|
-
// evidence from one slice to cover another slice's browser requirements.
|
|
112
|
-
const sliceEvidencePairs: Array<{ sliceRequirementText: string; evidenceText: string }> = [];
|
|
113
|
-
for (const slice of slices) {
|
|
114
|
-
const chunks: string[] = [];
|
|
115
|
-
const artifactPath = `milestones/${params.milestoneId}/slices/${slice.id}/${slice.id}-ASSESSMENT.md`;
|
|
116
|
-
const artifact = getArtifact(artifactPath);
|
|
117
|
-
if (artifact?.full_content) chunks.push(artifact.full_content);
|
|
118
|
-
const assessmentPath = resolveSliceFile(basePath, params.milestoneId, slice.id, "ASSESSMENT");
|
|
119
|
-
const assessmentContent = assessmentPath ? await loadFile(assessmentPath) : null;
|
|
120
|
-
if (assessmentContent) chunks.push(assessmentContent);
|
|
121
|
-
sliceEvidencePairs.push({
|
|
122
|
-
sliceRequirementText: compactTextParts([slice.demo, slice.goal, slice.success_criteria]),
|
|
123
|
-
evidenceText: chunks.join("\n\n"),
|
|
124
|
-
});
|
|
125
|
-
}
|
|
126
|
-
const persistedEvidence = sliceEvidencePairs.map((s) => s.evidenceText).join("\n\n");
|
|
127
|
-
|
|
128
|
-
// Runtime bypass: each slice whose own requirement text has browser-observable
|
|
129
|
-
// criteria must have its own runtime-executable UAT evidence. When no individual
|
|
130
|
-
// slice has slice-level browser requirements (e.g., they come from milestone-level
|
|
131
|
-
// fields only), fall back to checking whether any slice has runtime evidence.
|
|
132
|
-
const browserRequiringSlices = sliceEvidencePairs.filter((s) =>
|
|
133
|
-
hasBrowserRequiredText(s.sliceRequirementText),
|
|
134
|
-
);
|
|
135
|
-
const runtimeBypasses =
|
|
136
|
-
browserRequiringSlices.length > 0
|
|
137
|
-
? browserRequiringSlices.every((s) => hasRuntimeExecutableUatEvidenceText(s.evidenceText))
|
|
138
|
-
: sliceEvidencePairs.some((s) => hasRuntimeExecutableUatEvidenceText(s.evidenceText));
|
|
139
|
-
if (runtimeBypasses) return false;
|
|
140
|
-
|
|
141
|
-
const validationEvidence = compactTextParts([
|
|
142
|
-
params.successCriteriaChecklist,
|
|
143
|
-
params.verificationClasses,
|
|
144
|
-
params.verdictRationale,
|
|
145
|
-
params.remediationPlan,
|
|
146
|
-
]);
|
|
147
|
-
return !hasBrowserEvidenceText(`${persistedEvidence}\n\n${validationEvidence}`);
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
function applyBrowserEvidenceGate(params: ValidateMilestoneParams): ValidateMilestoneParams {
|
|
151
|
-
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.";
|
|
152
|
-
return {
|
|
153
|
-
...params,
|
|
154
|
-
verdict: "needs-attention",
|
|
155
|
-
verdictRationale: params.verdictRationale.trim()
|
|
156
|
-
? `${params.verdictRationale.trim()}\n\n${note}`
|
|
157
|
-
: note,
|
|
158
|
-
};
|
|
159
|
-
}
|
|
160
|
-
|
|
161
84
|
function renderValidationMarkdown(params: ValidateMilestoneParams): string {
|
|
162
85
|
let md = `---
|
|
163
86
|
verdict: ${params.verdict}
|
|
@@ -279,6 +202,24 @@ export async function handleValidateMilestone(
|
|
|
279
202
|
let projectionStale = false;
|
|
280
203
|
try {
|
|
281
204
|
await saveFile(validationPath, validationMd);
|
|
205
|
+
const projectRoot = resolveWorktreeProjectRoot(basePath);
|
|
206
|
+
if (projectRoot !== artifactBasePath) {
|
|
207
|
+
const projectValidationPath = join(
|
|
208
|
+
gsdProjectionRoot(projectRoot),
|
|
209
|
+
"milestones",
|
|
210
|
+
effectiveParams.milestoneId,
|
|
211
|
+
`${effectiveParams.milestoneId}-VALIDATION.md`,
|
|
212
|
+
);
|
|
213
|
+
try {
|
|
214
|
+
await saveFile(projectValidationPath, validationMd);
|
|
215
|
+
} catch (mirrorErr) {
|
|
216
|
+
logWarning(
|
|
217
|
+
"projection",
|
|
218
|
+
`validate_milestone project-root VALIDATION mirror failed for ${effectiveParams.milestoneId}`,
|
|
219
|
+
{ error: (mirrorErr as Error).message },
|
|
220
|
+
);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
282
223
|
} catch (renderErr) {
|
|
283
224
|
projectionStale = true;
|
|
284
225
|
logWarning("projection", `validate_milestone projection write failed for ${effectiveParams.milestoneId}; DB validation remains committed`, {
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
import { extractUatType } from "./files.js";
|
|
5
5
|
import type { UatType } from "./files.js";
|
|
6
6
|
import { hasBrowserRequiredText } from "./browser-evidence.js";
|
|
7
|
+
import { parseMcpToolName } from "./mcp-tool-name.js";
|
|
7
8
|
|
|
8
9
|
export type { UatType } from "./files.js";
|
|
9
10
|
|
|
@@ -122,31 +123,39 @@ export function uatTypeIncludesBrowser(uatType: string | undefined): boolean {
|
|
|
122
123
|
return isUatType(uatType) && UAT_MODE_POLICIES[uatType].browserTools;
|
|
123
124
|
}
|
|
124
125
|
|
|
125
|
-
function canonicalPresentedToolName(toolName: string): string {
|
|
126
|
-
if (!toolName.startsWith("mcp__")) return toolName;
|
|
127
|
-
const toolSeparator = toolName.indexOf("__", "mcp__".length);
|
|
128
|
-
return toolSeparator >= 0 ? toolName.slice(toolSeparator + 2) : toolName;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
126
|
export function isUatBrowserToolName(toolName: string): boolean {
|
|
132
|
-
|
|
127
|
+
const parsed = parseMcpToolName(toolName);
|
|
128
|
+
const canonicalName = parsed?.toolName ?? toolName;
|
|
129
|
+
if (canonicalName.startsWith("browser_")) return true;
|
|
130
|
+
return parsed?.toolName === "*" && parsed.serverName.toLowerCase().includes("browser");
|
|
133
131
|
}
|
|
134
132
|
|
|
135
133
|
export function hasUatBrowserToolSurface(activeTools: readonly string[] | undefined): boolean {
|
|
136
134
|
return Array.isArray(activeTools) && activeTools.some(isUatBrowserToolName);
|
|
137
135
|
}
|
|
138
136
|
|
|
137
|
+
export function resolveUatBrowserToolSurface(options: {
|
|
138
|
+
activeTools: readonly string[] | undefined;
|
|
139
|
+
registeredTools?: readonly string[] | undefined;
|
|
140
|
+
}): readonly string[] | undefined {
|
|
141
|
+
const surfaces = [options.activeTools, options.registeredTools].filter(Array.isArray);
|
|
142
|
+
if (surfaces.length === 0) return undefined;
|
|
143
|
+
return [...new Set(surfaces.flat())];
|
|
144
|
+
}
|
|
145
|
+
|
|
139
146
|
export function getUatBrowserToolSupportError(options: {
|
|
140
147
|
uatType: UatType;
|
|
141
148
|
activeTools: readonly string[] | undefined;
|
|
149
|
+
registeredTools?: readonly string[] | undefined;
|
|
142
150
|
milestoneId: string;
|
|
143
151
|
sliceId: string;
|
|
144
152
|
}): string | null {
|
|
145
153
|
if (!uatTypeIncludesBrowser(options.uatType)) return null;
|
|
146
|
-
|
|
147
|
-
if (
|
|
154
|
+
const toolSurface = resolveUatBrowserToolSurface(options);
|
|
155
|
+
if (!toolSurface) return null;
|
|
156
|
+
if (hasUatBrowserToolSurface(toolSurface)) return null;
|
|
148
157
|
|
|
149
|
-
return `Cannot dispatch browser-backed run-uat for ${options.milestoneId}/${options.sliceId}: UAT mode "${options.uatType}" requires browser tools, but the
|
|
158
|
+
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.`;
|
|
150
159
|
}
|
|
151
160
|
|
|
152
161
|
export function isPartialEligibleUatType(uatType: UatType | undefined): boolean {
|
|
@@ -103,7 +103,7 @@ function mergeBlockedTools(
|
|
|
103
103
|
): UatPresentationInput["blockedTools"] {
|
|
104
104
|
const merged = new Map<string, { name: string; reason: string }>();
|
|
105
105
|
for (const entry of [...(current ?? []), ...canonical]) {
|
|
106
|
-
merged.set(canonicalWorkflowToolName(parseMcpToolName(entry.name)?.
|
|
106
|
+
merged.set(canonicalWorkflowToolName(parseMcpToolName(entry.name)?.toolName ?? entry.name), entry);
|
|
107
107
|
}
|
|
108
108
|
return [...merged.values()];
|
|
109
109
|
}
|
|
@@ -299,22 +299,18 @@ function quoteToolNames(toolNames: readonly string[]): string {
|
|
|
299
299
|
}
|
|
300
300
|
|
|
301
301
|
function validateCanonicalPresentation(params: UatResultSaveParams): string | null {
|
|
302
|
-
const aliasHints: Record<string, string> = {
|
|
303
|
-
gsd_save_summary: "gsd_summary_save",
|
|
304
|
-
gsd_complete_task: "gsd_task_complete",
|
|
305
|
-
gsd_complete_slice: "gsd_slice_complete",
|
|
306
|
-
gsd_milestone_complete: "gsd_complete_milestone",
|
|
307
|
-
};
|
|
308
302
|
const errors: string[] = [];
|
|
309
303
|
for (const toolName of params.presentation.presentedTools) {
|
|
310
|
-
const baseName = parseMcpToolName(toolName)?.
|
|
311
|
-
const canonical =
|
|
312
|
-
if (canonical
|
|
304
|
+
const baseName = parseMcpToolName(toolName)?.toolName ?? toolName;
|
|
305
|
+
const canonical = canonicalWorkflowToolName(baseName);
|
|
306
|
+
if (canonical !== baseName) {
|
|
307
|
+
errors.push(`presentation tool "${toolName}" uses an alias; use canonical "${canonical}"`);
|
|
308
|
+
}
|
|
313
309
|
}
|
|
314
310
|
|
|
315
311
|
const presentedCanonical = new Set(
|
|
316
312
|
params.presentation.presentedTools.map((toolName) =>
|
|
317
|
-
canonicalWorkflowToolName(parseMcpToolName(toolName)?.
|
|
313
|
+
canonicalWorkflowToolName(parseMcpToolName(toolName)?.toolName ?? toolName)
|
|
318
314
|
),
|
|
319
315
|
);
|
|
320
316
|
const missingRequiredTools = RUN_UAT_WORKFLOW_TOOL_NAMES.filter(
|
|
@@ -329,11 +325,11 @@ function validateCanonicalPresentation(params: UatResultSaveParams): string | nu
|
|
|
329
325
|
const forbiddenCanonical = new Set(
|
|
330
326
|
RUN_UAT_FORBIDDEN_TOOL_NAMES
|
|
331
327
|
.filter((toolName) => !toolName.includes("*"))
|
|
332
|
-
.map((toolName) => canonicalWorkflowToolName(parseMcpToolName(toolName)?.
|
|
328
|
+
.map((toolName) => canonicalWorkflowToolName(parseMcpToolName(toolName)?.toolName ?? toolName)),
|
|
333
329
|
);
|
|
334
330
|
const forbiddenPresentedTools: string[] = [];
|
|
335
331
|
for (const toolName of params.presentation.presentedTools) {
|
|
336
|
-
const canonical = canonicalWorkflowToolName(parseMcpToolName(toolName)?.
|
|
332
|
+
const canonical = canonicalWorkflowToolName(parseMcpToolName(toolName)?.toolName ?? toolName);
|
|
337
333
|
if (toolName === "mcp__gsd-workflow__*" || forbiddenCanonical.has(canonical)) {
|
|
338
334
|
forbiddenPresentedTools.push(toolName);
|
|
339
335
|
}
|
|
@@ -346,7 +342,7 @@ function validateCanonicalPresentation(params: UatResultSaveParams): string | nu
|
|
|
346
342
|
|
|
347
343
|
const blockedCanonical = new Set(
|
|
348
344
|
params.presentation.blockedTools.map((entry) =>
|
|
349
|
-
canonicalWorkflowToolName(parseMcpToolName(entry.name)?.
|
|
345
|
+
canonicalWorkflowToolName(parseMcpToolName(entry.name)?.toolName ?? entry.name)
|
|
350
346
|
),
|
|
351
347
|
);
|
|
352
348
|
const missingBlockedTools = ["gsd_exec", "gsd_summary_save", "gsd_save_gate_result"].filter(
|
|
@@ -45,6 +45,7 @@ import {
|
|
|
45
45
|
type ContextModePolicy,
|
|
46
46
|
type UnitContextManifest,
|
|
47
47
|
} from "./unit-context-manifest.js";
|
|
48
|
+
import type { UnitPromptContextContract } from "./tool-contract.js";
|
|
48
49
|
|
|
49
50
|
/**
|
|
50
51
|
* Async function mapping an artifact key to its inlined-content string,
|
|
@@ -195,8 +196,32 @@ export interface ComposedUnitContext {
|
|
|
195
196
|
readonly inline: string;
|
|
196
197
|
}
|
|
197
198
|
|
|
199
|
+
export type UnitContextBlockMode = "prepend" | "inline" | "excerpt" | "computed";
|
|
200
|
+
|
|
201
|
+
export interface ComposedUnitContextBlock {
|
|
202
|
+
readonly key: string;
|
|
203
|
+
readonly mode: UnitContextBlockMode;
|
|
204
|
+
readonly body: string;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
export interface ComposedContractedUnitContext extends ComposedUnitContext {
|
|
208
|
+
readonly blocks: readonly ComposedUnitContextBlock[];
|
|
209
|
+
readonly onDemand: readonly ArtifactKey[];
|
|
210
|
+
}
|
|
211
|
+
|
|
198
212
|
const SECTION_SEPARATOR = "\n\n---\n\n";
|
|
199
213
|
|
|
214
|
+
interface UnitContextCompositionContract {
|
|
215
|
+
readonly unitType: string;
|
|
216
|
+
readonly artifacts: {
|
|
217
|
+
readonly inline: readonly ArtifactKey[];
|
|
218
|
+
readonly excerpt: readonly ArtifactKey[];
|
|
219
|
+
readonly onDemand: readonly ArtifactKey[];
|
|
220
|
+
readonly computed: readonly ComputedArtifactId[];
|
|
221
|
+
readonly prepend: readonly ComputedArtifactId[];
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
|
|
200
225
|
/**
|
|
201
226
|
* Compose all manifest-declared context for a unit type using the v2
|
|
202
227
|
* surface. Walks `prepend` first (computed-only), then the `inline` list
|
|
@@ -220,36 +245,73 @@ export async function composeUnitContext(
|
|
|
220
245
|
const manifest: UnitContextManifest | null = resolveManifest(unitType);
|
|
221
246
|
if (!manifest) return { prepend: "", inline: "" };
|
|
222
247
|
|
|
223
|
-
|
|
248
|
+
const composed = await composeDeclaredUnitContext({
|
|
249
|
+
unitType,
|
|
250
|
+
artifacts: {
|
|
251
|
+
inline: manifest.artifacts.inline,
|
|
252
|
+
excerpt: manifest.artifacts.excerpt,
|
|
253
|
+
onDemand: manifest.artifacts.onDemand,
|
|
254
|
+
computed: manifest.artifacts.computed ?? [],
|
|
255
|
+
prepend: manifest.prepend ?? [],
|
|
256
|
+
},
|
|
257
|
+
}, opts);
|
|
258
|
+
return {
|
|
259
|
+
prepend: composed.prepend,
|
|
260
|
+
inline: composed.inline,
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
export async function composeContractedUnitContext(
|
|
265
|
+
contract: UnitPromptContextContract,
|
|
266
|
+
opts: ComposeUnitContextOptions,
|
|
267
|
+
): Promise<ComposedContractedUnitContext> {
|
|
268
|
+
return composeDeclaredUnitContext(contract, opts);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
async function composeDeclaredUnitContext(
|
|
272
|
+
contract: UnitContextCompositionContract,
|
|
273
|
+
opts: ComposeUnitContextOptions,
|
|
274
|
+
): Promise<ComposedContractedUnitContext> {
|
|
275
|
+
// Single-source `unitType`: contract/manifest selection comes from the
|
|
224
276
|
// function arg, but computed builders read it from `base.unitType`.
|
|
225
|
-
//
|
|
226
|
-
// but a different one in opts.base), the composer would silently
|
|
227
|
-
// mix one unit's manifest with another unit's computed context.
|
|
228
|
-
// Normalize here so the composer dispatches a consistent identity
|
|
229
|
-
// through to every builder.
|
|
277
|
+
// Normalize here so every builder sees the same Unit identity.
|
|
230
278
|
const normalizedOpts: ComposeUnitContextOptions = {
|
|
231
279
|
...opts,
|
|
232
|
-
base: { ...opts.base, unitType },
|
|
280
|
+
base: { ...opts.base, unitType: contract.unitType },
|
|
233
281
|
};
|
|
234
282
|
|
|
235
|
-
const prependBlocks = await
|
|
236
|
-
|
|
283
|
+
const prependBlocks = await runComputedBlocks(
|
|
284
|
+
contract.artifacts.prepend,
|
|
285
|
+
normalizedOpts,
|
|
286
|
+
"prepend",
|
|
287
|
+
);
|
|
288
|
+
const inlineBlocks: ComposedUnitContextBlock[] = [];
|
|
237
289
|
|
|
238
|
-
for (const key of
|
|
290
|
+
for (const key of contract.artifacts.inline) {
|
|
239
291
|
if (!normalizedOpts.resolveArtifact) break;
|
|
240
292
|
const body = await normalizedOpts.resolveArtifact(key);
|
|
241
|
-
if (body && body.length > 0)
|
|
293
|
+
if (body && body.length > 0) {
|
|
294
|
+
inlineBlocks.push({ key, mode: "inline", body });
|
|
295
|
+
}
|
|
242
296
|
}
|
|
243
|
-
for (const key of
|
|
297
|
+
for (const key of contract.artifacts.excerpt) {
|
|
244
298
|
if (!normalizedOpts.resolveExcerpt) break;
|
|
245
299
|
const body = await normalizedOpts.resolveExcerpt(key);
|
|
246
|
-
if (body && body.length > 0)
|
|
300
|
+
if (body && body.length > 0) {
|
|
301
|
+
inlineBlocks.push({ key, mode: "excerpt", body });
|
|
302
|
+
}
|
|
247
303
|
}
|
|
248
|
-
inlineBlocks.push(...await
|
|
304
|
+
inlineBlocks.push(...await runComputedBlocks(
|
|
305
|
+
contract.artifacts.computed,
|
|
306
|
+
normalizedOpts,
|
|
307
|
+
"computed",
|
|
308
|
+
));
|
|
249
309
|
|
|
250
310
|
return {
|
|
251
|
-
prepend: prependBlocks.join(SECTION_SEPARATOR),
|
|
252
|
-
inline: inlineBlocks.join(SECTION_SEPARATOR),
|
|
311
|
+
prepend: prependBlocks.map((block) => block.body).join(SECTION_SEPARATOR),
|
|
312
|
+
inline: inlineBlocks.map((block) => block.body).join(SECTION_SEPARATOR),
|
|
313
|
+
blocks: [...prependBlocks, ...inlineBlocks],
|
|
314
|
+
onDemand: contract.artifacts.onDemand,
|
|
253
315
|
};
|
|
254
316
|
}
|
|
255
317
|
|
|
@@ -258,10 +320,11 @@ export async function composeUnitContext(
|
|
|
258
320
|
* Missing registry entries (manifest declares the id but caller didn't
|
|
259
321
|
* register it) are skipped silently — see composeUnitContext rationale.
|
|
260
322
|
*/
|
|
261
|
-
async function
|
|
323
|
+
async function runComputedBlocks(
|
|
262
324
|
ids: readonly ComputedArtifactId[],
|
|
263
325
|
opts: ComposeUnitContextOptions,
|
|
264
|
-
|
|
326
|
+
mode: Extract<UnitContextBlockMode, "prepend" | "computed">,
|
|
327
|
+
): Promise<ComposedUnitContextBlock[]> {
|
|
265
328
|
if (ids.length === 0 || !opts.computed) return [];
|
|
266
329
|
// Type safety lives at the registration boundary (caller-supplied
|
|
267
330
|
// `computed` is typed against ComputedArtifactInputs[K] per id). Inside
|
|
@@ -274,12 +337,14 @@ async function runComputed(
|
|
|
274
337
|
inputs: unknown;
|
|
275
338
|
};
|
|
276
339
|
const registry = opts.computed as Record<string, AnyEntry | undefined>;
|
|
277
|
-
const out:
|
|
340
|
+
const out: ComposedUnitContextBlock[] = [];
|
|
278
341
|
for (const id of ids) {
|
|
279
342
|
const entry = registry[id];
|
|
280
343
|
if (!entry) continue;
|
|
281
344
|
const body = await entry.build(entry.inputs, opts.base);
|
|
282
|
-
if (body && body.length > 0)
|
|
345
|
+
if (body && body.length > 0) {
|
|
346
|
+
out.push({ key: id, mode, body });
|
|
347
|
+
}
|
|
283
348
|
}
|
|
284
349
|
return out;
|
|
285
350
|
}
|
|
@@ -10,7 +10,8 @@ import {
|
|
|
10
10
|
} from "./paths.js";
|
|
11
11
|
import { loadFile, parseTaskPlanMustHaves, countMustHavesMentionedInSummary } from "./files.js";
|
|
12
12
|
import { parseUnitId } from "./unit-id.js";
|
|
13
|
-
import { getTask, isDbAvailable
|
|
13
|
+
import { getTask, isDbAvailable } from "./gsd-db.js";
|
|
14
|
+
import { refreshWorkflowDatabaseFromDisk } from "./db-workspace.js";
|
|
14
15
|
import { isClosedStatus } from "./status-guards.js";
|
|
15
16
|
|
|
16
17
|
// Per-record advisory lock — prevents read-modify-write races between
|
|
@@ -218,7 +219,7 @@ export async function inspectExecuteTaskDurability(
|
|
|
218
219
|
const nextActionAdvanced = !new RegExp(`Execute ${tid}\\b`).test(stateContent);
|
|
219
220
|
let dbComplete = false;
|
|
220
221
|
if (isDbAvailable()) {
|
|
221
|
-
|
|
222
|
+
refreshWorkflowDatabaseFromDisk();
|
|
222
223
|
const task = getTask(mid, sid, tid);
|
|
223
224
|
dbComplete = !!task && isClosedStatus(task.status);
|
|
224
225
|
}
|
|
@@ -71,6 +71,7 @@ export const UNIT_TOOL_CONTRACTS: Record<string, UnitToolSurfaceContract> = {
|
|
|
71
71
|
"gsd_milestone_generate_id",
|
|
72
72
|
],
|
|
73
73
|
requiredWorkflowTools: [
|
|
74
|
+
"ask_user_questions",
|
|
74
75
|
"gsd_summary_save",
|
|
75
76
|
"gsd_requirement_save",
|
|
76
77
|
"gsd_requirement_update",
|
|
@@ -80,7 +81,7 @@ export const UNIT_TOOL_CONTRACTS: Record<string, UnitToolSurfaceContract> = {
|
|
|
80
81
|
},
|
|
81
82
|
"discuss-slice": {
|
|
82
83
|
allowedGsdTools: ["gsd_summary_save", "gsd_decision_save"],
|
|
83
|
-
requiredWorkflowTools: ["gsd_summary_save"],
|
|
84
|
+
requiredWorkflowTools: ["ask_user_questions", "gsd_summary_save"],
|
|
84
85
|
},
|
|
85
86
|
"validate-milestone": {
|
|
86
87
|
allowedGsdTools: ["gsd_milestone_status", "gsd_validate_milestone", "gsd_reassess_roadmap", "subagent"],
|
|
@@ -183,6 +183,24 @@ export function isAwaitingApprovalBoundary(messages: unknown[] | undefined): boo
|
|
|
183
183
|
return hasApprovalQuestion(text);
|
|
184
184
|
}
|
|
185
185
|
|
|
186
|
+
/** True when an assistant message already has an in-flight ask_user_questions tool call. */
|
|
187
|
+
export function messageHasPendingAskUserQuestionsTool(message: unknown): boolean {
|
|
188
|
+
if (!message || typeof message !== "object") return false;
|
|
189
|
+
const content = (message as { content?: unknown }).content;
|
|
190
|
+
if (!Array.isArray(content)) return false;
|
|
191
|
+
return content.some((block) => {
|
|
192
|
+
if (!block || typeof block !== "object") return false;
|
|
193
|
+
// Claude Code marks completion by attaching externalResult, not by setting state.
|
|
194
|
+
// Streaming blocks often carry no state; serverToolUse is the claude-code-cli MCP path.
|
|
195
|
+
const tool = block as { type?: string; name?: string; state?: string; externalResult?: unknown };
|
|
196
|
+
if (tool.type !== "toolCall" && tool.type !== "serverToolUse") return false;
|
|
197
|
+
const name = String(tool.name ?? "").toLowerCase();
|
|
198
|
+
if (!name.includes("ask_user_questions")) return false;
|
|
199
|
+
if (tool.externalResult !== undefined) return false;
|
|
200
|
+
return tool.state !== "completed" && tool.state !== "done";
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
|
|
186
204
|
export function shouldPauseForUserApprovalQuestion(
|
|
187
205
|
unitType: string | undefined,
|
|
188
206
|
messages: unknown[] | undefined,
|
|
@@ -5,6 +5,7 @@ import { existsSync } from "node:fs";
|
|
|
5
5
|
|
|
6
6
|
import { getAutoWorktreePath, isInAutoWorktree } from "./auto-worktree.js";
|
|
7
7
|
import { ensureDbOpen } from "./bootstrap/dynamic-tools.js";
|
|
8
|
+
import { refreshWorkflowDatabaseFromDisk } from "./db-workspace.js";
|
|
8
9
|
import { getIsolationMode } from "./preferences.js";
|
|
9
10
|
import { deriveState } from "./state.js";
|
|
10
11
|
import type { GSDState } from "./types.js";
|
|
@@ -91,6 +92,7 @@ export async function getValidationBlockMessageForBase(
|
|
|
91
92
|
attemptedCommand = "",
|
|
92
93
|
): Promise<string | null> {
|
|
93
94
|
await ensureDbOpen(base);
|
|
95
|
+
refreshWorkflowDatabaseFromDisk();
|
|
94
96
|
let state = await deriveState(base);
|
|
95
97
|
|
|
96
98
|
if (
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
// Project/App: gsd-pi
|
|
2
|
+
// File Purpose: Web-app detection and Playwright/UAT guidance for planning and slice closeout.
|
|
3
|
+
|
|
4
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
5
|
+
import { resolve } from "node:path";
|
|
6
|
+
|
|
7
|
+
import { detectWebApp } from "../browser-tools/web-app-detect.js";
|
|
8
|
+
|
|
9
|
+
export { detectWebApp };
|
|
10
|
+
|
|
11
|
+
interface MinimalPackageJson {
|
|
12
|
+
dependencies?: Record<string, unknown>;
|
|
13
|
+
devDependencies?: Record<string, unknown>;
|
|
14
|
+
scripts?: Record<string, unknown>;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function readPackageJson(projectRoot: string): MinimalPackageJson | null {
|
|
18
|
+
const packageJsonPath = resolve(projectRoot, "package.json");
|
|
19
|
+
if (!existsSync(packageJsonPath)) return null;
|
|
20
|
+
try {
|
|
21
|
+
const parsed = JSON.parse(readFileSync(packageJsonPath, "utf-8")) as unknown;
|
|
22
|
+
return parsed && typeof parsed === "object" ? (parsed as MinimalPackageJson) : null;
|
|
23
|
+
} catch {
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function hasPlaywrightTestDependency(projectRoot: string): boolean {
|
|
29
|
+
const pkg = readPackageJson(projectRoot);
|
|
30
|
+
if (!pkg) return false;
|
|
31
|
+
const names = [
|
|
32
|
+
...Object.keys(pkg.dependencies ?? {}),
|
|
33
|
+
...Object.keys(pkg.devDependencies ?? {}),
|
|
34
|
+
];
|
|
35
|
+
return names.some((name) => name === "playwright" || name === "@playwright/test");
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function findPlaywrightTestScript(projectRoot: string): string | null {
|
|
39
|
+
const pkg = readPackageJson(projectRoot);
|
|
40
|
+
if (!pkg?.scripts) return null;
|
|
41
|
+
for (const [name, value] of Object.entries(pkg.scripts)) {
|
|
42
|
+
if (typeof value !== "string") continue;
|
|
43
|
+
if (/\bplaywright\s+test\b/.test(value)) {
|
|
44
|
+
return `npm run ${name}`;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Markdown block injected into plan/complete-slice prompts when the project
|
|
52
|
+
* looks browser-facing. Returns null for CLI/library-only repos.
|
|
53
|
+
*/
|
|
54
|
+
export function buildWebAppUatGuidanceBlock(projectRoot: string): string | null {
|
|
55
|
+
if (!detectWebApp(projectRoot)) return null;
|
|
56
|
+
|
|
57
|
+
const playwrightScript = findPlaywrightTestScript(projectRoot);
|
|
58
|
+
const hasPlaywright = hasPlaywrightTestDependency(projectRoot) || playwrightScript !== null;
|
|
59
|
+
const lines = [
|
|
60
|
+
"### Web App UAT (detected)",
|
|
61
|
+
"",
|
|
62
|
+
"This project looks browser-facing. GSD exposes Playwright-backed `browser_*` tools by default for run-uat.",
|
|
63
|
+
"",
|
|
64
|
+
"**UAT modes (pick one per slice — do not use `artifact-driven` for browser steps):**",
|
|
65
|
+
"- `browser-executable` — navigate to `http://localhost:…`, click, screenshot, assert via `browser_*` tools during run-uat",
|
|
66
|
+
"- `runtime-executable` — run an automated browser test command via `gsd_uat_exec` (for example `npx playwright test`)",
|
|
67
|
+
"- `mixed` / `live-runtime` — combine runtime startup checks with interactive browser verification",
|
|
68
|
+
"",
|
|
69
|
+
"**Planning / closeout rules:**",
|
|
70
|
+
"- Preconditions must name the dev-server command and URL (for example `npm run dev` → `http://localhost:3000`)",
|
|
71
|
+
"- Slice Verification and UAT test cases must not say \"open in browser\" under `artifact-driven` — complete-slice rejects that",
|
|
72
|
+
"- Milestone `Verification Classes` → UAT row must describe browser-observable acceptance, not \"manual spot check\" alone",
|
|
73
|
+
];
|
|
74
|
+
|
|
75
|
+
if (hasPlaywright) {
|
|
76
|
+
lines.push(
|
|
77
|
+
"",
|
|
78
|
+
"**Playwright:** dependency detected.",
|
|
79
|
+
);
|
|
80
|
+
if (playwrightScript) {
|
|
81
|
+
lines.push(
|
|
82
|
+
`- Prefer slice verification and runtime-executable UAT referencing \`${playwrightScript}\` or a focused \`npx playwright test <spec>\` command`,
|
|
83
|
+
);
|
|
84
|
+
} else {
|
|
85
|
+
lines.push(
|
|
86
|
+
"- Prefer runtime-executable UAT with `npx playwright test` (or a focused spec path) when UI behavior is covered by specs",
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
lines.push("- Name concrete spec paths in slice Verification (for example `e2e/smoke.spec.ts`)");
|
|
90
|
+
} else {
|
|
91
|
+
lines.push(
|
|
92
|
+
"",
|
|
93
|
+
"**Playwright scaffolding (first UI slice):** no `playwright` / `@playwright/test` dependency yet.",
|
|
94
|
+
"- Add a planning task that installs Playwright, adds `playwright.config.ts`, and creates a minimal smoke spec (for example `e2e/smoke.spec.ts`)",
|
|
95
|
+
"- Task `verify` should run `npx playwright test` (or the focused spec) with a safe, simple command",
|
|
96
|
+
"- Until specs exist, use `browser-executable` UAT with localhost preconditions and interactive `browser_*` checks at slice closeout",
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return lines.join("\n");
|
|
101
|
+
}
|