@opengsd/gsd-pi 1.1.1-dev.616a1a1 → 1.1.1-dev.75048e7
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.js +3 -2
- package/dist/help-text.js +10 -6
- package/dist/resources/.managed-resources-content-hash +1 -1
- package/dist/resources/extensions/browser-tools/engine/managed-gsd-browser.js +495 -0
- package/dist/resources/extensions/browser-tools/engine/selection.js +16 -0
- package/dist/resources/extensions/browser-tools/extension-manifest.json +2 -2
- package/dist/resources/extensions/browser-tools/index.js +57 -9
- package/dist/resources/extensions/browser-tools/package.json +5 -1
- package/dist/resources/extensions/claude-code-cli/stream-adapter.js +167 -16
- package/dist/resources/extensions/gsd/auto/orchestrator.js +0 -1
- package/dist/resources/extensions/gsd/auto/phases.js +4 -3
- package/dist/resources/extensions/gsd/auto-dashboard.js +92 -17
- package/dist/resources/extensions/gsd/auto-dispatch.js +55 -0
- package/dist/resources/extensions/gsd/auto-post-unit.js +134 -10
- package/dist/resources/extensions/gsd/auto-prompts.js +72 -22
- package/dist/resources/extensions/gsd/auto-recovery.js +7 -8
- package/dist/resources/extensions/gsd/auto-runtime-state.js +3 -0
- package/dist/resources/extensions/gsd/auto-start.js +94 -15
- package/dist/resources/extensions/gsd/auto-tool-tracking.js +1 -1
- package/dist/resources/extensions/gsd/auto-unit-tool-scope.js +18 -65
- package/dist/resources/extensions/gsd/auto-worktree.js +18 -5
- package/dist/resources/extensions/gsd/auto.js +31 -6
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +89 -4
- package/dist/resources/extensions/gsd/bootstrap/exec-tools.js +43 -0
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +56 -20
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +33 -38
- package/dist/resources/extensions/gsd/browser-evidence.js +29 -2
- package/dist/resources/extensions/gsd/closeout-consistency-gate.js +61 -0
- package/dist/resources/extensions/gsd/commands/catalog.js +6 -1
- package/dist/resources/extensions/gsd/commands/handlers/core.js +6 -2
- package/dist/resources/extensions/gsd/commands/handlers/ops.js +9 -5
- package/dist/resources/extensions/gsd/commands-handlers.js +76 -11
- package/dist/resources/extensions/gsd/commands-maintenance.js +172 -2
- package/dist/resources/extensions/gsd/commands-mcp-status.js +109 -60
- package/dist/resources/extensions/gsd/commands-prefs-wizard.js +3 -1
- package/dist/resources/extensions/gsd/commands-verdict.js +1 -1
- package/dist/resources/extensions/gsd/config-overlay.js +2 -1
- package/dist/resources/extensions/gsd/dashboard-overlay.js +21 -7
- package/dist/resources/extensions/gsd/docs/preferences-reference.md +8 -0
- package/dist/resources/extensions/gsd/doctor-runtime-checks.js +2 -2
- package/dist/resources/extensions/gsd/error-classifier.js +2 -1
- package/dist/resources/extensions/gsd/escalation.js +4 -4
- package/dist/resources/extensions/gsd/exec-sandbox.js +2 -0
- package/dist/resources/extensions/gsd/forensics.js +74 -2
- package/dist/resources/extensions/gsd/gsd-db.js +42 -6
- package/dist/resources/extensions/gsd/guided-flow.js +119 -176
- package/dist/resources/extensions/gsd/mcp-filter.js +3 -0
- package/dist/resources/extensions/gsd/mcp-project-config.js +76 -84
- package/dist/resources/extensions/gsd/memory-store.js +4 -1
- package/dist/resources/extensions/gsd/migration-auto-check.js +2 -2
- package/dist/resources/extensions/gsd/milestone-closeout.js +3 -1
- package/dist/resources/extensions/gsd/pending-auto-start.js +0 -1
- package/dist/resources/extensions/gsd/post-unit-hooks.js +9 -0
- package/dist/resources/extensions/gsd/preferences-validation.js +39 -0
- package/dist/resources/extensions/gsd/prompt-loader.js +7 -0
- package/dist/resources/extensions/gsd/prompts/forensics.md +61 -1
- package/dist/resources/extensions/gsd/prompts/gate-evaluate.md +3 -1
- package/dist/resources/extensions/gsd/prompts/parallel-research-slices.md +3 -1
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/reactive-execute.md +3 -1
- package/dist/resources/extensions/gsd/prompts/run-uat.md +33 -23
- package/dist/resources/extensions/gsd/prompts/system.md +3 -1
- package/dist/resources/extensions/gsd/prompts/validate-milestone.md +3 -3
- package/dist/resources/extensions/gsd/recovery-classification.js +20 -0
- package/dist/resources/extensions/gsd/rule-registry.js +428 -52
- package/dist/resources/extensions/gsd/safety/destructive-guard.js +3 -0
- package/dist/resources/extensions/gsd/skill-activation.js +20 -3
- package/dist/resources/extensions/gsd/state-reconciliation/drift/artifact-db.js +4 -2
- package/dist/resources/extensions/gsd/state-reconciliation/drift/project-md.js +1 -1
- package/dist/resources/extensions/gsd/state-reconciliation/drift/roadmap.js +18 -1
- package/dist/resources/extensions/gsd/state-reconciliation/index.js +6 -0
- package/dist/resources/extensions/gsd/state.js +17 -14
- package/dist/resources/extensions/gsd/templates/plan.md +3 -1
- package/dist/resources/extensions/gsd/tool-contract.js +5 -0
- package/dist/resources/extensions/gsd/tool-presentation-plan.js +143 -0
- package/dist/resources/extensions/gsd/tools/complete-slice.js +15 -1
- package/dist/resources/extensions/gsd/tools/complete-task.js +11 -1
- package/dist/resources/extensions/gsd/tools/exec-tool.js +109 -0
- package/dist/resources/extensions/gsd/tools/plan-slice.js +14 -9
- package/dist/resources/extensions/gsd/tools/reopen-milestone.js +2 -2
- package/dist/resources/extensions/gsd/tools/validate-milestone.js +46 -16
- package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +483 -6
- package/dist/resources/extensions/gsd/unit-context-manifest.js +8 -3
- package/dist/resources/extensions/gsd/unit-tool-contracts.js +169 -0
- package/dist/resources/extensions/gsd/validation-block-guard.js +2 -0
- package/dist/resources/extensions/gsd/verdict-parser.js +59 -15
- package/dist/resources/extensions/gsd/verification-gate.js +72 -1
- package/dist/resources/extensions/gsd/workflow-mcp-auto-prep.js +3 -1
- package/dist/resources/extensions/gsd/workflow-mcp.js +5 -73
- package/dist/resources/extensions/gsd/worktree-lifecycle.js +24 -0
- package/dist/resources/extensions/mcp-client/manager.js +31 -1
- package/dist/resources/extensions/shared/gsd-browser-cli.js +145 -0
- package/dist/rtk.d.ts +7 -1
- package/dist/rtk.js +27 -11
- package/dist/update-check.d.ts +15 -1
- package/dist/update-check.js +87 -12
- package/dist/update-cmd.d.ts +1 -0
- package/dist/update-cmd.js +53 -2
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +5 -5
- package/dist/web/standalone/.next/build-manifest.json +2 -2
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- 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/api/update/route.js +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 +5 -5
- 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/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/package.json +5 -3
- package/packages/cloud-mcp-gateway/package.json +2 -2
- package/packages/contracts/dist/workflow.d.ts +14 -0
- package/packages/contracts/dist/workflow.d.ts.map +1 -1
- package/packages/contracts/dist/workflow.js +16 -0
- package/packages/contracts/dist/workflow.js.map +1 -1
- package/packages/contracts/package.json +1 -1
- package/packages/daemon/package.json +4 -4
- package/packages/gsd-agent-core/dist/agent-session.d.ts +9 -0
- package/packages/gsd-agent-core/dist/agent-session.d.ts.map +1 -1
- package/packages/gsd-agent-core/dist/agent-session.js +32 -0
- package/packages/gsd-agent-core/dist/agent-session.js.map +1 -1
- package/packages/gsd-agent-core/dist/index.d.ts +1 -0
- package/packages/gsd-agent-core/dist/index.d.ts.map +1 -1
- package/packages/gsd-agent-core/dist/index.js +1 -0
- package/packages/gsd-agent-core/dist/index.js.map +1 -1
- package/packages/gsd-agent-core/dist/session/agent-session-compaction.d.ts +2 -0
- package/packages/gsd-agent-core/dist/session/agent-session-compaction.d.ts.map +1 -1
- package/packages/gsd-agent-core/dist/session/agent-session-compaction.js +8 -2
- package/packages/gsd-agent-core/dist/session/agent-session-compaction.js.map +1 -1
- package/packages/gsd-agent-core/dist/session/agent-session-host.d.ts +7 -0
- package/packages/gsd-agent-core/dist/session/agent-session-host.d.ts.map +1 -1
- package/packages/gsd-agent-core/dist/session/agent-session-host.js.map +1 -1
- package/packages/gsd-agent-core/dist/session/agent-session-prompt.d.ts.map +1 -1
- package/packages/gsd-agent-core/dist/session/agent-session-prompt.js +69 -1
- package/packages/gsd-agent-core/dist/session/agent-session-prompt.js.map +1 -1
- package/packages/gsd-agent-core/dist/turn-latency.d.ts +47 -0
- package/packages/gsd-agent-core/dist/turn-latency.d.ts.map +1 -0
- package/packages/gsd-agent-core/dist/turn-latency.js +123 -0
- package/packages/gsd-agent-core/dist/turn-latency.js.map +1 -0
- package/packages/gsd-agent-core/package.json +6 -6
- package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/gsd-widget-prototype.d.ts +21 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/gsd-widget-prototype.d.ts.map +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/gsd-widget-prototype.js +213 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/gsd-widget-prototype.js.map +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/components/settings-selector.d.ts +2 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/settings-selector.js +10 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.js +5 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.d.ts +1 -0
- 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 +92 -31
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/input-controller.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/input-controller.js +7 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/input-controller.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-command-handlers.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-command-handlers.js +6 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-command-handlers.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-extension-dialogs.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-extension-dialogs.js +2 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-extension-dialogs.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-class-constants.d.ts +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-class-constants.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-class-constants.js +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-class-constants.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode.js +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-settings.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-settings.js +5 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-settings.js.map +1 -1
- package/packages/gsd-agent-modes/package.json +7 -7
- package/packages/mcp-server/dist/remote-questions.d.ts.map +1 -1
- package/packages/mcp-server/dist/remote-questions.js +23 -9
- package/packages/mcp-server/dist/remote-questions.js.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.js +84 -2
- 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/dist/agent-loop.js +42 -3
- package/packages/pi-agent-core/dist/agent-loop.js.map +1 -1
- package/packages/pi-agent-core/dist/agent.d.ts +5 -1
- package/packages/pi-agent-core/dist/agent.d.ts.map +1 -1
- package/packages/pi-agent-core/dist/agent.js +2 -0
- package/packages/pi-agent-core/dist/agent.js.map +1 -1
- package/packages/pi-agent-core/dist/harness/agent-harness.d.ts.map +1 -1
- package/packages/pi-agent-core/dist/harness/agent-harness.js +3 -1
- package/packages/pi-agent-core/dist/harness/agent-harness.js.map +1 -1
- package/packages/pi-agent-core/dist/harness/types.d.ts +1 -0
- package/packages/pi-agent-core/dist/harness/types.d.ts.map +1 -1
- package/packages/pi-agent-core/dist/harness/types.js.map +1 -1
- package/packages/pi-agent-core/dist/types.d.ts +6 -1
- package/packages/pi-agent-core/dist/types.d.ts.map +1 -1
- package/packages/pi-agent-core/dist/types.js.map +1 -1
- package/packages/pi-agent-core/package.json +1 -1
- package/packages/pi-ai/dist/api-registry.d.ts +2 -0
- package/packages/pi-ai/dist/api-registry.d.ts.map +1 -1
- package/packages/pi-ai/dist/api-registry.js +23 -0
- package/packages/pi-ai/dist/api-registry.js.map +1 -1
- package/packages/pi-ai/dist/image-models.generated.d.ts +15 -0
- package/packages/pi-ai/dist/image-models.generated.d.ts.map +1 -1
- package/packages/pi-ai/dist/image-models.generated.js +15 -0
- package/packages/pi-ai/dist/image-models.generated.js.map +1 -1
- package/packages/pi-ai/dist/models.generated.d.ts +411 -39
- package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
- package/packages/pi-ai/dist/models.generated.js +504 -153
- package/packages/pi-ai/dist/models.generated.js.map +1 -1
- package/packages/pi-ai/dist/stream.js +6 -6
- package/packages/pi-ai/dist/stream.js.map +1 -1
- package/packages/pi-ai/package.json +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/extension-upstream-types.d.ts +3 -0
- package/packages/pi-coding-agent/dist/core/extensions/extension-upstream-types.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/extension-upstream-types.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-registry.js +2 -2
- package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +3 -0
- package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.js +11 -0
- package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/bash.js +2 -2
- package/packages/pi-coding-agent/dist/core/tools/bash.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/edit.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/edit.js +3 -2
- package/packages/pi-coding-agent/dist/core/tools/edit.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/render-utils.d.ts +1 -0
- package/packages/pi-coding-agent/dist/core/tools/render-utils.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/render-utils.js +6 -0
- package/packages/pi-coding-agent/dist/core/tools/render-utils.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/write.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/write.js +3 -2
- package/packages/pi-coding-agent/dist/core/tools/write.js.map +1 -1
- package/packages/pi-coding-agent/package.json +7 -7
- package/packages/pi-tui/dist/terminal.d.ts +1 -0
- package/packages/pi-tui/dist/terminal.d.ts.map +1 -1
- package/packages/pi-tui/dist/terminal.js +8 -4
- package/packages/pi-tui/dist/terminal.js.map +1 -1
- package/packages/pi-tui/package.json +1 -1
- package/packages/rpc-client/package.json +2 -2
- package/pkg/package.json +1 -1
- package/src/resources/extensions/browser-tools/engine/managed-gsd-browser.ts +579 -0
- package/src/resources/extensions/browser-tools/engine/selection.ts +19 -0
- package/src/resources/extensions/browser-tools/extension-manifest.json +2 -2
- package/src/resources/extensions/browser-tools/index.ts +60 -9
- package/src/resources/extensions/browser-tools/package.json +5 -1
- package/src/resources/extensions/browser-tools/tests/browser-engine-selection.test.mjs +35 -0
- package/src/resources/extensions/browser-tools/tests/managed-gsd-browser-tools.test.mjs +33 -0
- package/src/resources/extensions/claude-code-cli/stream-adapter.ts +196 -16
- package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +239 -63
- package/src/resources/extensions/gsd/auto/orchestrator.ts +0 -1
- package/src/resources/extensions/gsd/auto/phases.ts +5 -3
- package/src/resources/extensions/gsd/auto-dashboard.ts +98 -18
- package/src/resources/extensions/gsd/auto-dispatch.ts +67 -0
- package/src/resources/extensions/gsd/auto-post-unit.ts +166 -9
- package/src/resources/extensions/gsd/auto-prompts.ts +106 -15
- package/src/resources/extensions/gsd/auto-recovery.ts +7 -7
- package/src/resources/extensions/gsd/auto-runtime-state.ts +4 -0
- package/src/resources/extensions/gsd/auto-start.ts +112 -17
- package/src/resources/extensions/gsd/auto-tool-tracking.ts +1 -1
- package/src/resources/extensions/gsd/auto-unit-tool-scope.ts +43 -73
- package/src/resources/extensions/gsd/auto-worktree.ts +23 -5
- package/src/resources/extensions/gsd/auto.ts +47 -5
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +96 -4
- package/src/resources/extensions/gsd/bootstrap/exec-tools.ts +51 -0
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +81 -25
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +70 -63
- package/src/resources/extensions/gsd/browser-evidence.ts +26 -2
- package/src/resources/extensions/gsd/closeout-consistency-gate.ts +137 -0
- package/src/resources/extensions/gsd/commands/catalog.ts +6 -1
- package/src/resources/extensions/gsd/commands/handlers/core.ts +6 -2
- package/src/resources/extensions/gsd/commands/handlers/ops.ts +9 -5
- package/src/resources/extensions/gsd/commands-handlers.ts +76 -11
- package/src/resources/extensions/gsd/commands-maintenance.ts +197 -2
- package/src/resources/extensions/gsd/commands-mcp-status.ts +136 -58
- package/src/resources/extensions/gsd/commands-prefs-wizard.ts +4 -1
- package/src/resources/extensions/gsd/commands-verdict.ts +1 -1
- package/src/resources/extensions/gsd/config-overlay.ts +3 -1
- package/src/resources/extensions/gsd/dashboard-overlay.ts +28 -7
- package/src/resources/extensions/gsd/docs/preferences-reference.md +8 -0
- package/src/resources/extensions/gsd/doctor-runtime-checks.ts +2 -2
- package/src/resources/extensions/gsd/error-classifier.ts +2 -1
- package/src/resources/extensions/gsd/escalation.ts +4 -4
- package/src/resources/extensions/gsd/exec-sandbox.ts +4 -0
- package/src/resources/extensions/gsd/forensics.ts +99 -5
- package/src/resources/extensions/gsd/gsd-db.ts +46 -8
- package/src/resources/extensions/gsd/guided-flow.ts +215 -217
- package/src/resources/extensions/gsd/mcp-filter.ts +3 -0
- package/src/resources/extensions/gsd/mcp-project-config.ts +105 -88
- package/src/resources/extensions/gsd/memory-store.ts +4 -1
- package/src/resources/extensions/gsd/migration-auto-check.ts +2 -2
- package/src/resources/extensions/gsd/milestone-closeout.ts +3 -1
- package/src/resources/extensions/gsd/pending-auto-start.ts +0 -2
- package/src/resources/extensions/gsd/post-unit-hooks.ts +14 -1
- package/src/resources/extensions/gsd/preferences-types.ts +1 -1
- package/src/resources/extensions/gsd/preferences-validation.ts +36 -0
- package/src/resources/extensions/gsd/prompt-loader.ts +8 -0
- package/src/resources/extensions/gsd/prompts/forensics.md +61 -1
- package/src/resources/extensions/gsd/prompts/gate-evaluate.md +3 -1
- package/src/resources/extensions/gsd/prompts/parallel-research-slices.md +3 -1
- package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/reactive-execute.md +3 -1
- package/src/resources/extensions/gsd/prompts/run-uat.md +33 -23
- package/src/resources/extensions/gsd/prompts/system.md +3 -1
- package/src/resources/extensions/gsd/prompts/validate-milestone.md +3 -3
- package/src/resources/extensions/gsd/recovery-classification.ts +20 -0
- package/src/resources/extensions/gsd/rule-registry.ts +558 -58
- package/src/resources/extensions/gsd/rule-types.ts +2 -0
- package/src/resources/extensions/gsd/safety/destructive-guard.ts +3 -0
- package/src/resources/extensions/gsd/skill-activation.ts +20 -2
- package/src/resources/extensions/gsd/state-reconciliation/drift/artifact-db.ts +4 -2
- package/src/resources/extensions/gsd/state-reconciliation/drift/project-md.ts +1 -1
- package/src/resources/extensions/gsd/state-reconciliation/drift/roadmap.ts +20 -0
- package/src/resources/extensions/gsd/state-reconciliation/index.ts +6 -0
- package/src/resources/extensions/gsd/state-reconciliation/types.ts +1 -0
- package/src/resources/extensions/gsd/state.ts +18 -14
- package/src/resources/extensions/gsd/templates/plan.md +3 -1
- package/src/resources/extensions/gsd/tests/auto-dashboard.test.ts +156 -4
- package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +123 -0
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +10 -2
- package/src/resources/extensions/gsd/tests/auto-start-bootstrap-await-3420.test.ts +4 -1
- package/src/resources/extensions/gsd/tests/auto-start-orphan-bootstrap.test.ts +143 -2
- package/src/resources/extensions/gsd/tests/auto-start-project-milestone-reconcile.test.ts +24 -2
- package/src/resources/extensions/gsd/tests/auto-warning-noise-regression.test.ts +12 -2
- package/src/resources/extensions/gsd/tests/browser-evidence.test.ts +142 -0
- package/src/resources/extensions/gsd/tests/check-auto-start-pending-gate.test.ts +9 -15
- package/src/resources/extensions/gsd/tests/check-auto-start-ready-guard.test.ts +26 -16
- package/src/resources/extensions/gsd/tests/commands-dispatcher-unmerged-milestone.test.ts +21 -0
- package/src/resources/extensions/gsd/tests/commands-dispatcher-validation-block.test.ts +38 -3
- package/src/resources/extensions/gsd/tests/commands-verdict.test.ts +6 -2
- package/src/resources/extensions/gsd/tests/complete-milestone-excerpt.test.ts +30 -0
- package/src/resources/extensions/gsd/tests/complete-slice-verification-gate.test.ts +42 -0
- package/src/resources/extensions/gsd/tests/dashboard-overlay.test.ts +45 -0
- package/src/resources/extensions/gsd/tests/deep-planning-mode-dispatch.test.ts +53 -0
- package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +8 -0
- package/src/resources/extensions/gsd/tests/derive-state-helpers.test.ts +50 -13
- package/src/resources/extensions/gsd/tests/discuss-milestone-structured-questions.test.ts +31 -0
- package/src/resources/extensions/gsd/tests/dispatch-complete-milestone-guard.test.ts +40 -1
- package/src/resources/extensions/gsd/tests/dispatch-missing-task-plans.test.ts +60 -0
- package/src/resources/extensions/gsd/tests/doctor-runtime-checks.test.ts +27 -0
- package/src/resources/extensions/gsd/tests/escalation.test.ts +16 -27
- package/src/resources/extensions/gsd/tests/exec-sandbox.test.ts +18 -0
- package/src/resources/extensions/gsd/tests/exec-tool.test.ts +69 -0
- package/src/resources/extensions/gsd/tests/forensics-issue-routing.test.ts +20 -0
- package/src/resources/extensions/gsd/tests/forensics-prompt-rendering.test.ts +3 -0
- package/src/resources/extensions/gsd/tests/forensics-tool-scope.test.ts +69 -0
- package/src/resources/extensions/gsd/tests/gate-1b-orphan-discrimination.test.ts +31 -79
- package/src/resources/extensions/gsd/tests/gsd-rebuild.test.ts +199 -0
- package/src/resources/extensions/gsd/tests/gsd-recover.test.ts +75 -0
- package/src/resources/extensions/gsd/tests/guided-discuss-milestone-prompt-rendering.test.ts +40 -1
- package/src/resources/extensions/gsd/tests/guided-dispatch-root.test.ts +86 -0
- package/src/resources/extensions/gsd/tests/guided-flow-session-isolation.test.ts +5 -3
- package/src/resources/extensions/gsd/tests/guided-flow-state-rebuild.test.ts +40 -4
- package/src/resources/extensions/gsd/tests/guided-flow.test.ts +12 -9
- package/src/resources/extensions/gsd/tests/integration/auto-recovery.test.ts +4 -4
- package/src/resources/extensions/gsd/tests/integration/auto-worktree-milestone-merge.test.ts +8 -0
- package/src/resources/extensions/gsd/tests/integration/parallel-merge.test.ts +16 -0
- package/src/resources/extensions/gsd/tests/integration/run-uat.test.ts +72 -10
- package/src/resources/extensions/gsd/tests/integration/state-machine-live-validation.test.ts +13 -6
- package/src/resources/extensions/gsd/tests/mcp-filter.test.ts +15 -0
- package/src/resources/extensions/gsd/tests/mcp-project-config.test.ts +100 -0
- package/src/resources/extensions/gsd/tests/mcp-status.test.ts +179 -0
- package/src/resources/extensions/gsd/tests/memory-maintenance.test.ts +39 -8
- package/src/resources/extensions/gsd/tests/merge-closeout-consistency-gate.test.ts +63 -0
- package/src/resources/extensions/gsd/tests/merge-db-cycle.test.ts +10 -1
- package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +3 -3
- package/src/resources/extensions/gsd/tests/milestone-closeout.test.ts +9 -1
- package/src/resources/extensions/gsd/tests/new-milestone-discuss-routing.test.ts +3 -3
- package/src/resources/extensions/gsd/tests/parallel-skill-prompt-integration.test.ts +54 -7
- package/src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +9 -0
- package/src/resources/extensions/gsd/tests/plan-slice.test.ts +39 -1
- package/src/resources/extensions/gsd/tests/post-unit-hooks.test.ts +157 -0
- package/src/resources/extensions/gsd/tests/post-unit-retry-on-orchestrator-bridge.test.ts +179 -0
- package/src/resources/extensions/gsd/tests/preferences.test.ts +29 -0
- package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +83 -1
- package/src/resources/extensions/gsd/tests/prompt-loader-extension-dir.test.ts +14 -0
- package/src/resources/extensions/gsd/tests/provider-errors.test.ts +18 -1
- package/src/resources/extensions/gsd/tests/queued-discuss-fast-path.test.ts +7 -8
- package/src/resources/extensions/gsd/tests/reactive-executor.test.ts +36 -0
- package/src/resources/extensions/gsd/tests/register-hooks-depth-verification.test.ts +79 -0
- package/src/resources/extensions/gsd/tests/restore-tools-after-discuss.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/rule-registry.test.ts +75 -0
- package/src/resources/extensions/gsd/tests/run-uat-composer.test.ts +4 -0
- package/src/resources/extensions/gsd/tests/runtime-invariant-modules.test.ts +36 -0
- package/src/resources/extensions/gsd/tests/session-start-footer.test.ts +100 -0
- package/src/resources/extensions/gsd/tests/skill-activation.test.ts +55 -0
- package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +6 -2
- package/src/resources/extensions/gsd/tests/state-reconciliation-drift.test.ts +191 -0
- package/src/resources/extensions/gsd/tests/token-tool-gating.test.ts +84 -10
- package/src/resources/extensions/gsd/tests/tool-invocation-error-loop-break.test.ts +19 -0
- package/src/resources/extensions/gsd/tests/tool-naming.test.ts +12 -2
- package/src/resources/extensions/gsd/tests/tool-param-optionality.test.ts +7 -1
- package/src/resources/extensions/gsd/tests/tui-header-lifecycle.test.ts +29 -6
- package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +29 -6
- package/src/resources/extensions/gsd/tests/validate-milestone-prompt-verification-classes.test.ts +6 -3
- package/src/resources/extensions/gsd/tests/validate-milestone-write-order.test.ts +133 -0
- package/src/resources/extensions/gsd/tests/validation-block-guard.test.ts +21 -0
- package/src/resources/extensions/gsd/tests/verification-gate.test.ts +51 -0
- package/src/resources/extensions/gsd/tests/workflow-mcp-auto-prep.test.ts +17 -2
- package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +493 -0
- package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +40 -0
- package/src/resources/extensions/gsd/tool-contract.ts +6 -0
- package/src/resources/extensions/gsd/tool-presentation-plan.ts +223 -0
- package/src/resources/extensions/gsd/tools/complete-slice.ts +14 -1
- package/src/resources/extensions/gsd/tools/complete-task.ts +20 -2
- package/src/resources/extensions/gsd/tools/exec-tool.ts +130 -0
- package/src/resources/extensions/gsd/tools/plan-slice.ts +14 -9
- package/src/resources/extensions/gsd/tools/reopen-milestone.ts +2 -2
- package/src/resources/extensions/gsd/tools/validate-milestone.ts +46 -15
- package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +589 -8
- package/src/resources/extensions/gsd/types.ts +69 -5
- package/src/resources/extensions/gsd/unit-context-manifest.ts +14 -5
- package/src/resources/extensions/gsd/unit-tool-contracts.ts +186 -0
- package/src/resources/extensions/gsd/validation-block-guard.ts +2 -0
- package/src/resources/extensions/gsd/verdict-parser.ts +54 -13
- package/src/resources/extensions/gsd/verification-gate.ts +87 -1
- package/src/resources/extensions/gsd/workflow-mcp-auto-prep.ts +2 -1
- package/src/resources/extensions/gsd/workflow-mcp.ts +5 -73
- package/src/resources/extensions/gsd/worktree-lifecycle.ts +26 -0
- package/src/resources/extensions/mcp-client/manager.ts +33 -1
- package/src/resources/extensions/mcp-client/tests/manager.test.ts +35 -0
- package/src/resources/extensions/shared/gsd-browser-cli.ts +172 -0
- package/src/resources/extensions/gsd/tests/gate-1b-recovery-bound-corrections.test.ts +0 -246
- package/src/resources/extensions/gsd/tests/gate-1b-recovery-bound.test.ts +0 -218
- /package/dist/web/standalone/.next/static/{L9N5SPFi7f-Ne4u2uXzCe → h4TGni4xJzlZjGkxaT6uU}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{L9N5SPFi7f-Ne4u2uXzCe → h4TGni4xJzlZjGkxaT6uU}/_ssgManifest.js +0 -0
|
@@ -19,6 +19,14 @@ test("shouldAutoPrepareWorkflowMcp enables prep for externalCli local transport"
|
|
|
19
19
|
assert.equal(result, true);
|
|
20
20
|
});
|
|
21
21
|
|
|
22
|
+
test("shouldAutoPrepareWorkflowMcp enables prep when Claude Code provider is known before auth mode settles", () => {
|
|
23
|
+
const result = shouldAutoPrepareWorkflowMcp({
|
|
24
|
+
model: { provider: "claude-code", baseUrl: "local://claude-code" },
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
assert.equal(result, true);
|
|
28
|
+
});
|
|
29
|
+
|
|
22
30
|
test("prepareWorkflowMcpForProject uses the selected unit model when session provider differs", (t) => {
|
|
23
31
|
const projectRoot = mkdtempSync(join(tmpdir(), "gsd-mcp-unit-model-"));
|
|
24
32
|
const notifications: Array<{ message: string; level: "info" | "warning" | "error" | "success" }> = [];
|
|
@@ -46,7 +54,7 @@ test("prepareWorkflowMcpForProject uses the selected unit model when session pro
|
|
|
46
54
|
|
|
47
55
|
assert.equal(result?.status, "created");
|
|
48
56
|
assert.equal(existsSync(join(projectRoot, ".mcp.json")), true);
|
|
49
|
-
assert.match(notifications.map((entry) => entry.message).join("\n"), /
|
|
57
|
+
assert.match(notifications.map((entry) => entry.message).join("\n"), /GSD MCP Server Prepared/);
|
|
50
58
|
});
|
|
51
59
|
|
|
52
60
|
test("shouldAutoPrepareWorkflowMcp stays disabled for non-Claude active provider even when claude-code is ready", () => {
|
|
@@ -163,7 +171,14 @@ test("before_agent_start auto-prepares project workflow MCP for Claude Code CLI"
|
|
|
163
171
|
};
|
|
164
172
|
assert.ok(parsed.mcpServers?.[GSD_WORKFLOW_MCP_SERVER_NAME]);
|
|
165
173
|
assert.ok(parsed.mcpServers?.[GSD_BROWSER_MCP_SERVER_NAME]);
|
|
166
|
-
|
|
174
|
+
const settings = JSON.parse(readFileSync(join(projectRoot, ".claude", "settings.local.json"), "utf-8")) as {
|
|
175
|
+
enabledMcpjsonServers?: string[];
|
|
176
|
+
};
|
|
177
|
+
assert.deepEqual(settings.enabledMcpjsonServers, [
|
|
178
|
+
GSD_WORKFLOW_MCP_SERVER_NAME,
|
|
179
|
+
GSD_BROWSER_MCP_SERVER_NAME,
|
|
180
|
+
]);
|
|
181
|
+
assert.match(notifications.join("\n"), /GSD MCP Server Prepared/);
|
|
167
182
|
});
|
|
168
183
|
|
|
169
184
|
test("before_agent_start returns discovered skill fallback without project .gsd", async (t) => {
|
|
@@ -30,6 +30,7 @@ import {
|
|
|
30
30
|
executeSliceComplete,
|
|
31
31
|
executeSliceReopen,
|
|
32
32
|
executeValidateMilestone,
|
|
33
|
+
executeUatResultSave,
|
|
33
34
|
} from "../tools/workflow-tool-executors.ts";
|
|
34
35
|
|
|
35
36
|
function makeTmpBase(): string {
|
|
@@ -74,6 +75,11 @@ test("closeout executors reject phase escalation from the wrong active auto unit
|
|
|
74
75
|
const milestone = await executeCompleteMilestone({} as Parameters<typeof executeCompleteMilestone>[0], "/tmp/project");
|
|
75
76
|
assert.equal(milestone.isError, true);
|
|
76
77
|
assert.match(String(milestone.details.error), /complete_milestone may only run from complete-milestone/);
|
|
78
|
+
|
|
79
|
+
const uat = await executeUatResultSave({} as Parameters<typeof executeUatResultSave>[0], "/tmp/project");
|
|
80
|
+
assert.equal(uat.isError, true);
|
|
81
|
+
assert.match(String(uat.details.error), /save_uat_result may only run from run-uat/);
|
|
82
|
+
assert.match(String(uat.details.error), /Tool Contract failure/);
|
|
77
83
|
} finally {
|
|
78
84
|
autoSession.reset();
|
|
79
85
|
}
|
|
@@ -234,6 +240,62 @@ test("executeTaskComplete derives missing verification from evidence", async ()
|
|
|
234
240
|
}
|
|
235
241
|
});
|
|
236
242
|
|
|
243
|
+
test("executeTaskComplete surfaces escalation questions and metadata", async () => {
|
|
244
|
+
const base = makeTmpBase();
|
|
245
|
+
try {
|
|
246
|
+
openTestDb(base);
|
|
247
|
+
writeFileSync(join(base, ".gsd", "PREFERENCES.md"), [
|
|
248
|
+
"---",
|
|
249
|
+
"version: 1",
|
|
250
|
+
"phases:",
|
|
251
|
+
" mid_execution_escalation: true",
|
|
252
|
+
"---",
|
|
253
|
+
].join("\n"));
|
|
254
|
+
const planDir = join(base, ".gsd", "milestones", "M001", "slices", "S01");
|
|
255
|
+
mkdirSync(planDir, { recursive: true });
|
|
256
|
+
writeFileSync(join(planDir, "S01-PLAN.md"), "# S01\n\n- [ ] **T01: Demo** `est:5m`\n");
|
|
257
|
+
|
|
258
|
+
const result = await inProjectDir(base, () => executeTaskComplete({
|
|
259
|
+
milestoneId: "M001",
|
|
260
|
+
sliceId: "S01",
|
|
261
|
+
taskId: "T01",
|
|
262
|
+
oneLiner: "Completed task",
|
|
263
|
+
narrative: "Did the work but found an ambiguity.",
|
|
264
|
+
verification: "npm test",
|
|
265
|
+
escalation: {
|
|
266
|
+
question: "Should the cache use write-through or write-back?",
|
|
267
|
+
options: [
|
|
268
|
+
{ id: "A", label: "Write-through", tradeoffs: "Simpler reads; slower writes." },
|
|
269
|
+
{ id: "B", label: "Write-back", tradeoffs: "Faster writes; more flush complexity." },
|
|
270
|
+
],
|
|
271
|
+
recommendation: "A",
|
|
272
|
+
recommendationRationale: "Current usage favors correctness over write latency.",
|
|
273
|
+
continueWithDefault: true,
|
|
274
|
+
},
|
|
275
|
+
}, base));
|
|
276
|
+
|
|
277
|
+
assert.equal(result.details.operation, "complete_task");
|
|
278
|
+
assert.match(
|
|
279
|
+
String(result.content[0]?.text),
|
|
280
|
+
/Task completed with escalation decision required: Should the cache use write-through or write-back\?/,
|
|
281
|
+
);
|
|
282
|
+
assert.match(String(result.content[0]?.text), /Resolve with: \/gsd escalate resolve T01/);
|
|
283
|
+
assert.equal((result.details.escalation as { question?: string }).question, "Should the cache use write-through or write-back?");
|
|
284
|
+
|
|
285
|
+
const db = _getAdapter();
|
|
286
|
+
assert.ok(db, "DB should be open");
|
|
287
|
+
const row = db!.prepare(
|
|
288
|
+
"SELECT escalation_pending, escalation_awaiting_review, escalation_artifact_path FROM tasks WHERE milestone_id = ? AND slice_id = ? AND id = ?",
|
|
289
|
+
).get("M001", "S01", "T01") as Record<string, unknown> | undefined;
|
|
290
|
+
assert.equal(row?.escalation_pending, 0);
|
|
291
|
+
assert.equal(row?.escalation_awaiting_review, 1);
|
|
292
|
+
assert.ok(String(row?.escalation_artifact_path ?? "").endsWith("T01-ESCALATION.json"));
|
|
293
|
+
} finally {
|
|
294
|
+
closeDatabase();
|
|
295
|
+
cleanup(base);
|
|
296
|
+
}
|
|
297
|
+
});
|
|
298
|
+
|
|
237
299
|
test("executeTaskComplete returns a tool error when verification cannot be derived", async () => {
|
|
238
300
|
const base = makeTmpBase();
|
|
239
301
|
try {
|
|
@@ -504,6 +566,425 @@ test("executePlanSlice marks validation failures with isError", async () => {
|
|
|
504
566
|
}
|
|
505
567
|
});
|
|
506
568
|
|
|
569
|
+
test("executeUatResultSave accepts gsd_uat_exec evidence written in a milestone worktree", async () => {
|
|
570
|
+
const base = makeTmpBase();
|
|
571
|
+
const worktree = join(base, ".gsd", "worktrees", "M001");
|
|
572
|
+
const worktreeExecDir = join(worktree, ".gsd", "exec");
|
|
573
|
+
const browserTimelineDir = join(base, ".artifacts", "browser", "session");
|
|
574
|
+
const evidenceId = "worktree-uat-evidence";
|
|
575
|
+
const browserTimelinePath = join(browserTimelineDir, "s02-uat-browser-timeline.json");
|
|
576
|
+
try {
|
|
577
|
+
openTestDb(base);
|
|
578
|
+
seedMilestone("M001", "Milestone One");
|
|
579
|
+
seedSlice("M001", "S02", "complete");
|
|
580
|
+
mkdirSync(worktreeExecDir, { recursive: true });
|
|
581
|
+
mkdirSync(browserTimelineDir, { recursive: true });
|
|
582
|
+
writeFileSync(browserTimelinePath, JSON.stringify({ summary: "browser timeline evidence" }), "utf-8");
|
|
583
|
+
writeFileSync(
|
|
584
|
+
join(worktreeExecDir, `${evidenceId}.meta.json`),
|
|
585
|
+
JSON.stringify({
|
|
586
|
+
id: evidenceId,
|
|
587
|
+
metadata: {
|
|
588
|
+
kind: "uat_exec",
|
|
589
|
+
milestoneId: "M001",
|
|
590
|
+
sliceId: "S02",
|
|
591
|
+
checkId: "UAT-01",
|
|
592
|
+
intent: "uat-runtime-check",
|
|
593
|
+
},
|
|
594
|
+
}),
|
|
595
|
+
"utf-8",
|
|
596
|
+
);
|
|
597
|
+
|
|
598
|
+
const result = await inProjectDir(worktree, () => executeUatResultSave({
|
|
599
|
+
milestoneId: "M001",
|
|
600
|
+
sliceId: "S02",
|
|
601
|
+
uatType: "runtime-executable",
|
|
602
|
+
verdict: "PASS",
|
|
603
|
+
checks: [{
|
|
604
|
+
id: "UAT-01",
|
|
605
|
+
description: "Runtime path C:\\tmp|uat evidence was captured in the active worktree",
|
|
606
|
+
mode: "runtime",
|
|
607
|
+
result: "PASS",
|
|
608
|
+
evidence: [
|
|
609
|
+
{ kind: "gsd_uat_exec", ref: evidenceId },
|
|
610
|
+
{ kind: "browser", ref: browserTimelinePath },
|
|
611
|
+
],
|
|
612
|
+
notes: "Worktree-local gsd_uat_exec metadata should resolve with backslash \\ and pipe |.",
|
|
613
|
+
}],
|
|
614
|
+
presentation: {
|
|
615
|
+
surface: "mcp",
|
|
616
|
+
presentedTools: [
|
|
617
|
+
"gsd_uat_exec",
|
|
618
|
+
"gsd_uat_result_save",
|
|
619
|
+
"gsd_resume",
|
|
620
|
+
"gsd_milestone_status",
|
|
621
|
+
"gsd_journal_query",
|
|
622
|
+
],
|
|
623
|
+
blockedTools: [
|
|
624
|
+
{ name: "gsd_exec", reason: "forbidden during run-uat" },
|
|
625
|
+
{ name: "gsd_summary_save", reason: "forbidden during run-uat" },
|
|
626
|
+
{ name: "gsd_save_gate_result", reason: "forbidden during run-uat" },
|
|
627
|
+
],
|
|
628
|
+
},
|
|
629
|
+
notes: "UAT passed with worktree-local evidence.",
|
|
630
|
+
}, worktree));
|
|
631
|
+
|
|
632
|
+
assert.equal(result.isError, undefined);
|
|
633
|
+
assert.equal(result.details.operation, "save_uat_result");
|
|
634
|
+
assert.equal(result.details.verdict, "PASS");
|
|
635
|
+
assert.ok(
|
|
636
|
+
existsSync(join(base, ".gsd", "uat", "M001", "S02", "attempt-1.json")),
|
|
637
|
+
"attempt JSON should be persisted under the authoritative project .gsd",
|
|
638
|
+
);
|
|
639
|
+
const assessment = readFileSync(
|
|
640
|
+
join(base, ".gsd", "milestones", "M001", "slices", "S02", "S02-ASSESSMENT.md"),
|
|
641
|
+
"utf-8",
|
|
642
|
+
);
|
|
643
|
+
assert.match(assessment, /Runtime path C:\\\\tmp\\\|uat evidence/);
|
|
644
|
+
assert.match(assessment, /backslash \\\\ and pipe \\\|/);
|
|
645
|
+
} finally {
|
|
646
|
+
closeDatabase();
|
|
647
|
+
cleanup(base);
|
|
648
|
+
}
|
|
649
|
+
});
|
|
650
|
+
|
|
651
|
+
test("executeUatResultSave supplies canonical presentation and normalizes verdict casing", async () => {
|
|
652
|
+
const base = makeTmpBase();
|
|
653
|
+
const worktree = join(base, ".gsd", "worktrees", "M001");
|
|
654
|
+
const worktreeExecDir = join(worktree, ".gsd", "exec");
|
|
655
|
+
const evidenceId = "uat-lowercase-verdict";
|
|
656
|
+
try {
|
|
657
|
+
openTestDb(base);
|
|
658
|
+
seedMilestone("M001", "Milestone One");
|
|
659
|
+
seedSlice("M001", "S03", "complete");
|
|
660
|
+
mkdirSync(worktreeExecDir, { recursive: true });
|
|
661
|
+
writeFileSync(
|
|
662
|
+
join(worktreeExecDir, `${evidenceId}.meta.json`),
|
|
663
|
+
JSON.stringify({
|
|
664
|
+
id: evidenceId,
|
|
665
|
+
metadata: {
|
|
666
|
+
kind: "uat_exec",
|
|
667
|
+
milestoneId: "M001",
|
|
668
|
+
sliceId: "S03",
|
|
669
|
+
checkId: "UAT-01",
|
|
670
|
+
intent: "uat-artifact-check",
|
|
671
|
+
},
|
|
672
|
+
}),
|
|
673
|
+
"utf-8",
|
|
674
|
+
);
|
|
675
|
+
|
|
676
|
+
const result = await inProjectDir(worktree, () => executeUatResultSave({
|
|
677
|
+
milestoneId: "M001",
|
|
678
|
+
sliceId: "S03",
|
|
679
|
+
uatType: "artifact-driven",
|
|
680
|
+
verdict: "pass",
|
|
681
|
+
checks: [{
|
|
682
|
+
id: "UAT-01",
|
|
683
|
+
description: "Static artifact contract passes",
|
|
684
|
+
mode: "artifact",
|
|
685
|
+
result: "PASS",
|
|
686
|
+
evidence: [{ kind: "gsd_uat_exec", ref: evidenceId }],
|
|
687
|
+
notes: "Artifact check passed.",
|
|
688
|
+
}],
|
|
689
|
+
notes: "UAT passed with canonical presentation supplied by the executor.",
|
|
690
|
+
} as unknown as Parameters<typeof executeUatResultSave>[0], worktree));
|
|
691
|
+
|
|
692
|
+
assert.equal(result.isError, undefined);
|
|
693
|
+
assert.equal(result.details.verdict, "PASS");
|
|
694
|
+
|
|
695
|
+
const attempt = JSON.parse(readFileSync(
|
|
696
|
+
join(base, ".gsd", "uat", "M001", "S03", "attempt-1.json"),
|
|
697
|
+
"utf-8",
|
|
698
|
+
)) as { presentation?: { toolPresentationPlanId?: string; presentedTools?: string[] } };
|
|
699
|
+
assert.equal(attempt.presentation?.toolPresentationPlanId, "run-uat/default-v1");
|
|
700
|
+
assert.ok(attempt.presentation?.presentedTools?.includes("gsd_uat_result_save"));
|
|
701
|
+
assert.ok(attempt.presentation?.presentedTools?.includes("read"));
|
|
702
|
+
} finally {
|
|
703
|
+
closeDatabase();
|
|
704
|
+
cleanup(base);
|
|
705
|
+
}
|
|
706
|
+
});
|
|
707
|
+
|
|
708
|
+
test("executeUatResultSave supplies direct browser tools for browser-executable UAT", async () => {
|
|
709
|
+
const base = makeTmpBase();
|
|
710
|
+
const worktree = join(base, ".gsd", "worktrees", "M001");
|
|
711
|
+
const worktreeExecDir = join(worktree, ".gsd", "exec");
|
|
712
|
+
const evidenceId = "uat-direct-browser-evidence";
|
|
713
|
+
try {
|
|
714
|
+
openTestDb(base);
|
|
715
|
+
seedMilestone("M001", "Milestone One");
|
|
716
|
+
seedSlice("M001", "S06", "complete");
|
|
717
|
+
mkdirSync(worktreeExecDir, { recursive: true });
|
|
718
|
+
writeFileSync(
|
|
719
|
+
join(worktreeExecDir, `${evidenceId}.meta.json`),
|
|
720
|
+
JSON.stringify({
|
|
721
|
+
id: evidenceId,
|
|
722
|
+
metadata: {
|
|
723
|
+
kind: "uat_exec",
|
|
724
|
+
milestoneId: "M001",
|
|
725
|
+
sliceId: "S06",
|
|
726
|
+
checkId: "UAT-01",
|
|
727
|
+
intent: "uat-browser-check",
|
|
728
|
+
},
|
|
729
|
+
}),
|
|
730
|
+
"utf-8",
|
|
731
|
+
);
|
|
732
|
+
|
|
733
|
+
const result = await inProjectDir(worktree, () => executeUatResultSave({
|
|
734
|
+
milestoneId: "M001",
|
|
735
|
+
sliceId: "S06",
|
|
736
|
+
uatType: "browser-executable",
|
|
737
|
+
verdict: "PASS",
|
|
738
|
+
checks: [{
|
|
739
|
+
id: "UAT-01",
|
|
740
|
+
description: "Browser flow used managed gsd-browser tools",
|
|
741
|
+
mode: "browser",
|
|
742
|
+
result: "PASS",
|
|
743
|
+
evidence: [{ kind: "gsd_uat_exec", ref: evidenceId }],
|
|
744
|
+
notes: "Browser check passed.",
|
|
745
|
+
}],
|
|
746
|
+
notes: "UAT passed with managed browser evidence.",
|
|
747
|
+
} as unknown as Parameters<typeof executeUatResultSave>[0], worktree));
|
|
748
|
+
|
|
749
|
+
assert.equal(result.isError, undefined);
|
|
750
|
+
const attempt = JSON.parse(readFileSync(
|
|
751
|
+
join(base, ".gsd", "uat", "M001", "S06", "attempt-1.json"),
|
|
752
|
+
"utf-8",
|
|
753
|
+
)) as { presentation?: { presentedTools?: string[] } };
|
|
754
|
+
|
|
755
|
+
assert.ok(attempt.presentation?.presentedTools?.includes("browser_navigate"));
|
|
756
|
+
assert.ok(attempt.presentation?.presentedTools?.includes("browser_assert"));
|
|
757
|
+
assert.equal(
|
|
758
|
+
attempt.presentation?.presentedTools?.some((toolName) => toolName.startsWith("mcp__gsd-browser__")),
|
|
759
|
+
false,
|
|
760
|
+
);
|
|
761
|
+
} finally {
|
|
762
|
+
closeDatabase();
|
|
763
|
+
cleanup(base);
|
|
764
|
+
}
|
|
765
|
+
});
|
|
766
|
+
|
|
767
|
+
test("executeUatResultSave merges canonical plan ID and read-only tools when presentation lacks plan ID", async () => {
|
|
768
|
+
const base = makeTmpBase();
|
|
769
|
+
const worktree = join(base, ".gsd", "worktrees", "M001");
|
|
770
|
+
const worktreeExecDir = join(worktree, ".gsd", "exec");
|
|
771
|
+
const evidenceId = "uat-no-plan-id-evidence";
|
|
772
|
+
try {
|
|
773
|
+
openTestDb(base);
|
|
774
|
+
seedMilestone("M001", "Milestone One");
|
|
775
|
+
seedSlice("M001", "S05", "complete");
|
|
776
|
+
mkdirSync(worktreeExecDir, { recursive: true });
|
|
777
|
+
writeFileSync(
|
|
778
|
+
join(worktreeExecDir, `${evidenceId}.meta.json`),
|
|
779
|
+
JSON.stringify({
|
|
780
|
+
id: evidenceId,
|
|
781
|
+
metadata: {
|
|
782
|
+
kind: "uat_exec",
|
|
783
|
+
milestoneId: "M001",
|
|
784
|
+
sliceId: "S05",
|
|
785
|
+
checkId: "UAT-01",
|
|
786
|
+
intent: "uat-artifact-check",
|
|
787
|
+
},
|
|
788
|
+
}),
|
|
789
|
+
"utf-8",
|
|
790
|
+
);
|
|
791
|
+
|
|
792
|
+
const result = await inProjectDir(worktree, () => executeUatResultSave({
|
|
793
|
+
milestoneId: "M001",
|
|
794
|
+
sliceId: "S05",
|
|
795
|
+
uatType: "artifact-driven",
|
|
796
|
+
verdict: "PASS",
|
|
797
|
+
checks: [{
|
|
798
|
+
id: "UAT-01",
|
|
799
|
+
description: "Presentation plan ID absent from provider call",
|
|
800
|
+
mode: "artifact",
|
|
801
|
+
result: "PASS",
|
|
802
|
+
evidence: [{ kind: "gsd_uat_exec", ref: evidenceId }],
|
|
803
|
+
notes: "Canonical merge should apply even when toolPresentationPlanId is absent.",
|
|
804
|
+
}],
|
|
805
|
+
presentation: {
|
|
806
|
+
surface: "mcp",
|
|
807
|
+
presentedTools: [
|
|
808
|
+
"gsd_uat_exec",
|
|
809
|
+
"gsd_uat_result_save",
|
|
810
|
+
"gsd_resume",
|
|
811
|
+
"gsd_milestone_status",
|
|
812
|
+
"gsd_journal_query",
|
|
813
|
+
],
|
|
814
|
+
blockedTools: [
|
|
815
|
+
{ name: "gsd_exec", reason: "forbidden during run-uat" },
|
|
816
|
+
{ name: "gsd_summary_save", reason: "forbidden during run-uat" },
|
|
817
|
+
{ name: "gsd_save_gate_result", reason: "forbidden during run-uat" },
|
|
818
|
+
],
|
|
819
|
+
},
|
|
820
|
+
notes: "Provider omitted toolPresentationPlanId; executor must canonicalize.",
|
|
821
|
+
} as unknown as Parameters<typeof executeUatResultSave>[0], worktree));
|
|
822
|
+
|
|
823
|
+
assert.equal(result.isError, undefined);
|
|
824
|
+
assert.equal(result.details.verdict, "PASS");
|
|
825
|
+
|
|
826
|
+
const attempt = JSON.parse(readFileSync(
|
|
827
|
+
join(base, ".gsd", "uat", "M001", "S05", "attempt-1.json"),
|
|
828
|
+
"utf-8",
|
|
829
|
+
)) as { presentation?: { toolPresentationPlanId?: string; presentedTools?: string[] } };
|
|
830
|
+
assert.equal(attempt.presentation?.toolPresentationPlanId, "run-uat/default-v1");
|
|
831
|
+
assert.ok(attempt.presentation?.presentedTools?.includes("read"), "read-only tool must be merged in");
|
|
832
|
+
assert.ok(attempt.presentation?.presentedTools?.includes("gsd_uat_result_save"));
|
|
833
|
+
} finally {
|
|
834
|
+
closeDatabase();
|
|
835
|
+
cleanup(base);
|
|
836
|
+
}
|
|
837
|
+
});
|
|
838
|
+
|
|
839
|
+
test("executeUatResultSave rejects saved UAT without fresh UAT-owned evidence", async () => {
|
|
840
|
+
const base = makeTmpBase();
|
|
841
|
+
const worktree = join(base, ".gsd", "worktrees", "M001");
|
|
842
|
+
const worktreeExecDir = join(worktree, ".gsd", "exec");
|
|
843
|
+
const evidenceId = "generic-exec-evidence";
|
|
844
|
+
try {
|
|
845
|
+
openTestDb(base);
|
|
846
|
+
seedMilestone("M001", "Milestone One");
|
|
847
|
+
seedSlice("M001", "S04", "complete");
|
|
848
|
+
mkdirSync(worktreeExecDir, { recursive: true });
|
|
849
|
+
writeFileSync(
|
|
850
|
+
join(worktreeExecDir, `${evidenceId}.meta.json`),
|
|
851
|
+
JSON.stringify({
|
|
852
|
+
id: evidenceId,
|
|
853
|
+
metadata: { kind: "exec" },
|
|
854
|
+
}),
|
|
855
|
+
"utf-8",
|
|
856
|
+
);
|
|
857
|
+
|
|
858
|
+
const result = await inProjectDir(worktree, () => executeUatResultSave({
|
|
859
|
+
milestoneId: "M001",
|
|
860
|
+
sliceId: "S04",
|
|
861
|
+
uatType: "artifact-driven",
|
|
862
|
+
verdict: "PASS",
|
|
863
|
+
checks: [{
|
|
864
|
+
id: "UAT-01",
|
|
865
|
+
description: "Static artifact contract passes",
|
|
866
|
+
mode: "artifact",
|
|
867
|
+
result: "PASS",
|
|
868
|
+
evidence: [{ kind: "gsd_exec", ref: evidenceId }],
|
|
869
|
+
notes: "Generic evidence should not satisfy fresh UAT evidence.",
|
|
870
|
+
}],
|
|
871
|
+
notes: "UAT should not pass without fresh UAT-owned evidence.",
|
|
872
|
+
} as unknown as Parameters<typeof executeUatResultSave>[0], worktree));
|
|
873
|
+
|
|
874
|
+
assert.equal(result.isError, true);
|
|
875
|
+
assert.match(String(result.content[0]?.text), /fresh gsd_uat_exec evidence/);
|
|
876
|
+
} finally {
|
|
877
|
+
closeDatabase();
|
|
878
|
+
cleanup(base);
|
|
879
|
+
}
|
|
880
|
+
});
|
|
881
|
+
|
|
882
|
+
test("executeUatResultSave rejects an unrecognized uatType", async () => {
|
|
883
|
+
const base = makeTmpBase();
|
|
884
|
+
const worktree = join(base, ".gsd", "worktrees", "M001");
|
|
885
|
+
try {
|
|
886
|
+
openTestDb(base);
|
|
887
|
+
mkdirSync(worktree, { recursive: true });
|
|
888
|
+
seedMilestone("M001", "Milestone One");
|
|
889
|
+
seedSlice("M001", "S06", "complete");
|
|
890
|
+
|
|
891
|
+
const result = await inProjectDir(worktree, () => executeUatResultSave({
|
|
892
|
+
milestoneId: "M001",
|
|
893
|
+
sliceId: "S06",
|
|
894
|
+
uatType: "hallucinated-mode",
|
|
895
|
+
verdict: "PASS",
|
|
896
|
+
checks: [{
|
|
897
|
+
id: "UAT-01",
|
|
898
|
+
description: "Static artifact contract passes",
|
|
899
|
+
mode: "artifact",
|
|
900
|
+
result: "PASS",
|
|
901
|
+
evidence: [{ kind: "gsd_uat_exec", ref: "some-ref" }],
|
|
902
|
+
}],
|
|
903
|
+
notes: "Should fail before evidence validation.",
|
|
904
|
+
} as unknown as Parameters<typeof executeUatResultSave>[0], worktree));
|
|
905
|
+
|
|
906
|
+
assert.equal(result.isError, true);
|
|
907
|
+
assert.match(String(result.content[0]?.text), /uatType must be one of/);
|
|
908
|
+
} finally {
|
|
909
|
+
closeDatabase();
|
|
910
|
+
cleanup(base);
|
|
911
|
+
}
|
|
912
|
+
});
|
|
913
|
+
|
|
914
|
+
test("executeUatResultSave rejects artifact-driven PASS with human follow-up checks", async () => {
|
|
915
|
+
const base = makeTmpBase();
|
|
916
|
+
const worktree = join(base, ".gsd", "worktrees", "M001");
|
|
917
|
+
const evidenceId = "uat-artifact-nonautomatable";
|
|
918
|
+
const worktreeExecDir = join(worktree, ".gsd", "exec");
|
|
919
|
+
try {
|
|
920
|
+
openTestDb(base);
|
|
921
|
+
seedMilestone("M001", "Milestone One");
|
|
922
|
+
seedSlice("M001", "S01", "complete");
|
|
923
|
+
mkdirSync(worktreeExecDir, { recursive: true });
|
|
924
|
+
writeFileSync(
|
|
925
|
+
join(worktreeExecDir, `${evidenceId}.meta.json`),
|
|
926
|
+
JSON.stringify({
|
|
927
|
+
id: evidenceId,
|
|
928
|
+
metadata: {
|
|
929
|
+
kind: "uat_exec",
|
|
930
|
+
milestoneId: "M001",
|
|
931
|
+
sliceId: "S01",
|
|
932
|
+
checkId: "UAT-01",
|
|
933
|
+
intent: "uat-artifact-check",
|
|
934
|
+
},
|
|
935
|
+
}),
|
|
936
|
+
"utf-8",
|
|
937
|
+
);
|
|
938
|
+
|
|
939
|
+
const result = await inProjectDir(worktree, () => executeUatResultSave({
|
|
940
|
+
milestoneId: "M001",
|
|
941
|
+
sliceId: "S01",
|
|
942
|
+
uatType: "artifact-driven",
|
|
943
|
+
verdict: "PASS",
|
|
944
|
+
checks: [
|
|
945
|
+
{
|
|
946
|
+
id: "UAT-01",
|
|
947
|
+
description: "Static contract passes",
|
|
948
|
+
mode: "artifact",
|
|
949
|
+
result: "PASS",
|
|
950
|
+
evidence: [{ kind: "gsd_uat_exec", ref: evidenceId }],
|
|
951
|
+
notes: "Artifact check passed.",
|
|
952
|
+
},
|
|
953
|
+
{
|
|
954
|
+
id: "UAT-02",
|
|
955
|
+
description: "Browser polish is deferred to the next slice",
|
|
956
|
+
mode: "human-follow-up",
|
|
957
|
+
result: "NEEDS-HUMAN",
|
|
958
|
+
notes: "Out of scope for this artifact-driven UAT.",
|
|
959
|
+
nonAutomatable: true,
|
|
960
|
+
},
|
|
961
|
+
],
|
|
962
|
+
presentation: {
|
|
963
|
+
surface: "mcp",
|
|
964
|
+
presentedTools: [
|
|
965
|
+
"gsd_uat_exec",
|
|
966
|
+
"gsd_uat_result_save",
|
|
967
|
+
"gsd_resume",
|
|
968
|
+
"gsd_milestone_status",
|
|
969
|
+
"gsd_journal_query",
|
|
970
|
+
],
|
|
971
|
+
blockedTools: [
|
|
972
|
+
{ name: "gsd_exec", reason: "forbidden during run-uat" },
|
|
973
|
+
{ name: "gsd_summary_save", reason: "forbidden during run-uat" },
|
|
974
|
+
{ name: "gsd_save_gate_result", reason: "forbidden during run-uat" },
|
|
975
|
+
],
|
|
976
|
+
},
|
|
977
|
+
notes: "UAT passed; non-automatable browser polish is deferred.",
|
|
978
|
+
}, worktree));
|
|
979
|
+
|
|
980
|
+
assert.equal(result.isError, true);
|
|
981
|
+
assert.match(String(result.content[0]?.text), /artifact-driven UAT cannot PASS with human-only checks/);
|
|
982
|
+
} finally {
|
|
983
|
+
closeDatabase();
|
|
984
|
+
cleanup(base);
|
|
985
|
+
}
|
|
986
|
+
});
|
|
987
|
+
|
|
507
988
|
test("executeSliceComplete coerces string enrichment entries and writes summary/UAT artifacts", async () => {
|
|
508
989
|
const base = makeTmpBase();
|
|
509
990
|
try {
|
|
@@ -1196,6 +1677,10 @@ test("executeSummarySave blocks final root artifacts while approval gate is pend
|
|
|
1196
1677
|
|
|
1197
1678
|
assert.equal(result.isError, true);
|
|
1198
1679
|
assert.equal(result.details.error, "root_artifact_write_blocked");
|
|
1680
|
+
assert.equal(
|
|
1681
|
+
result.details.displayReason,
|
|
1682
|
+
"Approval confirmation required before saving final project setup artifacts.",
|
|
1683
|
+
);
|
|
1199
1684
|
assert.match(result.content[0].text, /has not been confirmed/);
|
|
1200
1685
|
assert.equal(existsSync(join(base, ".gsd", "REQUIREMENTS.md")), false);
|
|
1201
1686
|
|
|
@@ -1238,6 +1723,10 @@ test("executeSummarySave requires verified root approval in deep mode", async ()
|
|
|
1238
1723
|
|
|
1239
1724
|
assert.equal(blocked.isError, true);
|
|
1240
1725
|
assert.equal(blocked.details.error, "root_artifact_write_blocked");
|
|
1726
|
+
assert.equal(
|
|
1727
|
+
blocked.details.displayReason,
|
|
1728
|
+
"Approval confirmation required before saving final project setup artifacts.",
|
|
1729
|
+
);
|
|
1241
1730
|
assert.match(blocked.content[0].text, /fail-closed/);
|
|
1242
1731
|
assert.equal(existsSync(join(base, ".gsd", "PROJECT.md")), false);
|
|
1243
1732
|
|
|
@@ -1454,6 +1943,10 @@ test("executeSummarySave CONTEXT HARD BLOCK clears after write-gate state file i
|
|
|
1454
1943
|
content: "# Context\n\ncontent",
|
|
1455
1944
|
}, base));
|
|
1456
1945
|
assert.equal(blocked.isError, true, "should be blocked without depth verification");
|
|
1946
|
+
assert.equal(
|
|
1947
|
+
blocked.details.displayReason,
|
|
1948
|
+
"Depth check required before writing milestone context.",
|
|
1949
|
+
);
|
|
1457
1950
|
assert.match(
|
|
1458
1951
|
blocked.content[0].text,
|
|
1459
1952
|
/HARD BLOCK/,
|
|
@@ -9,6 +9,7 @@ import test from 'node:test';
|
|
|
9
9
|
import assert from 'node:assert/strict';
|
|
10
10
|
import { join, sep } from 'node:path';
|
|
11
11
|
|
|
12
|
+
import { GSD_PHASE_SCOPE_DISPLAY_REASON } from '../auto-unit-tool-scope.ts';
|
|
12
13
|
import { ALLOWED_PLANNING_DISPATCH_AGENTS, shouldBlockPlanningUnit } from '../bootstrap/write-gate.ts';
|
|
13
14
|
import { extractSubagentAgentClasses } from '../bootstrap/subagent-input.ts';
|
|
14
15
|
import { isDeterministicPolicyError } from '../auto-tool-tracking.ts';
|
|
@@ -27,6 +28,10 @@ const PLANNING_DISPATCH_REVIEW: ToolsPolicy = {
|
|
|
27
28
|
const READ_ONLY: ToolsPolicy = { mode: 'read-only' };
|
|
28
29
|
const ALL: ToolsPolicy = { mode: 'all' };
|
|
29
30
|
const VERIFICATION: ToolsPolicy = { mode: 'verification' };
|
|
31
|
+
const VERIFICATION_UAT: ToolsPolicy = {
|
|
32
|
+
mode: 'verification',
|
|
33
|
+
allowedSubagents: ['mnemo', 'scout', 'reviewer', 'tester'],
|
|
34
|
+
};
|
|
30
35
|
const DOCS: ToolsPolicy = {
|
|
31
36
|
mode: 'docs',
|
|
32
37
|
allowedPathGlobs: ['docs/**', 'README.md', 'README.*.md', 'CHANGELOG.md', '*.md'],
|
|
@@ -61,6 +66,19 @@ test('planning-unit: deterministic block reason is suitable for retry short-circ
|
|
|
61
66
|
assert.strictEqual(isDeterministicPolicyError(r.reason!), true);
|
|
62
67
|
});
|
|
63
68
|
|
|
69
|
+
test('planning-unit: blocked tool-policy calls include UI-safe display reason', () => {
|
|
70
|
+
const r = shouldBlockPlanningUnit(
|
|
71
|
+
'edit',
|
|
72
|
+
'src/main.ts',
|
|
73
|
+
BASE,
|
|
74
|
+
'discuss-milestone',
|
|
75
|
+
PLANNING,
|
|
76
|
+
);
|
|
77
|
+
assert.strictEqual(r.block, true);
|
|
78
|
+
assert.match(r.reason!, /HARD BLOCK/);
|
|
79
|
+
assert.strictEqual(r.displayReason, GSD_PHASE_SCOPE_DISPLAY_REASON);
|
|
80
|
+
});
|
|
81
|
+
|
|
64
82
|
test('planning-unit: blocks write to user source via relative path', () => {
|
|
65
83
|
const r = shouldBlockPlanningUnit('write', 'src/main.ts', BASE, 'plan-milestone', PLANNING);
|
|
66
84
|
assert.strictEqual(r.block, true);
|
|
@@ -363,6 +381,7 @@ test('auto-unit scope: execute-task allows only its task completion lifecycle to
|
|
|
363
381
|
assert.strictEqual(blocked.block, true);
|
|
364
382
|
assert.match(blocked.reason!, /HARD BLOCK/);
|
|
365
383
|
assert.match(blocked.reason!, /gsd_save_gate_result/);
|
|
384
|
+
assert.strictEqual(blocked.displayReason, GSD_PHASE_SCOPE_DISPLAY_REASON);
|
|
366
385
|
assert.strictEqual(isDeterministicPolicyError(blocked.reason!), true);
|
|
367
386
|
});
|
|
368
387
|
|
|
@@ -469,6 +488,27 @@ test('verification-mode: run-uat still blocks subagent dispatch', () => {
|
|
|
469
488
|
assert.match(r.reason!, /subagent dispatch is not permitted/);
|
|
470
489
|
});
|
|
471
490
|
|
|
491
|
+
test('verification-mode: run-uat allows explicit UAT specialist subagents', () => {
|
|
492
|
+
for (const agent of ['mnemo', 'scout', 'reviewer', 'tester']) {
|
|
493
|
+
const r = shouldBlockPlanningUnit('subagent', '', BASE, 'run-uat', VERIFICATION_UAT, [agent]);
|
|
494
|
+
assert.strictEqual(r.block, false, `expected ${agent} to be allowed: ${r.reason}`);
|
|
495
|
+
}
|
|
496
|
+
});
|
|
497
|
+
|
|
498
|
+
test('verification-mode: run-uat blocks implementation-tier subagents', () => {
|
|
499
|
+
const r = shouldBlockPlanningUnit('subagent', '', BASE, 'run-uat', VERIFICATION_UAT, ['worker']);
|
|
500
|
+
assert.strictEqual(r.block, true);
|
|
501
|
+
assert.match(r.reason!, /"worker"/);
|
|
502
|
+
assert.match(r.reason!, /read-only specialists/);
|
|
503
|
+
});
|
|
504
|
+
|
|
505
|
+
test('verification-mode: run-uat blocks read-only specialists not listed by policy', () => {
|
|
506
|
+
const r = shouldBlockPlanningUnit('subagent', '', BASE, 'run-uat', VERIFICATION_UAT, ['security']);
|
|
507
|
+
assert.strictEqual(r.block, true);
|
|
508
|
+
assert.match(r.reason!, /"security"/);
|
|
509
|
+
assert.match(r.reason!, /ToolsPolicy\.allowedSubagents|permitted agents for this unit/);
|
|
510
|
+
});
|
|
511
|
+
|
|
472
512
|
// ─── read-only mode ───────────────────────────────────────────────────────
|
|
473
513
|
|
|
474
514
|
test('read-only: blocks any edit even to .gsd/', () => {
|
|
@@ -8,12 +8,14 @@ import {
|
|
|
8
8
|
type ToolsPolicy,
|
|
9
9
|
} from "./unit-context-manifest.js";
|
|
10
10
|
import { getRequiredWorkflowToolsForAutoUnit } from "./workflow-mcp.js";
|
|
11
|
+
import { getUnitToolSurfaceContract } from "./unit-tool-contracts.js";
|
|
11
12
|
|
|
12
13
|
export interface UnitToolContract {
|
|
13
14
|
unitType: string;
|
|
14
15
|
contextMode: ContextModePolicy;
|
|
15
16
|
toolsPolicy: ToolsPolicy;
|
|
16
17
|
requiredWorkflowTools: readonly string[];
|
|
18
|
+
forbiddenWorkflowTools: readonly { name: string; reason: string }[];
|
|
17
19
|
promptObligations: readonly string[];
|
|
18
20
|
validationRules: readonly string[];
|
|
19
21
|
closeoutTools: readonly string[];
|
|
@@ -30,6 +32,7 @@ export type ToolContractResult =
|
|
|
30
32
|
|
|
31
33
|
export function compileUnitToolContract(unitType: string): ToolContractResult {
|
|
32
34
|
const manifest = resolveManifest(unitType);
|
|
35
|
+
const surfaceContract = getUnitToolSurfaceContract(unitType);
|
|
33
36
|
if (!manifest) {
|
|
34
37
|
return {
|
|
35
38
|
ok: false,
|
|
@@ -39,6 +42,8 @@ export function compileUnitToolContract(unitType: string): ToolContractResult {
|
|
|
39
42
|
}
|
|
40
43
|
|
|
41
44
|
const requiredWorkflowTools = getRequiredWorkflowToolsForAutoUnit(unitType);
|
|
45
|
+
const forbiddenWorkflowTools = Object.entries(surfaceContract?.forbiddenGsdTools ?? {})
|
|
46
|
+
.map(([name, reason]) => ({ name, reason }));
|
|
42
47
|
const closeoutTools = requiredWorkflowTools.filter((tool) =>
|
|
43
48
|
/^gsd_(?:task|slice|milestone|complete|validate|save|summary)/.test(tool),
|
|
44
49
|
);
|
|
@@ -58,6 +63,7 @@ export function compileUnitToolContract(unitType: string): ToolContractResult {
|
|
|
58
63
|
contextMode: manifest.contextMode,
|
|
59
64
|
toolsPolicy: manifest.tools,
|
|
60
65
|
requiredWorkflowTools,
|
|
66
|
+
forbiddenWorkflowTools,
|
|
61
67
|
promptObligations: [
|
|
62
68
|
`context-mode:${manifest.contextMode}`,
|
|
63
69
|
`tools-policy:${manifest.tools.mode}`,
|