@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
|
@@ -13,7 +13,7 @@ import type { GSDEcosystemBeforeAgentStartHandler } from "../ecosystem/gsd-exten
|
|
|
13
13
|
import { updateSnapshot } from "../ecosystem/gsd-extension-api.js";
|
|
14
14
|
|
|
15
15
|
import { buildMilestoneFileName, clearPathCache, milestonesDir, resolveMilestonePath, resolveSliceFile, resolveSlicePath } from "../paths.js";
|
|
16
|
-
import { applyAskUserQuestionsGateResult, canonicalToolName, clearDiscussionFlowState, formatPendingAskUserQuestionsGateMessage, isApprovalGateVerifiedInSnapshot, isMilestoneDepthVerified, isMilestoneDepthVerifiedInSnapshot, isQueuePhaseActive, loadWriteGateSnapshot, markApprovalGateVerified, markDepthVerified, refreshWriteGateStateFromDisk, resetWriteGateState, shouldBlockContextWrite, shouldBlockPlanningUnit, shouldBlockQueueExecution, shouldBlockWorktreeWrite, isGateQuestionId, setPendingGate, clearPendingGate, getPendingGate, shouldBlockPendingGate, shouldBlockPendingGateBash, extractDepthVerificationMilestoneId } from "./write-gate.js";
|
|
16
|
+
import { applyAskUserQuestionsGateResult, canonicalToolName, clearDiscussionFlowState, formatPendingAskUserQuestionsGateMessage, isApprovalGateVerifiedInSnapshot, isDepthConfirmationAnswer, isMilestoneDepthVerified, isMilestoneDepthVerifiedInSnapshot, isQueuePhaseActive, loadWriteGateSnapshot, markApprovalGateVerified, markDepthVerified, refreshWriteGateStateFromDisk, resetWriteGateState, shouldBlockContextWrite, shouldBlockPlanningUnit, shouldBlockQueueExecution, shouldBlockWorktreeWrite, isGateQuestionId, setPendingGate, clearPendingGate, getPendingGate, shouldBlockPendingGate, shouldBlockPendingGateBash, extractDepthVerificationMilestoneId } from "./write-gate.js";
|
|
17
17
|
import { resolveManifest } from "../unit-context-manifest.js";
|
|
18
18
|
import { isBlockedStateFile, isBashWriteToStateFile, BLOCKED_WRITE_ERROR } from "../write-intercept.js";
|
|
19
19
|
import { loadFile, saveFile, formatContinue } from "../files.js";
|
|
@@ -39,7 +39,14 @@ import { saveActivityLog } from "../activity-log.js";
|
|
|
39
39
|
import { recordToolCall as safetyRecordToolCall, recordToolResult as safetyRecordToolResult, saveEvidenceToDisk } from "../safety/evidence-collector.js";
|
|
40
40
|
import { parseUnitId } from "../unit-id.js";
|
|
41
41
|
import { classifyCommand } from "../safety/destructive-guard.js";
|
|
42
|
+
import {
|
|
43
|
+
confirmDestructiveCommand,
|
|
44
|
+
consumeDestructiveConfirmation,
|
|
45
|
+
isDestructiveConfirmGateId,
|
|
46
|
+
requestDestructiveConfirmation,
|
|
47
|
+
} from "../safety/destructive-confirmation.js";
|
|
42
48
|
import { logWarning as safetyLogWarning } from "../workflow-logger.js";
|
|
49
|
+
import { isUnitCloseoutTool, runInteractiveUnitCloseout } from "../unit-closeout.js";
|
|
43
50
|
import { installNotifyInterceptor } from "./notify-interceptor.js";
|
|
44
51
|
import { initNotificationStore } from "../notification-store.js";
|
|
45
52
|
import { initNotificationWidget } from "../notification-widget.js";
|
|
@@ -57,11 +64,14 @@ import { applyUnitSkillVisibility, unitHasSkillManifest } from "../skill-scope.j
|
|
|
57
64
|
import { getGuidedUnitContext } from "../guided-unit-context.js";
|
|
58
65
|
import { registerPlanMilestoneSchemaRecovery } from "./plan-milestone-schema-recovery.js";
|
|
59
66
|
import { AUTO_UNIT_SCOPED_TOOLS, RUN_UAT_BROWSER_TOOL_NAMES, canonicalWorkflowToolName, isWorkflowAliasTool } from "../auto-unit-tool-scope.js";
|
|
67
|
+
import { hasBrowserContractPrefix } from "../../shared/browser-contract.js";
|
|
60
68
|
import { filterToolsForProvider } from "../model-router.js";
|
|
61
69
|
import { mcpToolMatchesBaseName } from "../mcp-tool-name.js";
|
|
62
70
|
import { RUN_UAT_READ_ONLY_TOOL_NAMES, RUN_UAT_WORKFLOW_TOOL_NAMES } from "../tool-presentation-plan.js";
|
|
63
71
|
import { supportsSourceObservationsForUnit } from "../source-observations.js";
|
|
64
72
|
import { clearPendingAutoStart } from "../pending-auto-start.js";
|
|
73
|
+
import { resolveWorkflowToolBasePath } from "./dynamic-tools.js";
|
|
74
|
+
import { getRequiredWorkflowToolsForUnit } from "../unit-tool-contracts.js";
|
|
65
75
|
|
|
66
76
|
let approvalQuestionAbortInFlight = false;
|
|
67
77
|
|
|
@@ -178,7 +188,7 @@ function withPreservedShimTools(toolNames: readonly string[]): string[] {
|
|
|
178
188
|
|
|
179
189
|
/** True for the browser automation tools (browser_navigate, browser_click, ...). */
|
|
180
190
|
function isBrowserTool(toolName: string): boolean {
|
|
181
|
-
return canonicalToolName(toolName)
|
|
191
|
+
return hasBrowserContractPrefix(canonicalToolName(toolName));
|
|
182
192
|
}
|
|
183
193
|
|
|
184
194
|
/**
|
|
@@ -259,6 +269,7 @@ export function buildMinimalAutoGsdToolSet(
|
|
|
259
269
|
activeToolNames: readonly string[],
|
|
260
270
|
unitType: string | undefined,
|
|
261
271
|
registeredToolNames: readonly string[] = activeToolNames,
|
|
272
|
+
warnOnUnresolvedRequiredTools = registeredToolNames !== activeToolNames,
|
|
262
273
|
): string[] {
|
|
263
274
|
if (unitType === "run-uat") {
|
|
264
275
|
return buildRunUatGsdToolSet(activeToolNames, registeredToolNames);
|
|
@@ -274,7 +285,36 @@ export function buildMinimalAutoGsdToolSet(
|
|
|
274
285
|
[...activeToolNames, ...registeredToolNames],
|
|
275
286
|
[...MINIMAL_GSD_TOOL_NAMES, ...unitTools],
|
|
276
287
|
);
|
|
277
|
-
|
|
288
|
+
const result = withPreservedShimTools([...new Set([...preserved, ...scoped])]);
|
|
289
|
+
warnIfRequiredWorkflowToolsUnresolved(unitType, result, warnOnUnresolvedRequiredTools);
|
|
290
|
+
return result;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
function hasResolvedWorkflowTool(
|
|
294
|
+
resolvedToolNames: readonly string[],
|
|
295
|
+
requiredToolName: string,
|
|
296
|
+
): boolean {
|
|
297
|
+
return resolvedToolNames.some(
|
|
298
|
+
(name) => name === requiredToolName || mcpToolMatchesBaseName(name, requiredToolName),
|
|
299
|
+
);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
function warnIfRequiredWorkflowToolsUnresolved(
|
|
303
|
+
unitType: string | undefined,
|
|
304
|
+
scopedToolNames: readonly string[],
|
|
305
|
+
shouldWarn: boolean,
|
|
306
|
+
): void {
|
|
307
|
+
if (!unitType || !shouldWarn) return;
|
|
308
|
+
|
|
309
|
+
const unresolved = getRequiredWorkflowToolsForUnit(unitType).filter(
|
|
310
|
+
(toolName) => !hasResolvedWorkflowTool(scopedToolNames, toolName),
|
|
311
|
+
);
|
|
312
|
+
if (unresolved.length === 0) return;
|
|
313
|
+
|
|
314
|
+
safetyLogWarning(
|
|
315
|
+
"bootstrap",
|
|
316
|
+
`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.`,
|
|
317
|
+
);
|
|
278
318
|
}
|
|
279
319
|
|
|
280
320
|
export function buildRunUatGsdToolSet(
|
|
@@ -327,6 +367,7 @@ export function buildRequestScopedGsdToolSet(
|
|
|
327
367
|
requestCustomMessages: readonly { customType?: string }[] | undefined,
|
|
328
368
|
registeredToolNames: readonly string[] = activeToolNames,
|
|
329
369
|
guidedUnitType?: string,
|
|
370
|
+
warnOnUnresolvedRequiredTools = registeredToolNames !== activeToolNames,
|
|
330
371
|
): string[] | undefined {
|
|
331
372
|
for (let index = (requestCustomMessages?.length ?? 0) - 1; index >= 0; index--) {
|
|
332
373
|
const currentCustomType = requestCustomMessages?.[index]?.customType;
|
|
@@ -337,7 +378,12 @@ export function buildRequestScopedGsdToolSet(
|
|
|
337
378
|
currentCustomType === "gsd-triage"
|
|
338
379
|
) {
|
|
339
380
|
if (guidedUnitType) {
|
|
340
|
-
return buildMinimalAutoGsdToolSet(
|
|
381
|
+
return buildMinimalAutoGsdToolSet(
|
|
382
|
+
activeToolNames,
|
|
383
|
+
guidedUnitType,
|
|
384
|
+
registeredToolNames,
|
|
385
|
+
warnOnUnresolvedRequiredTools,
|
|
386
|
+
);
|
|
341
387
|
}
|
|
342
388
|
return buildMinimalGsdWorkflowToolSet(activeToolNames, registeredToolNames);
|
|
343
389
|
}
|
|
@@ -386,11 +432,13 @@ function applyMinimalGsdToolSurface(pi: ExtensionAPI): void {
|
|
|
386
432
|
const dash = getAutoRuntimeSnapshot();
|
|
387
433
|
if (dash.active && dash.currentUnit) {
|
|
388
434
|
const currentToolNames = pi.getActiveTools();
|
|
435
|
+
const hasRegisteredSurface = typeof pi.getAllTools === "function";
|
|
389
436
|
const registeredToolNames = resolveRegisteredToolNames(pi, currentToolNames);
|
|
390
437
|
const scopedToolNames = buildMinimalAutoGsdToolSet(
|
|
391
438
|
currentToolNames,
|
|
392
439
|
dash.currentUnit.type,
|
|
393
440
|
registeredToolNames,
|
|
441
|
+
hasRegisteredSurface,
|
|
394
442
|
);
|
|
395
443
|
recordAutoToolSurfaceSnapshot({
|
|
396
444
|
source: "runtime-scope",
|
|
@@ -412,9 +460,10 @@ export function scopeGsdWorkflowToolsForDispatch(
|
|
|
412
460
|
): ScopedGsdWorkflowState | null {
|
|
413
461
|
if (isFullGsdToolSurfaceRequested()) return null;
|
|
414
462
|
const current = pi.getActiveTools();
|
|
463
|
+
const hasRegisteredSurface = typeof pi.getAllTools === "function";
|
|
415
464
|
const registeredToolNames = resolveRegisteredToolNames(pi, current);
|
|
416
465
|
const scoped = unitType
|
|
417
|
-
? buildMinimalAutoGsdToolSet(current, unitType, registeredToolNames)
|
|
466
|
+
? buildMinimalAutoGsdToolSet(current, unitType, registeredToolNames, hasRegisteredSurface)
|
|
418
467
|
: buildMinimalGsdWorkflowToolSet(current, registeredToolNames);
|
|
419
468
|
recordAutoToolSurfaceSnapshot({
|
|
420
469
|
source: "dispatch-scope",
|
|
@@ -575,8 +624,7 @@ function activateDeferredApprovalGate(basePath: string): void {
|
|
|
575
624
|
if (deferredApprovalGate?.basePath !== basePath) return;
|
|
576
625
|
const gateId = deferredApprovalGate.gateId;
|
|
577
626
|
deferredApprovalGate = null;
|
|
578
|
-
refreshWriteGateStateFromDisk(basePath);
|
|
579
|
-
const snapshot = loadWriteGateSnapshot(basePath);
|
|
627
|
+
const snapshot = refreshWriteGateStateFromDisk(basePath);
|
|
580
628
|
const milestoneId = extractDepthVerificationMilestoneId(gateId);
|
|
581
629
|
if (isApprovalGateVerifiedInSnapshot(snapshot, gateId)) return;
|
|
582
630
|
if (milestoneId && isMilestoneDepthVerifiedInSnapshot(snapshot, milestoneId)) return;
|
|
@@ -600,6 +648,26 @@ function isContextDraftSummarySave(toolName: string, input: unknown): boolean {
|
|
|
600
648
|
return (input as { artifact_type?: unknown }).artifact_type === "CONTEXT-DRAFT";
|
|
601
649
|
}
|
|
602
650
|
|
|
651
|
+
/**
|
|
652
|
+
* External engines (claude-code-cli) deliver ask_user_questions results as
|
|
653
|
+
* relayed MCP tool results: the structured round payload arrives in
|
|
654
|
+
* `result.structuredContent`, not in pi-native `event.details`. Without this
|
|
655
|
+
* fallback, applyAskUserQuestionsGateResult sees no response for an answered
|
|
656
|
+
* gate question and lands in the "waiting" branch — leaving a re-armed gate
|
|
657
|
+
* permanently pending and the discuss→auto handoff blocked.
|
|
658
|
+
*/
|
|
659
|
+
function resolveAskUserQuestionsGateDetails(event: { details?: unknown; result?: unknown }): any {
|
|
660
|
+
const hasRoundShape = (value: any): boolean =>
|
|
661
|
+
!!value && typeof value === "object" &&
|
|
662
|
+
(value.cancelled !== undefined || value.response !== undefined);
|
|
663
|
+
|
|
664
|
+
const details = event.details as any;
|
|
665
|
+
if (hasRoundShape(details)) return details;
|
|
666
|
+
const structured = (event.result as { structuredContent?: unknown } | undefined)?.structuredContent;
|
|
667
|
+
if (hasRoundShape(structured)) return structured;
|
|
668
|
+
return details ?? {};
|
|
669
|
+
}
|
|
670
|
+
|
|
603
671
|
type StructuredQuestion = {
|
|
604
672
|
id?: string;
|
|
605
673
|
header?: string;
|
|
@@ -1328,23 +1396,39 @@ export function registerHooks(
|
|
|
1328
1396
|
|
|
1329
1397
|
// Destructive command classification + hard gate in all modes.
|
|
1330
1398
|
if (isToolCallEventType("bash", event)) {
|
|
1331
|
-
const
|
|
1399
|
+
const command = event.input.command;
|
|
1400
|
+
const classification = classifyCommand(command);
|
|
1332
1401
|
if (classification.destructive) {
|
|
1402
|
+
const guardBasePath = contextBasePath(ctx);
|
|
1403
|
+
// Escape hatch: if the user already confirmed this exact command via a
|
|
1404
|
+
// destructive_confirm gate, consume the one-shot token and let it run.
|
|
1405
|
+
// Without this, the block below loops forever — the model cannot satisfy
|
|
1406
|
+
// "confirm in the current turn" because nothing ever clears the gate.
|
|
1407
|
+
if (consumeDestructiveConfirmation(command, guardBasePath)) {
|
|
1408
|
+
safetyLogWarning("safety", `destructive command confirmed: ${classification.labels.join(", ")}`, {
|
|
1409
|
+
command: String(command).slice(0, 200),
|
|
1410
|
+
});
|
|
1411
|
+
return;
|
|
1412
|
+
}
|
|
1413
|
+
// Record the command as pending so an affirmative answer to a
|
|
1414
|
+
// destructive_confirm gate (handled in tool_result) can confirm it.
|
|
1415
|
+
requestDestructiveConfirmation(command, guardBasePath);
|
|
1333
1416
|
const reason = [
|
|
1334
1417
|
"HARD BLOCK: destructive Bash command requires explicit human confirmation.",
|
|
1335
1418
|
`Detected: ${classification.labels.join(", ")}`,
|
|
1336
|
-
"
|
|
1337
|
-
"
|
|
1419
|
+
"Call ask_user_questions with a question id containing \"destructive_confirm\"",
|
|
1420
|
+
"and a first option that affirms the action; wait for the user's response,",
|
|
1421
|
+
"then re-issue this exact command in the same turn to run it once.",
|
|
1338
1422
|
].join(" ");
|
|
1339
1423
|
safetyLogWarning("safety", `destructive command: ${classification.labels.join(", ")}`, {
|
|
1340
|
-
command: String(
|
|
1424
|
+
command: String(command).slice(0, 200),
|
|
1341
1425
|
});
|
|
1342
1426
|
if (ctx) {
|
|
1343
1427
|
await maybePauseAutoForApprovalGate(
|
|
1344
1428
|
ctx,
|
|
1345
1429
|
pi,
|
|
1346
1430
|
isAutoActive(),
|
|
1347
|
-
"
|
|
1431
|
+
"Destructive-command confirmation is waiting for your answer — pausing auto-mode.",
|
|
1348
1432
|
);
|
|
1349
1433
|
}
|
|
1350
1434
|
return { block: true, reason };
|
|
@@ -1382,13 +1466,27 @@ export function registerHooks(
|
|
|
1382
1466
|
} else if (isAutoActive()) {
|
|
1383
1467
|
clearToolInvocationError();
|
|
1384
1468
|
}
|
|
1469
|
+
// Interactive Closeout adapter (ADR-032): auto-mode owns closeout for its
|
|
1470
|
+
// own units; interactive completions get the durable git subset (commit +
|
|
1471
|
+
// Closeout Git Verdict) instead of silently bypassing git.isolation.
|
|
1472
|
+
if (!event.isError && !isAutoActive() && isUnitCloseoutTool(toolName)) {
|
|
1473
|
+
try {
|
|
1474
|
+
runInteractiveUnitCloseout({
|
|
1475
|
+
basePath: resolveWorkflowToolBasePath(ctx, event.input as { milestone_id?: string }),
|
|
1476
|
+
canonicalToolName: toolName,
|
|
1477
|
+
input: event.input,
|
|
1478
|
+
});
|
|
1479
|
+
} catch (err) {
|
|
1480
|
+
safetyLogWarning("engine", `interactive unit closeout failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
1481
|
+
}
|
|
1482
|
+
}
|
|
1385
1483
|
if (toolName !== "ask_user_questions") return;
|
|
1386
1484
|
const basePath = contextBasePath(ctx);
|
|
1387
1485
|
const milestoneId = await getDiscussionMilestoneIdFor(basePath);
|
|
1388
1486
|
|
|
1389
|
-
const details = event
|
|
1487
|
+
const details = resolveAskUserQuestionsGateDetails(event);
|
|
1390
1488
|
|
|
1391
|
-
const questions: any[] = (event.input as any)?.questions ?? [];
|
|
1489
|
+
const questions: any[] = (event.input as any)?.questions ?? details?.questions ?? [];
|
|
1392
1490
|
const gateResult = applyAskUserQuestionsGateResult({
|
|
1393
1491
|
basePath,
|
|
1394
1492
|
questions,
|
|
@@ -1419,6 +1517,24 @@ export function registerHooks(
|
|
|
1419
1517
|
}
|
|
1420
1518
|
|
|
1421
1519
|
if (details?.cancelled || !details?.response) return;
|
|
1520
|
+
|
|
1521
|
+
// Destructive-command confirmation: an affirmative answer to a
|
|
1522
|
+
// destructive_confirm gate promotes the pending blocked command to a
|
|
1523
|
+
// one-shot confirmed token, which the bash tool_call guard consumes on the
|
|
1524
|
+
// next attempt. Rejecting/declining leaves the command blocked.
|
|
1525
|
+
// (Depth-verification gate handling now lives in
|
|
1526
|
+
// applyAskUserQuestionsGateResult above; only the destructive-confirm gate
|
|
1527
|
+
// is handled inline here.)
|
|
1528
|
+
for (const question of questions) {
|
|
1529
|
+
if (isDestructiveConfirmGateId(question?.id)) {
|
|
1530
|
+
const answer = details.response?.answers?.[question.id];
|
|
1531
|
+
if (isDepthConfirmationAnswer(answer?.selected, question.options)) {
|
|
1532
|
+
confirmDestructiveCommand(basePath);
|
|
1533
|
+
}
|
|
1534
|
+
break;
|
|
1535
|
+
}
|
|
1536
|
+
}
|
|
1537
|
+
|
|
1422
1538
|
if (!milestoneId) return;
|
|
1423
1539
|
await saveDiscussionQuestionRound(basePath, milestoneId, questions, details);
|
|
1424
1540
|
});
|
|
@@ -1429,7 +1545,24 @@ export function registerHooks(
|
|
|
1429
1545
|
if (toolName === "ask_user_questions") {
|
|
1430
1546
|
const questionId = extractGateQuestionId(event.args);
|
|
1431
1547
|
if (typeof questionId === "string") {
|
|
1432
|
-
|
|
1548
|
+
// External engines (claude-code-cli) ingest the SDK turn's tool blocks
|
|
1549
|
+
// post-hoc, so this event can fire AFTER the workflow MCP child already
|
|
1550
|
+
// verified this gate and allowed the CONTEXT save. setPendingGate also
|
|
1551
|
+
// revokes verifiedDepthMilestones/verifiedApprovalGates, so an
|
|
1552
|
+
// unconditional re-arm here wipes the child's verification and leaves
|
|
1553
|
+
// the discuss→auto handoff permanently blocked. Skip the re-arm when
|
|
1554
|
+
// the snapshot already records this exact gate as verified — mirrors
|
|
1555
|
+
// activateDeferredApprovalGate's guard. Stale verified state cannot
|
|
1556
|
+
// leak into a later re-discussion: a successful handoff deletes the
|
|
1557
|
+
// snapshot via clearDiscussionFlowState.
|
|
1558
|
+
const snapshot = refreshWriteGateStateFromDisk(basePath);
|
|
1559
|
+
const gateMilestoneId = extractDepthVerificationMilestoneId(questionId);
|
|
1560
|
+
const alreadyVerified =
|
|
1561
|
+
isApprovalGateVerifiedInSnapshot(snapshot, questionId) ||
|
|
1562
|
+
isMilestoneDepthVerifiedInSnapshot(snapshot, gateMilestoneId);
|
|
1563
|
+
if (!alreadyVerified) {
|
|
1564
|
+
setPendingGate(questionId, basePath);
|
|
1565
|
+
}
|
|
1433
1566
|
clearDeferredApprovalGate(basePath);
|
|
1434
1567
|
}
|
|
1435
1568
|
}
|
|
@@ -1528,6 +1661,7 @@ export function registerHooks(
|
|
|
1528
1661
|
return surfaceReduced ? { toolNames: providerCompatible } : undefined;
|
|
1529
1662
|
}
|
|
1530
1663
|
const registeredToolNames = resolveRegisteredToolNames(pi, event.activeToolNames);
|
|
1664
|
+
const hasRegisteredSurface = typeof pi.getAllTools === "function";
|
|
1531
1665
|
const compatibleRegisteredToolNames = filterToolsForProvider(
|
|
1532
1666
|
registeredToolNames,
|
|
1533
1667
|
event.selectedModelApi,
|
|
@@ -1542,6 +1676,7 @@ export function registerHooks(
|
|
|
1542
1676
|
event.requestCustomMessages,
|
|
1543
1677
|
requestRegisteredToolNames,
|
|
1544
1678
|
guidedUnit?.unitType,
|
|
1679
|
+
hasRegisteredSurface,
|
|
1545
1680
|
);
|
|
1546
1681
|
if (requestScoped) {
|
|
1547
1682
|
recordAutoToolSurfaceSnapshot({
|
|
@@ -1562,6 +1697,7 @@ export function registerHooks(
|
|
|
1562
1697
|
dash.currentUnit.type === "run-uat" ? aliasFilteredCompatible : providerCompatible,
|
|
1563
1698
|
dash.currentUnit.type,
|
|
1564
1699
|
registeredForUnit,
|
|
1700
|
+
hasRegisteredSurface,
|
|
1565
1701
|
);
|
|
1566
1702
|
recordAutoToolSurfaceSnapshot({
|
|
1567
1703
|
source: "provider-adjustment",
|
|
@@ -251,15 +251,19 @@ export function loadWriteGateSnapshot(basePath: string): WriteGateSnapshot {
|
|
|
251
251
|
* verification there; without this refresh the extension host keeps stale
|
|
252
252
|
* pending-gate memory and `activateDeferredApprovalGate` can re-arm a gate
|
|
253
253
|
* that the subprocess already cleared on disk.
|
|
254
|
+
*
|
|
255
|
+
* Returns the snapshot used for the refresh so callers that need to inspect
|
|
256
|
+
* it (e.g. re-arm guards) avoid a second disk read.
|
|
254
257
|
*/
|
|
255
|
-
export function refreshWriteGateStateFromDisk(basePath: string):
|
|
256
|
-
if (!shouldPersistWriteGateSnapshot()) return;
|
|
258
|
+
export function refreshWriteGateStateFromDisk(basePath: string): WriteGateSnapshot {
|
|
257
259
|
const snapshot = loadWriteGateSnapshot(basePath);
|
|
260
|
+
if (!shouldPersistWriteGateSnapshot()) return snapshot;
|
|
258
261
|
const state = getWriteGateState(basePath);
|
|
259
262
|
state.pendingGateId = snapshot.pendingGateId;
|
|
260
263
|
state.activeQueuePhase = snapshot.activeQueuePhase;
|
|
261
264
|
state.verifiedDepthMilestones = new Set(snapshot.verifiedDepthMilestones);
|
|
262
265
|
state.verifiedApprovalGates = new Set(snapshot.verifiedApprovalGates ?? []);
|
|
266
|
+
return snapshot;
|
|
263
267
|
}
|
|
264
268
|
|
|
265
269
|
export function isDepthVerified(basePath: string = process.cwd()): boolean {
|
|
@@ -14,3 +14,6 @@ export const QUICK_BRANCH_RE = /^gsd\/quick\//;
|
|
|
14
14
|
|
|
15
15
|
/** Matches GSD-generated workflow template branches, not arbitrary user gsd/* branches. */
|
|
16
16
|
export const WORKFLOW_BRANCH_RE = /^gsd\/(?:hotfix|bugfix|small-feature|refactor|spike|security-audit|dep-upgrade|full-project)\//;
|
|
17
|
+
|
|
18
|
+
/** Auto-mode milestone branch prefix: milestone/<MID>. */
|
|
19
|
+
export const MILESTONE_BRANCH_PREFIX = "milestone/";
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { execFileSync } from "node:child_process";
|
|
2
|
+
import { resolve } from "node:path";
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
resolveAmbientBrowserEngineResolution,
|
|
6
|
+
resolveBrowserEngineResolution,
|
|
7
|
+
type BrowserEngineMode,
|
|
8
|
+
} from "../browser-tools/engine/selection.js";
|
|
9
|
+
import {
|
|
10
|
+
resolveGsdBrowserCliAvailability,
|
|
11
|
+
resolveGsdBrowserDaemonStartInvocation,
|
|
12
|
+
} from "../shared/gsd-browser-cli.js";
|
|
13
|
+
import { uatTypeIncludesBrowser, type UatType } from "./uat-policy.js";
|
|
14
|
+
|
|
15
|
+
const DEFAULT_DAEMON_START_TIMEOUT_MS = 30_000;
|
|
16
|
+
|
|
17
|
+
function isEnvDisabled(value: string | undefined): boolean {
|
|
18
|
+
if (!value) return false;
|
|
19
|
+
const normalized = value.trim().toLowerCase();
|
|
20
|
+
return normalized === "0" || normalized === "false" || normalized === "off";
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function isWarmUpDisabled(env: NodeJS.ProcessEnv = process.env): boolean {
|
|
24
|
+
const value = env.GSD_BROWSER_WARMUP?.trim().toLowerCase();
|
|
25
|
+
return value === "0" || value === "false" || value === "off";
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface BrowserDaemonWarmContext {
|
|
29
|
+
uatType: UatType;
|
|
30
|
+
sessionProvider?: string;
|
|
31
|
+
sessionAuthMode?: "apiKey" | "oauth" | "externalCli" | "none";
|
|
32
|
+
sessionBaseUrl?: string;
|
|
33
|
+
projectRoot: string;
|
|
34
|
+
env?: NodeJS.ProcessEnv;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** Active engine for warm-up: explicit env override, else session-committed ambient resolution. */
|
|
38
|
+
function resolveActiveBrowserEngine(projectRoot: string, env: NodeJS.ProcessEnv): BrowserEngineMode {
|
|
39
|
+
if (env.GSD_BROWSER_ENGINE?.trim()) {
|
|
40
|
+
return resolveBrowserEngineResolution(env, projectRoot).engine;
|
|
41
|
+
}
|
|
42
|
+
return resolveAmbientBrowserEngineResolution(projectRoot).engine;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function shouldWarmBrowserDaemonForUat(ctx: BrowserDaemonWarmContext): boolean {
|
|
46
|
+
if (!uatTypeIncludesBrowser(ctx.uatType)) return false;
|
|
47
|
+
|
|
48
|
+
const env = ctx.env ?? process.env;
|
|
49
|
+
if (isWarmUpDisabled(env)) return false;
|
|
50
|
+
if (isEnvDisabled(env.GSD_BROWSER_MCP_ENABLED)) return false;
|
|
51
|
+
|
|
52
|
+
const availability = resolveGsdBrowserCliAvailability(env);
|
|
53
|
+
if (!availability.available) return false;
|
|
54
|
+
|
|
55
|
+
const projectRoot = resolve(ctx.projectRoot);
|
|
56
|
+
return resolveActiveBrowserEngine(projectRoot, env) === "gsd-browser";
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export function ensureBrowserDaemonStarted(
|
|
60
|
+
projectRoot: string,
|
|
61
|
+
options: { env?: NodeJS.ProcessEnv; timeoutMs?: number } = {},
|
|
62
|
+
): { ok: true } | { ok: false; error: string } {
|
|
63
|
+
const env = options.env ?? process.env;
|
|
64
|
+
const availability = resolveGsdBrowserCliAvailability(env);
|
|
65
|
+
if (!availability.available) {
|
|
66
|
+
return { ok: false, error: availability.detail };
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
let invocation: ReturnType<typeof resolveGsdBrowserDaemonStartInvocation>;
|
|
70
|
+
try {
|
|
71
|
+
invocation = resolveGsdBrowserDaemonStartInvocation(projectRoot, env);
|
|
72
|
+
} catch (error) {
|
|
73
|
+
return {
|
|
74
|
+
ok: false,
|
|
75
|
+
error: error instanceof Error ? error.message : String(error),
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
try {
|
|
80
|
+
execFileSync(invocation.command, invocation.args, {
|
|
81
|
+
cwd: invocation.cwd,
|
|
82
|
+
env: { ...process.env, ...env, ...(invocation.env ?? {}) },
|
|
83
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
84
|
+
timeout: options.timeoutMs ?? DEFAULT_DAEMON_START_TIMEOUT_MS,
|
|
85
|
+
encoding: "utf-8",
|
|
86
|
+
});
|
|
87
|
+
return { ok: true };
|
|
88
|
+
} catch (error) {
|
|
89
|
+
return {
|
|
90
|
+
ok: false,
|
|
91
|
+
error: error instanceof Error ? error.message : String(error),
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Best-effort pre-warm of the gsd-browser session daemon before browser-backed
|
|
98
|
+
* run-uat dispatch. Returns an actionable stop reason when warm-up is required
|
|
99
|
+
* but fails; returns null when warm-up is skipped or succeeds.
|
|
100
|
+
*/
|
|
101
|
+
export function prepareBrowserDaemonForUat(ctx: BrowserDaemonWarmContext): string | null {
|
|
102
|
+
if (!shouldWarmBrowserDaemonForUat(ctx)) return null;
|
|
103
|
+
|
|
104
|
+
const result = ensureBrowserDaemonStarted(ctx.projectRoot, { env: ctx.env });
|
|
105
|
+
if (result.ok) return null;
|
|
106
|
+
|
|
107
|
+
return `Cannot dispatch browser-backed run-uat: gsd-browser daemon failed to start (${result.error}). Ensure Chrome/Chromium is installed, run \`gsd-browser daemon health\` with the project session flags from .mcp.json, or set GSD_BROWSER_PATH to a Chromium binary.`;
|
|
108
|
+
}
|
|
@@ -1,9 +1,25 @@
|
|
|
1
1
|
// Project/App: gsd-pi
|
|
2
2
|
// File Purpose: Shared browser-observable UAT requirement and evidence detection.
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
import { BROWSER_EVIDENCE_SIGNAL_TOOL_NAMES } from "../shared/browser-contract.js";
|
|
5
|
+
|
|
6
|
+
// Alternation fragment over the contract's evidence-signal names, e.g.
|
|
7
|
+
// `browser_(?:assert|batch|...)`. The names are `browser_`-prefixed
|
|
8
|
+
// identifiers (pinned by tests/browser-contract.test.ts), so no escaping is
|
|
9
|
+
// needed.
|
|
10
|
+
const BROWSER_TOOL_SIGNAL = `browser_(?:${
|
|
11
|
+
BROWSER_EVIDENCE_SIGNAL_TOOL_NAMES.map((name) => name.slice("browser_".length)).join("|")
|
|
12
|
+
})`;
|
|
13
|
+
|
|
14
|
+
export const BROWSER_REQUIREMENT_RE = new RegExp(
|
|
15
|
+
String.raw`\b(?:file://|localhost|playwright|chrome|screenshot|snapshot|${BROWSER_TOOL_SIGNAL})\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`,
|
|
16
|
+
"i",
|
|
17
|
+
);
|
|
5
18
|
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;
|
|
6
|
-
export const BROWSER_RUNTIME_RE =
|
|
19
|
+
export const BROWSER_RUNTIME_RE = new RegExp(
|
|
20
|
+
String.raw`\b(?:browser|playwright|chrome|camoufox|${BROWSER_TOOL_SIGNAL}|screenshot|snapshot|file://|localhost)\b`,
|
|
21
|
+
"i",
|
|
22
|
+
);
|
|
7
23
|
export const BROWSER_ACTION_RE = /\b(?:open(?:ed)?|navigate(?:d)?|click(?:ed)?|type(?:d)?|reload(?:ed)?|capture(?:d)?|screenshot|snapshot)\b/i;
|
|
8
24
|
export const BROWSER_ASSERTION_RE = /\b(?:assert(?:ed|ion)?|observed|confirmed|verified|expected|visible|text|count|label|strikethrough|localstorage|screenshot|snapshot|passed)\b/i;
|
|
9
25
|
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;
|
|
@@ -12,7 +12,7 @@ import { existsSync, readFileSync, writeFileSync, mkdirSync } from "node:fs";
|
|
|
12
12
|
import { join, resolve } from "node:path";
|
|
13
13
|
import { randomUUID } from "node:crypto";
|
|
14
14
|
import { gsdRoot } from "./paths.js";
|
|
15
|
-
import {
|
|
15
|
+
import { projectRootFromWorktreePath } from "./worktree-root.js";
|
|
16
16
|
|
|
17
17
|
// ─── Types ────────────────────────────────────────────────────────────────────
|
|
18
18
|
|
|
@@ -60,11 +60,9 @@ const VALID_CLASSIFICATIONS: readonly string[] = [
|
|
|
60
60
|
* directory that contains `.gsd/worktrees/` — that's the project root.
|
|
61
61
|
*/
|
|
62
62
|
export function resolveCapturesPath(basePath: string): string {
|
|
63
|
-
|
|
64
|
-
const
|
|
65
|
-
if (
|
|
66
|
-
// basePath is inside a worktree — resolve to project root
|
|
67
|
-
const projectRoot = resolved.slice(0, segment.gsdIdx);
|
|
63
|
+
// If basePath is inside a worktree, resolve to the project root.
|
|
64
|
+
const projectRoot = projectRootFromWorktreePath(resolve(basePath));
|
|
65
|
+
if (projectRoot) {
|
|
68
66
|
return join(projectRoot, ".gsd", CAPTURES_FILENAME);
|
|
69
67
|
}
|
|
70
68
|
return join(gsdRoot(basePath), CAPTURES_FILENAME);
|
|
@@ -9,9 +9,6 @@
|
|
|
9
9
|
/** Default timeout for verification-gate commands (ms). */
|
|
10
10
|
export const DEFAULT_COMMAND_TIMEOUT_MS = 120_000;
|
|
11
11
|
|
|
12
|
-
/** Default timeout for the dynamic bash tool (seconds). */
|
|
13
|
-
export const DEFAULT_BASH_TIMEOUT_SECS = 120;
|
|
14
|
-
|
|
15
12
|
// ─── Cache Sizes ──────────────────────────────────────────────────────────────
|
|
16
13
|
|
|
17
14
|
/** Max directory-listing cache entries before eviction (#611). */
|
|
@@ -39,6 +39,7 @@ import { markLatestActiveForWorkerCanceled, type DispatchStatus } from "./db/uni
|
|
|
39
39
|
import { getRuntimeKv, setRuntimeKv, deleteRuntimeKv } from "./db/runtime-kv.js";
|
|
40
40
|
import { _getAdapter, isDbAvailable } from "./gsd-db.js";
|
|
41
41
|
import { gsdRoot, normalizeRealPath } from "./paths.js";
|
|
42
|
+
import { crashResumeHint } from "./guidance.js";
|
|
42
43
|
import { atomicWriteSync } from "./atomic-write.js";
|
|
43
44
|
import { effectiveLockFile } from "./session-lock.js";
|
|
44
45
|
import { isInFlightRuntimePhase, listUnitRuntimeRecords, type AutoUnitRuntimeRecord } from "./unit-runtime.js";
|
|
@@ -321,15 +322,8 @@ export function formatCrashInfo(lock: LockData): string {
|
|
|
321
322
|
` PID: ${lock.pid}`,
|
|
322
323
|
];
|
|
323
324
|
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
} else if (lock.unitType.includes("research") || lock.unitType.includes("plan")) {
|
|
327
|
-
lines.push(`The ${lock.unitType} unit may be incomplete. Run /gsd auto to re-run it.`);
|
|
328
|
-
} else if (lock.unitType.includes("execute")) {
|
|
329
|
-
lines.push(`Task execution was interrupted. Run /gsd auto to resume — completed work is preserved.`);
|
|
330
|
-
} else if (lock.unitType.includes("complete")) {
|
|
331
|
-
lines.push(`Slice/milestone completion was interrupted. Run /gsd auto to finish.`);
|
|
332
|
-
}
|
|
325
|
+
const hint = crashResumeHint(lock.unitType, lock.unitId);
|
|
326
|
+
if (hint) lines.push(hint);
|
|
333
327
|
|
|
334
328
|
return lines.join("\n");
|
|
335
329
|
}
|
|
@@ -15,7 +15,7 @@ import { join } from "node:path";
|
|
|
15
15
|
|
|
16
16
|
import type { DoctorIssue, DoctorIssueCode } from "./doctor-types.js";
|
|
17
17
|
import { detectPythonExecutable } from "./python-resolver.js";
|
|
18
|
-
import {
|
|
18
|
+
import { projectRootFromWorktreePath } from "./worktree-root.js";
|
|
19
19
|
|
|
20
20
|
// ── Types ──────────────────────────────────────────────────────────────────
|
|
21
21
|
|
|
@@ -50,12 +50,7 @@ const CMD_TIMEOUT = 5_000;
|
|
|
50
50
|
function resolveWorktreeProjectRoot(basePath: string): string | null {
|
|
51
51
|
const envRoot = process.env.GSD_WORKTREE;
|
|
52
52
|
if (envRoot) return envRoot;
|
|
53
|
-
|
|
54
|
-
const segment = findWorktreeSegment(basePath.replace(/\\/g, "/"));
|
|
55
|
-
if (!segment) return null;
|
|
56
|
-
|
|
57
|
-
// Everything before the worktree segment is the project root
|
|
58
|
-
return basePath.slice(0, segment.gsdIdx);
|
|
53
|
+
return projectRootFromWorktreePath(basePath);
|
|
59
54
|
}
|
|
60
55
|
|
|
61
56
|
function tryExec(cmd: string, cwd: string): string | null {
|
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
import type { DoctorIssue, DoctorIssueCode, DoctorReport, DoctorSummary } from "./doctor-types.js";
|
|
1
|
+
import type { DoctorIssue, DoctorIssueCode, DoctorReport, DoctorSummary, DoctorSeverity } from "./doctor-types.js";
|
|
2
|
+
import { doctorFixHint } from "./guidance.js";
|
|
3
|
+
|
|
4
|
+
function severityTag(severity: DoctorSeverity): string {
|
|
5
|
+
return severity === "error" ? "ERROR" : severity === "warning" ? "WARN" : "INFO";
|
|
6
|
+
}
|
|
2
7
|
|
|
3
8
|
function matchesScope(unitId: string, scope?: string): boolean {
|
|
4
9
|
if (!scope) return true;
|
|
@@ -53,8 +58,9 @@ export function formatDoctorReport(
|
|
|
53
58
|
if (scopedIssues.length > 0) {
|
|
54
59
|
lines.push("Priority issues:");
|
|
55
60
|
for (const issue of scopedIssues.slice(0, maxIssues)) {
|
|
56
|
-
|
|
57
|
-
|
|
61
|
+
lines.push(`- [${severityTag(issue.severity)}] ${issue.unitId}: ${issue.message}${issue.file ? ` (${issue.file})` : ""}`);
|
|
62
|
+
const hint = doctorFixHint(issue.code);
|
|
63
|
+
if (hint && issue.severity !== "info") lines.push(` Fix: ${hint}`);
|
|
58
64
|
}
|
|
59
65
|
if (scopedIssues.length > maxIssues) {
|
|
60
66
|
lines.push(`- ...and ${scopedIssues.length - maxIssues} more in scope`);
|
|
@@ -72,10 +78,9 @@ export function formatDoctorReport(
|
|
|
72
78
|
|
|
73
79
|
export function formatDoctorIssuesForPrompt(issues: DoctorIssue[]): string {
|
|
74
80
|
if (issues.length === 0) return "- No remaining issues in scope.";
|
|
75
|
-
return issues.map(issue =>
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
}).join("\n");
|
|
81
|
+
return issues.map(issue =>
|
|
82
|
+
`- [${severityTag(issue.severity)}] ${issue.unitId} | ${issue.code} | ${issue.message}${issue.file ? ` | file: ${issue.file}` : ""} | fixable: ${issue.fixable ? "yes" : "no"}`
|
|
83
|
+
).join("\n");
|
|
79
84
|
}
|
|
80
85
|
|
|
81
86
|
/**
|
|
@@ -425,22 +425,20 @@ export async function checkRuntimeHealth(
|
|
|
425
425
|
missing.push(...criticalPatterns.filter(p => !existingLines.has(p)));
|
|
426
426
|
}
|
|
427
427
|
|
|
428
|
-
{
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
});
|
|
428
|
+
if (missing.length > 0) {
|
|
429
|
+
issues.push({
|
|
430
|
+
severity: "warning",
|
|
431
|
+
code: "gitignore_missing_patterns",
|
|
432
|
+
scope: "project",
|
|
433
|
+
unitId: "project",
|
|
434
|
+
message: `${missing.length} critical GSD runtime pattern(s) missing from .gitignore: ${missing.join(", ")}`,
|
|
435
|
+
file: ".gitignore",
|
|
436
|
+
fixable: true,
|
|
437
|
+
});
|
|
439
438
|
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
}
|
|
439
|
+
if (shouldFix("gitignore_missing_patterns")) {
|
|
440
|
+
ensureGitignore(basePath, { manageGitignore });
|
|
441
|
+
fixesApplied.push("added missing GSD runtime patterns to .gitignore");
|
|
444
442
|
}
|
|
445
443
|
}
|
|
446
444
|
}
|