@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
|
@@ -41,6 +41,16 @@ function tokenizeSkillContext(...parts) {
|
|
|
41
41
|
}
|
|
42
42
|
return tokens;
|
|
43
43
|
}
|
|
44
|
+
function tokenizeUnitType(unitType) {
|
|
45
|
+
const tokens = new Set();
|
|
46
|
+
const value = unitType?.trim().toLowerCase();
|
|
47
|
+
if (!value)
|
|
48
|
+
return tokens;
|
|
49
|
+
tokens.add(value);
|
|
50
|
+
tokens.add(value.replace(/[-_]+/g, " "));
|
|
51
|
+
tokens.add(value.replace(/[-_\s]+/g, ""));
|
|
52
|
+
return tokens;
|
|
53
|
+
}
|
|
44
54
|
function skillMatchesContext(skill, contextTokens) {
|
|
45
55
|
const haystacks = [
|
|
46
56
|
skill.name.toLowerCase(),
|
|
@@ -63,13 +73,20 @@ function ruleMatchesContext(when, contextTokens) {
|
|
|
63
73
|
const whenTokens = tokenizeSkillContext(when);
|
|
64
74
|
return [...whenTokens].some(token => contextTokens.has(token) || [...contextTokens].some(ctx => ctx.includes(token) || token.includes(ctx)));
|
|
65
75
|
}
|
|
66
|
-
function
|
|
76
|
+
function ruleMatchesUnitType(when, unitType) {
|
|
77
|
+
if (!unitType)
|
|
78
|
+
return false;
|
|
79
|
+
const whenTokens = tokenizeSkillContext(when);
|
|
80
|
+
const unitTokens = tokenizeUnitType(unitType);
|
|
81
|
+
return [...unitTokens].some(token => whenTokens.has(token));
|
|
82
|
+
}
|
|
83
|
+
function resolveSkillRuleMatches(prefs, contextTokens, base, unitType) {
|
|
67
84
|
if (!prefs?.skill_rules?.length)
|
|
68
85
|
return { include: [], avoid: [] };
|
|
69
86
|
const include = [];
|
|
70
87
|
const avoid = [];
|
|
71
88
|
for (const rule of prefs.skill_rules) {
|
|
72
|
-
if (!ruleMatchesContext(rule.when, contextTokens))
|
|
89
|
+
if (!ruleMatchesContext(rule.when, contextTokens) && !ruleMatchesUnitType(rule.when, unitType))
|
|
73
90
|
continue;
|
|
74
91
|
include.push(...resolvePreferenceSkillNames([...(rule.use ?? []), ...(rule.prefer ?? [])], base));
|
|
75
92
|
avoid.push(...resolvePreferenceSkillNames(rule.avoid ?? [], base));
|
|
@@ -141,7 +158,7 @@ export function buildSkillActivationBlock(params) {
|
|
|
141
158
|
for (const name of resolvePreferenceSkillNames(prefs?.always_use_skills ?? [], params.base)) {
|
|
142
159
|
matched.add(name);
|
|
143
160
|
}
|
|
144
|
-
const ruleMatches = resolveSkillRuleMatches(prefs, contextTokens, params.base);
|
|
161
|
+
const ruleMatches = resolveSkillRuleMatches(prefs, contextTokens, params.base, params.unitType);
|
|
145
162
|
for (const name of ruleMatches.include)
|
|
146
163
|
matched.add(name);
|
|
147
164
|
for (const name of ruleMatches.avoid)
|
|
@@ -313,7 +313,8 @@ export function repairArtifactDbDrift(record, ctx) {
|
|
|
313
313
|
throw new Error(`Artifact/DB status drift in ${record.milestoneId}` +
|
|
314
314
|
`${record.sliceId ? `/${record.sliceId}` : ""}` +
|
|
315
315
|
`${record.taskId ? `/${record.taskId}` : ""}: ${record.reason}. ` +
|
|
316
|
-
"Runtime will not silently import completion artifacts into DB state
|
|
316
|
+
"Runtime will not silently import completion artifacts into DB state. " +
|
|
317
|
+
"Run `/gsd rebuild markdown` after review to quarantine stale projections and re-render from the DB; use `/gsd recover --confirm` only when markdown should repopulate a lost or corrupt DB.");
|
|
317
318
|
}
|
|
318
319
|
export function describeArtifactDbDriftBlocker(record) {
|
|
319
320
|
if (record.kind === "disk-slice-id-divergence") {
|
|
@@ -329,7 +330,8 @@ export function describeArtifactDbDriftBlocker(record) {
|
|
|
329
330
|
return (`Artifact/DB status drift in ${record.milestoneId}` +
|
|
330
331
|
`${record.sliceId ? `/${record.sliceId}` : ""}` +
|
|
331
332
|
`${record.taskId ? `/${record.taskId}` : ""}: ${record.reason}. ` +
|
|
332
|
-
"Runtime will not silently import completion artifacts into DB state
|
|
333
|
+
"Runtime will not silently import completion artifacts into DB state. " +
|
|
334
|
+
"Run `/gsd rebuild markdown` after review to quarantine stale projections and re-render from the DB; use `/gsd recover --confirm` only when markdown should repopulate a lost or corrupt DB.");
|
|
333
335
|
}
|
|
334
336
|
export const diskSliceIdDivergenceHandler = {
|
|
335
337
|
kind: "disk-slice-id-divergence",
|
|
@@ -36,7 +36,7 @@ export function detectUnregisteredMilestoneDrift(_state, ctx) {
|
|
|
36
36
|
*/
|
|
37
37
|
export function repairUnregisteredMilestone(record, _ctx) {
|
|
38
38
|
throw new Error(`Milestone ${record.milestoneId} exists only as markdown projection. ` +
|
|
39
|
-
"Runtime reconciliation will not import markdown into the authoritative DB; run `/gsd recover` if this markdown should repopulate the database.");
|
|
39
|
+
"Runtime reconciliation will not import markdown into the authoritative DB; run `/gsd recover --confirm` if this markdown should repopulate the database.");
|
|
40
40
|
}
|
|
41
41
|
export const unregisteredMilestoneHandler = {
|
|
42
42
|
kind: "unregistered-milestone",
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
// checkboxes) and the DB slice rows for that milestone, then re-renders the
|
|
5
5
|
// ROADMAP projection from the authoritative DB rows.
|
|
6
6
|
import { existsSync, readFileSync } from "node:fs";
|
|
7
|
-
import { getMilestone, getMilestoneSlices, isDbAvailable, } from "../../gsd-db.js";
|
|
7
|
+
import { getMilestone, getMilestoneSlices, getSliceTasks, isDbAvailable, } from "../../gsd-db.js";
|
|
8
8
|
import { renderRoadmapFromDb } from "../../markdown-renderer.js";
|
|
9
9
|
import { findMilestoneIds } from "../../milestone-ids.js";
|
|
10
10
|
import { parseRoadmap } from "../../parsers-legacy.js";
|
|
@@ -18,6 +18,15 @@ function arraysEqual(a, b) {
|
|
|
18
18
|
return false;
|
|
19
19
|
return true;
|
|
20
20
|
}
|
|
21
|
+
function getSlicesReadyForDivergenceCheck(milestoneId, dbSlices) {
|
|
22
|
+
const ready = new Set();
|
|
23
|
+
for (const slice of dbSlices) {
|
|
24
|
+
if (isClosedStatus(slice.status) || getSliceTasks(milestoneId, slice.id).length > 0) {
|
|
25
|
+
ready.add(slice.id);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return ready;
|
|
29
|
+
}
|
|
21
30
|
function milestoneHasDivergence(basePath, milestoneId) {
|
|
22
31
|
const roadmapPath = resolveMilestoneFile(basePath, milestoneId, "ROADMAP");
|
|
23
32
|
if (!roadmapPath || !existsSync(roadmapPath))
|
|
@@ -31,6 +40,10 @@ function milestoneHasDivergence(basePath, milestoneId) {
|
|
|
31
40
|
}
|
|
32
41
|
const dbSlices = getMilestoneSlices(milestoneId);
|
|
33
42
|
const dbSliceMap = new Map(dbSlices.map((s) => [s.id, s]));
|
|
43
|
+
const readySliceIds = getSlicesReadyForDivergenceCheck(milestoneId, dbSlices);
|
|
44
|
+
if (dbSlices.length > 0 && readySliceIds.size === 0) {
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
34
47
|
const roadmapSliceIds = new Set();
|
|
35
48
|
for (let i = 0; i < roadmap.slices.length; i++) {
|
|
36
49
|
const roadmapSlice = roadmap.slices[i];
|
|
@@ -39,6 +52,8 @@ function milestoneHasDivergence(basePath, milestoneId) {
|
|
|
39
52
|
const dbSlice = dbSliceMap.get(roadmapSlice.id);
|
|
40
53
|
if (!dbSlice)
|
|
41
54
|
return true; // Roadmap has a slice the DB doesn't.
|
|
55
|
+
if (!readySliceIds.has(dbSlice.id))
|
|
56
|
+
continue;
|
|
42
57
|
if (dbSlice.sequence !== expectedSequence)
|
|
43
58
|
return true;
|
|
44
59
|
if (!arraysEqual(dbSlice.depends, roadmapSlice.depends))
|
|
@@ -47,6 +62,8 @@ function milestoneHasDivergence(basePath, milestoneId) {
|
|
|
47
62
|
return true;
|
|
48
63
|
}
|
|
49
64
|
for (const dbSlice of dbSlices) {
|
|
65
|
+
if (!readySliceIds.has(dbSlice.id))
|
|
66
|
+
continue;
|
|
50
67
|
if (!roadmapSliceIds.has(dbSlice.id))
|
|
51
68
|
return true;
|
|
52
69
|
}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
// File Purpose: ADR-017 drift-driven State Reconciliation Module entry point.
|
|
3
3
|
// reconcileBeforeDispatch runs before every Dispatch decision and worker spawn.
|
|
4
4
|
import { deriveState as defaultDeriveState, invalidateStateCache as defaultInvalidate, } from "../state.js";
|
|
5
|
+
import { clearParseCache as defaultClearParseCache } from "../files.js";
|
|
5
6
|
import { ReconciliationFailedError, } from "./errors.js";
|
|
6
7
|
import { DRIFT_REGISTRY } from "./registry.js";
|
|
7
8
|
export { ReconciliationFailedError } from "./errors.js";
|
|
@@ -10,6 +11,7 @@ const MAX_PASSES = 2;
|
|
|
10
11
|
const defaultDeps = {
|
|
11
12
|
invalidateStateCache: defaultInvalidate,
|
|
12
13
|
deriveState: defaultDeriveState,
|
|
14
|
+
clearParseCache: defaultClearParseCache,
|
|
13
15
|
};
|
|
14
16
|
/**
|
|
15
17
|
* Drift-driven pre-dispatch reconciliation per ADR-017.
|
|
@@ -27,6 +29,7 @@ const defaultDeps = {
|
|
|
27
29
|
*/
|
|
28
30
|
export async function reconcileBeforeDispatch(basePath, deps = defaultDeps) {
|
|
29
31
|
const registry = deps.registry ?? DRIFT_REGISTRY;
|
|
32
|
+
const clearParseCache = deps.clearParseCache ?? defaultClearParseCache;
|
|
30
33
|
const repaired = [];
|
|
31
34
|
for (let pass = 0; pass < MAX_PASSES; pass++) {
|
|
32
35
|
deps.invalidateStateCache();
|
|
@@ -67,6 +70,9 @@ export async function reconcileBeforeDispatch(basePath, deps = defaultDeps) {
|
|
|
67
70
|
failures.push({ drift: record, cause });
|
|
68
71
|
}
|
|
69
72
|
}
|
|
73
|
+
if (repairedThisPass) {
|
|
74
|
+
clearParseCache();
|
|
75
|
+
}
|
|
70
76
|
if (blockers.length > 0) {
|
|
71
77
|
let blockerState = stateSnapshot;
|
|
72
78
|
if (repairedThisPass) {
|
|
@@ -35,7 +35,7 @@ function formatNeedsRemediationBlocker(milestoneId) {
|
|
|
35
35
|
return [
|
|
36
36
|
`Milestone ${milestoneId} is blocked because milestone validation returned needs-remediation, but all slices are complete.`,
|
|
37
37
|
`Fix options:`,
|
|
38
|
-
`1.
|
|
38
|
+
`1. Run \`/gsd dispatch reassess\` to add remediation slices, then run \`/gsd auto\``,
|
|
39
39
|
`2. If the finding is acceptable, override it: \`/gsd verdict pass --rationale "why this is okay"\``,
|
|
40
40
|
`3. If this should wait, defer it explicitly: \`/gsd park ${milestoneId}\``,
|
|
41
41
|
].join("\n");
|
|
@@ -204,10 +204,16 @@ export function invalidateStateCache() {
|
|
|
204
204
|
/**
|
|
205
205
|
* Returns the ID of the first incomplete milestone, or null if all are complete.
|
|
206
206
|
*/
|
|
207
|
+
function getRequestedMilestoneLock() {
|
|
208
|
+
const lock = process.env.GSD_MILESTONE_LOCK?.trim();
|
|
209
|
+
return lock || undefined;
|
|
210
|
+
}
|
|
207
211
|
export async function getActiveMilestoneId(basePath) {
|
|
208
|
-
//
|
|
209
|
-
//
|
|
210
|
-
|
|
212
|
+
// Milestone-scoped execution. Parallel workers and explicit solo commands
|
|
213
|
+
// such as `/gsd auto M002` both set GSD_MILESTONE_LOCK; state derivation must
|
|
214
|
+
// honor it so recovery/adoption sees the requested milestone, not the first
|
|
215
|
+
// open milestone in queue order.
|
|
216
|
+
const milestoneLock = getRequestedMilestoneLock();
|
|
211
217
|
if (milestoneLock) {
|
|
212
218
|
if (isDbAvailable()) {
|
|
213
219
|
const locked = getAllMilestones().find(m => m.id === milestoneLock);
|
|
@@ -573,7 +579,7 @@ function checkReplanTrigger(basePath, milestoneId, sliceId) {
|
|
|
573
579
|
export async function deriveStateFromDb(basePath, artifactReadRoot = basePath) {
|
|
574
580
|
const requirements = getRequirementCounts();
|
|
575
581
|
const allMilestones = getAllMilestones();
|
|
576
|
-
const milestoneLock =
|
|
582
|
+
const milestoneLock = getRequestedMilestoneLock();
|
|
577
583
|
const milestones = milestoneLock
|
|
578
584
|
? allMilestones.filter(m => m.id === milestoneLock)
|
|
579
585
|
: allMilestones;
|
|
@@ -718,8 +724,8 @@ export async function deriveStateFromDb(basePath, artifactReadRoot = basePath) {
|
|
|
718
724
|
}
|
|
719
725
|
}
|
|
720
726
|
// ADR-011 Phase 2: pause-on-escalation takes precedence over dispatching the
|
|
721
|
-
// next task. `awaiting_review` tasks (continueWithDefault=true)
|
|
722
|
-
//
|
|
727
|
+
// next task. `awaiting_review` tasks (continueWithDefault=true) still pause
|
|
728
|
+
// here so silence is never treated as consent.
|
|
723
729
|
//
|
|
724
730
|
// We do NOT gate this on `phases.mid_execution_escalation` — creation of
|
|
725
731
|
// new escalations is gated at the write site (tools/complete-task.ts:315),
|
|
@@ -779,13 +785,10 @@ export async function _deriveStateImpl(basePath, opts) {
|
|
|
779
785
|
const diskIds = findMilestoneIds(basePath);
|
|
780
786
|
const customOrder = loadQueueOrder(basePath);
|
|
781
787
|
const milestoneIds = sortByQueueOrder(diskIds, customOrder);
|
|
782
|
-
// ──
|
|
783
|
-
//
|
|
784
|
-
//
|
|
785
|
-
|
|
786
|
-
// don't exist). This gives each worker complete isolation without
|
|
787
|
-
// modifying any other state derivation logic.
|
|
788
|
-
const milestoneLock = process.env.GSD_PARALLEL_WORKER ? process.env.GSD_MILESTONE_LOCK : undefined;
|
|
788
|
+
// ── Milestone-scoped execution ─────────────────────────────────────────
|
|
789
|
+
// Parallel workers and explicit solo recovery both scope auto-mode to one
|
|
790
|
+
// milestone through GSD_MILESTONE_LOCK.
|
|
791
|
+
const milestoneLock = getRequestedMilestoneLock();
|
|
789
792
|
if (milestoneLock && milestoneIds.includes(milestoneLock)) {
|
|
790
793
|
milestoneIds.length = 0;
|
|
791
794
|
milestoneIds.push(milestoneLock);
|
|
@@ -132,14 +132,16 @@
|
|
|
132
132
|
Verify field rules:
|
|
133
133
|
- MUST be a mechanically executable command: `npm test`, `grep -q "pattern" file`, `test -f path`
|
|
134
134
|
- MUST NOT use shell pipes, redirects, semicolons, backticks, command substitution, output trimming, or grep regex alternation with `|`
|
|
135
|
+
- For absence checks, use `! grep -q "pattern" file` or `! rg -q "pattern" file`; do not use `grep -c` or `rg -c` to assert zero matches because count commands exit 1 when they find zero matches
|
|
135
136
|
- MUST NOT use inline `node -e` assertions for verification; put assertions in a real test file and run it with `node --test` or a package test script
|
|
136
137
|
- For content/document tasks: verify file existence, section count, YAML validity, or word count
|
|
137
138
|
NOT exact phrasing, specific formulas, or "zero TBD" aspirational criteria
|
|
138
139
|
- If no command can verify the output, write: "Manual review — file exists and is non-empty"
|
|
139
140
|
- BAD: `python3 -m pytest tests/ -q --tb=short 2>&1 | tail -5`
|
|
141
|
+
- BAD: `grep -c "old_api" src/index.ts`
|
|
140
142
|
- BAD: "Sections 3.1 and 3.2 exist with exact formulas. Zero TBD/TODO."
|
|
141
143
|
- GOOD: `python3 -m pytest tests/ -q --tb=short`
|
|
142
|
-
- GOOD: `node --test tests/verify-doc.test.js`, `grep -q "Required heading" doc.md`, `test -s doc.md`
|
|
144
|
+
- GOOD: `node --test tests/verify-doc.test.js`, `grep -q "Required heading" doc.md`, `! grep -q "old_api" src/index.ts`, `test -s doc.md`
|
|
143
145
|
|
|
144
146
|
Integration closure rule:
|
|
145
147
|
- At least one slice in any multi-boundary milestone should perform real composition/wiring, not just contract hardening
|
|
@@ -2,8 +2,10 @@
|
|
|
2
2
|
// File Purpose: ADR-015 Tool Contract module for Unit prompt, policy, and tool parity.
|
|
3
3
|
import { resolveManifest, } from "./unit-context-manifest.js";
|
|
4
4
|
import { getRequiredWorkflowToolsForAutoUnit } from "./workflow-mcp.js";
|
|
5
|
+
import { getUnitToolSurfaceContract } from "./unit-tool-contracts.js";
|
|
5
6
|
export function compileUnitToolContract(unitType) {
|
|
6
7
|
const manifest = resolveManifest(unitType);
|
|
8
|
+
const surfaceContract = getUnitToolSurfaceContract(unitType);
|
|
7
9
|
if (!manifest) {
|
|
8
10
|
return {
|
|
9
11
|
ok: false,
|
|
@@ -12,6 +14,8 @@ export function compileUnitToolContract(unitType) {
|
|
|
12
14
|
};
|
|
13
15
|
}
|
|
14
16
|
const requiredWorkflowTools = getRequiredWorkflowToolsForAutoUnit(unitType);
|
|
17
|
+
const forbiddenWorkflowTools = Object.entries(surfaceContract?.forbiddenGsdTools ?? {})
|
|
18
|
+
.map(([name, reason]) => ({ name, reason }));
|
|
15
19
|
const closeoutTools = requiredWorkflowTools.filter((tool) => /^gsd_(?:task|slice|milestone|complete|validate|save|summary)/.test(tool));
|
|
16
20
|
if (requiresCloseoutTool(unitType) && closeoutTools.length === 0) {
|
|
17
21
|
return {
|
|
@@ -27,6 +31,7 @@ export function compileUnitToolContract(unitType) {
|
|
|
27
31
|
contextMode: manifest.contextMode,
|
|
28
32
|
toolsPolicy: manifest.tools,
|
|
29
33
|
requiredWorkflowTools,
|
|
34
|
+
forbiddenWorkflowTools,
|
|
30
35
|
promptObligations: [
|
|
31
36
|
`context-mode:${manifest.contextMode}`,
|
|
32
37
|
`tools-policy:${manifest.tools.mode}`,
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
// Project/App: gsd-pi
|
|
2
|
+
// File Purpose: Resolve phase-aware tool surfaces for GSD model presentations.
|
|
3
|
+
import { RUN_UAT_BROWSER_TOOL_NAMES, RUN_UAT_READ_ONLY_TOOL_NAMES, RUN_UAT_TOOL_PRESENTATION_PLAN_ID, RUN_UAT_WORKFLOW_TOOL_NAMES, } from "./unit-tool-contracts.js";
|
|
4
|
+
export { RUN_UAT_BROWSER_TOOL_NAMES, RUN_UAT_READ_ONLY_TOOL_NAMES, RUN_UAT_TOOL_PRESENTATION_PLAN_ID, RUN_UAT_WORKFLOW_TOOL_NAMES, } from "./unit-tool-contracts.js";
|
|
5
|
+
export const RUN_UAT_FORBIDDEN_TOOL_NAMES = [
|
|
6
|
+
"edit",
|
|
7
|
+
"write",
|
|
8
|
+
"gsd_exec",
|
|
9
|
+
"gsd_summary_save",
|
|
10
|
+
"gsd_save_gate_result",
|
|
11
|
+
"search-the-web",
|
|
12
|
+
"WebSearch",
|
|
13
|
+
"Bash",
|
|
14
|
+
"Write",
|
|
15
|
+
"Edit",
|
|
16
|
+
"mcp__gsd-workflow__*",
|
|
17
|
+
];
|
|
18
|
+
export const RUN_UAT_CLAUDE_NATIVE_TOOL_NAMES = [
|
|
19
|
+
"Read",
|
|
20
|
+
"Glob",
|
|
21
|
+
"Grep",
|
|
22
|
+
];
|
|
23
|
+
const WORKFLOW_ALIAS_TO_CANONICAL = {
|
|
24
|
+
gsd_save_decision: "gsd_decision_save",
|
|
25
|
+
gsd_update_requirement: "gsd_requirement_update",
|
|
26
|
+
gsd_save_requirement: "gsd_requirement_save",
|
|
27
|
+
gsd_save_summary: "gsd_summary_save",
|
|
28
|
+
gsd_generate_milestone_id: "gsd_milestone_generate_id",
|
|
29
|
+
gsd_milestone_plan: "gsd_plan_milestone",
|
|
30
|
+
gsd_slice_plan: "gsd_plan_slice",
|
|
31
|
+
gsd_task_plan: "gsd_plan_task",
|
|
32
|
+
gsd_slice_replan: "gsd_replan_slice",
|
|
33
|
+
gsd_complete_slice: "gsd_slice_complete",
|
|
34
|
+
gsd_milestone_complete: "gsd_complete_milestone",
|
|
35
|
+
gsd_milestone_validate: "gsd_validate_milestone",
|
|
36
|
+
gsd_roadmap_reassess: "gsd_reassess_roadmap",
|
|
37
|
+
gsd_complete_task: "gsd_task_complete",
|
|
38
|
+
gsd_reopen_task: "gsd_task_reopen",
|
|
39
|
+
gsd_reopen_slice: "gsd_slice_reopen",
|
|
40
|
+
gsd_reopen_milestone: "gsd_milestone_reopen",
|
|
41
|
+
};
|
|
42
|
+
export function canonicalWorkflowToolName(toolName) {
|
|
43
|
+
const mcp = parseMcpToolName(toolName);
|
|
44
|
+
const baseName = mcp?.tool ?? toolName;
|
|
45
|
+
return WORKFLOW_ALIAS_TO_CANONICAL[baseName] ?? baseName;
|
|
46
|
+
}
|
|
47
|
+
export function parseMcpToolName(toolName) {
|
|
48
|
+
if (!toolName.startsWith("mcp__"))
|
|
49
|
+
return null;
|
|
50
|
+
const toolSeparator = toolName.indexOf("__", "mcp__".length);
|
|
51
|
+
if (toolSeparator < 0)
|
|
52
|
+
return null;
|
|
53
|
+
return {
|
|
54
|
+
server: toolName.slice("mcp__".length, toolSeparator),
|
|
55
|
+
tool: toolName.slice(toolSeparator + 2),
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
export function toWorkflowMcpToolName(serverName, toolName) {
|
|
59
|
+
return `mcp__${serverName}__${canonicalWorkflowToolName(toolName)}`;
|
|
60
|
+
}
|
|
61
|
+
function dedupe(values) {
|
|
62
|
+
return [...new Set(values)];
|
|
63
|
+
}
|
|
64
|
+
function addBlockedTool(blocked, name, reason) {
|
|
65
|
+
if (!blocked.some((entry) => entry.name === name)) {
|
|
66
|
+
blocked.push({ name, reason });
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
export function buildRunUatCanonicalToolNames(options = {}) {
|
|
70
|
+
return dedupe([
|
|
71
|
+
...RUN_UAT_WORKFLOW_TOOL_NAMES,
|
|
72
|
+
...RUN_UAT_READ_ONLY_TOOL_NAMES,
|
|
73
|
+
...(options.includeBrowserTools ?? []),
|
|
74
|
+
]);
|
|
75
|
+
}
|
|
76
|
+
export function runUatBrowserToolsForType(uatType) {
|
|
77
|
+
return uatType === "browser-executable" ? RUN_UAT_BROWSER_TOOL_NAMES : [];
|
|
78
|
+
}
|
|
79
|
+
export function runUatPresentationSurfaceForType(uatType) {
|
|
80
|
+
return uatType === "browser-executable" ? "hybrid" : "mcp";
|
|
81
|
+
}
|
|
82
|
+
export function buildRunUatPresentationForType(uatType, options = {}) {
|
|
83
|
+
return buildRunUatResultPresentation({
|
|
84
|
+
...options,
|
|
85
|
+
surface: options.surface ?? runUatPresentationSurfaceForType(uatType),
|
|
86
|
+
includeBrowserTools: runUatBrowserToolsForType(uatType),
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
export function buildRunUatResultPresentation(options = {}) {
|
|
90
|
+
const presentedTools = options.presentedTools
|
|
91
|
+
? dedupe(options.presentedTools)
|
|
92
|
+
: buildRunUatCanonicalToolNames({ includeBrowserTools: options.includeBrowserTools });
|
|
93
|
+
const blockedTools = RUN_UAT_FORBIDDEN_TOOL_NAMES
|
|
94
|
+
.filter((toolName) => !toolName.includes("*"))
|
|
95
|
+
.map((name) => ({ name, reason: "forbidden during run-uat" }));
|
|
96
|
+
return {
|
|
97
|
+
surface: options.surface ?? "mcp",
|
|
98
|
+
presentedTools,
|
|
99
|
+
blockedTools,
|
|
100
|
+
toolPresentationPlanId: RUN_UAT_TOOL_PRESENTATION_PLAN_ID,
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
export function resolveToolPresentationPlan(options) {
|
|
104
|
+
const requested = options.requestedToolNames ?? (options.phase === "run-uat"
|
|
105
|
+
? buildRunUatCanonicalToolNames({ includeBrowserTools: options.includeBrowserTools })
|
|
106
|
+
: []);
|
|
107
|
+
const available = new Set(options.availableToolNames ?? requested);
|
|
108
|
+
const aliases = [];
|
|
109
|
+
const blockedToolNames = [];
|
|
110
|
+
const allowed = [];
|
|
111
|
+
for (const name of requested) {
|
|
112
|
+
const canonical = canonicalWorkflowToolName(name);
|
|
113
|
+
if (canonical !== name)
|
|
114
|
+
aliases.push({ requested: name, canonical });
|
|
115
|
+
if (!available.has(name) && !available.has(canonical)) {
|
|
116
|
+
addBlockedTool(blockedToolNames, canonical, "not registered or provider-incompatible");
|
|
117
|
+
continue;
|
|
118
|
+
}
|
|
119
|
+
allowed.push(canonical);
|
|
120
|
+
}
|
|
121
|
+
const allowedToolNames = dedupe(allowed);
|
|
122
|
+
const workflowServerName = options.workflowMcpServerName || "gsd-workflow";
|
|
123
|
+
const presentedToolNames = options.surface === "claude-code-sdk" || options.surface === "mcp"
|
|
124
|
+
? allowedToolNames.map((name) => name.startsWith("gsd_") || name === "ask_user_questions"
|
|
125
|
+
? toWorkflowMcpToolName(workflowServerName, name)
|
|
126
|
+
: name)
|
|
127
|
+
: allowedToolNames;
|
|
128
|
+
if (options.phase === "run-uat") {
|
|
129
|
+
for (const forbidden of RUN_UAT_FORBIDDEN_TOOL_NAMES) {
|
|
130
|
+
addBlockedTool(blockedToolNames, forbidden, "forbidden during run-uat");
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
return {
|
|
134
|
+
phase: options.phase,
|
|
135
|
+
surface: options.surface,
|
|
136
|
+
model: options.model,
|
|
137
|
+
allowedToolNames,
|
|
138
|
+
presentedToolNames,
|
|
139
|
+
blockedToolNames,
|
|
140
|
+
aliases,
|
|
141
|
+
diagnostics: [],
|
|
142
|
+
};
|
|
143
|
+
}
|
|
@@ -158,7 +158,7 @@ ${params.narrative}
|
|
|
158
158
|
|
|
159
159
|
## Verification
|
|
160
160
|
|
|
161
|
-
${params.verification}
|
|
161
|
+
${params.verification ?? ""}
|
|
162
162
|
|
|
163
163
|
## Requirements Advanced
|
|
164
164
|
|
|
@@ -351,6 +351,20 @@ export async function handleCompleteSlice(params, basePath) {
|
|
|
351
351
|
if (parsed.length > 0)
|
|
352
352
|
effectiveParams.requirementsInvalidated = parsed;
|
|
353
353
|
}
|
|
354
|
+
if (effectiveParams.verification === undefined) {
|
|
355
|
+
const headingLine = "## Verification\n\n";
|
|
356
|
+
const start = existingSummaryMd.indexOf(headingLine);
|
|
357
|
+
if (start !== -1) {
|
|
358
|
+
const contentStart = start + headingLine.length;
|
|
359
|
+
const nextHeading = existingSummaryMd.indexOf("\n\n## ", contentStart);
|
|
360
|
+
const prior = nextHeading === -1
|
|
361
|
+
? existingSummaryMd.slice(contentStart)
|
|
362
|
+
: existingSummaryMd.slice(contentStart, nextHeading);
|
|
363
|
+
const trimmed = prior.trim();
|
|
364
|
+
if (trimmed)
|
|
365
|
+
effectiveParams.verification = trimmed;
|
|
366
|
+
}
|
|
367
|
+
}
|
|
354
368
|
}
|
|
355
369
|
// Render summary markdown
|
|
356
370
|
const summaryMd = renderSliceSummaryMarkdown(effectiveParams);
|
|
@@ -314,9 +314,18 @@ export async function handleCompleteTask(params, basePath) {
|
|
|
314
314
|
// overwrite it; gate rows are UPSERT-keyed per task and will also be
|
|
315
315
|
// overwritten. This restores the invariant that deriveState() sees a
|
|
316
316
|
// consistent "task not done" view so the loop re-dispatches the task.
|
|
317
|
+
let escalationMetadata;
|
|
317
318
|
if (validatedEscalationArtifact) {
|
|
318
319
|
try {
|
|
319
|
-
writeEscalationArtifact(artifactBasePath, validatedEscalationArtifact);
|
|
320
|
+
const escalationPath = writeEscalationArtifact(artifactBasePath, validatedEscalationArtifact);
|
|
321
|
+
escalationMetadata = {
|
|
322
|
+
artifactPath: escalationPath,
|
|
323
|
+
question: validatedEscalationArtifact.question,
|
|
324
|
+
options: validatedEscalationArtifact.options,
|
|
325
|
+
recommendation: validatedEscalationArtifact.recommendation,
|
|
326
|
+
recommendationRationale: validatedEscalationArtifact.recommendationRationale,
|
|
327
|
+
continueWithDefault: validatedEscalationArtifact.continueWithDefault,
|
|
328
|
+
};
|
|
320
329
|
}
|
|
321
330
|
catch (escalationErr) {
|
|
322
331
|
const msg = `complete-task escalation write failed for ${params.milestoneId}/${params.sliceId}/${params.taskId}: ${escalationErr.message}`;
|
|
@@ -378,6 +387,7 @@ export async function handleCompleteTask(params, basePath) {
|
|
|
378
387
|
sliceId: params.sliceId,
|
|
379
388
|
milestoneId: params.milestoneId,
|
|
380
389
|
summaryPath,
|
|
390
|
+
...(escalationMetadata ? { escalation: escalationMetadata } : {}),
|
|
381
391
|
...(projectionStale ? { stale: true } : {}),
|
|
382
392
|
};
|
|
383
393
|
}
|
|
@@ -5,6 +5,27 @@ import { realpathSync } from "node:fs";
|
|
|
5
5
|
import path from "node:path";
|
|
6
6
|
import { isContextModeEnabled } from "../preferences-types.js";
|
|
7
7
|
import { contextModeDisabledResult } from "./context-mode-tool-result.js";
|
|
8
|
+
const UAT_EXEC_INTENTS = [
|
|
9
|
+
"uat-artifact-check",
|
|
10
|
+
"uat-runtime-check",
|
|
11
|
+
"uat-browser-check",
|
|
12
|
+
"uat-service-start",
|
|
13
|
+
"uat-log-inspection",
|
|
14
|
+
];
|
|
15
|
+
const UAT_EXEC_INTENT_ALIASES = {
|
|
16
|
+
artifact: "uat-artifact-check",
|
|
17
|
+
"artifact-driven": "uat-artifact-check",
|
|
18
|
+
runtime: "uat-runtime-check",
|
|
19
|
+
"runtime-executable": "uat-runtime-check",
|
|
20
|
+
"live-runtime": "uat-runtime-check",
|
|
21
|
+
browser: "uat-browser-check",
|
|
22
|
+
"browser-executable": "uat-browser-check",
|
|
23
|
+
service: "uat-service-start",
|
|
24
|
+
"service-start": "uat-service-start",
|
|
25
|
+
log: "uat-log-inspection",
|
|
26
|
+
logs: "uat-log-inspection",
|
|
27
|
+
"log-inspection": "uat-log-inspection",
|
|
28
|
+
};
|
|
8
29
|
export function buildExecOptions(baseDir, cfg, extras) {
|
|
9
30
|
const allowlist = Array.isArray(cfg?.exec_env_allowlist) ? cfg.exec_env_allowlist : EXEC_DEFAULTS.envAllowlist;
|
|
10
31
|
const stdoutCap = clampNumber(cfg?.exec_stdout_cap_bytes, EXEC_DEFAULTS.stdoutCapBytes, 4_096, 16_777_216);
|
|
@@ -73,6 +94,39 @@ function normalizeScript(params) {
|
|
|
73
94
|
}
|
|
74
95
|
return paramError("script is required and must be a non-empty string");
|
|
75
96
|
}
|
|
97
|
+
function normalizeRequiredString(value, field) {
|
|
98
|
+
if (typeof value !== "string" || value.trim().length === 0) {
|
|
99
|
+
return paramError(`${field} is required and must be a non-empty string`);
|
|
100
|
+
}
|
|
101
|
+
return value.trim();
|
|
102
|
+
}
|
|
103
|
+
function normalizeUatIntent(value) {
|
|
104
|
+
if (typeof value !== "string") {
|
|
105
|
+
return paramError(`intent is required and must be one of: ${UAT_EXEC_INTENTS.join(", ")}`);
|
|
106
|
+
}
|
|
107
|
+
const normalized = value.trim().toLowerCase();
|
|
108
|
+
if (UAT_EXEC_INTENTS.includes(normalized))
|
|
109
|
+
return normalized;
|
|
110
|
+
const alias = UAT_EXEC_INTENT_ALIASES[normalized];
|
|
111
|
+
if (alias)
|
|
112
|
+
return alias;
|
|
113
|
+
return paramError(`invalid intent "${value}" — must be one of: ${UAT_EXEC_INTENTS.join(", ")}`);
|
|
114
|
+
}
|
|
115
|
+
function rejectUatScript(script) {
|
|
116
|
+
const patterns = [
|
|
117
|
+
{ re: /\b(?:npm|pnpm|yarn|bun)\s+(?:i|install|add|remove|update|upgrade)\b/i, reason: "package dependency mutation is not allowed during UAT" },
|
|
118
|
+
{ re: /\b(?:pip|pip3|python\s+-m\s+pip)\s+install\b/i, reason: "package dependency mutation is not allowed during UAT" },
|
|
119
|
+
{ re: /\bgit\s+(?:add|commit|push|reset|checkout|switch|merge|rebase|clean|rm|mv|tag|branch)\b/i, reason: "git mutations are not allowed during UAT" },
|
|
120
|
+
{ re: /\brm\s+-[^\n\r;|&]*r[^\n\r;|&]*f\b/i, reason: "destructive filesystem cleanup is not allowed during UAT" },
|
|
121
|
+
{ re: /\b(?:env|printenv)\b(?:\s|$)/i, reason: "dumping environment variables is not allowed during UAT" },
|
|
122
|
+
{ re: /\bcat\s+\.env(?:\b|\.|$)/i, reason: "reading credential files is not allowed during UAT" },
|
|
123
|
+
];
|
|
124
|
+
for (const pattern of patterns) {
|
|
125
|
+
if (pattern.re.test(script))
|
|
126
|
+
return pattern.reason;
|
|
127
|
+
}
|
|
128
|
+
return null;
|
|
129
|
+
}
|
|
76
130
|
function isToolExecutionResult(value) {
|
|
77
131
|
return typeof value === "object" && value !== null && Array.isArray(value.content);
|
|
78
132
|
}
|
|
@@ -207,6 +261,7 @@ export async function executeGsdExec(params, deps) {
|
|
|
207
261
|
runtime,
|
|
208
262
|
script,
|
|
209
263
|
...(typeof params.purpose === "string" ? { purpose: params.purpose } : {}),
|
|
264
|
+
...(params.metadata && typeof params.metadata === "object" ? { metadata: params.metadata } : {}),
|
|
210
265
|
...(typeof params.timeout_ms === "number" ? { timeout_ms: params.timeout_ms } : {}),
|
|
211
266
|
}, opts);
|
|
212
267
|
return formatResult(result);
|
|
@@ -220,6 +275,60 @@ export async function executeGsdExec(params, deps) {
|
|
|
220
275
|
};
|
|
221
276
|
}
|
|
222
277
|
}
|
|
278
|
+
export async function executeUatExec(params, deps) {
|
|
279
|
+
const milestoneId = normalizeRequiredString(params.milestoneId, "milestoneId");
|
|
280
|
+
if (isToolExecutionResult(milestoneId))
|
|
281
|
+
return milestoneId;
|
|
282
|
+
const sliceId = normalizeRequiredString(params.sliceId, "sliceId");
|
|
283
|
+
if (isToolExecutionResult(sliceId))
|
|
284
|
+
return sliceId;
|
|
285
|
+
const checkId = normalizeRequiredString(params.checkId, "checkId");
|
|
286
|
+
if (isToolExecutionResult(checkId))
|
|
287
|
+
return checkId;
|
|
288
|
+
const intent = normalizeUatIntent(params.intent);
|
|
289
|
+
if (isToolExecutionResult(intent))
|
|
290
|
+
return intent;
|
|
291
|
+
const script = normalizeScript(params);
|
|
292
|
+
if (isToolExecutionResult(script))
|
|
293
|
+
return script;
|
|
294
|
+
const rejected = rejectUatScript(script);
|
|
295
|
+
if (rejected) {
|
|
296
|
+
return {
|
|
297
|
+
content: [{ type: "text", text: `Error: gsd_uat_exec blocked command — ${rejected}` }],
|
|
298
|
+
details: { operation: "gsd_uat_exec", error: "uat_exec_policy_block", reason: rejected },
|
|
299
|
+
isError: true,
|
|
300
|
+
};
|
|
301
|
+
}
|
|
302
|
+
const result = await executeGsdExec({
|
|
303
|
+
...params,
|
|
304
|
+
script,
|
|
305
|
+
purpose: typeof params.purpose === "string" && params.purpose.trim().length > 0
|
|
306
|
+
? params.purpose
|
|
307
|
+
: `UAT ${milestoneId}/${sliceId}/${checkId} (${intent})`,
|
|
308
|
+
metadata: {
|
|
309
|
+
kind: "uat_exec",
|
|
310
|
+
milestoneId,
|
|
311
|
+
sliceId,
|
|
312
|
+
checkId,
|
|
313
|
+
intent,
|
|
314
|
+
...(typeof params.expected === "string" && params.expected.trim().length > 0
|
|
315
|
+
? { expected: params.expected.trim() }
|
|
316
|
+
: {}),
|
|
317
|
+
},
|
|
318
|
+
}, deps);
|
|
319
|
+
const details = result.details ?? {};
|
|
320
|
+
return {
|
|
321
|
+
...result,
|
|
322
|
+
details: {
|
|
323
|
+
...details,
|
|
324
|
+
operation: "gsd_uat_exec",
|
|
325
|
+
milestoneId,
|
|
326
|
+
sliceId,
|
|
327
|
+
checkId,
|
|
328
|
+
intent,
|
|
329
|
+
},
|
|
330
|
+
};
|
|
331
|
+
}
|
|
223
332
|
function formatResult(result) {
|
|
224
333
|
const headerLines = [
|
|
225
334
|
`gsd_exec[${result.id}] runtime=${result.runtime} exit=${formatExit(result)} duration=${result.duration_ms}ms`,
|
|
@@ -268,15 +268,9 @@ export async function handlePlanSlice(rawParams, basePath) {
|
|
|
268
268
|
for (const taskId of omittedTaskIds) {
|
|
269
269
|
deleteTask(params.milestoneId, params.sliceId, taskId);
|
|
270
270
|
}
|
|
271
|
+
const existingTaskById = new Map(existingTasks.map((task) => [task.id, task]));
|
|
271
272
|
for (const task of params.tasks) {
|
|
272
|
-
|
|
273
|
-
id: task.taskId,
|
|
274
|
-
sliceId: params.sliceId,
|
|
275
|
-
milestoneId: params.milestoneId,
|
|
276
|
-
title: task.title,
|
|
277
|
-
status: "pending",
|
|
278
|
-
});
|
|
279
|
-
upsertTaskPlanning(params.milestoneId, params.sliceId, task.taskId, {
|
|
273
|
+
const planning = {
|
|
280
274
|
title: task.title,
|
|
281
275
|
description: task.description,
|
|
282
276
|
estimate: task.estimate,
|
|
@@ -287,7 +281,18 @@ export async function handlePlanSlice(rawParams, basePath) {
|
|
|
287
281
|
observabilityImpact: task.observabilityImpact ?? "",
|
|
288
282
|
fullPlanMd: task.fullPlanMd,
|
|
289
283
|
targetRepositories: task.targetRepositories ?? params.targetRepositories ?? defaultTargets,
|
|
290
|
-
}
|
|
284
|
+
};
|
|
285
|
+
const existingTask = existingTaskById.get(task.taskId);
|
|
286
|
+
if (!existingTask || !isClosedStatus(existingTask.status)) {
|
|
287
|
+
insertTask({
|
|
288
|
+
id: task.taskId,
|
|
289
|
+
sliceId: params.sliceId,
|
|
290
|
+
milestoneId: params.milestoneId,
|
|
291
|
+
title: task.title,
|
|
292
|
+
status: "pending",
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
upsertTaskPlanning(params.milestoneId, params.sliceId, task.taskId, planning);
|
|
291
296
|
}
|
|
292
297
|
// Seed quality gate rows inside the transaction — all-or-nothing with
|
|
293
298
|
// the plan data so a crash can't leave orphaned gates without tasks.
|