@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
|
@@ -20,6 +20,49 @@ async function loadContextModePreferences(baseDir) {
|
|
|
20
20
|
}
|
|
21
21
|
}
|
|
22
22
|
export function registerExecTools(pi) {
|
|
23
|
+
pi.registerTool({
|
|
24
|
+
name: "gsd_uat_exec",
|
|
25
|
+
label: "UAT Exec",
|
|
26
|
+
description: "Run a UAT-scoped bash/node/python check with milestone/slice/check metadata. " +
|
|
27
|
+
"Uses the same capped .gsd/exec evidence store as gsd_exec, but rejects commands that mutate dependencies, git state, credentials, or destructive files.",
|
|
28
|
+
promptSnippet: "Run one UAT check and save typed evidence under .gsd/exec",
|
|
29
|
+
promptGuidelines: [
|
|
30
|
+
"Use gsd_uat_exec for each automated UAT check.",
|
|
31
|
+
"Every PASS/FAIL check saved by gsd_uat_result_save must reference objective evidence from this tool or another approved GSD evidence path.",
|
|
32
|
+
"Do not install packages, mutate git state, edit source files, or dump credentials during UAT.",
|
|
33
|
+
],
|
|
34
|
+
parameters: Type.Object({
|
|
35
|
+
milestoneId: Type.String({ description: "Milestone ID (e.g. M001)" }),
|
|
36
|
+
sliceId: Type.String({ description: "Slice ID (e.g. S01)" }),
|
|
37
|
+
checkId: Type.String({ description: "Stable check ID from the UAT spec (e.g. UAT-01)" }),
|
|
38
|
+
intent: Type.String({
|
|
39
|
+
description: "UAT command intent. Use one canonical value: uat-artifact-check, uat-runtime-check, " +
|
|
40
|
+
"uat-browser-check, uat-service-start, or uat-log-inspection. Short aliases such as artifact, " +
|
|
41
|
+
"runtime, browser, service-start, and log-inspection are accepted.",
|
|
42
|
+
}),
|
|
43
|
+
runtime: Type.Optional(Type.String({
|
|
44
|
+
description: "Optional interpreter. Defaults to bash. Supported: bash, node, python; sh/shell, js/nodejs, and py/python3 aliases are accepted.",
|
|
45
|
+
})),
|
|
46
|
+
script: Type.Optional(Type.String({ description: "Script body. Keep output small (log the finding, not the data)." })),
|
|
47
|
+
command: Type.Optional(Type.String({ description: "Alias for script; defaults to bash when runtime is omitted." })),
|
|
48
|
+
cmd: Type.Optional(Type.String({ description: "Short alias for script." })),
|
|
49
|
+
code: Type.Optional(Type.String({ description: "Alias for script, useful for node/python snippets." })),
|
|
50
|
+
expected: Type.Optional(Type.String({ description: "Expected outcome for this UAT check." })),
|
|
51
|
+
timeout_ms: Type.Optional(Type.Number({
|
|
52
|
+
description: "Per-invocation timeout (ms). Capped at 600000. Default from preferences.",
|
|
53
|
+
minimum: 1_000,
|
|
54
|
+
maximum: 600_000,
|
|
55
|
+
})),
|
|
56
|
+
}),
|
|
57
|
+
async execute(_toolCallId, params, _signal, _onUpdate, _ctx) {
|
|
58
|
+
const { executeUatExec } = await import("../tools/exec-tool.js");
|
|
59
|
+
const baseDir = resolveCtxCwd(_ctx);
|
|
60
|
+
return executeUatExec(params, {
|
|
61
|
+
baseDir,
|
|
62
|
+
preferences: await loadContextModePreferences(baseDir),
|
|
63
|
+
});
|
|
64
|
+
},
|
|
65
|
+
});
|
|
23
66
|
pi.registerTool({
|
|
24
67
|
name: "gsd_exec",
|
|
25
68
|
label: "Exec (Sandboxed)",
|
|
@@ -11,7 +11,7 @@ import { canonicalToolName, clearDiscussionFlowState, isDepthConfirmationAnswer,
|
|
|
11
11
|
import { resolveManifest } from "../unit-context-manifest.js";
|
|
12
12
|
import { isBlockedStateFile, isBashWriteToStateFile, BLOCKED_WRITE_ERROR } from "../write-intercept.js";
|
|
13
13
|
import { loadFile, saveFile, formatContinue } from "../files.js";
|
|
14
|
-
import { clearToolInvocationError, getAutoRuntimeSnapshot, isAutoActive, isAutoPaused, markToolEnd, markToolStart, recordToolInvocationError } from "../auto-runtime-state.js";
|
|
14
|
+
import { clearToolInvocationError, getAutoRuntimeSnapshot, isAutoActive, isAutoCompletionStopInProgress, isAutoPaused, markToolEnd, markToolStart, recordToolInvocationError } from "../auto-runtime-state.js";
|
|
15
15
|
import { checkToolCallLoop, resetToolCallLoopGuard } from "./tool-call-loop-guard.js";
|
|
16
16
|
import { maybePauseAutoForApprovalGate, resetPendingGatePauseGuard } from "./pending-gate-pause.js";
|
|
17
17
|
import { saveActivityLog } from "../activity-log.js";
|
|
@@ -28,7 +28,9 @@ import { approvalGateIdForUnit, isExplicitApprovalResponse, shouldPauseForUserAp
|
|
|
28
28
|
import { applyUnitSkillVisibility, unitHasSkillManifest } from "../skill-scope.js";
|
|
29
29
|
import { getGuidedUnitContext } from "../guided-unit-context.js";
|
|
30
30
|
import { registerPlanMilestoneSchemaRecovery } from "./plan-milestone-schema-recovery.js";
|
|
31
|
-
import { AUTO_UNIT_SCOPED_TOOLS, isWorkflowAliasTool } from "../auto-unit-tool-scope.js";
|
|
31
|
+
import { AUTO_UNIT_SCOPED_TOOLS, RUN_UAT_BROWSER_TOOL_NAMES, isWorkflowAliasTool } from "../auto-unit-tool-scope.js";
|
|
32
|
+
import { filterToolsForProvider } from "../model-router.js";
|
|
33
|
+
import { RUN_UAT_READ_ONLY_TOOL_NAMES, RUN_UAT_WORKFLOW_TOOL_NAMES } from "../tool-presentation-plan.js";
|
|
32
34
|
let approvalQuestionAbortInFlight = false;
|
|
33
35
|
async function loadWelcomeScreenModule() {
|
|
34
36
|
const candidates = [];
|
|
@@ -104,6 +106,7 @@ export const MINIMAL_GSD_TOOL_NAMES = [
|
|
|
104
106
|
"gsd_resume",
|
|
105
107
|
"gsd_milestone_status",
|
|
106
108
|
"gsd_checkpoint_db",
|
|
109
|
+
"gsd_plan_milestone",
|
|
107
110
|
"memory_query",
|
|
108
111
|
"capture_thought",
|
|
109
112
|
];
|
|
@@ -187,6 +190,9 @@ export function buildMinimalGsdToolSet(activeToolNames) {
|
|
|
187
190
|
return withPreservedShimTools([...new Set([...preserved, ...minimal])]);
|
|
188
191
|
}
|
|
189
192
|
export function buildMinimalAutoGsdToolSet(activeToolNames, unitType, registeredToolNames = activeToolNames) {
|
|
193
|
+
if (unitType === "run-uat") {
|
|
194
|
+
return buildRunUatGsdToolSet(activeToolNames, registeredToolNames);
|
|
195
|
+
}
|
|
190
196
|
const unitTools = unitType ? AUTO_UNIT_SCOPED_TOOLS[unitType] ?? [] : [];
|
|
191
197
|
const autoBaseTools = new Set(MINIMAL_AUTO_BASE_TOOL_NAMES);
|
|
192
198
|
const availableBaseTools = registeredToolNames.filter((name) => autoBaseTools.has(name));
|
|
@@ -197,6 +203,15 @@ export function buildMinimalAutoGsdToolSet(activeToolNames, unitType, registered
|
|
|
197
203
|
const scoped = resolveScopedToolNames([...activeToolNames, ...registeredToolNames], [...MINIMAL_GSD_TOOL_NAMES, ...unitTools]);
|
|
198
204
|
return withPreservedShimTools([...new Set([...preserved, ...scoped])]);
|
|
199
205
|
}
|
|
206
|
+
export function buildRunUatGsdToolSet(activeToolNames, registeredToolNames = activeToolNames) {
|
|
207
|
+
const scoped = resolveScopedToolNames([...activeToolNames, ...registeredToolNames], [
|
|
208
|
+
...RUN_UAT_WORKFLOW_TOOL_NAMES,
|
|
209
|
+
...RUN_UAT_READ_ONLY_TOOL_NAMES,
|
|
210
|
+
"subagent",
|
|
211
|
+
...RUN_UAT_BROWSER_TOOL_NAMES,
|
|
212
|
+
]);
|
|
213
|
+
return [...new Set(scoped)];
|
|
214
|
+
}
|
|
200
215
|
export function buildMinimalGsdWorkflowToolSet(activeToolNames, registeredToolNames = activeToolNames) {
|
|
201
216
|
const autoBaseTools = new Set(MINIMAL_AUTO_BASE_TOOL_NAMES);
|
|
202
217
|
const availableBaseTools = registeredToolNames.filter((name) => autoBaseTools.has(name));
|
|
@@ -372,6 +387,11 @@ function isContextDraftSummarySave(toolName, input) {
|
|
|
372
387
|
return false;
|
|
373
388
|
return input.artifact_type === "CONTEXT-DRAFT";
|
|
374
389
|
}
|
|
390
|
+
function withDepthGateDisplayReason(result, displayReason = "Depth confirmation is waiting for your answer.") {
|
|
391
|
+
if (!result.block)
|
|
392
|
+
return result;
|
|
393
|
+
return { ...result, displayReason };
|
|
394
|
+
}
|
|
375
395
|
function shouldBlockDeferredApprovalTool(toolName, input, basePath) {
|
|
376
396
|
if (deferredApprovalGate?.basePath !== basePath)
|
|
377
397
|
return { block: false };
|
|
@@ -379,14 +399,14 @@ function shouldBlockDeferredApprovalTool(toolName, input, basePath) {
|
|
|
379
399
|
return { block: false };
|
|
380
400
|
if (isContextDraftSummarySave(toolName, input))
|
|
381
401
|
return { block: false };
|
|
382
|
-
return {
|
|
402
|
+
return withDepthGateDisplayReason({
|
|
383
403
|
block: true,
|
|
384
404
|
reason: [
|
|
385
405
|
`HARD BLOCK: Approval question "${deferredApprovalGate.gateId}" has been shown to the user.`,
|
|
386
406
|
`Only CONTEXT-DRAFT persistence may finish in this same assistant turn.`,
|
|
387
407
|
`Wait for the user's answer before calling additional tools.`,
|
|
388
408
|
].join(" "),
|
|
389
|
-
};
|
|
409
|
+
});
|
|
390
410
|
}
|
|
391
411
|
export function resolveNotificationStoreBasePath(basePath) {
|
|
392
412
|
return resolveWorktreeProjectRoot(basePath);
|
|
@@ -414,8 +434,9 @@ export function registerHooks(pi, ecosystemHandlers) {
|
|
|
414
434
|
registerPlanMilestoneSchemaRecovery(pi);
|
|
415
435
|
pi.on("session_start", async (_event, ctx) => {
|
|
416
436
|
const basePath = contextBasePath(ctx);
|
|
437
|
+
const preserveCloseoutSurface = isAutoCompletionStopInProgress();
|
|
417
438
|
initSessionNotifications(ctx);
|
|
418
|
-
if (!isAutoActive()) {
|
|
439
|
+
if (!isAutoActive() && !preserveCloseoutSurface) {
|
|
419
440
|
const { initHealthWidget } = await import("../health-widget.js");
|
|
420
441
|
initHealthWidget(ctx);
|
|
421
442
|
}
|
|
@@ -435,14 +456,17 @@ export function registerHooks(pi, ecosystemHandlers) {
|
|
|
435
456
|
process.env.GSD_SHOW_TOKEN_COST = prefs?.preferences.show_token_cost ? "1" : "";
|
|
436
457
|
}
|
|
437
458
|
catch { /* non-fatal */ }
|
|
438
|
-
|
|
459
|
+
if (!preserveCloseoutSurface) {
|
|
460
|
+
await installWelcomeHeader(ctx);
|
|
461
|
+
}
|
|
439
462
|
await loadToolApiKeysForSession();
|
|
440
|
-
if (isAutoActive()) {
|
|
463
|
+
if (isAutoActive() || preserveCloseoutSurface) {
|
|
441
464
|
ctx.ui.setWidget("gsd-health", undefined);
|
|
442
465
|
}
|
|
443
466
|
});
|
|
444
467
|
pi.on("session_switch", async (_event, ctx) => {
|
|
445
468
|
const basePath = contextBasePath(ctx);
|
|
469
|
+
const preserveCloseoutSurface = isAutoCompletionStopInProgress();
|
|
446
470
|
initSessionNotifications(ctx);
|
|
447
471
|
resetWriteGateState(basePath);
|
|
448
472
|
resetToolCallLoopGuard();
|
|
@@ -454,7 +478,7 @@ export function registerHooks(pi, ecosystemHandlers) {
|
|
|
454
478
|
await applyCompactionThresholdOverride(ctx);
|
|
455
479
|
await prepareWorkflowMcpForHookContext(ctx, basePath);
|
|
456
480
|
await loadToolApiKeysForSession();
|
|
457
|
-
if (!isAutoActive()) {
|
|
481
|
+
if (!isAutoActive() && !preserveCloseoutSurface) {
|
|
458
482
|
ctx.ui.setWidget("gsd-progress", undefined);
|
|
459
483
|
ctx.ui.setWidget("gsd-outcome", undefined);
|
|
460
484
|
const { initHealthWidget } = await import("../health-widget.js");
|
|
@@ -740,7 +764,7 @@ export function registerHooks(pi, ecosystemHandlers) {
|
|
|
740
764
|
if (ctx) {
|
|
741
765
|
await maybePauseAutoForApprovalGate(ctx, pi, true, "Depth confirmation is waiting for your answer — pausing auto-mode.");
|
|
742
766
|
}
|
|
743
|
-
return bashGuard;
|
|
767
|
+
return withDepthGateDisplayReason(bashGuard);
|
|
744
768
|
}
|
|
745
769
|
}
|
|
746
770
|
else {
|
|
@@ -749,7 +773,7 @@ export function registerHooks(pi, ecosystemHandlers) {
|
|
|
749
773
|
if (ctx) {
|
|
750
774
|
await maybePauseAutoForApprovalGate(ctx, pi, true, "Depth confirmation is waiting for your answer — pausing auto-mode.");
|
|
751
775
|
}
|
|
752
|
-
return gateGuard;
|
|
776
|
+
return withDepthGateDisplayReason(gateGuard);
|
|
753
777
|
}
|
|
754
778
|
}
|
|
755
779
|
}
|
|
@@ -833,13 +857,12 @@ export function registerHooks(pi, ecosystemHandlers) {
|
|
|
833
857
|
if (!isToolCallEventType("write", event))
|
|
834
858
|
return;
|
|
835
859
|
const result = shouldBlockContextWrite(event.toolName, event.input.path, await getDiscussionMilestoneIdFor(discussionBasePath), isQueuePhaseActive(discussionBasePath), discussionBasePath);
|
|
836
|
-
if (result.block)
|
|
837
|
-
return result;
|
|
860
|
+
if (result.block) {
|
|
861
|
+
return withDepthGateDisplayReason(result, "Depth check required before writing milestone context.");
|
|
862
|
+
}
|
|
838
863
|
});
|
|
839
|
-
// ── Safety harness: evidence collection + destructive command
|
|
864
|
+
// ── Safety harness: evidence collection + destructive command blocking ──
|
|
840
865
|
pi.on("tool_call", async (event, ctx) => {
|
|
841
|
-
if (!isAutoActive())
|
|
842
|
-
return;
|
|
843
866
|
markToolStart(event.toolCallId, event.toolName);
|
|
844
867
|
safetyRecordToolCall(event.toolCallId, event.toolName, event.input);
|
|
845
868
|
// Persist immediately at dispatch so a mid-unit re-dispatch — which calls
|
|
@@ -854,14 +877,23 @@ export function registerHooks(pi, ecosystemHandlers) {
|
|
|
854
877
|
saveEvidenceToDisk(callDash.basePath, cMid, cSid, cTid);
|
|
855
878
|
}
|
|
856
879
|
}
|
|
857
|
-
// Destructive command classification
|
|
880
|
+
// Destructive command classification + hard gate in all modes.
|
|
858
881
|
if (isToolCallEventType("bash", event)) {
|
|
859
882
|
const classification = classifyCommand(event.input.command);
|
|
860
883
|
if (classification.destructive) {
|
|
884
|
+
const reason = [
|
|
885
|
+
"HARD BLOCK: destructive Bash command requires explicit human confirmation.",
|
|
886
|
+
`Detected: ${classification.labels.join(", ")}`,
|
|
887
|
+
"Run this via ask_user_questions, wait for the user's response,",
|
|
888
|
+
"then issue the command only when confirmed in the current turn.",
|
|
889
|
+
].join(" ");
|
|
861
890
|
safetyLogWarning("safety", `destructive command: ${classification.labels.join(", ")}`, {
|
|
862
891
|
command: String(event.input.command).slice(0, 200),
|
|
863
892
|
});
|
|
864
|
-
|
|
893
|
+
if (ctx) {
|
|
894
|
+
await maybePauseAutoForApprovalGate(ctx, pi, isAutoActive(), "Depth confirmation is waiting for your answer — pausing auto-mode.");
|
|
895
|
+
}
|
|
896
|
+
return { block: true, reason };
|
|
865
897
|
}
|
|
866
898
|
}
|
|
867
899
|
});
|
|
@@ -1123,21 +1155,25 @@ export function registerHooks(pi, ecosystemHandlers) {
|
|
|
1123
1155
|
const fullToolsRequested = isFullGsdToolSurfaceRequested();
|
|
1124
1156
|
const dropAliases = !fullToolsRequested;
|
|
1125
1157
|
const dropBrowser = !fullToolsRequested && !isBrowserToolSurfaceRequested();
|
|
1126
|
-
const
|
|
1158
|
+
const aliasFilteredCompatible = compatible.filter((name) => !(dropAliases && isWorkflowAliasTool(name)));
|
|
1159
|
+
const providerCompatible = aliasFilteredCompatible.filter((name) => !(dropBrowser && isBrowserTool(name)));
|
|
1127
1160
|
const surfaceReduced = providerCompatible.length !== compatible.length;
|
|
1128
1161
|
if (fullToolsRequested) {
|
|
1129
1162
|
return surfaceReduced ? { toolNames: providerCompatible } : undefined;
|
|
1130
1163
|
}
|
|
1131
1164
|
const registeredToolNames = resolveRegisteredToolNames(pi, event.activeToolNames);
|
|
1165
|
+
const compatibleRegisteredToolNames = filterToolsForProvider(registeredToolNames, event.selectedModelApi, event.selectedModelProvider).compatible.filter((name) => !(dropAliases && isWorkflowAliasTool(name)));
|
|
1132
1166
|
const guidedUnit = getGuidedUnitContext();
|
|
1133
|
-
const requestScoped = buildRequestScopedGsdToolSet(providerCompatible, event.requestCustomMessages, registeredToolNames, guidedUnit?.unitType);
|
|
1167
|
+
const requestScoped = buildRequestScopedGsdToolSet(guidedUnit?.unitType === "run-uat" ? aliasFilteredCompatible : providerCompatible, event.requestCustomMessages, guidedUnit?.unitType === "run-uat" ? compatibleRegisteredToolNames : registeredToolNames, guidedUnit?.unitType);
|
|
1134
1168
|
if (requestScoped) {
|
|
1135
1169
|
return { toolNames: requestScoped };
|
|
1136
1170
|
}
|
|
1137
1171
|
const dash = getAutoRuntimeSnapshot();
|
|
1138
1172
|
if (dash.active && dash.currentUnit) {
|
|
1139
1173
|
return {
|
|
1140
|
-
toolNames: buildMinimalAutoGsdToolSet(providerCompatible, dash.currentUnit.type,
|
|
1174
|
+
toolNames: buildMinimalAutoGsdToolSet(dash.currentUnit.type === "run-uat" ? aliasFilteredCompatible : providerCompatible, dash.currentUnit.type, dash.currentUnit.type === "run-uat"
|
|
1175
|
+
? compatibleRegisteredToolNames
|
|
1176
|
+
: resolveRegisteredToolNames(pi, event.activeToolNames)),
|
|
1141
1177
|
};
|
|
1142
1178
|
}
|
|
1143
1179
|
if (isGeneralGsdToolScopingRequested()) {
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { copyFileSync, existsSync, lstatSync, mkdirSync, readFileSync, readlinkSync, realpathSync, renameSync, unlinkSync, writeFileSync } from "node:fs";
|
|
3
3
|
import { isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
4
4
|
import { minimatch } from "minimatch";
|
|
5
|
-
import { shouldBlockAutoUnitToolCall } from "../auto-unit-tool-scope.js";
|
|
5
|
+
import { GSD_PHASE_SCOPE_DISPLAY_REASON, shouldBlockAutoUnitToolCall } from "../auto-unit-tool-scope.js";
|
|
6
6
|
import { getIsolationMode } from "../preferences.js";
|
|
7
7
|
import { compileSubagentPermissionContract } from "../unit-context-manifest.js";
|
|
8
8
|
import { logWarning } from "../workflow-logger.js";
|
|
@@ -565,6 +565,7 @@ const PLANNING_SUBAGENT_TOOLS = new Set(["subagent", "task"]);
|
|
|
565
565
|
* manifests still declare per-unit subsets via ToolsPolicy.allowedSubagents.
|
|
566
566
|
*/
|
|
567
567
|
const PLANNING_DISPATCH_AGENT_REGISTRY = {
|
|
568
|
+
mnemo: { readOnlySpecialist: true },
|
|
568
569
|
scout: { readOnlySpecialist: true },
|
|
569
570
|
planner: { readOnlySpecialist: true },
|
|
570
571
|
reviewer: { readOnlySpecialist: true },
|
|
@@ -574,7 +575,7 @@ const PLANNING_DISPATCH_AGENT_REGISTRY = {
|
|
|
574
575
|
export const ALLOWED_PLANNING_DISPATCH_AGENTS = new Set(Object.entries(PLANNING_DISPATCH_AGENT_REGISTRY)
|
|
575
576
|
.filter(([, metadata]) => metadata.readOnlySpecialist)
|
|
576
577
|
.map(([agentId]) => agentId));
|
|
577
|
-
let
|
|
578
|
+
let warnedMissingControlledDispatchAgentClasses = false;
|
|
578
579
|
function isReadOnlySpecialist(agentId) {
|
|
579
580
|
const metadata = PLANNING_DISPATCH_AGENT_REGISTRY[agentId];
|
|
580
581
|
return metadata?.readOnlySpecialist === true;
|
|
@@ -582,12 +583,16 @@ function isReadOnlySpecialist(agentId) {
|
|
|
582
583
|
function allowedPlanningDispatchAgentsList() {
|
|
583
584
|
return [...ALLOWED_PLANNING_DISPATCH_AGENTS].join(", ");
|
|
584
585
|
}
|
|
585
|
-
function
|
|
586
|
-
|
|
586
|
+
function allowsControlledSubagentDispatch(policy) {
|
|
587
|
+
return ((policy.mode === "planning-dispatch" || policy.mode === "verification") &&
|
|
588
|
+
Array.isArray(policy.allowedSubagents));
|
|
589
|
+
}
|
|
590
|
+
function warnMissingControlledDispatchAgentClasses(unitType, mode, toolName) {
|
|
591
|
+
if (warnedMissingControlledDispatchAgentClasses)
|
|
587
592
|
return;
|
|
588
|
-
|
|
593
|
+
warnedMissingControlledDispatchAgentClasses = true;
|
|
589
594
|
// TODO(#5060): Remove this migration shim once all subagent/task callers are verified to forward agent identities.
|
|
590
|
-
const message = `[write-gate]
|
|
595
|
+
const message = `[write-gate] controlled-dispatch: shouldBlockPlanningUnit called for tool "${toolName}" ` +
|
|
591
596
|
`on unit "${unitType}" without agentClasses - stale caller; blocking dispatch.`;
|
|
592
597
|
console.warn(message);
|
|
593
598
|
logWarning("intercept", message, {
|
|
@@ -638,6 +643,13 @@ function blockReason(unitType, mode, what) {
|
|
|
638
643
|
`the work belongs in execute-task, not in a planning unit.`,
|
|
639
644
|
].join(" ");
|
|
640
645
|
}
|
|
646
|
+
function planningBlock(unitType, mode, what) {
|
|
647
|
+
return {
|
|
648
|
+
block: true,
|
|
649
|
+
reason: blockReason(unitType, mode, what),
|
|
650
|
+
displayReason: GSD_PHASE_SCOPE_DISPLAY_REASON,
|
|
651
|
+
};
|
|
652
|
+
}
|
|
641
653
|
/**
|
|
642
654
|
* Planning-unit tool-policy enforcement. Returns { block } per the policy
|
|
643
655
|
* resolved from the active unit's manifest:
|
|
@@ -653,8 +665,9 @@ function blockReason(unitType, mode, what) {
|
|
|
653
665
|
* - "docs" → like "planning" but also allows writes to paths
|
|
654
666
|
* matching `allowedPathGlobs` relative to basePath.
|
|
655
667
|
* - "verification"
|
|
656
|
-
* → allows Bash for project verification commands,
|
|
657
|
-
* writes restricted to .gsd
|
|
668
|
+
* → allows Bash for project verification commands, keeps
|
|
669
|
+
* writes restricted to .gsd/, and permits subagent dispatch
|
|
670
|
+
* only when the manifest declares allowedSubagents.
|
|
658
671
|
*
|
|
659
672
|
* `pathOrCommand` is the file path for write/edit-shaped tools and the
|
|
660
673
|
* shell command for bash. Other tools ignore this argument.
|
|
@@ -684,10 +697,10 @@ export function shouldBlockPlanningUnit(toolName, pathOrCommand, basePath, unitT
|
|
|
684
697
|
if (tool.startsWith("gsd_"))
|
|
685
698
|
return { block: false };
|
|
686
699
|
if (PLANNING_WRITE_TOOLS.has(tool) || tool === "bash" || PLANNING_SUBAGENT_TOOLS.has(tool)) {
|
|
687
|
-
return
|
|
700
|
+
return planningBlock(unitType, policy.mode, `${tool} is not permitted (read-only)`);
|
|
688
701
|
}
|
|
689
702
|
// Unknown tool in read-only mode — block by default.
|
|
690
|
-
return
|
|
703
|
+
return planningBlock(unitType, policy.mode, `tool "${tool}" is not on the read-only allowlist`);
|
|
691
704
|
}
|
|
692
705
|
// planning / planning-dispatch / docs / verification modes share the same surface for safe tools, bash, and subagent.
|
|
693
706
|
if (PLANNING_SAFE_TOOLS.has(tool))
|
|
@@ -695,7 +708,7 @@ export function shouldBlockPlanningUnit(toolName, pathOrCommand, basePath, unitT
|
|
|
695
708
|
if (tool.startsWith("gsd_"))
|
|
696
709
|
return { block: false };
|
|
697
710
|
if (PLANNING_SUBAGENT_TOOLS.has(tool)) {
|
|
698
|
-
if (policy
|
|
711
|
+
if (allowsControlledSubagentDispatch(policy)) {
|
|
699
712
|
const requested = (agentClasses ?? []).map(a => a.trim()).filter(Boolean);
|
|
700
713
|
const dispatchContract = compileSubagentPermissionContract(policy);
|
|
701
714
|
const allowedSubagents = dispatchContract.allowedSubagents;
|
|
@@ -704,11 +717,8 @@ export function shouldBlockPlanningUnit(toolName, pathOrCommand, basePath, unitT
|
|
|
704
717
|
// agent identities yet. Block and warn so stale callers surface in telemetry
|
|
705
718
|
// instead of silently bypassing the gate.
|
|
706
719
|
if (agentClasses === undefined) {
|
|
707
|
-
|
|
708
|
-
return {
|
|
709
|
-
block: true,
|
|
710
|
-
reason: blockReason(unitType, policy.mode, `subagent dispatch blocked: stale caller did not supply agent identities for "${tool}"; update extractSubagentAgentClasses to handle this input shape`),
|
|
711
|
-
};
|
|
720
|
+
warnMissingControlledDispatchAgentClasses(unitType, policy.mode, tool);
|
|
721
|
+
return planningBlock(unitType, policy.mode, `subagent dispatch blocked: stale caller did not supply agent identities for "${tool}"; update extractSubagentAgentClasses to handle this input shape`);
|
|
712
722
|
}
|
|
713
723
|
// agentClasses was explicitly provided but resolved to an empty list (for
|
|
714
724
|
// example, a bare tool call with no agent field). Pass through; no agents
|
|
@@ -718,41 +728,29 @@ export function shouldBlockPlanningUnit(toolName, pathOrCommand, basePath, unitT
|
|
|
718
728
|
}
|
|
719
729
|
const globallyDisallowed = requested.find(a => !isReadOnlySpecialist(a));
|
|
720
730
|
if (globallyDisallowed) {
|
|
721
|
-
return {
|
|
722
|
-
block: true,
|
|
723
|
-
reason: blockReason(unitType, policy.mode, `subagent dispatch of "${globallyDisallowed}" not permitted; only read-only specialists (${allowedPlanningDispatchAgentsList()}) may be dispatched from planning-dispatch units`),
|
|
724
|
-
};
|
|
731
|
+
return planningBlock(unitType, policy.mode, `subagent dispatch of "${globallyDisallowed}" not permitted; only read-only specialists (${allowedPlanningDispatchAgentsList()}) may be dispatched from ${policy.mode} units`);
|
|
725
732
|
}
|
|
726
733
|
const disallowedByPolicy = requested.find(a => !allowed.has(a));
|
|
727
734
|
if (disallowedByPolicy) {
|
|
728
|
-
return {
|
|
729
|
-
block: true,
|
|
730
|
-
reason: blockReason(unitType, policy.mode, `subagent dispatch of "${disallowedByPolicy}" not permitted by ToolsPolicy.allowedSubagents; permitted agents for this unit: ${allowedSubagents.join(", ")}`),
|
|
731
|
-
};
|
|
735
|
+
return planningBlock(unitType, policy.mode, `subagent dispatch of "${disallowedByPolicy}" not permitted by ToolsPolicy.allowedSubagents; permitted agents for this unit: ${allowedSubagents.join(", ")}`);
|
|
732
736
|
}
|
|
733
737
|
return { block: false };
|
|
734
738
|
}
|
|
735
|
-
return
|
|
739
|
+
return planningBlock(unitType, policy.mode, "subagent dispatch is not permitted in planning units");
|
|
736
740
|
}
|
|
737
741
|
if (tool === "bash") {
|
|
738
742
|
if (policy.mode === "verification") {
|
|
739
743
|
if (BASH_VERIFICATION_RE.test(pathOrCommand) || BASH_READ_ONLY_RE.test(pathOrCommand))
|
|
740
744
|
return { block: false };
|
|
741
|
-
return {
|
|
742
|
-
block: true,
|
|
743
|
-
reason: blockReason(unitType, policy.mode, `bash is restricted to build/test verification commands (npm run build, npm test, etc.); cannot run "${pathOrCommand.slice(0, 80)}${pathOrCommand.length > 80 ? "…" : ""}"`),
|
|
744
|
-
};
|
|
745
|
+
return planningBlock(unitType, policy.mode, `bash is restricted to build/test verification commands (npm run build, npm test, etc.); cannot run "${pathOrCommand.slice(0, 80)}${pathOrCommand.length > 80 ? "…" : ""}"`);
|
|
745
746
|
}
|
|
746
747
|
if (BASH_READ_ONLY_RE.test(pathOrCommand))
|
|
747
748
|
return { block: false };
|
|
748
|
-
return {
|
|
749
|
-
block: true,
|
|
750
|
-
reason: blockReason(unitType, policy.mode, `bash is restricted to read-only commands (cat/grep/git log/etc); cannot run "${pathOrCommand.slice(0, 80)}${pathOrCommand.length > 80 ? "…" : ""}"`),
|
|
751
|
-
};
|
|
749
|
+
return planningBlock(unitType, policy.mode, `bash is restricted to read-only commands (cat/grep/git log/etc); cannot run "${pathOrCommand.slice(0, 80)}${pathOrCommand.length > 80 ? "…" : ""}"`);
|
|
752
750
|
}
|
|
753
751
|
if (PLANNING_WRITE_TOOLS.has(tool)) {
|
|
754
752
|
if (!pathOrCommand) {
|
|
755
|
-
return
|
|
753
|
+
return planningBlock(unitType, policy.mode, `${tool} called with empty path`);
|
|
756
754
|
}
|
|
757
755
|
const absPath = isAbsolute(pathOrCommand) ? pathOrCommand : resolve(basePath, pathOrCommand);
|
|
758
756
|
// Always allow .gsd/ writes — that's where planning artifacts live.
|
|
@@ -762,10 +760,7 @@ export function shouldBlockPlanningUnit(toolName, pathOrCommand, basePath, unitT
|
|
|
762
760
|
if (policy.mode === "docs" && matchesAllowedGlob(absPath, basePath, policy.allowedPathGlobs)) {
|
|
763
761
|
return { block: false };
|
|
764
762
|
}
|
|
765
|
-
return {
|
|
766
|
-
block: true,
|
|
767
|
-
reason: blockReason(unitType, policy.mode, `cannot ${tool} "${pathOrCommand}" — writes are restricted to .gsd/${policy.mode === "docs" ? " and " + policy.allowedPathGlobs.join(", ") : ""}`),
|
|
768
|
-
};
|
|
763
|
+
return planningBlock(unitType, policy.mode, `cannot ${tool} "${pathOrCommand}" — writes are restricted to .gsd/${policy.mode === "docs" ? " and " + policy.allowedPathGlobs.join(", ") : ""}`);
|
|
769
764
|
}
|
|
770
765
|
// Unknown tool name — pass through. Other layers (queue, pending-gate,
|
|
771
766
|
// CONTEXT.md write) catch known mutating shapes; defaulting to allow here
|
|
@@ -1,17 +1,44 @@
|
|
|
1
1
|
// Project/App: gsd-pi
|
|
2
2
|
// File Purpose: Shared browser-observable UAT requirement and evidence detection.
|
|
3
|
-
export const BROWSER_REQUIREMENT_RE = /\b(?:
|
|
3
|
+
export const BROWSER_REQUIREMENT_RE = /\b(?:file:\/\/|localhost|playwright|chrome|screenshot|snapshot|browser_(?:assert|batch|find|verify|snapshot_refs))\b|\b(?:open|launch|navigate|load|visit|serve|start)\b.{0,80}\b(?:browser|page|localhost|file:\/\/)\b|\bbrowser\s+(?:check|session|test|uat|tool|automation|interaction|flow)\b/i;
|
|
4
4
|
export const NO_BROWSER_EVIDENCE_RE = /\b(?:no|without|not|wasn'?t|isn'?t)\s+(?:automated\s+)?(?:live\s+)?browser(?:\s+(?:session|test|uat))?|\bno\s+automated\s+browser\b|\bnot\s+conducted\b/i;
|
|
5
5
|
export const BROWSER_RUNTIME_RE = /\b(?:browser|playwright|chrome|camoufox|browser_(?:assert|batch|find|verify|snapshot_refs)|screenshot|snapshot|file:\/\/|localhost)\b/i;
|
|
6
6
|
export const BROWSER_ACTION_RE = /\b(?:open(?:ed)?|navigate(?:d)?|click(?:ed)?|type(?:d)?|reload(?:ed)?|capture(?:d)?|screenshot|snapshot)\b/i;
|
|
7
7
|
export const BROWSER_ASSERTION_RE = /\b(?:assert(?:ed|ion)?|observed|confirmed|verified|expected|visible|text|count|label|strikethrough|localstorage|screenshot|snapshot|passed)\b/i;
|
|
8
|
+
const NON_REQUIREMENT_BROWSER_HEADING_RE = /^(?:not\s+proven|not\s+covered|out\s+of\s+scope|deferred|follow-?ups?|known\s+limitations|notes\s+for\s+tester)\b/i;
|
|
9
|
+
const NON_REQUIREMENT_BROWSER_LINE_RE = /\b(?:deferred|not\s+proven|not\s+covered|out\s+of\s+scope|future\s+slice|follow-?up|no\s+(?:live\s+)?browser|without\s+(?:a\s+)?browser|not\s+(?:a\s+)?browser)\b/i;
|
|
8
10
|
export function compactTextParts(parts) {
|
|
9
11
|
return parts.flatMap((part) => Array.isArray(part) ? part : [part])
|
|
10
12
|
.filter((part) => typeof part === "string" && part.trim().length > 0)
|
|
11
13
|
.join("\n");
|
|
12
14
|
}
|
|
13
15
|
export function hasBrowserRequiredText(text) {
|
|
14
|
-
|
|
16
|
+
let inNonRequirementSection = false;
|
|
17
|
+
let nonRequirementDepth = 0;
|
|
18
|
+
for (const line of text.split(/\r?\n/)) {
|
|
19
|
+
const headingMatch = line.match(/^(#{1,6})\s+(.+?)\s*$/);
|
|
20
|
+
if (headingMatch) {
|
|
21
|
+
const depth = headingMatch[1].length;
|
|
22
|
+
const title = headingMatch[2] ?? "";
|
|
23
|
+
// Only update section context when at the same or higher level than the
|
|
24
|
+
// heading that opened the non-requirement zone. A sub-heading deeper than
|
|
25
|
+
// the opening heading must not escape or re-enter the zone on its own.
|
|
26
|
+
if (!inNonRequirementSection || depth <= nonRequirementDepth) {
|
|
27
|
+
inNonRequirementSection = NON_REQUIREMENT_BROWSER_HEADING_RE.test(title);
|
|
28
|
+
nonRequirementDepth = inNonRequirementSection ? depth : 0;
|
|
29
|
+
}
|
|
30
|
+
// Check the heading title itself — section state is already updated, so
|
|
31
|
+
// we correctly skip headings that opened a non-requirement zone.
|
|
32
|
+
if (!inNonRequirementSection && BROWSER_REQUIREMENT_RE.test(title))
|
|
33
|
+
return true;
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
if (inNonRequirementSection || NON_REQUIREMENT_BROWSER_LINE_RE.test(line))
|
|
37
|
+
continue;
|
|
38
|
+
if (BROWSER_REQUIREMENT_RE.test(line))
|
|
39
|
+
return true;
|
|
40
|
+
}
|
|
41
|
+
return false;
|
|
15
42
|
}
|
|
16
43
|
export function hasBrowserEvidenceText(text) {
|
|
17
44
|
if (!text.trim())
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
// Project/App: gsd-pi
|
|
2
|
+
// File Purpose: Shared DB-backed guard for milestone closeout finalization.
|
|
3
|
+
import { getDbPath, getLatestAssessmentByScope, getMilestone, getMilestoneSlices, getPendingGates, getSliceTasks, isDbAvailable, refreshOpenDatabaseFromDisk, } from "./gsd-db.js";
|
|
4
|
+
import { isClosedStatus } from "./status-guards.js";
|
|
5
|
+
export const CLOSEOUT_CONSISTENCY_BLOCKED_REASON = "closeout-consistency-blocked";
|
|
6
|
+
function blocked(reason, message) {
|
|
7
|
+
return {
|
|
8
|
+
ok: false,
|
|
9
|
+
reason,
|
|
10
|
+
recoveryReason: CLOSEOUT_CONSISTENCY_BLOCKED_REASON,
|
|
11
|
+
message,
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
function isFileBackedDbPath(path) {
|
|
15
|
+
return Boolean(path && path !== ":memory:");
|
|
16
|
+
}
|
|
17
|
+
export function checkCloseoutConsistencyGate(milestoneId, options = {}) {
|
|
18
|
+
if (!isDbAvailable()) {
|
|
19
|
+
return blocked("db-unavailable", `Closeout consistency blocked for ${milestoneId}: canonical DB is unavailable.`);
|
|
20
|
+
}
|
|
21
|
+
if (options.refreshFromDisk && isFileBackedDbPath(getDbPath()) && !refreshOpenDatabaseFromDisk()) {
|
|
22
|
+
return blocked("db-refresh-failed", `Closeout consistency blocked for ${milestoneId}: canonical DB refresh failed.`);
|
|
23
|
+
}
|
|
24
|
+
const milestone = getMilestone(milestoneId);
|
|
25
|
+
if (!milestone) {
|
|
26
|
+
return blocked("milestone-missing", `Closeout consistency blocked for ${milestoneId}: milestone is missing from canonical DB.`);
|
|
27
|
+
}
|
|
28
|
+
if (!isClosedStatus(milestone.status)) {
|
|
29
|
+
return blocked("milestone-open", `Closeout consistency blocked for ${milestoneId}: canonical DB milestone status is "${milestone.status}".`);
|
|
30
|
+
}
|
|
31
|
+
if (milestone.status !== "skipped") {
|
|
32
|
+
const validation = getLatestAssessmentByScope(milestoneId, "milestone-validation");
|
|
33
|
+
if (validation?.status !== "pass") {
|
|
34
|
+
return blocked("validation-not-pass", `Closeout consistency blocked for ${milestoneId}: latest milestone validation is "${validation?.status ?? "absent"}".`);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
const slices = getMilestoneSlices(milestoneId);
|
|
38
|
+
if (slices.length === 0 && milestone.status !== "skipped") {
|
|
39
|
+
return blocked("slice-missing", `Closeout consistency blocked for ${milestoneId}: no slices exist in canonical DB.`);
|
|
40
|
+
}
|
|
41
|
+
for (const slice of slices) {
|
|
42
|
+
if (!isClosedStatus(slice.status)) {
|
|
43
|
+
return blocked("slice-open", `Closeout consistency blocked for ${milestoneId}: slice ${slice.id} status is "${slice.status}".`);
|
|
44
|
+
}
|
|
45
|
+
for (const task of getSliceTasks(milestoneId, slice.id)) {
|
|
46
|
+
if (!isClosedStatus(task.status)) {
|
|
47
|
+
return blocked("task-open", `Closeout consistency blocked for ${milestoneId}: task ${slice.id}/${task.id} status is "${task.status}".`);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
const pendingGate = getPendingGates(milestoneId, slice.id)[0];
|
|
51
|
+
if (pendingGate) {
|
|
52
|
+
return blocked("quality-gate-pending", `Closeout consistency blocked for ${milestoneId}: quality gate ${pendingGate.gate_id} is still pending for ${slice.id}.`);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return { ok: true };
|
|
56
|
+
}
|
|
57
|
+
export function formatCloseoutConsistencyBlock(result) {
|
|
58
|
+
if (result.ok)
|
|
59
|
+
return "";
|
|
60
|
+
return `${result.message} Recovery reason: ${result.recoveryReason}. Resolve the canonical DB state and run /gsd auto to retry.`;
|
|
61
|
+
}
|
|
@@ -3,7 +3,7 @@ import { join, resolve } from "node:path";
|
|
|
3
3
|
import { loadRegistry } from "../workflow-templates.js";
|
|
4
4
|
import { gsdHome } from "../gsd-home.js";
|
|
5
5
|
import { VISUAL_BRIEF_MODES } from "../../visual-brief/prompts.js";
|
|
6
|
-
export const GSD_COMMAND_DESCRIPTION = "GSD — Git Ship Done: /gsd help|start|templates|next|auto|stop|pause|status|widget|visualize|brief|report|queue|quick|discuss|capture|triage|dispatch|verdict|history|undo|undo-task|reset-slice|rate|skip|export|cleanup|closeout|model|mode|prefs|config|keys|hooks|run-hook|skill-health|doctor|debug|logs|forensics|changelog|migrate|remote|steer|knowledge|memory|new-milestone|new-project|parallel|cmux|park|unpark|init|setup|onboarding|inspect|extensions|update|upgrade|fast|mcp|rethink|workflow|codebase|notifications|ship|do|usage|context|session-report|backlog|pr-branch|add-tests|scan|language|worktree|eval-review";
|
|
6
|
+
export const GSD_COMMAND_DESCRIPTION = "GSD — Git Ship Done: /gsd help|start|templates|next|auto|stop|pause|status|widget|visualize|brief|report|queue|quick|discuss|capture|triage|dispatch|verdict|history|undo|undo-task|reset-slice|rate|skip|export|cleanup|closeout|rebuild|model|mode|prefs|config|keys|hooks|run-hook|skill-health|doctor|debug|logs|forensics|changelog|migrate|remote|steer|knowledge|memory|new-milestone|new-project|parallel|cmux|park|unpark|init|setup|onboarding|inspect|extensions|update|upgrade|fast|mcp|rethink|workflow|codebase|notifications|ship|do|usage|context|session-report|backlog|pr-branch|add-tests|scan|language|worktree|eval-review";
|
|
7
7
|
export const TOP_LEVEL_SUBCOMMANDS = [
|
|
8
8
|
{ cmd: "help", desc: "Categorized command reference with descriptions" },
|
|
9
9
|
{ cmd: "next", desc: "Explicit step mode — run one unit, then pause" },
|
|
@@ -32,6 +32,7 @@ export const TOP_LEVEL_SUBCOMMANDS = [
|
|
|
32
32
|
{ cmd: "export", desc: "Alias for /gsd report" },
|
|
33
33
|
{ cmd: "cleanup", desc: "Remove merged branches or snapshots" },
|
|
34
34
|
{ cmd: "closeout", desc: "Recover failed git closeout actions (status, retry, resolve)" },
|
|
35
|
+
{ cmd: "rebuild", desc: "Rebuild markdown projections from the canonical DB" },
|
|
35
36
|
{ cmd: "model", desc: "Switch the active session model or open a picker" },
|
|
36
37
|
{ cmd: "mode", desc: "Switch workflow mode (solo/team)" },
|
|
37
38
|
{ cmd: "prefs", desc: "Manage preferences (model selection, timeouts, etc.)" },
|
|
@@ -201,6 +202,10 @@ const NESTED_COMPLETIONS = {
|
|
|
201
202
|
{ cmd: "retry", desc: "Retry the latest failed closeout git action" },
|
|
202
203
|
{ cmd: "resolve", desc: "Mark closeout resolved after the worktree is clean" },
|
|
203
204
|
],
|
|
205
|
+
rebuild: [
|
|
206
|
+
{ cmd: "markdown", desc: "Rebuild markdown projections from the canonical DB" },
|
|
207
|
+
{ cmd: "database", desc: "Reserved for DB-native rebuilds; does not import markdown" },
|
|
208
|
+
],
|
|
204
209
|
knowledge: [
|
|
205
210
|
{ cmd: "rule", desc: "Add a project rule (always/never do X)" },
|
|
206
211
|
{ cmd: "pattern", desc: "Add a code pattern to follow" },
|
|
@@ -51,6 +51,7 @@ export function showHelp(ctx, args = "") {
|
|
|
51
51
|
" /gsd keys API key manager (LLM + tool keys)",
|
|
52
52
|
" /gsd doctor Diagnose and repair .gsd/ state",
|
|
53
53
|
" /gsd closeout Recover failed git closeout actions",
|
|
54
|
+
" /gsd rebuild Rebuild markdown projections from the DB [markdown]",
|
|
54
55
|
"",
|
|
55
56
|
"Use /gsd help full for the complete command reference.",
|
|
56
57
|
];
|
|
@@ -68,7 +69,7 @@ export function showHelp(ctx, args = "") {
|
|
|
68
69
|
" /gsd new-milestone Create milestone from headless context (used by gsd headless)",
|
|
69
70
|
" /gsd new-project Bootstrap a new project (use --deep for staged project-level discovery)",
|
|
70
71
|
" /gsd quick Execute a quick task without full planning overhead",
|
|
71
|
-
" /gsd dispatch Dispatch a specific phase directly [research|plan|execute|complete|uat|replan]",
|
|
72
|
+
" /gsd dispatch Dispatch a specific phase directly [research|plan|execute|complete|validate|reassess|uat|replan]",
|
|
72
73
|
" /gsd verdict <v> Override milestone validation verdict [pass|needs-attention|needs-remediation] [--milestone Mxxx] [--rationale \"...\"]",
|
|
73
74
|
" /gsd parallel Parallel milestone orchestration [start|status|stop|pause|resume|merge|watch]",
|
|
74
75
|
" /gsd workflow Custom workflow lifecycle [new|run|list|validate|pause|resume]",
|
|
@@ -132,7 +133,7 @@ export function showHelp(ctx, args = "") {
|
|
|
132
133
|
" /gsd skill-health Skill lifecycle dashboard",
|
|
133
134
|
" /gsd extensions Manage extensions [list|enable|disable|info]",
|
|
134
135
|
" /gsd fast Toggle OpenAI service tier [on|off|flex|status]",
|
|
135
|
-
" /gsd mcp MCP server management [status|check|test|enable|disable|import|delete|init]",
|
|
136
|
+
" /gsd mcp MCP server management [status|check|discover|test|enable|disable|import|delete|init]",
|
|
136
137
|
"",
|
|
137
138
|
"MAINTENANCE",
|
|
138
139
|
" /gsd doctor Diagnose and repair .gsd/ state [audit|fix|heal] [scope]",
|
|
@@ -141,6 +142,9 @@ export function showHelp(ctx, args = "") {
|
|
|
141
142
|
" /gsd export Alias for /gsd report",
|
|
142
143
|
" /gsd cleanup Remove merged branches or snapshots [branches|snapshots]",
|
|
143
144
|
" /gsd closeout Recover failed git closeout actions [status|retry|resolve] [unit-id]",
|
|
145
|
+
" /gsd rebuild markdown Rebuild markdown projections from the canonical DB",
|
|
146
|
+
" /gsd rebuild database Reserved for DB-native rebuilds; does not import markdown",
|
|
147
|
+
" /gsd recover --confirm Import markdown into the DB after DB loss/corruption",
|
|
144
148
|
" /gsd worktree Manage worktrees from the TUI [list|merge|clean|remove]",
|
|
145
149
|
" /gsd migrate Migrate .planning/ (v1) to DB-backed .gsd/ with backup + audit",
|
|
146
150
|
" /gsd remote Control remote auto-mode [slack|discord|status|disconnect]",
|
|
@@ -4,7 +4,7 @@ import { handleDoctor, handleCapture, handleKnowledge, handleRunHook, handleSkil
|
|
|
4
4
|
import { handleInspect } from "../../commands-inspect.js";
|
|
5
5
|
import { handleLogs } from "../../commands-logs.js";
|
|
6
6
|
import { handleDebug } from "../../commands-debug.js";
|
|
7
|
-
import { handleCleanupBranches, handleCleanupSnapshots, handleSkip, handleCleanupProjects, handleCleanupWorktrees, handleRecover } from "../../commands-maintenance.js";
|
|
7
|
+
import { handleCleanupBranches, handleCleanupSnapshots, handleSkip, handleCleanupProjects, handleCleanupWorktrees, handleRecover, handleRebuild } from "../../commands-maintenance.js";
|
|
8
8
|
import { handleExport } from "../../export.js";
|
|
9
9
|
import { handleHistory } from "../../history.js";
|
|
10
10
|
import { handleUndo } from "../../undo.js";
|
|
@@ -130,8 +130,12 @@ export async function handleOpsCommand(trimmed, ctx, pi) {
|
|
|
130
130
|
await handleSkip(trimmed.replace(/^skip\s*/, "").trim(), ctx, projectRoot());
|
|
131
131
|
return true;
|
|
132
132
|
}
|
|
133
|
-
if (trimmed === "recover") {
|
|
134
|
-
await handleRecover(ctx, projectRoot());
|
|
133
|
+
if (trimmed === "recover" || trimmed.startsWith("recover ")) {
|
|
134
|
+
await handleRecover(ctx, projectRoot(), trimmed.replace(/^recover\s*/, "").trim());
|
|
135
|
+
return true;
|
|
136
|
+
}
|
|
137
|
+
if (trimmed === "rebuild" || trimmed.startsWith("rebuild ")) {
|
|
138
|
+
await handleRebuild(ctx, projectRoot(), trimmed.replace(/^rebuild\s*/, "").trim());
|
|
135
139
|
return true;
|
|
136
140
|
}
|
|
137
141
|
if (trimmed === "closeout" || trimmed.startsWith("closeout ")) {
|
|
@@ -262,8 +266,8 @@ Examples:
|
|
|
262
266
|
await handleInspect(ctx);
|
|
263
267
|
return true;
|
|
264
268
|
}
|
|
265
|
-
if (trimmed === "update" || trimmed === "upgrade") {
|
|
266
|
-
await handleUpdate(ctx);
|
|
269
|
+
if (trimmed === "update" || trimmed.startsWith("update ") || trimmed === "upgrade" || trimmed.startsWith("upgrade ")) {
|
|
270
|
+
await handleUpdate(ctx, trimmed.replace(/^(?:update|upgrade)\s*/, "").trim());
|
|
267
271
|
return true;
|
|
268
272
|
}
|
|
269
273
|
if (trimmed === "fast" || trimmed.startsWith("fast ")) {
|