@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
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* artifacts so the DB-filesystem reconciler does not auto-correct
|
|
8
8
|
* entities back to "complete".
|
|
9
9
|
*/
|
|
10
|
-
import { getMilestone, getMilestoneSlices, getSliceTasks,
|
|
10
|
+
import { getMilestone, getMilestoneSlices, getSliceTasks, reopenMilestoneStatus, updateSliceStatus, updateTaskStatus, transaction, } from "../gsd-db.js";
|
|
11
11
|
import { invalidateStateCache } from "../state.js";
|
|
12
12
|
import { isClosedStatus } from "../status-guards.js";
|
|
13
13
|
import { renderAllProjections } from "../workflow-projections.js";
|
|
@@ -37,7 +37,7 @@ export async function handleReopenMilestone(params, basePath) {
|
|
|
37
37
|
guardError = `milestone ${params.milestoneId} is not closed (status: ${milestone.status}) — nothing to reopen`;
|
|
38
38
|
return;
|
|
39
39
|
}
|
|
40
|
-
|
|
40
|
+
reopenMilestoneStatus(params.milestoneId);
|
|
41
41
|
const slices = getMilestoneSlices(params.milestoneId);
|
|
42
42
|
slicesResetCount = slices.length;
|
|
43
43
|
for (const slice of slices) {
|
|
@@ -44,19 +44,12 @@ function getRequiredVerificationClasses(milestoneId) {
|
|
|
44
44
|
required.push("UAT");
|
|
45
45
|
return required;
|
|
46
46
|
}
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
chunks.push(artifact.full_content);
|
|
54
|
-
const assessmentPath = resolveSliceFile(basePath, milestoneId, slice.id, "ASSESSMENT");
|
|
55
|
-
const assessmentContent = assessmentPath ? await loadFile(assessmentPath) : null;
|
|
56
|
-
if (assessmentContent)
|
|
57
|
-
chunks.push(assessmentContent);
|
|
58
|
-
}
|
|
59
|
-
return chunks.join("\n\n");
|
|
47
|
+
function hasRuntimeExecutableUatEvidenceText(text) {
|
|
48
|
+
if (!/\buatType:\s*runtime-executable\b/i.test(text))
|
|
49
|
+
return false;
|
|
50
|
+
if (!/\bverdict:\s*PASS\b/i.test(text))
|
|
51
|
+
return false;
|
|
52
|
+
return /^\|\s*[^|\n]+\s*\|\s*runtime\s*\|\s*PASS\s*\|[^|\n]*\bgsd_uat_exec\b/mi.test(text);
|
|
60
53
|
}
|
|
61
54
|
async function browserEvidenceGateRequiresAttention(params, basePath) {
|
|
62
55
|
if (params.verdict !== "pass")
|
|
@@ -77,7 +70,36 @@ async function browserEvidenceGateRequiresAttention(params, basePath) {
|
|
|
77
70
|
]);
|
|
78
71
|
if (!hasBrowserRequiredText(requirementText))
|
|
79
72
|
return false;
|
|
80
|
-
|
|
73
|
+
// Collect per-slice evidence so the runtime bypass is checked independently
|
|
74
|
+
// for each slice. Concatenating all slices before checking would allow runtime
|
|
75
|
+
// evidence from one slice to cover another slice's browser requirements.
|
|
76
|
+
const sliceEvidencePairs = [];
|
|
77
|
+
for (const slice of slices) {
|
|
78
|
+
const chunks = [];
|
|
79
|
+
const artifactPath = `milestones/${params.milestoneId}/slices/${slice.id}/${slice.id}-ASSESSMENT.md`;
|
|
80
|
+
const artifact = getArtifact(artifactPath);
|
|
81
|
+
if (artifact?.full_content)
|
|
82
|
+
chunks.push(artifact.full_content);
|
|
83
|
+
const assessmentPath = resolveSliceFile(basePath, params.milestoneId, slice.id, "ASSESSMENT");
|
|
84
|
+
const assessmentContent = assessmentPath ? await loadFile(assessmentPath) : null;
|
|
85
|
+
if (assessmentContent)
|
|
86
|
+
chunks.push(assessmentContent);
|
|
87
|
+
sliceEvidencePairs.push({
|
|
88
|
+
sliceRequirementText: compactTextParts([slice.demo, slice.goal, slice.success_criteria]),
|
|
89
|
+
evidenceText: chunks.join("\n\n"),
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
const persistedEvidence = sliceEvidencePairs.map((s) => s.evidenceText).join("\n\n");
|
|
93
|
+
// Runtime bypass: each slice whose own requirement text has browser-observable
|
|
94
|
+
// criteria must have its own runtime-executable UAT evidence. When no individual
|
|
95
|
+
// slice has slice-level browser requirements (e.g., they come from milestone-level
|
|
96
|
+
// fields only), fall back to checking whether any slice has runtime evidence.
|
|
97
|
+
const browserRequiringSlices = sliceEvidencePairs.filter((s) => hasBrowserRequiredText(s.sliceRequirementText));
|
|
98
|
+
const runtimeBypasses = browserRequiringSlices.length > 0
|
|
99
|
+
? browserRequiringSlices.every((s) => hasRuntimeExecutableUatEvidenceText(s.evidenceText))
|
|
100
|
+
: sliceEvidencePairs.some((s) => hasRuntimeExecutableUatEvidenceText(s.evidenceText));
|
|
101
|
+
if (runtimeBypasses)
|
|
102
|
+
return false;
|
|
81
103
|
const validationEvidence = compactTextParts([
|
|
82
104
|
params.successCriteriaChecklist,
|
|
83
105
|
params.verificationClasses,
|
|
@@ -138,12 +160,20 @@ export async function handleValidateMilestone(params, basePath, opts) {
|
|
|
138
160
|
const requiredClasses = getRequiredVerificationClasses(params.milestoneId);
|
|
139
161
|
if (requiredClasses.length > 0) {
|
|
140
162
|
const verificationClasses = params.verificationClasses ?? "";
|
|
141
|
-
const
|
|
142
|
-
if (
|
|
163
|
+
const missingClasses = requiredClasses.filter((className) => !new RegExp(`\\b${className}\\b`, "i").test(verificationClasses));
|
|
164
|
+
if (missingClasses.length === 1) {
|
|
165
|
+
const missingClass = missingClasses[0];
|
|
143
166
|
return {
|
|
144
167
|
error: `verificationClasses must include canonical row "${missingClass}" because this milestone planned ${missingClass.toLowerCase()} verification`,
|
|
145
168
|
};
|
|
146
169
|
}
|
|
170
|
+
if (missingClasses.length > 1) {
|
|
171
|
+
const quotedClasses = missingClasses.map((className) => `"${className}"`).join(", ");
|
|
172
|
+
const plannedClasses = missingClasses.map((className) => className.toLowerCase()).join(", ");
|
|
173
|
+
return {
|
|
174
|
+
error: `verificationClasses must include canonical rows ${quotedClasses} because this milestone planned ${plannedClasses} verification`,
|
|
175
|
+
};
|
|
176
|
+
}
|
|
147
177
|
}
|
|
148
178
|
const artifactBasePath = resolveCanonicalMilestoneRoot(basePath, params.milestoneId);
|
|
149
179
|
const shouldApplyBrowserEvidenceGate = !opts?.skipBrowserEvidenceGate &&
|
|
@@ -3,13 +3,13 @@
|
|
|
3
3
|
import { ensureDbOpen } from "../bootstrap/dynamic-tools.js";
|
|
4
4
|
import { sanitizeCompleteMilestoneParams } from "../bootstrap/sanitize-complete-milestone.js";
|
|
5
5
|
import { loadWriteGateSnapshot, shouldBlockContextArtifactSaveInSnapshot, shouldBlockRootArtifactSaveInSnapshot } from "../bootstrap/write-gate.js";
|
|
6
|
-
import { getActiveRequirements, insertMilestone, getMilestone, getSliceStatusSummary, getSliceTaskCounts, readTransaction, saveGateResult, } from "../gsd-db.js";
|
|
6
|
+
import { getActiveRequirements, insertMilestone, getMilestone, getSliceStatusSummary, getSliceTaskCounts, insertGateRun, readTransaction, saveGateResult, upsertQualityGate, } from "../gsd-db.js";
|
|
7
7
|
import { GATE_REGISTRY } from "../gate-registry.js";
|
|
8
8
|
import { generateRequirementsMd, saveArtifactToDb } from "../db-writer.js";
|
|
9
9
|
import { clearPathCache, resolveGsdPathContract, resolveMilestoneFile, resolveSliceFile } from "../paths.js";
|
|
10
10
|
import { saveFile, clearParseCache } from "../files.js";
|
|
11
|
-
import { unlinkSync } from "node:fs";
|
|
12
|
-
import { join } from "node:path";
|
|
11
|
+
import { existsSync, readdirSync, readFileSync, unlinkSync } from "node:fs";
|
|
12
|
+
import { isAbsolute, join, resolve } from "node:path";
|
|
13
13
|
import { handleCompleteMilestone } from "./complete-milestone.js";
|
|
14
14
|
import { handleCompleteTask } from "./complete-task.js";
|
|
15
15
|
import { handleCompleteSlice } from "./complete-slice.js";
|
|
@@ -26,6 +26,7 @@ import { invalidateStateCache } from "../state.js";
|
|
|
26
26
|
import { loadEffectiveGSDPreferences } from "../preferences.js";
|
|
27
27
|
import { parseProject } from "../schemas/parsers.js";
|
|
28
28
|
import { getAutoRuntimeSnapshot } from "../auto-runtime-state.js";
|
|
29
|
+
import { buildRunUatPresentationForType, canonicalWorkflowToolName, parseMcpToolName, RUN_UAT_FORBIDDEN_TOOL_NAMES, RUN_UAT_TOOL_PRESENTATION_PLAN_ID, RUN_UAT_WORKFLOW_TOOL_NAMES, } from "../tool-presentation-plan.js";
|
|
29
30
|
export const SUPPORTED_SUMMARY_ARTIFACT_TYPES = [
|
|
30
31
|
"SUMMARY",
|
|
31
32
|
"RESEARCH",
|
|
@@ -52,7 +53,7 @@ function blockIfWrongAutoUnit(requiredUnitType, operation) {
|
|
|
52
53
|
return null;
|
|
53
54
|
if (snapshot.currentUnit.type === requiredUnitType)
|
|
54
55
|
return null;
|
|
55
|
-
const error = `HARD BLOCK: ${operation} may only run from ${requiredUnitType}; active unit is ${snapshot.currentUnit.type}. The orchestrator owns phase transitions.`;
|
|
56
|
+
const error = `HARD BLOCK: Tool Contract failure: ${operation} may only run from ${requiredUnitType}; active unit is ${snapshot.currentUnit.type}. Fix unit-tool-contracts.ts or the active Unit prompt. The orchestrator owns phase transitions.`;
|
|
56
57
|
return {
|
|
57
58
|
content: [{ type: "text", text: error }],
|
|
58
59
|
details: { operation, error },
|
|
@@ -120,7 +121,11 @@ export async function executeSummarySave(params, basePath = process.cwd()) {
|
|
|
120
121
|
if (rootArtifactGuard.block) {
|
|
121
122
|
return {
|
|
122
123
|
content: [{ type: "text", text: `Error saving artifact: ${rootArtifactGuard.reason ?? "root artifact write blocked"}` }],
|
|
123
|
-
details: {
|
|
124
|
+
details: {
|
|
125
|
+
operation: "save_summary",
|
|
126
|
+
error: "root_artifact_write_blocked",
|
|
127
|
+
displayReason: "Approval confirmation required before saving final project setup artifacts.",
|
|
128
|
+
},
|
|
124
129
|
isError: true,
|
|
125
130
|
};
|
|
126
131
|
}
|
|
@@ -128,7 +133,11 @@ export async function executeSummarySave(params, basePath = process.cwd()) {
|
|
|
128
133
|
if (contextGuard.block) {
|
|
129
134
|
return {
|
|
130
135
|
content: [{ type: "text", text: `Error saving artifact: ${contextGuard.reason ?? "context write blocked"}` }],
|
|
131
|
-
details: {
|
|
136
|
+
details: {
|
|
137
|
+
operation: "save_summary",
|
|
138
|
+
error: "context_write_blocked",
|
|
139
|
+
displayReason: "Depth check required before writing milestone context.",
|
|
140
|
+
},
|
|
132
141
|
isError: true,
|
|
133
142
|
};
|
|
134
143
|
}
|
|
@@ -333,6 +342,28 @@ export async function executeTaskComplete(params, basePath = process.cwd()) {
|
|
|
333
342
|
isError: true,
|
|
334
343
|
};
|
|
335
344
|
}
|
|
345
|
+
if (result.escalation) {
|
|
346
|
+
const recommended = result.escalation.options.find((option) => option.id === result.escalation?.recommendation);
|
|
347
|
+
const optionIds = result.escalation.options.map((option) => option.id).join("|");
|
|
348
|
+
return {
|
|
349
|
+
content: [{
|
|
350
|
+
type: "text",
|
|
351
|
+
text: [
|
|
352
|
+
`Task completed with escalation decision required: ${result.escalation.question}`,
|
|
353
|
+
`Recommendation: ${result.escalation.recommendation}${recommended ? ` (${recommended.label})` : ""} — ${result.escalation.recommendationRationale}`,
|
|
354
|
+
`Resolve with: /gsd escalate resolve ${result.taskId} <${optionIds}|accept|reject-blocker> [rationale...]`,
|
|
355
|
+
].join("\n"),
|
|
356
|
+
}],
|
|
357
|
+
details: {
|
|
358
|
+
operation: "complete_task",
|
|
359
|
+
taskId: result.taskId,
|
|
360
|
+
sliceId: result.sliceId,
|
|
361
|
+
milestoneId: result.milestoneId,
|
|
362
|
+
summaryPath: result.summaryPath,
|
|
363
|
+
escalation: result.escalation,
|
|
364
|
+
},
|
|
365
|
+
};
|
|
366
|
+
}
|
|
336
367
|
return {
|
|
337
368
|
content: [{ type: "text", text: `Completed task ${result.taskId} (${result.sliceId}/${result.milestoneId})` }],
|
|
338
369
|
details: {
|
|
@@ -775,6 +806,452 @@ export async function executeSaveGateResult(params, basePath = process.cwd()) {
|
|
|
775
806
|
};
|
|
776
807
|
}
|
|
777
808
|
}
|
|
809
|
+
function errorResult(operation, message, error) {
|
|
810
|
+
return {
|
|
811
|
+
content: [{ type: "text", text: `Error: ${message}` }],
|
|
812
|
+
details: { operation, error },
|
|
813
|
+
isError: true,
|
|
814
|
+
};
|
|
815
|
+
}
|
|
816
|
+
function isNonEmptyString(value) {
|
|
817
|
+
return typeof value === "string" && value.trim().length > 0;
|
|
818
|
+
}
|
|
819
|
+
function mergeBlockedTools(current, canonical) {
|
|
820
|
+
const merged = new Map();
|
|
821
|
+
for (const entry of [...(current ?? []), ...canonical]) {
|
|
822
|
+
merged.set(canonicalWorkflowToolName(parseMcpToolName(entry.name)?.tool ?? entry.name), entry);
|
|
823
|
+
}
|
|
824
|
+
return [...merged.values()];
|
|
825
|
+
}
|
|
826
|
+
function mergePresentedTools(current, canonical) {
|
|
827
|
+
return [...new Set([...(current ?? []), ...canonical])];
|
|
828
|
+
}
|
|
829
|
+
function normalizeUatVerdict(params) {
|
|
830
|
+
const raw = params;
|
|
831
|
+
if (typeof raw.verdict === "string") {
|
|
832
|
+
return { ...params, verdict: raw.verdict.toUpperCase() };
|
|
833
|
+
}
|
|
834
|
+
return params;
|
|
835
|
+
}
|
|
836
|
+
function supplyDefaultPresentation(params) {
|
|
837
|
+
const raw = params;
|
|
838
|
+
if (!raw.presentation) {
|
|
839
|
+
return { ...params, presentation: buildRunUatPresentationForType(params.uatType) };
|
|
840
|
+
}
|
|
841
|
+
return params;
|
|
842
|
+
}
|
|
843
|
+
function mergeCanonicalPresentation(params) {
|
|
844
|
+
const canonicalPresentation = buildRunUatPresentationForType(params.uatType);
|
|
845
|
+
const providedPresentation = params.presentation;
|
|
846
|
+
return {
|
|
847
|
+
...params,
|
|
848
|
+
presentation: {
|
|
849
|
+
...providedPresentation,
|
|
850
|
+
surface: providedPresentation.surface ?? canonicalPresentation.surface,
|
|
851
|
+
presentedTools: mergePresentedTools(providedPresentation.presentedTools, canonicalPresentation.presentedTools),
|
|
852
|
+
blockedTools: mergeBlockedTools(providedPresentation.blockedTools, canonicalPresentation.blockedTools),
|
|
853
|
+
toolPresentationPlanId: RUN_UAT_TOOL_PRESENTATION_PLAN_ID,
|
|
854
|
+
},
|
|
855
|
+
};
|
|
856
|
+
}
|
|
857
|
+
const VALID_UAT_TYPES = [
|
|
858
|
+
"artifact-driven",
|
|
859
|
+
"browser-executable",
|
|
860
|
+
"runtime-executable",
|
|
861
|
+
"live-runtime",
|
|
862
|
+
"mixed",
|
|
863
|
+
"human-experience",
|
|
864
|
+
];
|
|
865
|
+
function ensureUatRequiredFields(params) {
|
|
866
|
+
if (!isNonEmptyString(params.milestoneId))
|
|
867
|
+
return "milestoneId is required";
|
|
868
|
+
if (!isNonEmptyString(params.sliceId))
|
|
869
|
+
return "sliceId is required";
|
|
870
|
+
if (!isNonEmptyString(params.uatType))
|
|
871
|
+
return "uatType is required";
|
|
872
|
+
if (!VALID_UAT_TYPES.includes(params.uatType)) {
|
|
873
|
+
return `uatType must be one of: ${VALID_UAT_TYPES.join(", ")}`;
|
|
874
|
+
}
|
|
875
|
+
if (!["PASS", "FAIL", "PARTIAL"].includes(params.verdict))
|
|
876
|
+
return "verdict must be PASS, FAIL, or PARTIAL";
|
|
877
|
+
if (!Array.isArray(params.checks) || params.checks.length === 0)
|
|
878
|
+
return "checks must contain at least one UAT check";
|
|
879
|
+
if (!params.presentation || !Array.isArray(params.presentation.presentedTools))
|
|
880
|
+
return "presentation.presentedTools is required";
|
|
881
|
+
if (!Array.isArray(params.presentation.blockedTools))
|
|
882
|
+
return "presentation.blockedTools is required";
|
|
883
|
+
return null;
|
|
884
|
+
}
|
|
885
|
+
function approvedEvidenceRoots(basePath) {
|
|
886
|
+
const contract = resolveGsdPathContract(basePath);
|
|
887
|
+
return [contract.worktreeGsd, contract.projectGsd].filter((root) => typeof root === "string");
|
|
888
|
+
}
|
|
889
|
+
function approvedBrowserArtifactRoots(basePath) {
|
|
890
|
+
const contract = resolveGsdPathContract(basePath);
|
|
891
|
+
const roots = [contract.workRoot, contract.projectRoot].map((root) => join(root, ".artifacts", "browser"));
|
|
892
|
+
return [...new Set(roots)];
|
|
893
|
+
}
|
|
894
|
+
function pathStartsWithin(parent, target) {
|
|
895
|
+
const normalizedParent = parent.replace(/\\/g, "/").replace(/\/+$/, "");
|
|
896
|
+
const normalizedTarget = target.replace(/\\/g, "/").replace(/\/+$/, "");
|
|
897
|
+
return normalizedTarget === normalizedParent || normalizedTarget.startsWith(`${normalizedParent}/`);
|
|
898
|
+
}
|
|
899
|
+
function pushUnique(paths, candidate) {
|
|
900
|
+
if (!paths.includes(candidate))
|
|
901
|
+
paths.push(candidate);
|
|
902
|
+
}
|
|
903
|
+
function execMetaPathCandidates(basePath, ref) {
|
|
904
|
+
const trimmed = ref.trim();
|
|
905
|
+
const candidates = [];
|
|
906
|
+
const execDirs = approvedEvidenceRoots(basePath).map((root) => join(root, "exec"));
|
|
907
|
+
const normalizedRef = trimmed.replace(/\\/g, "/");
|
|
908
|
+
const pathLike = normalizedRef.endsWith(".meta.json") || normalizedRef.includes("/.gsd/exec/");
|
|
909
|
+
if (pathLike) {
|
|
910
|
+
const rawPath = isAbsolute(trimmed) ? resolve(trimmed) : resolve(basePath, trimmed);
|
|
911
|
+
pushUnique(candidates, rawPath);
|
|
912
|
+
const relativeExecMarker = ".gsd/exec/";
|
|
913
|
+
const markerIndex = normalizedRef.indexOf(relativeExecMarker);
|
|
914
|
+
if (markerIndex >= 0) {
|
|
915
|
+
const execRelative = normalizedRef.slice(markerIndex + relativeExecMarker.length);
|
|
916
|
+
for (const execDir of execDirs) {
|
|
917
|
+
pushUnique(candidates, join(execDir, execRelative));
|
|
918
|
+
}
|
|
919
|
+
}
|
|
920
|
+
return candidates.filter((candidate) => execDirs.some((execDir) => pathStartsWithin(execDir, candidate)));
|
|
921
|
+
}
|
|
922
|
+
for (const execDir of execDirs) {
|
|
923
|
+
pushUnique(candidates, join(execDir, `${trimmed}.meta.json`));
|
|
924
|
+
}
|
|
925
|
+
return candidates;
|
|
926
|
+
}
|
|
927
|
+
function resolveExecMetaPath(basePath, ref) {
|
|
928
|
+
for (const candidate of execMetaPathCandidates(basePath, ref)) {
|
|
929
|
+
if (existsSync(candidate))
|
|
930
|
+
return candidate;
|
|
931
|
+
}
|
|
932
|
+
return null;
|
|
933
|
+
}
|
|
934
|
+
function evidencePathIsApproved(basePath, ref) {
|
|
935
|
+
const normalizedRef = ref.replace(/\\/g, "/");
|
|
936
|
+
if (normalizedRef.startsWith(".gsd/exec/") || normalizedRef.startsWith(".gsd/uat/"))
|
|
937
|
+
return true;
|
|
938
|
+
if (normalizedRef.startsWith(".artifacts/browser/")) {
|
|
939
|
+
const resolvedRef = resolve(basePath, ref);
|
|
940
|
+
return approvedBrowserArtifactRoots(basePath).some((root) => pathStartsWithin(root, resolvedRef));
|
|
941
|
+
}
|
|
942
|
+
const gsdEvidenceApproved = approvedEvidenceRoots(basePath).some((root) => {
|
|
943
|
+
return pathStartsWithin(join(root, "exec"), ref) || pathStartsWithin(join(root, "uat"), ref);
|
|
944
|
+
});
|
|
945
|
+
if (gsdEvidenceApproved)
|
|
946
|
+
return true;
|
|
947
|
+
return approvedBrowserArtifactRoots(basePath).some((root) => pathStartsWithin(root, ref));
|
|
948
|
+
}
|
|
949
|
+
function validateEvidenceRef(basePath, evidence) {
|
|
950
|
+
if (!isNonEmptyString(evidence.ref))
|
|
951
|
+
return "evidence.ref is required";
|
|
952
|
+
if (evidence.kind === "gsd_uat_exec" || evidence.kind === "gsd_exec") {
|
|
953
|
+
const path = resolveExecMetaPath(basePath, evidence.ref.trim());
|
|
954
|
+
if (!path)
|
|
955
|
+
return `missing gsd_exec metadata for evidence id "${evidence.ref}"`;
|
|
956
|
+
if (evidence.kind === "gsd_uat_exec") {
|
|
957
|
+
try {
|
|
958
|
+
const meta = JSON.parse(readFileSync(path, "utf-8"));
|
|
959
|
+
if (meta.metadata?.kind !== "uat_exec")
|
|
960
|
+
return `evidence id "${evidence.ref}" is not typed as uat_exec`;
|
|
961
|
+
}
|
|
962
|
+
catch {
|
|
963
|
+
return `invalid gsd_exec metadata JSON for evidence id "${evidence.ref}"`;
|
|
964
|
+
}
|
|
965
|
+
}
|
|
966
|
+
return null;
|
|
967
|
+
}
|
|
968
|
+
if (evidence.kind === "url") {
|
|
969
|
+
try {
|
|
970
|
+
const parsed = new URL(evidence.ref);
|
|
971
|
+
return parsed.protocol === "http:" || parsed.protocol === "https:"
|
|
972
|
+
? null
|
|
973
|
+
: `invalid URL evidence ref "${evidence.ref}"`;
|
|
974
|
+
}
|
|
975
|
+
catch {
|
|
976
|
+
return `invalid URL evidence ref "${evidence.ref}"`;
|
|
977
|
+
}
|
|
978
|
+
}
|
|
979
|
+
return evidencePathIsApproved(basePath, evidence.ref)
|
|
980
|
+
? null
|
|
981
|
+
: `evidence ref "${evidence.ref}" is outside approved evidence locations`;
|
|
982
|
+
}
|
|
983
|
+
function validateUatChecks(basePath, params) {
|
|
984
|
+
for (const check of params.checks) {
|
|
985
|
+
if (!isNonEmptyString(check.id))
|
|
986
|
+
return "every check must have a non-empty id";
|
|
987
|
+
if (!isNonEmptyString(check.description))
|
|
988
|
+
return `check ${check.id} must have a description`;
|
|
989
|
+
if (!["artifact", "runtime", "browser", "human-follow-up"].includes(check.mode)) {
|
|
990
|
+
return `check ${check.id} has invalid mode "${check.mode}"`;
|
|
991
|
+
}
|
|
992
|
+
if (!["PASS", "FAIL", "NEEDS-HUMAN"].includes(check.result)) {
|
|
993
|
+
return `check ${check.id} has invalid result "${check.result}"`;
|
|
994
|
+
}
|
|
995
|
+
if (check.result === "PASS" || check.result === "FAIL") {
|
|
996
|
+
if (!Array.isArray(check.evidence) || check.evidence.length === 0) {
|
|
997
|
+
return `check ${check.id} is ${check.result} but has no objective evidence`;
|
|
998
|
+
}
|
|
999
|
+
for (const evidence of check.evidence) {
|
|
1000
|
+
const error = validateEvidenceRef(basePath, evidence);
|
|
1001
|
+
if (error)
|
|
1002
|
+
return `check ${check.id}: ${error}`;
|
|
1003
|
+
}
|
|
1004
|
+
}
|
|
1005
|
+
else if (!isNonEmptyString(check.notes)) {
|
|
1006
|
+
return `check ${check.id} is NEEDS-HUMAN but has no manual instruction or reason`;
|
|
1007
|
+
}
|
|
1008
|
+
}
|
|
1009
|
+
return null;
|
|
1010
|
+
}
|
|
1011
|
+
function validateFreshUatOwnedEvidence(params) {
|
|
1012
|
+
const hasFreshUatEvidence = params.checks.some((check) => (check.evidence ?? []).some((evidence) => evidence.kind === "gsd_uat_exec"));
|
|
1013
|
+
return hasFreshUatEvidence
|
|
1014
|
+
? null
|
|
1015
|
+
: "UAT Assessment requires at least one fresh gsd_uat_exec evidence reference from run-uat";
|
|
1016
|
+
}
|
|
1017
|
+
function validateUatMode(params) {
|
|
1018
|
+
const modes = new Set(params.checks.map((check) => check.mode));
|
|
1019
|
+
const hasHuman = params.checks.some((check) => check.result === "NEEDS-HUMAN");
|
|
1020
|
+
if (params.uatType === "artifact-driven" && hasHuman && params.verdict === "PASS") {
|
|
1021
|
+
return "artifact-driven UAT cannot PASS with human-only checks";
|
|
1022
|
+
}
|
|
1023
|
+
if (hasHuman &&
|
|
1024
|
+
params.verdict === "PASS" &&
|
|
1025
|
+
!["human-experience", "mixed", "live-runtime"].includes(params.uatType) &&
|
|
1026
|
+
!params.checks.every((check) => check.result !== "NEEDS-HUMAN" || check.nonAutomatable === true)) {
|
|
1027
|
+
return "NEEDS-HUMAN checks can only coexist with PASS for human-experience, mixed, live-runtime, or explicitly non-automatable checks";
|
|
1028
|
+
}
|
|
1029
|
+
if (params.uatType === "runtime-executable" && !modes.has("runtime")) {
|
|
1030
|
+
return "runtime-executable UAT requires at least one runtime check";
|
|
1031
|
+
}
|
|
1032
|
+
if (params.uatType === "browser-executable" && !modes.has("browser")) {
|
|
1033
|
+
return "browser-executable UAT requires at least one browser check";
|
|
1034
|
+
}
|
|
1035
|
+
if (params.uatType === "live-runtime" && !modes.has("runtime") && !modes.has("browser")) {
|
|
1036
|
+
return "live-runtime UAT requires runtime or browser evidence";
|
|
1037
|
+
}
|
|
1038
|
+
return null;
|
|
1039
|
+
}
|
|
1040
|
+
function quoteToolNames(toolNames) {
|
|
1041
|
+
return toolNames.map((toolName) => `"${toolName}"`).join(", ");
|
|
1042
|
+
}
|
|
1043
|
+
function validateCanonicalPresentation(params) {
|
|
1044
|
+
const aliasHints = {
|
|
1045
|
+
gsd_save_summary: "gsd_summary_save",
|
|
1046
|
+
gsd_complete_task: "gsd_task_complete",
|
|
1047
|
+
gsd_complete_slice: "gsd_slice_complete",
|
|
1048
|
+
gsd_milestone_complete: "gsd_complete_milestone",
|
|
1049
|
+
};
|
|
1050
|
+
const errors = [];
|
|
1051
|
+
for (const toolName of params.presentation.presentedTools) {
|
|
1052
|
+
const baseName = parseMcpToolName(toolName)?.tool ?? toolName;
|
|
1053
|
+
const canonical = aliasHints[baseName];
|
|
1054
|
+
if (canonical)
|
|
1055
|
+
errors.push(`presentation tool "${toolName}" uses an alias; use canonical "${canonical}"`);
|
|
1056
|
+
}
|
|
1057
|
+
const presentedCanonical = new Set(params.presentation.presentedTools.map((toolName) => canonicalWorkflowToolName(parseMcpToolName(toolName)?.tool ?? toolName)));
|
|
1058
|
+
const missingRequiredTools = RUN_UAT_WORKFLOW_TOOL_NAMES.filter((requiredTool) => !presentedCanonical.has(requiredTool));
|
|
1059
|
+
if (missingRequiredTools.length === 1) {
|
|
1060
|
+
errors.push(`presentation is missing required UAT tool "${missingRequiredTools[0]}"`);
|
|
1061
|
+
}
|
|
1062
|
+
else if (missingRequiredTools.length > 1) {
|
|
1063
|
+
errors.push(`presentation is missing required UAT tools ${quoteToolNames(missingRequiredTools)}`);
|
|
1064
|
+
}
|
|
1065
|
+
const forbiddenCanonical = new Set(RUN_UAT_FORBIDDEN_TOOL_NAMES
|
|
1066
|
+
.filter((toolName) => !toolName.includes("*"))
|
|
1067
|
+
.map((toolName) => canonicalWorkflowToolName(parseMcpToolName(toolName)?.tool ?? toolName)));
|
|
1068
|
+
const forbiddenPresentedTools = [];
|
|
1069
|
+
for (const toolName of params.presentation.presentedTools) {
|
|
1070
|
+
const canonical = canonicalWorkflowToolName(parseMcpToolName(toolName)?.tool ?? toolName);
|
|
1071
|
+
if (toolName === "mcp__gsd-workflow__*" || forbiddenCanonical.has(canonical)) {
|
|
1072
|
+
forbiddenPresentedTools.push(toolName);
|
|
1073
|
+
}
|
|
1074
|
+
}
|
|
1075
|
+
if (forbiddenPresentedTools.length === 1) {
|
|
1076
|
+
errors.push(`presentation includes forbidden run-uat tool "${forbiddenPresentedTools[0]}"`);
|
|
1077
|
+
}
|
|
1078
|
+
else if (forbiddenPresentedTools.length > 1) {
|
|
1079
|
+
errors.push(`presentation includes forbidden run-uat tools ${quoteToolNames(forbiddenPresentedTools)}`);
|
|
1080
|
+
}
|
|
1081
|
+
const blockedCanonical = new Set(params.presentation.blockedTools.map((entry) => canonicalWorkflowToolName(parseMcpToolName(entry.name)?.tool ?? entry.name)));
|
|
1082
|
+
const missingBlockedTools = ["gsd_exec", "gsd_summary_save", "gsd_save_gate_result"].filter((blockedTool) => !blockedCanonical.has(blockedTool));
|
|
1083
|
+
if (missingBlockedTools.length === 1) {
|
|
1084
|
+
errors.push(`presentation must record "${missingBlockedTools[0]}" as blocked during run-uat`);
|
|
1085
|
+
}
|
|
1086
|
+
else if (missingBlockedTools.length > 1) {
|
|
1087
|
+
errors.push(`presentation must record ${quoteToolNames(missingBlockedTools)} as blocked during run-uat`);
|
|
1088
|
+
}
|
|
1089
|
+
return errors.length > 0 ? errors.join("; ") : null;
|
|
1090
|
+
}
|
|
1091
|
+
function nextUatAttempt(basePath, milestoneId, sliceId) {
|
|
1092
|
+
const contract = resolveGsdPathContract(basePath);
|
|
1093
|
+
const dir = join(contract.projectGsd, "uat", milestoneId, sliceId);
|
|
1094
|
+
if (!existsSync(dir))
|
|
1095
|
+
return 1;
|
|
1096
|
+
let max = 0;
|
|
1097
|
+
for (const entry of readdirSync(dir)) {
|
|
1098
|
+
const match = /^attempt-(\d+)\.json$/.exec(entry);
|
|
1099
|
+
if (match)
|
|
1100
|
+
max = Math.max(max, Number(match[1]));
|
|
1101
|
+
}
|
|
1102
|
+
return max + 1;
|
|
1103
|
+
}
|
|
1104
|
+
function escapeMarkdownTableCell(value) {
|
|
1105
|
+
return String(value ?? "")
|
|
1106
|
+
.replace(/[\\|]/g, (char) => `\\${char}`)
|
|
1107
|
+
.replace(/\r?\n/g, "<br>");
|
|
1108
|
+
}
|
|
1109
|
+
function renderUatAssessment(params, attempt, gateVerdict) {
|
|
1110
|
+
const lines = [
|
|
1111
|
+
"---",
|
|
1112
|
+
`sliceId: ${params.sliceId}`,
|
|
1113
|
+
`uatType: ${params.uatType}`,
|
|
1114
|
+
`verdict: ${params.verdict}`,
|
|
1115
|
+
`attempt: ${attempt}`,
|
|
1116
|
+
`date: ${new Date().toISOString()}`,
|
|
1117
|
+
"---",
|
|
1118
|
+
"",
|
|
1119
|
+
`# UAT Result - ${params.sliceId}`,
|
|
1120
|
+
"",
|
|
1121
|
+
"## Checks",
|
|
1122
|
+
"",
|
|
1123
|
+
"| Check | Mode | Result | Evidence | Notes |",
|
|
1124
|
+
"|-------|------|--------|----------|-------|",
|
|
1125
|
+
...params.checks.map((check) => {
|
|
1126
|
+
const evidence = (check.evidence ?? []).map((entry) => `${entry.kind}:${entry.ref}`).join("<br>") || "-";
|
|
1127
|
+
return `| ${escapeMarkdownTableCell(check.description)} | ${escapeMarkdownTableCell(check.mode)} | ${escapeMarkdownTableCell(check.result)} | ${escapeMarkdownTableCell(evidence)} | ${escapeMarkdownTableCell(check.notes)} |`;
|
|
1128
|
+
}),
|
|
1129
|
+
"",
|
|
1130
|
+
"## Overall Verdict",
|
|
1131
|
+
"",
|
|
1132
|
+
`${params.verdict} - ${params.notes ?? "UAT result saved."}`,
|
|
1133
|
+
"",
|
|
1134
|
+
"## Tool Presentation",
|
|
1135
|
+
"",
|
|
1136
|
+
"```json",
|
|
1137
|
+
JSON.stringify(params.presentation, null, 2),
|
|
1138
|
+
"```",
|
|
1139
|
+
"",
|
|
1140
|
+
"## Gate",
|
|
1141
|
+
"",
|
|
1142
|
+
`Aggregate UAT gate saved as ${gateVerdict}.`,
|
|
1143
|
+
];
|
|
1144
|
+
return `${lines.join("\n")}\n`;
|
|
1145
|
+
}
|
|
1146
|
+
async function saveUatAttemptArtifact(basePath, params, attempt) {
|
|
1147
|
+
const contract = resolveGsdPathContract(basePath);
|
|
1148
|
+
const relativePath = `uat/${params.milestoneId}/${params.sliceId}/attempt-${attempt}.json`;
|
|
1149
|
+
await saveFile(join(contract.projectGsd, relativePath), `${JSON.stringify({ ...params, attempt }, null, 2)}\n`);
|
|
1150
|
+
return relativePath;
|
|
1151
|
+
}
|
|
1152
|
+
export async function executeUatResultSave(params, basePath = process.cwd()) {
|
|
1153
|
+
const unitGuard = blockIfWrongAutoUnit("run-uat", "save_uat_result");
|
|
1154
|
+
if (unitGuard)
|
|
1155
|
+
return unitGuard;
|
|
1156
|
+
// Phase 1: normalize verdict and supply the canonical presentation when none was provided.
|
|
1157
|
+
params = normalizeUatVerdict(params);
|
|
1158
|
+
params = supplyDefaultPresentation(params);
|
|
1159
|
+
const dbAvailable = await ensureDbOpen(basePath);
|
|
1160
|
+
if (!dbAvailable)
|
|
1161
|
+
return errorResult("save_uat_result", "GSD database is not available.", "db_unavailable");
|
|
1162
|
+
// Phase 2: validate the submitted presentation before the canonical merge so that
|
|
1163
|
+
// presentations missing required workflow tools are rejected rather than silently patched.
|
|
1164
|
+
const requiredError = ensureUatRequiredFields(params);
|
|
1165
|
+
if (requiredError)
|
|
1166
|
+
return errorResult("save_uat_result", requiredError, "invalid_params");
|
|
1167
|
+
const presentationError = validateCanonicalPresentation(params);
|
|
1168
|
+
if (presentationError)
|
|
1169
|
+
return errorResult("save_uat_result", presentationError, "alias_tool_name");
|
|
1170
|
+
// Phase 3: merge in the canonical plan ID and read-only audit tools so the persisted
|
|
1171
|
+
// artifact always carries the full audit surface even when the provider omitted them.
|
|
1172
|
+
params = mergeCanonicalPresentation(params);
|
|
1173
|
+
const checkError = validateUatChecks(basePath, params);
|
|
1174
|
+
if (checkError)
|
|
1175
|
+
return errorResult("save_uat_result", checkError, "invalid_evidence");
|
|
1176
|
+
const freshEvidenceError = validateFreshUatOwnedEvidence(params);
|
|
1177
|
+
if (freshEvidenceError)
|
|
1178
|
+
return errorResult("save_uat_result", freshEvidenceError, "missing_fresh_uat_evidence");
|
|
1179
|
+
const modeError = validateUatMode(params);
|
|
1180
|
+
if (modeError)
|
|
1181
|
+
return errorResult("save_uat_result", modeError, "uat_mode_mismatch");
|
|
1182
|
+
try {
|
|
1183
|
+
const attempt = params.attempt === "auto" || params.attempt === undefined
|
|
1184
|
+
? nextUatAttempt(basePath, params.milestoneId, params.sliceId)
|
|
1185
|
+
: typeof params.attempt === "string"
|
|
1186
|
+
? Number.parseInt(params.attempt, 10)
|
|
1187
|
+
: params.attempt;
|
|
1188
|
+
if (!Number.isInteger(attempt) || attempt < 1) {
|
|
1189
|
+
return errorResult("save_uat_result", "attempt must be a positive integer or auto", "invalid_attempt");
|
|
1190
|
+
}
|
|
1191
|
+
const gateVerdict = params.verdict === "PASS" ? "pass" : "flag";
|
|
1192
|
+
const rationale = params.notes ?? `UAT ${params.verdict} for ${params.sliceId}.`;
|
|
1193
|
+
const assessment = renderUatAssessment(params, attempt, gateVerdict);
|
|
1194
|
+
const summary = await executeSummarySave({
|
|
1195
|
+
milestone_id: params.milestoneId,
|
|
1196
|
+
slice_id: params.sliceId,
|
|
1197
|
+
artifact_type: "ASSESSMENT",
|
|
1198
|
+
content: assessment,
|
|
1199
|
+
}, basePath);
|
|
1200
|
+
if (summary.isError)
|
|
1201
|
+
return summary;
|
|
1202
|
+
const attemptPath = await saveUatAttemptArtifact(basePath, params, attempt);
|
|
1203
|
+
const evaluatedAt = new Date().toISOString();
|
|
1204
|
+
upsertQualityGate({
|
|
1205
|
+
milestoneId: params.milestoneId,
|
|
1206
|
+
sliceId: params.sliceId,
|
|
1207
|
+
gateId: "UAT",
|
|
1208
|
+
scope: "slice",
|
|
1209
|
+
taskId: "",
|
|
1210
|
+
status: "complete",
|
|
1211
|
+
verdict: gateVerdict,
|
|
1212
|
+
rationale,
|
|
1213
|
+
findings: assessment,
|
|
1214
|
+
evaluatedAt,
|
|
1215
|
+
});
|
|
1216
|
+
insertGateRun({
|
|
1217
|
+
traceId: `uat:${params.milestoneId}:${params.sliceId}`,
|
|
1218
|
+
turnId: `uat:${params.sliceId}:attempt-${attempt}`,
|
|
1219
|
+
gateId: "UAT",
|
|
1220
|
+
gateType: "uat",
|
|
1221
|
+
unitType: "run-uat",
|
|
1222
|
+
unitId: `run-uat:${params.milestoneId}/${params.sliceId}`,
|
|
1223
|
+
milestoneId: params.milestoneId,
|
|
1224
|
+
sliceId: params.sliceId,
|
|
1225
|
+
outcome: params.verdict === "PASS" ? "pass" : "fail",
|
|
1226
|
+
failureClass: params.verdict === "PASS" ? "none" : "verification",
|
|
1227
|
+
rationale,
|
|
1228
|
+
findings: assessment,
|
|
1229
|
+
attempt,
|
|
1230
|
+
maxAttempts: attempt,
|
|
1231
|
+
retryable: params.verdict !== "PASS",
|
|
1232
|
+
evaluatedAt,
|
|
1233
|
+
});
|
|
1234
|
+
invalidateStateCache();
|
|
1235
|
+
return {
|
|
1236
|
+
content: [{ type: "text", text: `UAT result saved for ${params.milestoneId}/${params.sliceId}: ${params.verdict}` }],
|
|
1237
|
+
details: {
|
|
1238
|
+
operation: "save_uat_result",
|
|
1239
|
+
milestoneId: params.milestoneId,
|
|
1240
|
+
sliceId: params.sliceId,
|
|
1241
|
+
verdict: params.verdict,
|
|
1242
|
+
gateVerdict,
|
|
1243
|
+
attempt,
|
|
1244
|
+
attemptPath,
|
|
1245
|
+
recommendedNextUnit: params.verdict === "PASS" ? null : "reactive-execute",
|
|
1246
|
+
},
|
|
1247
|
+
};
|
|
1248
|
+
}
|
|
1249
|
+
catch (err) {
|
|
1250
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
1251
|
+
logError("tool", `gsd_uat_result_save failed: ${msg}`, { tool: "gsd_uat_result_save", error: String(err) });
|
|
1252
|
+
return errorResult("save_uat_result", `saving UAT result failed: ${msg}`, msg);
|
|
1253
|
+
}
|
|
1254
|
+
}
|
|
778
1255
|
export async function executePlanMilestone(params, basePath = process.cwd()) {
|
|
779
1256
|
const dbAvailable = await ensureDbOpen(basePath);
|
|
780
1257
|
if (!dbAvailable) {
|