@opengsd/gsd-pi 1.2.0-dev.955e4da0 → 1.2.0-dev.fb12b103
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-style.d.ts +17 -0
- package/dist/cli-style.js +28 -0
- package/dist/cli.js +1 -1
- package/dist/headless-events.d.ts +4 -2
- package/dist/headless-events.js +7 -29
- package/dist/models-resolver.d.ts +3 -13
- package/dist/models-resolver.js +3 -22
- package/dist/resource-loader.js +2 -14
- package/dist/resources/.managed-resources-content-hash +1 -1
- package/dist/resources/extensions/async-jobs/async-bash-tool.js +30 -64
- package/dist/resources/extensions/async-jobs/await-tool.js +80 -12
- package/dist/resources/extensions/async-jobs/index.js +65 -0
- package/dist/resources/extensions/async-jobs/job-manager.js +12 -1
- package/dist/resources/extensions/bg-shell/bg-shell-command.js +6 -6
- package/dist/resources/extensions/bg-shell/bg-shell-tool.js +10 -7
- package/dist/resources/extensions/bg-shell/overlay.js +9 -6
- package/dist/resources/extensions/bg-shell/process-manager.js +54 -25
- package/dist/resources/extensions/bg-shell/readiness-detector.js +11 -0
- package/dist/resources/extensions/bg-shell/utilities.js +3 -0
- package/dist/resources/extensions/browser-tools/engine/managed-gsd-browser.js +209 -88
- package/dist/resources/extensions/browser-tools/engine/selection.js +73 -5
- package/dist/resources/extensions/browser-tools/index.js +69 -12
- package/dist/resources/extensions/claude-code-cli/stream-adapter.js +30 -4
- package/dist/resources/extensions/gsd/auto/orchestrator.js +7 -5
- package/dist/resources/extensions/gsd/auto-dispatch.js +12 -1
- package/dist/resources/extensions/gsd/auto-model-selection.js +25 -6
- package/dist/resources/extensions/gsd/auto-post-unit.js +11 -2
- package/dist/resources/extensions/gsd/auto-prompts.js +15 -10
- package/dist/resources/extensions/gsd/auto-start.js +15 -10
- package/dist/resources/extensions/gsd/auto-tool-tracking.js +18 -0
- package/dist/resources/extensions/gsd/auto-unit-tool-scope.js +7 -16
- package/dist/resources/extensions/gsd/auto-worktree.js +30 -90
- package/dist/resources/extensions/gsd/auto.js +4 -13
- package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +3 -2
- package/dist/resources/extensions/gsd/bootstrap/dynamic-tools.js +23 -6
- package/dist/resources/extensions/gsd/bootstrap/register-extension.js +19 -0
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +122 -20
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +6 -2
- package/dist/resources/extensions/gsd/branch-patterns.js +2 -0
- package/dist/resources/extensions/gsd/browser-daemon-auto-prep.js +83 -0
- package/dist/resources/extensions/gsd/browser-evidence.js +8 -2
- package/dist/resources/extensions/gsd/captures.js +4 -6
- package/dist/resources/extensions/gsd/constants.js +0 -2
- package/dist/resources/extensions/gsd/crash-recovery.js +4 -12
- package/dist/resources/extensions/gsd/doctor-environment.js +2 -6
- package/dist/resources/extensions/gsd/doctor-format.js +9 -6
- package/dist/resources/extensions/gsd/doctor-runtime-checks.js +13 -15
- package/dist/resources/extensions/gsd/error-classifier.js +9 -0
- package/dist/resources/extensions/gsd/exec-sandbox.js +30 -10
- package/dist/resources/extensions/gsd/guidance.js +98 -0
- package/dist/resources/extensions/gsd/guided-flow.js +17 -2
- package/dist/resources/extensions/gsd/mcp-filter.js +2 -19
- package/dist/resources/extensions/gsd/mcp-tool-name.js +5 -13
- package/dist/resources/extensions/gsd/memory-consolidation-scanner.js +1 -1
- package/dist/resources/extensions/gsd/migrate/safety.js +4 -1
- package/dist/resources/extensions/gsd/notification-store.js +11 -4
- package/dist/resources/extensions/gsd/parallel-monitor-overlay.js +6 -4
- package/dist/resources/extensions/gsd/paths.js +27 -0
- package/dist/resources/extensions/gsd/pre-execution-checks.js +91 -3
- package/dist/resources/extensions/gsd/preferences-models.js +14 -48
- package/dist/resources/extensions/gsd/prompts/complete-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/refine-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/replan-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/run-uat.md +1 -1
- package/dist/resources/extensions/gsd/prompts/system.md +5 -2
- package/dist/resources/extensions/gsd/provider-error-guidance.js +1 -5
- package/dist/resources/extensions/gsd/provider-switch-observer.js +1 -1
- package/dist/resources/extensions/gsd/publication.js +87 -0
- package/dist/resources/extensions/gsd/recovery-classification.js +37 -94
- package/dist/resources/extensions/gsd/safety/destructive-confirmation.js +108 -0
- package/dist/resources/extensions/gsd/state.js +1 -20
- package/dist/resources/extensions/gsd/stop-notice.js +57 -0
- package/dist/resources/extensions/gsd/tool-surface-readiness.js +56 -0
- package/dist/resources/extensions/gsd/tools/exec-tool.js +9 -7
- package/dist/resources/extensions/gsd/tools/plan-slice.js +12 -6
- package/dist/resources/extensions/gsd/uat-policy.js +2 -1
- package/dist/resources/extensions/gsd/unit-closeout.js +138 -0
- package/dist/resources/extensions/gsd/unit-context-composer.js +74 -1
- package/dist/resources/extensions/gsd/unit-context-manifest.js +4 -27
- package/dist/resources/extensions/gsd/unit-registry.js +337 -0
- package/dist/resources/extensions/gsd/unit-tool-contracts.js +9 -182
- package/dist/resources/extensions/gsd/web-app-uat.js +45 -8
- package/dist/resources/extensions/gsd/workflow-tool-surface.js +1 -1
- package/dist/resources/extensions/gsd/worktree-git-recovery.js +15 -9
- package/dist/resources/extensions/gsd/worktree-root.js +11 -0
- package/dist/resources/extensions/gsd/worktree-session-state.js +4 -5
- package/dist/resources/extensions/search-the-web/native-search.js +5 -3
- package/dist/resources/extensions/shared/browser-contract.js +59 -0
- package/dist/resources/extensions/shared/gsd-browser-cli.js +96 -5
- package/dist/resources/shared/package.json +3 -0
- package/dist/resources/skills/create-skill/references/executable-code.md +1 -1
- package/dist/resources/skills/create-skill/workflows/add-reference.md +8 -3
- package/dist/resources/skills/create-skill/workflows/add-script.md +4 -2
- package/dist/resources/skills/create-skill/workflows/add-template.md +3 -1
- package/dist/resources/skills/create-skill/workflows/add-workflow.md +8 -3
- package/dist/resources/skills/create-skill/workflows/upgrade-to-router.md +10 -5
- package/dist/resources/skills/create-skill/workflows/verify-skill.md +9 -4
- package/dist/resources/skills/spike-wrap-up/SKILL.md +9 -9
- package/dist/tsconfig.extensions.tsbuildinfo +1 -1
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +13 -13
- package/dist/web/standalone/.next/build-manifest.json +3 -3
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- package/dist/web/standalone/.next/react-loadable-manifest.json +1 -1
- 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/api/update/route.js.nft.json +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 +13 -13
- package/dist/web/standalone/.next/server/chunks/5124.js +1 -1
- package/dist/web/standalone/.next/server/chunks/8357.js +1 -1
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
- package/dist/web/standalone/.next/server/pages/404.html +1 -1
- package/dist/web/standalone/.next/server/pages/500.html +1 -1
- package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
- package/dist/web/standalone/.next/static/chunks/{796.cf859a427a2cb2ac.js → 796.e0bdc932325d7e03.js} +1 -1
- package/dist/web/standalone/.next/static/chunks/{webpack-fbea77b5f9953368.js → webpack-f0285ce91d4ec9ef.js} +1 -1
- package/dist/web/standalone/node_modules/node-pty/build/Makefile +1 -1
- package/dist/web/standalone/node_modules/postcss/lib/container.js +18 -26
- package/dist/web/standalone/node_modules/postcss/lib/css-syntax-error.js +14 -47
- package/dist/web/standalone/node_modules/postcss/lib/declaration.js +4 -4
- package/dist/web/standalone/node_modules/postcss/lib/fromJSON.js +3 -3
- package/dist/web/standalone/node_modules/postcss/lib/input.js +29 -54
- package/dist/web/standalone/node_modules/postcss/lib/lazy-result.js +37 -47
- package/dist/web/standalone/node_modules/postcss/lib/map-generator.js +9 -26
- package/dist/web/standalone/node_modules/postcss/lib/no-work-result.js +55 -57
- package/dist/web/standalone/node_modules/postcss/lib/node.js +31 -99
- package/dist/web/standalone/node_modules/postcss/lib/parse.js +1 -1
- package/dist/web/standalone/node_modules/postcss/lib/parser.js +9 -10
- package/dist/web/standalone/node_modules/postcss/lib/postcss.js +12 -12
- package/dist/web/standalone/node_modules/postcss/lib/previous-map.js +11 -30
- package/dist/web/standalone/node_modules/postcss/lib/processor.js +7 -7
- package/dist/web/standalone/node_modules/postcss/lib/result.js +5 -5
- package/dist/web/standalone/node_modules/postcss/lib/rule.js +6 -6
- package/dist/web/standalone/node_modules/postcss/lib/stringifier.js +28 -69
- package/dist/web/standalone/node_modules/postcss/lib/tokenize.js +2 -6
- package/dist/web/standalone/node_modules/postcss/package.json +48 -48
- package/dist/web/standalone/package.json +1 -1
- package/dist/worktree-cli.js +3 -6
- package/dist/worktree-status-banner.js +7 -15
- package/package.json +1 -1
- package/packages/cloud-mcp-gateway/package.json +2 -2
- package/packages/contracts/dist/rpc.d.ts +1 -0
- package/packages/contracts/dist/rpc.d.ts.map +1 -1
- package/packages/contracts/dist/rpc.js.map +1 -1
- package/packages/contracts/dist/workflow.d.ts +4 -0
- package/packages/contracts/dist/workflow.d.ts.map +1 -1
- 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/package.json +5 -5
- package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.d.ts +5 -0
- 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.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js +7 -0
- 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 +8 -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-chat-render.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-chat-render.js +11 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-chat-render.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-auth.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-auth.js +4 -4
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-auth.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/rpc/rpc-mode.js +3 -1
- package/packages/gsd-agent-modes/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/packages/gsd-agent-modes/package.json +7 -7
- package/packages/mcp-server/dist/cli.js +6 -3
- package/packages/mcp-server/dist/cli.js.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.d.ts +8 -0
- package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.js +17 -1
- package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
- package/packages/mcp-server/package.json +3 -3
- package/packages/native/package.json +1 -1
- package/packages/pi-agent-core/dist/harness/env/nodejs.d.ts +1 -0
- package/packages/pi-agent-core/dist/harness/env/nodejs.d.ts.map +1 -1
- package/packages/pi-agent-core/dist/harness/env/nodejs.js +34 -3
- package/packages/pi-agent-core/dist/harness/env/nodejs.js.map +1 -1
- package/packages/pi-agent-core/dist/index.d.ts +1 -0
- package/packages/pi-agent-core/dist/index.d.ts.map +1 -1
- package/packages/pi-agent-core/dist/index.js +3 -0
- package/packages/pi-agent-core/dist/index.js.map +1 -1
- package/packages/pi-agent-core/package.json +1 -1
- package/packages/pi-ai/dist/models.generated.d.ts +94 -382
- package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
- package/packages/pi-ai/dist/models.generated.js +149 -422
- package/packages/pi-ai/dist/models.generated.js.map +1 -1
- package/packages/pi-ai/package.json +1 -1
- package/packages/pi-coding-agent/dist/core/auth-storage.d.ts +2 -2
- package/packages/pi-coding-agent/dist/core/auth-storage.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/auth-storage.js +19 -13
- package/packages/pi-coding-agent/dist/core/auth-storage.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/provider-readiness.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/provider-readiness.js +13 -6
- package/packages/pi-coding-agent/dist/core/provider-readiness.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/bash.d.ts +11 -0
- package/packages/pi-coding-agent/dist/core/tools/bash.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/bash.js +53 -11
- package/packages/pi-coding-agent/dist/core/tools/bash.js.map +1 -1
- package/packages/pi-coding-agent/dist/index.d.ts +1 -1
- package/packages/pi-coding-agent/dist/index.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/index.js +1 -1
- package/packages/pi-coding-agent/dist/index.js.map +1 -1
- package/packages/pi-coding-agent/dist/utils/shell.d.ts +28 -2
- package/packages/pi-coding-agent/dist/utils/shell.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/utils/shell.js +56 -10
- package/packages/pi-coding-agent/dist/utils/shell.js.map +1 -1
- package/packages/pi-coding-agent/package.json +7 -7
- package/packages/pi-tui/dist/tui.d.ts.map +1 -1
- package/packages/pi-tui/dist/tui.js +9 -0
- package/packages/pi-tui/dist/tui.js.map +1 -1
- package/packages/pi-tui/package.json +2 -2
- package/packages/rpc-client/package.json +2 -2
- package/pkg/package.json +1 -1
- package/src/resources/extensions/async-jobs/async-bash-cancel.test.ts +360 -0
- package/src/resources/extensions/async-jobs/async-bash-tool.ts +33 -56
- package/src/resources/extensions/async-jobs/await-tool.test.ts +139 -0
- package/src/resources/extensions/async-jobs/await-tool.ts +82 -12
- package/src/resources/extensions/async-jobs/index.ts +79 -0
- package/src/resources/extensions/async-jobs/job-manager.ts +21 -1
- package/src/resources/extensions/bg-shell/bg-shell-command.ts +6 -6
- package/src/resources/extensions/bg-shell/bg-shell-tool.ts +10 -6
- package/src/resources/extensions/bg-shell/overlay.ts +9 -5
- package/src/resources/extensions/bg-shell/process-manager.ts +50 -25
- package/src/resources/extensions/bg-shell/readiness-detector.ts +12 -0
- package/src/resources/extensions/bg-shell/tests/lifecycle-and-utilities.test.ts +48 -1
- package/src/resources/extensions/bg-shell/utilities.ts +3 -0
- package/src/resources/extensions/browser-tools/engine/managed-gsd-browser.ts +265 -98
- package/src/resources/extensions/browser-tools/engine/selection.ts +90 -4
- package/src/resources/extensions/browser-tools/index.ts +71 -13
- package/src/resources/extensions/browser-tools/tests/browser-engine-selection.test.mjs +83 -13
- package/src/resources/extensions/browser-tools/tests/gsd-browser-launch-config.test.mjs +29 -1
- package/src/resources/extensions/browser-tools/tests/managed-gsd-browser-tools.test.mjs +136 -0
- package/src/resources/extensions/claude-code-cli/stream-adapter.ts +34 -4
- package/src/resources/extensions/gsd/auto/orchestrator.ts +7 -5
- package/src/resources/extensions/gsd/auto-dispatch.ts +12 -0
- package/src/resources/extensions/gsd/auto-model-selection.ts +25 -5
- package/src/resources/extensions/gsd/auto-post-unit.ts +13 -2
- package/src/resources/extensions/gsd/auto-prompts.ts +40 -26
- package/src/resources/extensions/gsd/auto-start.ts +15 -10
- package/src/resources/extensions/gsd/auto-tool-tracking.ts +19 -0
- package/src/resources/extensions/gsd/auto-unit-tool-scope.ts +10 -17
- package/src/resources/extensions/gsd/auto-worktree.ts +30 -93
- package/src/resources/extensions/gsd/auto.ts +8 -15
- package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +3 -5
- package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +23 -6
- package/src/resources/extensions/gsd/bootstrap/register-extension.ts +24 -0
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +151 -15
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +6 -2
- package/src/resources/extensions/gsd/branch-patterns.ts +3 -0
- package/src/resources/extensions/gsd/browser-daemon-auto-prep.ts +108 -0
- package/src/resources/extensions/gsd/browser-evidence.ts +18 -2
- package/src/resources/extensions/gsd/captures.ts +4 -6
- package/src/resources/extensions/gsd/constants.ts +0 -3
- package/src/resources/extensions/gsd/crash-recovery.ts +3 -9
- package/src/resources/extensions/gsd/doctor-environment.ts +2 -7
- package/src/resources/extensions/gsd/doctor-format.ts +12 -7
- package/src/resources/extensions/gsd/doctor-runtime-checks.ts +13 -15
- package/src/resources/extensions/gsd/error-classifier.ts +11 -0
- package/src/resources/extensions/gsd/exec-sandbox.ts +49 -9
- package/src/resources/extensions/gsd/guidance.ts +139 -0
- package/src/resources/extensions/gsd/guided-flow.ts +16 -2
- package/src/resources/extensions/gsd/mcp-filter.ts +2 -23
- package/src/resources/extensions/gsd/mcp-tool-name.ts +6 -11
- package/src/resources/extensions/gsd/memory-consolidation-scanner.ts +1 -1
- package/src/resources/extensions/gsd/migrate/safety.ts +4 -1
- package/src/resources/extensions/gsd/notification-store.ts +26 -3
- package/src/resources/extensions/gsd/parallel-monitor-overlay.ts +6 -4
- package/src/resources/extensions/gsd/paths.ts +33 -0
- package/src/resources/extensions/gsd/pre-execution-checks.ts +109 -3
- package/src/resources/extensions/gsd/preferences-models.ts +12 -47
- package/src/resources/extensions/gsd/prompts/complete-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/refine-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/replan-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/run-uat.md +1 -1
- package/src/resources/extensions/gsd/prompts/system.md +5 -2
- package/src/resources/extensions/gsd/provider-error-guidance.ts +4 -9
- package/src/resources/extensions/gsd/provider-switch-observer.ts +1 -1
- package/src/resources/extensions/gsd/publication.ts +122 -0
- package/src/resources/extensions/gsd/recovery-classification.ts +42 -96
- package/src/resources/extensions/gsd/safety/destructive-confirmation.ts +134 -0
- package/src/resources/extensions/gsd/state.ts +4 -21
- package/src/resources/extensions/gsd/stop-notice.ts +75 -0
- package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +22 -0
- package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +16 -19
- package/src/resources/extensions/gsd/tests/browser-automation-contract-fixture.ts +39 -0
- package/src/resources/extensions/gsd/tests/browser-contract.test.ts +44 -0
- package/src/resources/extensions/gsd/tests/browser-daemon-auto-prep.test.ts +144 -0
- package/src/resources/extensions/gsd/tests/checkout-branch-stash-guard.test.ts +66 -1
- package/src/resources/extensions/gsd/tests/clear-stale-autostart.test.ts +22 -0
- package/src/resources/extensions/gsd/tests/commands-verdict.test.ts +8 -7
- package/src/resources/extensions/gsd/tests/destructive-confirmation.test.ts +303 -0
- package/src/resources/extensions/gsd/tests/dispatch-run-uat-browser-tools.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/dynamic-bash-no-cap.test.ts +132 -0
- package/src/resources/extensions/gsd/tests/exec-graceful-kill.test.ts +193 -0
- package/src/resources/extensions/gsd/tests/exec-tool.test.ts +29 -1
- package/src/resources/extensions/gsd/tests/extension-bootstrap-isolation.test.ts +35 -1
- package/src/resources/extensions/gsd/tests/guidance.test.ts +125 -0
- package/src/resources/extensions/gsd/tests/integration/auto-worktree-milestone-merge.test.ts +53 -11
- package/src/resources/extensions/gsd/tests/integration/auto-worktree.test.ts +73 -58
- package/src/resources/extensions/gsd/tests/integration/gsd-integration-fixture.ts +80 -0
- package/src/resources/extensions/gsd/tests/mcp-project-config.test.ts +3 -1
- package/src/resources/extensions/gsd/tests/model-unittype-mapping.test.ts +32 -1
- package/src/resources/extensions/gsd/tests/notification-store.test.ts +32 -0
- package/src/resources/extensions/gsd/tests/oauth-api-model-routing.test.ts +167 -0
- package/src/resources/extensions/gsd/tests/pre-execution-checks.test.ts +193 -1
- package/src/resources/extensions/gsd/tests/provider-error-guidance.test.ts +3 -3
- package/src/resources/extensions/gsd/tests/publication.test.ts +120 -0
- package/src/resources/extensions/gsd/tests/register-hooks-depth-verification.test.ts +157 -0
- package/src/resources/extensions/gsd/tests/runtime-invariant-modules.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/stop-notice.test.ts +70 -0
- package/src/resources/extensions/gsd/tests/token-tool-gating.test.ts +76 -0
- package/src/resources/extensions/gsd/tests/tool-invocation-error-loop-break.test.ts +8 -0
- package/src/resources/extensions/gsd/tests/tool-surface-readiness.test.ts +155 -0
- package/src/resources/extensions/gsd/tests/uat-policy.test.ts +24 -29
- package/src/resources/extensions/gsd/tests/unit-closeout.test.ts +209 -0
- package/src/resources/extensions/gsd/tests/unit-context-composer.test.ts +67 -2
- package/src/resources/extensions/gsd/tests/unit-registry.test.ts +163 -0
- package/src/resources/extensions/gsd/tests/web-app-uat.test.ts +44 -1
- package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +2 -2
- package/src/resources/extensions/gsd/tool-surface-readiness.ts +76 -0
- package/src/resources/extensions/gsd/tools/exec-tool.ts +8 -7
- package/src/resources/extensions/gsd/tools/plan-slice.ts +12 -6
- package/src/resources/extensions/gsd/uat-policy.ts +2 -1
- package/src/resources/extensions/gsd/unit-closeout.ts +201 -0
- package/src/resources/extensions/gsd/unit-context-composer.ts +111 -1
- package/src/resources/extensions/gsd/unit-context-manifest.ts +4 -28
- package/src/resources/extensions/gsd/unit-registry.ts +412 -0
- package/src/resources/extensions/gsd/unit-tool-contracts.ts +27 -192
- package/src/resources/extensions/gsd/web-app-uat.ts +51 -8
- package/src/resources/extensions/gsd/workflow-tool-surface.ts +4 -1
- package/src/resources/extensions/gsd/worktree-git-recovery.ts +15 -9
- package/src/resources/extensions/gsd/worktree-root.ts +12 -0
- package/src/resources/extensions/gsd/worktree-session-state.ts +3 -5
- package/src/resources/extensions/search-the-web/native-search.ts +5 -3
- package/src/resources/extensions/shared/browser-contract.ts +66 -0
- package/src/resources/extensions/shared/gsd-browser-cli.ts +119 -5
- package/src/resources/shared/package.json +3 -0
- package/src/resources/skills/create-skill/references/executable-code.md +1 -1
- package/src/resources/skills/create-skill/workflows/add-reference.md +8 -3
- package/src/resources/skills/create-skill/workflows/add-script.md +4 -2
- package/src/resources/skills/create-skill/workflows/add-template.md +3 -1
- package/src/resources/skills/create-skill/workflows/add-workflow.md +8 -3
- package/src/resources/skills/create-skill/workflows/upgrade-to-router.md +10 -5
- package/src/resources/skills/create-skill/workflows/verify-skill.md +9 -4
- package/src/resources/skills/spike-wrap-up/SKILL.md +9 -9
- /package/dist/web/standalone/.next/static/{C24pqUd-aru-l0Dp0gLZP → mU4QIDlpVHDdjDpeEKh5W}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{C24pqUd-aru-l0Dp0gLZP → mU4QIDlpVHDdjDpeEKh5W}/_ssgManifest.js +0 -0
|
@@ -15,16 +15,15 @@ import { closeWorkflowDatabase, getWorkflowDatabasePath, openWorkflowDatabasePat
|
|
|
15
15
|
import { execFileSync } from "node:child_process";
|
|
16
16
|
import { gsdRoot, resolveGsdPathContract } from "./paths.js";
|
|
17
17
|
import { createWorktree, removeWorktree, worktreePath, isInsideWorktreesDir, } from "./worktree-manager.js";
|
|
18
|
+
import { worktreePathFor } from "./worktree-placement.js";
|
|
18
19
|
import { detectWorktreeName, nudgeGitBranchCache, } from "./worktree.js";
|
|
19
|
-
import {
|
|
20
|
+
import { isGsdWorktreePath, projectRootFromWorktreePath, normalizeWorktreePathForCompare, resolveWorktreeProjectRoot, } from "./worktree-root.js";
|
|
20
21
|
import { autoResolveSafeConflictPaths } from "./git-conflict-resolve.js";
|
|
21
22
|
import { MergeConflictError, readIntegrationBranch, resolveMilestoneIntegrationBranch, RUNTIME_EXCLUSION_PATHS } from "./git-service.js";
|
|
22
|
-
import {
|
|
23
|
+
import { publishMilestone } from "./publication.js";
|
|
23
24
|
import { debugLog } from "./debug-logger.js";
|
|
24
25
|
import { logWarning, logError } from "./workflow-logger.js";
|
|
25
26
|
import { checkoutBranchWithStashGuard, cleanupConflictState, gsdJsonlFilesWithConflictMarkers, hasConflictMarkers, popStashByRef, removeMergeStateFiles, stashAlreadyExistsFilesFromError, stashRefFromError, } from "./worktree-git-recovery.js";
|
|
26
|
-
// Re-export for existing callers/tests (auto-start.ts, checkout-branch-stash-guard.test.ts).
|
|
27
|
-
export { checkoutBranchWithStashGuard } from "./worktree-git-recovery.js";
|
|
28
27
|
import { loadEffectiveGSDPreferences } from "./preferences.js";
|
|
29
28
|
import { MILESTONE_ID_RE } from "./milestone-ids.js";
|
|
30
29
|
import { runWorktreePostCreateHook } from "./worktree-post-create-hook.js";
|
|
@@ -184,19 +183,6 @@ function gitPathspecForWorktreePath(basePath, targetPath) {
|
|
|
184
183
|
export function _gitPathspecForWorktreePath(basePath, targetPath) {
|
|
185
184
|
return gitPathspecForWorktreePath(basePath, targetPath);
|
|
186
185
|
}
|
|
187
|
-
function gitRemoteExists(basePath, remote) {
|
|
188
|
-
try {
|
|
189
|
-
execFileSync("git", ["remote", "get-url", remote], {
|
|
190
|
-
cwd: basePath,
|
|
191
|
-
stdio: ["ignore", "pipe", "pipe"],
|
|
192
|
-
encoding: "utf-8",
|
|
193
|
-
});
|
|
194
|
-
return true;
|
|
195
|
-
}
|
|
196
|
-
catch {
|
|
197
|
-
return false;
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
186
|
function findRegularMergeChangedPaths(basePath, milestoneBranch, mainBranch) {
|
|
201
187
|
const changedPaths = new Set();
|
|
202
188
|
let mergeLog = "";
|
|
@@ -392,12 +378,9 @@ export function checkResourcesStale(versionOnStart) {
|
|
|
392
378
|
* Returns the corrected base path.
|
|
393
379
|
*/
|
|
394
380
|
export function escapeStaleWorktree(base) {
|
|
395
|
-
const
|
|
396
|
-
if (
|
|
381
|
+
const projectRoot = projectRootFromWorktreePath(base);
|
|
382
|
+
if (projectRoot === null)
|
|
397
383
|
return base;
|
|
398
|
-
// base is inside .gsd/worktrees/<something> — extract the project root.
|
|
399
|
-
// Normalization is 1:1 on characters, so the segment index is valid in `base`.
|
|
400
|
-
const projectRoot = base.slice(0, segment.gsdIdx);
|
|
401
384
|
// Guard: If the candidate project root's .gsd IS the user-level ~/.gsd,
|
|
402
385
|
// the string-slice heuristic matched the wrong /.gsd/ boundary. This happens
|
|
403
386
|
// when .gsd is a symlink into ~/.gsd/projects/<hash> and process.cwd()
|
|
@@ -1078,7 +1061,9 @@ export function isInAutoWorktree(basePath) {
|
|
|
1078
1061
|
*/
|
|
1079
1062
|
export function getAutoWorktreePath(basePath, milestoneId) {
|
|
1080
1063
|
basePath = resolveWorktreeProjectRoot(basePath);
|
|
1081
|
-
|
|
1064
|
+
// basePath is already the resolved project root — go straight to placement
|
|
1065
|
+
// instead of worktreePath(), which would re-resolve the root.
|
|
1066
|
+
const p = worktreePathFor(basePath, milestoneId);
|
|
1082
1067
|
if (!existsSync(p))
|
|
1083
1068
|
return null;
|
|
1084
1069
|
// Validate this is a real git worktree, not a stray directory.
|
|
@@ -1738,8 +1723,6 @@ export function mergeMilestoneToMain(originalBasePath_, milestoneId, roadmapCont
|
|
|
1738
1723
|
const isUntrackedRestoreFailure = stashPopMessage.includes("could not restore untracked files from stash");
|
|
1739
1724
|
const gsdContentConflicts = [];
|
|
1740
1725
|
const alreadyExists = stashAlreadyExistsFilesFromError(e);
|
|
1741
|
-
const gsdAlreadyExists = alreadyExists.filter((f) => f.startsWith(".gsd/"));
|
|
1742
|
-
const nonGsdAlreadyExists = alreadyExists.filter((f) => !f.startsWith(".gsd/"));
|
|
1743
1726
|
// Untracked-file restore failures can leave marker conflicts in tracked
|
|
1744
1727
|
// .gsd JSONL files without producing `U` status entries.
|
|
1745
1728
|
if (isUntrackedRestoreFailure) {
|
|
@@ -1800,10 +1783,11 @@ export function mergeMilestoneToMain(originalBasePath_, milestoneId, roadmapCont
|
|
|
1800
1783
|
}
|
|
1801
1784
|
else if (gsdUU.length === 0 &&
|
|
1802
1785
|
nonGsdUU.length === 0 &&
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
//
|
|
1806
|
-
//
|
|
1786
|
+
alreadyExists.length > 0) {
|
|
1787
|
+
// Untracked-file restore failure from stash pop where all collided paths
|
|
1788
|
+
// already exist after merge (committed on target). Safe to drop the stash
|
|
1789
|
+
// for the full alreadyExists set — they were untracked on source by
|
|
1790
|
+
// definition of the "already exists, no checkout" failure.
|
|
1807
1791
|
if (stashRefForDrop) {
|
|
1808
1792
|
try {
|
|
1809
1793
|
execFileSync("git", ["stash", "drop", stashRefForDrop], {
|
|
@@ -1826,11 +1810,6 @@ export function mergeMilestoneToMain(originalBasePath_, milestoneId, roadmapCont
|
|
|
1826
1810
|
files: nonGsdUU.join(", "),
|
|
1827
1811
|
});
|
|
1828
1812
|
}
|
|
1829
|
-
else if (nonGsdAlreadyExists.length > 0) {
|
|
1830
|
-
logWarning("reconcile", "Stash pop restore collision on non-.gsd files after merge", {
|
|
1831
|
-
files: nonGsdAlreadyExists.join(", "),
|
|
1832
|
-
});
|
|
1833
|
-
}
|
|
1834
1813
|
else {
|
|
1835
1814
|
logWarning("worktree", "git stash pop failed without resolvable conflict files; leaving stash for manual recovery");
|
|
1836
1815
|
}
|
|
@@ -1925,63 +1904,24 @@ export function mergeMilestoneToMain(originalBasePath_, milestoneId, roadmapCont
|
|
|
1925
1904
|
}
|
|
1926
1905
|
};
|
|
1927
1906
|
let shouldCleanup = false;
|
|
1928
|
-
let pushed = false;
|
|
1929
|
-
let prCreated = false;
|
|
1930
1907
|
try {
|
|
1931
|
-
// 10.
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
}
|
|
1949
|
-
// 9b. Auto-create PR if enabled (#2302: no longer gated on pushed/auto_push)
|
|
1950
|
-
if (prefs.auto_pr === true && !nothingToCommit) {
|
|
1951
|
-
const remote = prefs.remote ?? "origin";
|
|
1952
|
-
const prTarget = prefs.pr_target_branch ?? mainBranch;
|
|
1953
|
-
if (gitRemoteExists(originalBasePath_, remote)) {
|
|
1954
|
-
try {
|
|
1955
|
-
// Push the milestone branch to remote first
|
|
1956
|
-
execFileSync("git", ["push", remote, milestoneBranch], {
|
|
1957
|
-
cwd: originalBasePath_,
|
|
1958
|
-
stdio: ["ignore", "pipe", "pipe"],
|
|
1959
|
-
encoding: "utf-8",
|
|
1960
|
-
});
|
|
1961
|
-
const prEvidence = buildPullRequestEvidence({
|
|
1962
|
-
milestoneId,
|
|
1963
|
-
milestoneTitle,
|
|
1964
|
-
changeType: "feat",
|
|
1965
|
-
summaries: completedSlices.map((slice) => `### ${slice.id}\n${slice.title}`),
|
|
1966
|
-
testsRun: ["Auto-created after milestone merge. Run `npm run verify:merge` before marking this draft ready."],
|
|
1967
|
-
rollbackNotes: ["Close the draft PR or revert the merge commit if review finds a behavior regression."],
|
|
1968
|
-
how: "Generated by git.auto_pr after the milestone branch was pushed and merged locally.",
|
|
1969
|
-
});
|
|
1970
|
-
const prUrl = createDraftPullRequestFromEvidence(originalBasePath_, milestoneId, prEvidence, {
|
|
1971
|
-
head: milestoneBranch,
|
|
1972
|
-
base: prTarget,
|
|
1973
|
-
});
|
|
1974
|
-
if (!prUrl) {
|
|
1975
|
-
throw new Error("gh pr create returned no URL");
|
|
1976
|
-
}
|
|
1977
|
-
prCreated = true;
|
|
1978
|
-
}
|
|
1979
|
-
catch (err) {
|
|
1980
|
-
// PR creation failure is non-fatal — gh may not be installed or authenticated
|
|
1981
|
-
logWarning("worktree", `PR creation failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
1982
|
-
}
|
|
1983
|
-
}
|
|
1984
|
-
}
|
|
1908
|
+
// 10/9b. Publication (auto-push / draft PR) — Publication module seam (ADR-034).
|
|
1909
|
+
const publication = publishMilestone({
|
|
1910
|
+
basePath: originalBasePath_,
|
|
1911
|
+
milestoneId,
|
|
1912
|
+
milestoneTitle,
|
|
1913
|
+
integrationBranch: mainBranch,
|
|
1914
|
+
milestoneBranch,
|
|
1915
|
+
sliceSummaries: completedSlices.map((slice) => `### ${slice.id}\n${slice.title}`),
|
|
1916
|
+
nothingToCommit,
|
|
1917
|
+
prefs: {
|
|
1918
|
+
autoPush: prefs.auto_push === true,
|
|
1919
|
+
autoPr: prefs.auto_pr === true,
|
|
1920
|
+
remote: prefs.remote,
|
|
1921
|
+
prTargetBranch: prefs.pr_target_branch,
|
|
1922
|
+
},
|
|
1923
|
+
});
|
|
1924
|
+
const { pushed, prCreated } = publication;
|
|
1985
1925
|
// 11. Guard removed — step 9b (#1792) now handles this with a smarter check:
|
|
1986
1926
|
// throws only when the milestone has unanchored code changes, passes
|
|
1987
1927
|
// through when the code is genuinely already on the integration branch.
|
|
@@ -117,6 +117,7 @@ import { createWorkspace, scopeMilestone } from "./workspace.js";
|
|
|
117
117
|
import { registerAutoWorker, markWorkerStopping, } from "./db/auto-workers.js";
|
|
118
118
|
import { releaseMilestoneLease } from "./db/milestone-leases.js";
|
|
119
119
|
import { normalizeRealPath } from "./paths.js";
|
|
120
|
+
import { formatStopNoticePrefix, isBlockedStopReason, stopNoticeDisplayReason, } from "./stop-notice.js";
|
|
120
121
|
// ── ENCAPSULATION INVARIANT ─────────────────────────────────────────────────
|
|
121
122
|
// ALL mutable auto-mode state lives in the AutoSession class (auto/session.ts).
|
|
122
123
|
// This file must NOT declare module-level `let` or `var` variables for state.
|
|
@@ -137,17 +138,7 @@ export function formatAutoStopNotification(prefix, totals, unitCount) {
|
|
|
137
138
|
`Session: ${formatCost(totals.cost)} · ${formatTokenCount(totals.tokens.total)} tokens · ${unitCount} units`,
|
|
138
139
|
].join("\n");
|
|
139
140
|
}
|
|
140
|
-
|
|
141
|
-
return /^Blocked:\s*/i.test(reason ?? "");
|
|
142
|
-
}
|
|
143
|
-
function formatAutoStopDisplayReason(reason) {
|
|
144
|
-
return (reason ?? "").replace(/^Blocked:\s*/i, "").trim();
|
|
145
|
-
}
|
|
146
|
-
export function formatAutoStopNotificationPrefix(reason) {
|
|
147
|
-
const displayReason = formatAutoStopDisplayReason(reason);
|
|
148
|
-
const prefix = isBlockedStopReason(reason) ? "Auto-mode blocked" : "Auto-mode stopped";
|
|
149
|
-
return displayReason ? `${prefix} — ${displayReason}` : prefix;
|
|
150
|
-
}
|
|
141
|
+
export { formatStopNoticePrefix as formatAutoStopNotificationPrefix } from "./stop-notice.js";
|
|
151
142
|
function clearSessionModelOverrideForCommandSession(ctx) {
|
|
152
143
|
const sessionId = s.cmdCtx?.sessionManager?.getSessionId?.() ??
|
|
153
144
|
ctx?.sessionManager?.getSessionId?.();
|
|
@@ -990,8 +981,8 @@ export async function stopAuto(ctx, pi, reason, options = {}) {
|
|
|
990
981
|
if (!s.active && !s.paused)
|
|
991
982
|
return;
|
|
992
983
|
const loadedPreferences = loadEffectiveGSDPreferences(s.basePath || undefined)?.preferences;
|
|
993
|
-
const stopNotificationPrefix =
|
|
994
|
-
const displayReason =
|
|
984
|
+
const stopNotificationPrefix = formatStopNoticePrefix(reason);
|
|
985
|
+
const displayReason = stopNoticeDisplayReason(reason);
|
|
995
986
|
const isHeadlessStop = process.env.GSD_HEADLESS === "1";
|
|
996
987
|
const completionStopRequested = Boolean(options.completionWidget);
|
|
997
988
|
const preserveCloseoutTranscript = !isHeadlessStop && (options.preserveCloseoutTranscript ?? completionStopRequested);
|
|
@@ -15,7 +15,8 @@ import { resumeAutoAfterProviderDelay } from "./provider-error-resume.js";
|
|
|
15
15
|
import { classifyError, createRetryState, resetRetryState, isTransient, } from "../error-classifier.js";
|
|
16
16
|
import { blockModel, isModelBlocked } from "../blocked-models.js";
|
|
17
17
|
import { getProjectGSDPreferencesPath } from "../preferences.js";
|
|
18
|
-
import {
|
|
18
|
+
import { resolveProviderErrorGuidance } from "../provider-error-guidance.js";
|
|
19
|
+
import { formatGuidance } from "../guidance.js";
|
|
19
20
|
const retryState = createRetryState();
|
|
20
21
|
const MAX_NETWORK_RETRIES = 2;
|
|
21
22
|
function isObjectRecord(value) {
|
|
@@ -486,7 +487,7 @@ export async function handleAgentEnd(pi, event, ctx) {
|
|
|
486
487
|
preferencesPath: dash.basePath ? getProjectGSDPreferencesPath(dash.basePath) : undefined,
|
|
487
488
|
hasConfiguredFallbacks: (modelConfig?.fallbacks.length ?? 0) > 0,
|
|
488
489
|
});
|
|
489
|
-
const guidanceText =
|
|
490
|
+
const guidanceText = formatGuidance(guidance);
|
|
490
491
|
await pauseForProviderModelRejection(ctx, pi, {
|
|
491
492
|
errorDetail,
|
|
492
493
|
rawErrorMsg,
|
|
@@ -4,7 +4,6 @@ import { existsSync, readdirSync } from "node:fs";
|
|
|
4
4
|
import { homedir } from "node:os";
|
|
5
5
|
import { join } from "node:path";
|
|
6
6
|
import { createBashTool, createEditTool, createReadTool, createWriteTool } from "@gsd/pi-coding-agent";
|
|
7
|
-
import { DEFAULT_BASH_TIMEOUT_SECS } from "../constants.js";
|
|
8
7
|
import { logWarning } from "../workflow-logger.js";
|
|
9
8
|
import { openWorkflowDatabase } from "../db-workspace.js";
|
|
10
9
|
import { getAutoWorktreePath } from "../auto-worktree.js";
|
|
@@ -79,18 +78,36 @@ export function registerDynamicTools(pi) {
|
|
|
79
78
|
const baseBash = createBashTool(fallbackRoot, {
|
|
80
79
|
spawnHook: (ctx) => ctx,
|
|
81
80
|
});
|
|
81
|
+
// The auto-mode stalled-tool watchdog only exists in GSD/auto-mode, so the
|
|
82
|
+
// watchdog verbiage is injected here (the GSD-registered tool) rather than in
|
|
83
|
+
// core bash.ts, which is reused by non-GSD embeddings that have no watchdog.
|
|
84
|
+
const WATCHDOG_DETAIL = "Genuine hangs are caught by the auto-mode stalled-tool watchdog (stalled: 5m / idle: 10m / soft: 20m / hard: 30m).";
|
|
85
|
+
const gsdBashDescription = `${baseBash.description} ${WATCHDOG_DETAIL}`;
|
|
86
|
+
const gsdBashParameters = (() => {
|
|
87
|
+
const params = baseBash.parameters;
|
|
88
|
+
if (!params?.properties?.timeout)
|
|
89
|
+
return params;
|
|
90
|
+
return {
|
|
91
|
+
...params,
|
|
92
|
+
properties: {
|
|
93
|
+
...params.properties,
|
|
94
|
+
timeout: {
|
|
95
|
+
...params.properties.timeout,
|
|
96
|
+
description: `${params.properties.timeout.description} ${WATCHDOG_DETAIL}`,
|
|
97
|
+
},
|
|
98
|
+
},
|
|
99
|
+
};
|
|
100
|
+
})();
|
|
82
101
|
const dynamicBash = {
|
|
83
102
|
...baseBash,
|
|
103
|
+
description: gsdBashDescription,
|
|
104
|
+
parameters: gsdBashParameters,
|
|
84
105
|
execute: async (toolCallId, params, signal, onUpdate, ctx) => {
|
|
85
106
|
const basePath = resolveCtxCwd(ctx);
|
|
86
107
|
const fresh = createBashTool(basePath, {
|
|
87
108
|
spawnHook: (spawnCtx) => ({ ...spawnCtx, cwd: basePath }),
|
|
88
109
|
});
|
|
89
|
-
|
|
90
|
-
...params,
|
|
91
|
-
timeout: params.timeout ?? DEFAULT_BASH_TIMEOUT_SECS,
|
|
92
|
-
};
|
|
93
|
-
return fresh.execute(toolCallId, paramsWithTimeout, signal, onUpdate, ctx);
|
|
110
|
+
return fresh.execute(toolCallId, params, signal, onUpdate, ctx);
|
|
94
111
|
},
|
|
95
112
|
};
|
|
96
113
|
pi.registerTool(dynamicBash);
|
|
@@ -13,6 +13,7 @@ import { registerHooks } from "./register-hooks.js";
|
|
|
13
13
|
import { registerShortcuts } from "./register-shortcuts.js";
|
|
14
14
|
import { writeCrashLog } from "./crash-log.js";
|
|
15
15
|
import { logWarning } from "../workflow-logger.js";
|
|
16
|
+
import { UNIT_TOOL_CONTRACTS } from "../unit-tool-contracts.js";
|
|
16
17
|
// Static import so cmux event listeners are registered synchronously during
|
|
17
18
|
// extension bootstrap. Prior implementation used `void import().then()` which
|
|
18
19
|
// queued listener registration as a microtask — any CMUX_CHANNELS emit fired
|
|
@@ -30,6 +31,9 @@ const EPIPE_STORM_THRESHOLD = 100;
|
|
|
30
31
|
const EPIPE_STORM_WINDOW_MS = 10_000;
|
|
31
32
|
let epipeCount = 0;
|
|
32
33
|
let epipeWindowStart = 0;
|
|
34
|
+
export const CRITICAL_GSD_WORKFLOW_TOOL_NAMES = [...new Set(Object.values(UNIT_TOOL_CONTRACTS)
|
|
35
|
+
.flatMap((contract) => contract.requiredWorkflowTools)
|
|
36
|
+
.filter((toolName) => toolName.startsWith("gsd_")))].sort();
|
|
33
37
|
/** Write to stderr without ever re-throwing — stderr can EPIPE too, which would
|
|
34
38
|
* re-enter this handler and re-loop. */
|
|
35
39
|
function safeStderr(msg) {
|
|
@@ -121,6 +125,20 @@ export function installEpipeGuard() {
|
|
|
121
125
|
process.on("unhandledRejection", _gsdRejectionGuard);
|
|
122
126
|
}
|
|
123
127
|
}
|
|
128
|
+
function assertCriticalGsdWorkflowToolsRegistered(pi) {
|
|
129
|
+
if (typeof pi.getAllTools !== "function")
|
|
130
|
+
return;
|
|
131
|
+
const registered = new Set(pi.getAllTools().map((tool) => tool.name));
|
|
132
|
+
const missing = CRITICAL_GSD_WORKFLOW_TOOL_NAMES.filter((toolName) => !registered.has(toolName));
|
|
133
|
+
if (missing.length === 0)
|
|
134
|
+
return;
|
|
135
|
+
const message = [
|
|
136
|
+
`Critical GSD workflow tool registration failed; missing required tool(s): ${missing.join(", ")}.`,
|
|
137
|
+
"Check earlier bootstrap warnings for the registration slot that failed.",
|
|
138
|
+
].join(" ");
|
|
139
|
+
logWarning("bootstrap", message);
|
|
140
|
+
throw new Error(message);
|
|
141
|
+
}
|
|
124
142
|
export function registerGsdExtension(pi) {
|
|
125
143
|
// Note: registerGSDCommand is called by index.ts before this function,
|
|
126
144
|
// so we intentionally skip it here to avoid double-registration.
|
|
@@ -186,4 +204,5 @@ export function registerGsdExtension(pi) {
|
|
|
186
204
|
logWarning("bootstrap", `Failed to register ${name}: ${err instanceof Error ? err.message : String(err)}`);
|
|
187
205
|
}
|
|
188
206
|
}
|
|
207
|
+
assertCriticalGsdWorkflowToolsRegistered(pi);
|
|
189
208
|
}
|
|
@@ -7,7 +7,7 @@ import { isToolCallEventType } from "@gsd/pi-coding-agent";
|
|
|
7
7
|
import { ALWAYS_PRESERVED_SHIM_TOOL_NAMES } from "@gsd/pi-ai";
|
|
8
8
|
import { updateSnapshot } from "../ecosystem/gsd-extension-api.js";
|
|
9
9
|
import { buildMilestoneFileName, clearPathCache, milestonesDir, resolveMilestonePath, resolveSliceFile, resolveSlicePath } from "../paths.js";
|
|
10
|
-
import { applyAskUserQuestionsGateResult, canonicalToolName, clearDiscussionFlowState, formatPendingAskUserQuestionsGateMessage, isApprovalGateVerifiedInSnapshot, isMilestoneDepthVerified, isMilestoneDepthVerifiedInSnapshot, isQueuePhaseActive,
|
|
10
|
+
import { applyAskUserQuestionsGateResult, canonicalToolName, clearDiscussionFlowState, formatPendingAskUserQuestionsGateMessage, isApprovalGateVerifiedInSnapshot, isDepthConfirmationAnswer, isMilestoneDepthVerified, isMilestoneDepthVerifiedInSnapshot, isQueuePhaseActive, markApprovalGateVerified, markDepthVerified, refreshWriteGateStateFromDisk, resetWriteGateState, shouldBlockContextWrite, shouldBlockPlanningUnit, shouldBlockQueueExecution, shouldBlockWorktreeWrite, isGateQuestionId, setPendingGate, clearPendingGate, getPendingGate, shouldBlockPendingGate, shouldBlockPendingGateBash, extractDepthVerificationMilestoneId } from "./write-gate.js";
|
|
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";
|
|
@@ -19,7 +19,9 @@ import { saveActivityLog } from "../activity-log.js";
|
|
|
19
19
|
import { recordToolCall as safetyRecordToolCall, recordToolResult as safetyRecordToolResult, saveEvidenceToDisk } from "../safety/evidence-collector.js";
|
|
20
20
|
import { parseUnitId } from "../unit-id.js";
|
|
21
21
|
import { classifyCommand } from "../safety/destructive-guard.js";
|
|
22
|
+
import { confirmDestructiveCommand, consumeDestructiveConfirmation, isDestructiveConfirmGateId, requestDestructiveConfirmation, } from "../safety/destructive-confirmation.js";
|
|
22
23
|
import { logWarning as safetyLogWarning } from "../workflow-logger.js";
|
|
24
|
+
import { isUnitCloseoutTool, runInteractiveUnitCloseout } from "../unit-closeout.js";
|
|
23
25
|
import { installNotifyInterceptor } from "./notify-interceptor.js";
|
|
24
26
|
import { initNotificationStore } from "../notification-store.js";
|
|
25
27
|
import { initNotificationWidget } from "../notification-widget.js";
|
|
@@ -31,11 +33,14 @@ import { applyUnitSkillVisibility, unitHasSkillManifest } from "../skill-scope.j
|
|
|
31
33
|
import { getGuidedUnitContext } from "../guided-unit-context.js";
|
|
32
34
|
import { registerPlanMilestoneSchemaRecovery } from "./plan-milestone-schema-recovery.js";
|
|
33
35
|
import { AUTO_UNIT_SCOPED_TOOLS, RUN_UAT_BROWSER_TOOL_NAMES, canonicalWorkflowToolName, isWorkflowAliasTool } from "../auto-unit-tool-scope.js";
|
|
36
|
+
import { hasBrowserContractPrefix } from "../../shared/browser-contract.js";
|
|
34
37
|
import { filterToolsForProvider } from "../model-router.js";
|
|
35
38
|
import { mcpToolMatchesBaseName } from "../mcp-tool-name.js";
|
|
36
39
|
import { RUN_UAT_READ_ONLY_TOOL_NAMES, RUN_UAT_WORKFLOW_TOOL_NAMES } from "../tool-presentation-plan.js";
|
|
37
40
|
import { supportsSourceObservationsForUnit } from "../source-observations.js";
|
|
38
41
|
import { clearPendingAutoStart } from "../pending-auto-start.js";
|
|
42
|
+
import { resolveWorkflowToolBasePath } from "./dynamic-tools.js";
|
|
43
|
+
import { getRequiredWorkflowToolsForUnit } from "../unit-tool-contracts.js";
|
|
39
44
|
let approvalQuestionAbortInFlight = false;
|
|
40
45
|
async function loadWelcomeScreenModule() {
|
|
41
46
|
const candidates = [];
|
|
@@ -138,7 +143,7 @@ function withPreservedShimTools(toolNames) {
|
|
|
138
143
|
}
|
|
139
144
|
/** True for the browser automation tools (browser_navigate, browser_click, ...). */
|
|
140
145
|
function isBrowserTool(toolName) {
|
|
141
|
-
return canonicalToolName(toolName)
|
|
146
|
+
return hasBrowserContractPrefix(canonicalToolName(toolName));
|
|
142
147
|
}
|
|
143
148
|
/**
|
|
144
149
|
* True when any message in the request is driven by a GSD workflow command
|
|
@@ -200,7 +205,7 @@ export function buildMinimalGsdToolSet(activeToolNames) {
|
|
|
200
205
|
const minimal = resolveScopedToolNames(activeToolNames, MINIMAL_GSD_TOOL_NAMES);
|
|
201
206
|
return withPreservedShimTools([...new Set([...preserved, ...minimal])]);
|
|
202
207
|
}
|
|
203
|
-
export function buildMinimalAutoGsdToolSet(activeToolNames, unitType, registeredToolNames = activeToolNames) {
|
|
208
|
+
export function buildMinimalAutoGsdToolSet(activeToolNames, unitType, registeredToolNames = activeToolNames, warnOnUnresolvedRequiredTools = registeredToolNames !== activeToolNames) {
|
|
204
209
|
if (unitType === "run-uat") {
|
|
205
210
|
return buildRunUatGsdToolSet(activeToolNames, registeredToolNames);
|
|
206
211
|
}
|
|
@@ -212,7 +217,20 @@ export function buildMinimalAutoGsdToolSet(activeToolNames, unitType, registered
|
|
|
212
217
|
...availableBaseTools,
|
|
213
218
|
])];
|
|
214
219
|
const scoped = resolveScopedToolNames([...activeToolNames, ...registeredToolNames], [...MINIMAL_GSD_TOOL_NAMES, ...unitTools]);
|
|
215
|
-
|
|
220
|
+
const result = withPreservedShimTools([...new Set([...preserved, ...scoped])]);
|
|
221
|
+
warnIfRequiredWorkflowToolsUnresolved(unitType, result, warnOnUnresolvedRequiredTools);
|
|
222
|
+
return result;
|
|
223
|
+
}
|
|
224
|
+
function hasResolvedWorkflowTool(resolvedToolNames, requiredToolName) {
|
|
225
|
+
return resolvedToolNames.some((name) => name === requiredToolName || mcpToolMatchesBaseName(name, requiredToolName));
|
|
226
|
+
}
|
|
227
|
+
function warnIfRequiredWorkflowToolsUnresolved(unitType, scopedToolNames, shouldWarn) {
|
|
228
|
+
if (!unitType || !shouldWarn)
|
|
229
|
+
return;
|
|
230
|
+
const unresolved = getRequiredWorkflowToolsForUnit(unitType).filter((toolName) => !hasResolvedWorkflowTool(scopedToolNames, toolName));
|
|
231
|
+
if (unresolved.length === 0)
|
|
232
|
+
return;
|
|
233
|
+
safetyLogWarning("bootstrap", `buildMinimalAutoGsdToolSet(${unitType}): required workflow tool(s) not in active/registered surface after scoping: ${unresolved.join(", ")}. Tool registration may have partially failed, provider filtering may have removed a required tool, or workflow MCP may be disconnected.`);
|
|
216
234
|
}
|
|
217
235
|
export function buildRunUatGsdToolSet(activeToolNames, registeredToolNames = activeToolNames) {
|
|
218
236
|
const scoped = resolveScopedToolNames([...activeToolNames, ...registeredToolNames], [
|
|
@@ -238,7 +256,7 @@ export function buildMinimalGsdWorkflowToolSet(activeToolNames, registeredToolNa
|
|
|
238
256
|
const scoped = resolveScopedToolNames([...activeToolNames, ...registeredToolNames], WORKFLOW_GSD_TOOL_NAMES);
|
|
239
257
|
return withPreservedShimTools([...new Set([...preserved, ...scoped])]);
|
|
240
258
|
}
|
|
241
|
-
export function buildRequestScopedGsdToolSet(activeToolNames, requestCustomMessages, registeredToolNames = activeToolNames, guidedUnitType) {
|
|
259
|
+
export function buildRequestScopedGsdToolSet(activeToolNames, requestCustomMessages, registeredToolNames = activeToolNames, guidedUnitType, warnOnUnresolvedRequiredTools = registeredToolNames !== activeToolNames) {
|
|
242
260
|
for (let index = (requestCustomMessages?.length ?? 0) - 1; index >= 0; index--) {
|
|
243
261
|
const currentCustomType = requestCustomMessages?.[index]?.customType;
|
|
244
262
|
if (currentCustomType === "gsd-run" ||
|
|
@@ -246,7 +264,7 @@ export function buildRequestScopedGsdToolSet(activeToolNames, requestCustomMessa
|
|
|
246
264
|
currentCustomType === "gsd-doctor-heal" ||
|
|
247
265
|
currentCustomType === "gsd-triage") {
|
|
248
266
|
if (guidedUnitType) {
|
|
249
|
-
return buildMinimalAutoGsdToolSet(activeToolNames, guidedUnitType, registeredToolNames);
|
|
267
|
+
return buildMinimalAutoGsdToolSet(activeToolNames, guidedUnitType, registeredToolNames, warnOnUnresolvedRequiredTools);
|
|
250
268
|
}
|
|
251
269
|
return buildMinimalGsdWorkflowToolSet(activeToolNames, registeredToolNames);
|
|
252
270
|
}
|
|
@@ -280,8 +298,9 @@ function applyMinimalGsdToolSurface(pi) {
|
|
|
280
298
|
const dash = getAutoRuntimeSnapshot();
|
|
281
299
|
if (dash.active && dash.currentUnit) {
|
|
282
300
|
const currentToolNames = pi.getActiveTools();
|
|
301
|
+
const hasRegisteredSurface = typeof pi.getAllTools === "function";
|
|
283
302
|
const registeredToolNames = resolveRegisteredToolNames(pi, currentToolNames);
|
|
284
|
-
const scopedToolNames = buildMinimalAutoGsdToolSet(currentToolNames, dash.currentUnit.type, registeredToolNames);
|
|
303
|
+
const scopedToolNames = buildMinimalAutoGsdToolSet(currentToolNames, dash.currentUnit.type, registeredToolNames, hasRegisteredSurface);
|
|
285
304
|
recordAutoToolSurfaceSnapshot({
|
|
286
305
|
source: "runtime-scope",
|
|
287
306
|
unitType: dash.currentUnit.type,
|
|
@@ -300,9 +319,10 @@ export function scopeGsdWorkflowToolsForDispatch(pi, unitType) {
|
|
|
300
319
|
if (isFullGsdToolSurfaceRequested())
|
|
301
320
|
return null;
|
|
302
321
|
const current = pi.getActiveTools();
|
|
322
|
+
const hasRegisteredSurface = typeof pi.getAllTools === "function";
|
|
303
323
|
const registeredToolNames = resolveRegisteredToolNames(pi, current);
|
|
304
324
|
const scoped = unitType
|
|
305
|
-
? buildMinimalAutoGsdToolSet(current, unitType, registeredToolNames)
|
|
325
|
+
? buildMinimalAutoGsdToolSet(current, unitType, registeredToolNames, hasRegisteredSurface)
|
|
306
326
|
: buildMinimalGsdWorkflowToolSet(current, registeredToolNames);
|
|
307
327
|
recordAutoToolSurfaceSnapshot({
|
|
308
328
|
source: "dispatch-scope",
|
|
@@ -447,8 +467,7 @@ function activateDeferredApprovalGate(basePath) {
|
|
|
447
467
|
return;
|
|
448
468
|
const gateId = deferredApprovalGate.gateId;
|
|
449
469
|
deferredApprovalGate = null;
|
|
450
|
-
refreshWriteGateStateFromDisk(basePath);
|
|
451
|
-
const snapshot = loadWriteGateSnapshot(basePath);
|
|
470
|
+
const snapshot = refreshWriteGateStateFromDisk(basePath);
|
|
452
471
|
const milestoneId = extractDepthVerificationMilestoneId(gateId);
|
|
453
472
|
if (isApprovalGateVerifiedInSnapshot(snapshot, gateId))
|
|
454
473
|
return;
|
|
@@ -472,6 +491,25 @@ function isContextDraftSummarySave(toolName, input) {
|
|
|
472
491
|
return false;
|
|
473
492
|
return input.artifact_type === "CONTEXT-DRAFT";
|
|
474
493
|
}
|
|
494
|
+
/**
|
|
495
|
+
* External engines (claude-code-cli) deliver ask_user_questions results as
|
|
496
|
+
* relayed MCP tool results: the structured round payload arrives in
|
|
497
|
+
* `result.structuredContent`, not in pi-native `event.details`. Without this
|
|
498
|
+
* fallback, applyAskUserQuestionsGateResult sees no response for an answered
|
|
499
|
+
* gate question and lands in the "waiting" branch — leaving a re-armed gate
|
|
500
|
+
* permanently pending and the discuss→auto handoff blocked.
|
|
501
|
+
*/
|
|
502
|
+
function resolveAskUserQuestionsGateDetails(event) {
|
|
503
|
+
const hasRoundShape = (value) => !!value && typeof value === "object" &&
|
|
504
|
+
(value.cancelled !== undefined || value.response !== undefined);
|
|
505
|
+
const details = event.details;
|
|
506
|
+
if (hasRoundShape(details))
|
|
507
|
+
return details;
|
|
508
|
+
const structured = event.result?.structuredContent;
|
|
509
|
+
if (hasRoundShape(structured))
|
|
510
|
+
return structured;
|
|
511
|
+
return details ?? {};
|
|
512
|
+
}
|
|
475
513
|
function selectedAnswerLabel(selected) {
|
|
476
514
|
if (Array.isArray(selected))
|
|
477
515
|
return selected.map(String).join(", ");
|
|
@@ -1072,19 +1110,35 @@ export function registerHooks(pi, ecosystemHandlers) {
|
|
|
1072
1110
|
}
|
|
1073
1111
|
// Destructive command classification + hard gate in all modes.
|
|
1074
1112
|
if (isToolCallEventType("bash", event)) {
|
|
1075
|
-
const
|
|
1113
|
+
const command = event.input.command;
|
|
1114
|
+
const classification = classifyCommand(command);
|
|
1076
1115
|
if (classification.destructive) {
|
|
1116
|
+
const guardBasePath = contextBasePath(ctx);
|
|
1117
|
+
// Escape hatch: if the user already confirmed this exact command via a
|
|
1118
|
+
// destructive_confirm gate, consume the one-shot token and let it run.
|
|
1119
|
+
// Without this, the block below loops forever — the model cannot satisfy
|
|
1120
|
+
// "confirm in the current turn" because nothing ever clears the gate.
|
|
1121
|
+
if (consumeDestructiveConfirmation(command, guardBasePath)) {
|
|
1122
|
+
safetyLogWarning("safety", `destructive command confirmed: ${classification.labels.join(", ")}`, {
|
|
1123
|
+
command: String(command).slice(0, 200),
|
|
1124
|
+
});
|
|
1125
|
+
return;
|
|
1126
|
+
}
|
|
1127
|
+
// Record the command as pending so an affirmative answer to a
|
|
1128
|
+
// destructive_confirm gate (handled in tool_result) can confirm it.
|
|
1129
|
+
requestDestructiveConfirmation(command, guardBasePath);
|
|
1077
1130
|
const reason = [
|
|
1078
1131
|
"HARD BLOCK: destructive Bash command requires explicit human confirmation.",
|
|
1079
1132
|
`Detected: ${classification.labels.join(", ")}`,
|
|
1080
|
-
"
|
|
1081
|
-
"
|
|
1133
|
+
"Call ask_user_questions with a question id containing \"destructive_confirm\"",
|
|
1134
|
+
"and a first option that affirms the action; wait for the user's response,",
|
|
1135
|
+
"then re-issue this exact command in the same turn to run it once.",
|
|
1082
1136
|
].join(" ");
|
|
1083
1137
|
safetyLogWarning("safety", `destructive command: ${classification.labels.join(", ")}`, {
|
|
1084
|
-
command: String(
|
|
1138
|
+
command: String(command).slice(0, 200),
|
|
1085
1139
|
});
|
|
1086
1140
|
if (ctx) {
|
|
1087
|
-
await maybePauseAutoForApprovalGate(ctx, pi, isAutoActive(), "
|
|
1141
|
+
await maybePauseAutoForApprovalGate(ctx, pi, isAutoActive(), "Destructive-command confirmation is waiting for your answer — pausing auto-mode.");
|
|
1088
1142
|
}
|
|
1089
1143
|
return { block: true, reason };
|
|
1090
1144
|
}
|
|
@@ -1121,12 +1175,27 @@ export function registerHooks(pi, ecosystemHandlers) {
|
|
|
1121
1175
|
else if (isAutoActive()) {
|
|
1122
1176
|
clearToolInvocationError();
|
|
1123
1177
|
}
|
|
1178
|
+
// Interactive Closeout adapter (ADR-032): auto-mode owns closeout for its
|
|
1179
|
+
// own units; interactive completions get the durable git subset (commit +
|
|
1180
|
+
// Closeout Git Verdict) instead of silently bypassing git.isolation.
|
|
1181
|
+
if (!event.isError && !isAutoActive() && isUnitCloseoutTool(toolName)) {
|
|
1182
|
+
try {
|
|
1183
|
+
runInteractiveUnitCloseout({
|
|
1184
|
+
basePath: resolveWorkflowToolBasePath(ctx, event.input),
|
|
1185
|
+
canonicalToolName: toolName,
|
|
1186
|
+
input: event.input,
|
|
1187
|
+
});
|
|
1188
|
+
}
|
|
1189
|
+
catch (err) {
|
|
1190
|
+
safetyLogWarning("engine", `interactive unit closeout failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
1191
|
+
}
|
|
1192
|
+
}
|
|
1124
1193
|
if (toolName !== "ask_user_questions")
|
|
1125
1194
|
return;
|
|
1126
1195
|
const basePath = contextBasePath(ctx);
|
|
1127
1196
|
const milestoneId = await getDiscussionMilestoneIdFor(basePath);
|
|
1128
|
-
const details = event
|
|
1129
|
-
const questions = event.input?.questions ?? [];
|
|
1197
|
+
const details = resolveAskUserQuestionsGateDetails(event);
|
|
1198
|
+
const questions = event.input?.questions ?? details?.questions ?? [];
|
|
1130
1199
|
const gateResult = applyAskUserQuestionsGateResult({
|
|
1131
1200
|
basePath,
|
|
1132
1201
|
questions,
|
|
@@ -1152,6 +1221,22 @@ export function registerHooks(pi, ecosystemHandlers) {
|
|
|
1152
1221
|
}
|
|
1153
1222
|
if (details?.cancelled || !details?.response)
|
|
1154
1223
|
return;
|
|
1224
|
+
// Destructive-command confirmation: an affirmative answer to a
|
|
1225
|
+
// destructive_confirm gate promotes the pending blocked command to a
|
|
1226
|
+
// one-shot confirmed token, which the bash tool_call guard consumes on the
|
|
1227
|
+
// next attempt. Rejecting/declining leaves the command blocked.
|
|
1228
|
+
// (Depth-verification gate handling now lives in
|
|
1229
|
+
// applyAskUserQuestionsGateResult above; only the destructive-confirm gate
|
|
1230
|
+
// is handled inline here.)
|
|
1231
|
+
for (const question of questions) {
|
|
1232
|
+
if (isDestructiveConfirmGateId(question?.id)) {
|
|
1233
|
+
const answer = details.response?.answers?.[question.id];
|
|
1234
|
+
if (isDepthConfirmationAnswer(answer?.selected, question.options)) {
|
|
1235
|
+
confirmDestructiveCommand(basePath);
|
|
1236
|
+
}
|
|
1237
|
+
break;
|
|
1238
|
+
}
|
|
1239
|
+
}
|
|
1155
1240
|
if (!milestoneId)
|
|
1156
1241
|
return;
|
|
1157
1242
|
await saveDiscussionQuestionRound(basePath, milestoneId, questions, details);
|
|
@@ -1162,7 +1247,23 @@ export function registerHooks(pi, ecosystemHandlers) {
|
|
|
1162
1247
|
if (toolName === "ask_user_questions") {
|
|
1163
1248
|
const questionId = extractGateQuestionId(event.args);
|
|
1164
1249
|
if (typeof questionId === "string") {
|
|
1165
|
-
|
|
1250
|
+
// External engines (claude-code-cli) ingest the SDK turn's tool blocks
|
|
1251
|
+
// post-hoc, so this event can fire AFTER the workflow MCP child already
|
|
1252
|
+
// verified this gate and allowed the CONTEXT save. setPendingGate also
|
|
1253
|
+
// revokes verifiedDepthMilestones/verifiedApprovalGates, so an
|
|
1254
|
+
// unconditional re-arm here wipes the child's verification and leaves
|
|
1255
|
+
// the discuss→auto handoff permanently blocked. Skip the re-arm when
|
|
1256
|
+
// the snapshot already records this exact gate as verified — mirrors
|
|
1257
|
+
// activateDeferredApprovalGate's guard. Stale verified state cannot
|
|
1258
|
+
// leak into a later re-discussion: a successful handoff deletes the
|
|
1259
|
+
// snapshot via clearDiscussionFlowState.
|
|
1260
|
+
const snapshot = refreshWriteGateStateFromDisk(basePath);
|
|
1261
|
+
const gateMilestoneId = extractDepthVerificationMilestoneId(questionId);
|
|
1262
|
+
const alreadyVerified = isApprovalGateVerifiedInSnapshot(snapshot, questionId) ||
|
|
1263
|
+
isMilestoneDepthVerifiedInSnapshot(snapshot, gateMilestoneId);
|
|
1264
|
+
if (!alreadyVerified) {
|
|
1265
|
+
setPendingGate(questionId, basePath);
|
|
1266
|
+
}
|
|
1166
1267
|
clearDeferredApprovalGate(basePath);
|
|
1167
1268
|
}
|
|
1168
1269
|
}
|
|
@@ -1252,12 +1353,13 @@ export function registerHooks(pi, ecosystemHandlers) {
|
|
|
1252
1353
|
return surfaceReduced ? { toolNames: providerCompatible } : undefined;
|
|
1253
1354
|
}
|
|
1254
1355
|
const registeredToolNames = resolveRegisteredToolNames(pi, event.activeToolNames);
|
|
1356
|
+
const hasRegisteredSurface = typeof pi.getAllTools === "function";
|
|
1255
1357
|
const compatibleRegisteredToolNames = filterToolsForProvider(registeredToolNames, event.selectedModelApi, event.selectedModelProvider).compatible.filter((name) => !(dropAliases && isWorkflowAliasTool(name)));
|
|
1256
1358
|
const guidedUnit = getGuidedUnitContext();
|
|
1257
1359
|
const requestRegisteredToolNames = guidedUnit?.unitType === "run-uat"
|
|
1258
1360
|
? compatibleRegisteredToolNames
|
|
1259
1361
|
: registeredToolNames;
|
|
1260
|
-
const requestScoped = buildRequestScopedGsdToolSet(guidedUnit?.unitType === "run-uat" ? aliasFilteredCompatible : providerCompatible, event.requestCustomMessages, requestRegisteredToolNames, guidedUnit?.unitType);
|
|
1362
|
+
const requestScoped = buildRequestScopedGsdToolSet(guidedUnit?.unitType === "run-uat" ? aliasFilteredCompatible : providerCompatible, event.requestCustomMessages, requestRegisteredToolNames, guidedUnit?.unitType, hasRegisteredSurface);
|
|
1261
1363
|
if (requestScoped) {
|
|
1262
1364
|
recordAutoToolSurfaceSnapshot({
|
|
1263
1365
|
source: "provider-adjustment",
|
|
@@ -1273,7 +1375,7 @@ export function registerHooks(pi, ecosystemHandlers) {
|
|
|
1273
1375
|
const registeredForUnit = dash.currentUnit.type === "run-uat"
|
|
1274
1376
|
? compatibleRegisteredToolNames
|
|
1275
1377
|
: resolveRegisteredToolNames(pi, event.activeToolNames);
|
|
1276
|
-
const scopedToolNames = buildMinimalAutoGsdToolSet(dash.currentUnit.type === "run-uat" ? aliasFilteredCompatible : providerCompatible, dash.currentUnit.type, registeredForUnit);
|
|
1378
|
+
const scopedToolNames = buildMinimalAutoGsdToolSet(dash.currentUnit.type === "run-uat" ? aliasFilteredCompatible : providerCompatible, dash.currentUnit.type, registeredForUnit, hasRegisteredSurface);
|
|
1277
1379
|
recordAutoToolSurfaceSnapshot({
|
|
1278
1380
|
source: "provider-adjustment",
|
|
1279
1381
|
unitType: dash.currentUnit.type,
|