@opengsd/gsd-pi 1.2.0-dev.84c56d87 → 1.2.0-dev.9ad8ae33
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/headless-events.js +7 -5
- package/dist/mcp-server.js +2 -1
- package/dist/resource-loader.d.ts +10 -5
- package/dist/resource-loader.js +121 -6
- package/dist/resources/.managed-resources-content-hash +1 -1
- package/dist/resources/GSD-WORKFLOW.md +5 -4
- 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/gsd/auto/custom-verify-retry-store.js +17 -2
- package/dist/resources/extensions/gsd/auto/detect-stuck.js +33 -13
- package/dist/resources/extensions/gsd/auto/dispatch-history.js +105 -0
- package/dist/resources/extensions/gsd/auto/dispatch-key.js +37 -0
- package/dist/resources/extensions/gsd/auto/loop.js +4 -1
- package/dist/resources/extensions/gsd/auto/orchestrator.js +89 -54
- package/dist/resources/extensions/gsd/auto/phases.js +49 -6
- package/dist/resources/extensions/gsd/auto/session.js +3 -0
- package/dist/resources/extensions/gsd/auto-direct-dispatch.js +11 -34
- package/dist/resources/extensions/gsd/auto-dispatch.js +50 -58
- package/dist/resources/extensions/gsd/auto-model-selection.js +36 -13
- package/dist/resources/extensions/gsd/auto-post-unit.js +30 -12
- package/dist/resources/extensions/gsd/auto-prompts.js +78 -19
- package/dist/resources/extensions/gsd/auto-start.js +35 -15
- package/dist/resources/extensions/gsd/auto-unit-closeout.js +45 -21
- package/dist/resources/extensions/gsd/auto-unit-tool-scope.js +5 -4
- package/dist/resources/extensions/gsd/auto-verification.js +23 -30
- package/dist/resources/extensions/gsd/auto-worktree.js +14 -1
- package/dist/resources/extensions/gsd/auto.js +37 -1
- package/dist/resources/extensions/gsd/blocked-models.js +28 -0
- package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +26 -6
- package/dist/resources/extensions/gsd/bootstrap/dynamic-tools.js +23 -6
- package/dist/resources/extensions/gsd/bootstrap/exec-tools.js +2 -2
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +145 -50
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +302 -80
- package/dist/resources/extensions/gsd/browser-daemon-auto-prep.js +83 -0
- package/dist/resources/extensions/gsd/closeout-wizard.js +92 -0
- package/dist/resources/extensions/gsd/commands/context.js +16 -2
- package/dist/resources/extensions/gsd/commands-handlers.js +46 -3
- package/dist/resources/extensions/gsd/consent-question.js +353 -0
- package/dist/resources/extensions/gsd/consent-verdict.js +63 -0
- package/dist/resources/extensions/gsd/constants.js +0 -2
- package/dist/resources/extensions/gsd/crash-recovery.js +8 -3
- package/dist/resources/extensions/gsd/db/queries.js +26 -0
- package/dist/resources/extensions/gsd/db-writer.js +8 -17
- package/dist/resources/extensions/gsd/dispatch-guard.js +10 -35
- package/dist/resources/extensions/gsd/doctor-engine-checks.js +5 -5
- package/dist/resources/extensions/gsd/doctor-git-checks.js +2 -18
- package/dist/resources/extensions/gsd/engine-hook-contract.js +70 -0
- package/dist/resources/extensions/gsd/exec-sandbox.js +30 -10
- package/dist/resources/extensions/gsd/files.js +33 -19
- package/dist/resources/extensions/gsd/gsd-command-home.js +22 -12
- package/dist/resources/extensions/gsd/gsd-db.js +2 -1
- package/dist/resources/extensions/gsd/guidance.js +60 -0
- package/dist/resources/extensions/gsd/guided-flow.js +6 -3
- package/dist/resources/extensions/gsd/markdown-renderer.js +10 -0
- package/dist/resources/extensions/gsd/milestone-closeout.js +85 -24
- package/dist/resources/extensions/gsd/milestone-planning-persistence.js +2 -2
- package/dist/resources/extensions/gsd/milestone-reopen-events.js +3 -5
- package/dist/resources/extensions/gsd/parsers-legacy.js +16 -4
- package/dist/resources/extensions/gsd/preferences-models.js +2 -2
- package/dist/resources/extensions/gsd/projection-flush.js +7 -0
- package/dist/resources/extensions/gsd/prompts/complete-slice.md +3 -3
- package/dist/resources/extensions/gsd/prompts/execute-task.md +1 -1
- package/dist/resources/extensions/gsd/prompts/plan-milestone.md +1 -1
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/quick-task.md +1 -1
- package/dist/resources/extensions/gsd/prompts/reassess-roadmap.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/research-milestone.md +1 -1
- package/dist/resources/extensions/gsd/prompts/research-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/rewrite-docs.md +1 -1
- package/dist/resources/extensions/gsd/prompts/run-uat.md +7 -5
- package/dist/resources/extensions/gsd/prompts/system.md +5 -2
- package/dist/resources/extensions/gsd/prompts/triage-captures.md +1 -1
- package/dist/resources/extensions/gsd/prompts/validate-milestone.md +1 -1
- package/dist/resources/extensions/gsd/reactive-graph.js +8 -1
- package/dist/resources/extensions/gsd/roadmap-slices.js +25 -3
- package/dist/resources/extensions/gsd/safety/destructive-confirmation.js +108 -0
- package/dist/resources/extensions/gsd/session-lock.js +1 -1
- package/dist/resources/extensions/gsd/state.js +5 -0
- package/dist/resources/extensions/gsd/tool-contract.js +14 -3
- package/dist/resources/extensions/gsd/tool-presentation-plan.js +4 -4
- package/dist/resources/extensions/gsd/tools/complete-milestone.js +3 -2
- package/dist/resources/extensions/gsd/tools/complete-slice.js +22 -12
- package/dist/resources/extensions/gsd/tools/complete-task.js +3 -2
- package/dist/resources/extensions/gsd/tools/exec-tool.js +5 -0
- package/dist/resources/extensions/gsd/tools/plan-slice.js +2 -2
- package/dist/resources/extensions/gsd/tools/plan-task.js +2 -2
- package/dist/resources/extensions/gsd/tools/reassess-roadmap.js +2 -2
- package/dist/resources/extensions/gsd/tools/reopen-milestone.js +2 -2
- package/dist/resources/extensions/gsd/tools/reopen-slice.js +2 -2
- package/dist/resources/extensions/gsd/tools/reopen-task.js +2 -2
- package/dist/resources/extensions/gsd/tools/replan-slice.js +2 -2
- package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +67 -2
- package/dist/resources/extensions/gsd/uat-policy.js +40 -15
- package/dist/resources/extensions/gsd/unit-context-composer.js +65 -0
- package/dist/resources/extensions/gsd/verdict-parser.js +1 -1
- package/dist/resources/extensions/gsd/verification-verdict.js +2 -1
- package/dist/resources/extensions/gsd/workflow-event-ledger.js +91 -0
- package/dist/resources/extensions/gsd/workflow-event-vocabulary.js +46 -0
- package/dist/resources/extensions/gsd/workflow-events.js +6 -18
- package/dist/resources/extensions/gsd/workflow-reconcile.js +21 -56
- package/dist/resources/extensions/gsd/worktree-lifecycle.js +3 -2
- package/dist/resources/extensions/gsd/worktree-manager.js +7 -1
- package/dist/resources/extensions/gsd/worktree.js +8 -1
- package/dist/resources/extensions/shared/gsd-browser-cli.js +45 -3
- package/dist/resources/shared/gsd-browser-path-sync.js +214 -0
- package/dist/resources/shared/package-manager-detection.js +1 -1
- package/dist/resources/shared/package.json +3 -0
- package/dist/resources/skills/create-skill/SKILL.md +3 -0
- package/dist/resources/skills/create-skill/references/skill-structure.md +1 -0
- package/dist/tsconfig.extensions.tsbuildinfo +1 -1
- package/dist/update-check.d.ts +2 -0
- package/dist/update-check.js +24 -1
- package/dist/update-cmd.js +20 -3
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +6 -6
- 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 +6 -6
- package/dist/web/standalone/.next/server/chunks/8357.js +2 -2
- 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 +26 -18
- package/dist/web/standalone/node_modules/postcss/lib/css-syntax-error.js +47 -14
- 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 +54 -29
- package/dist/web/standalone/node_modules/postcss/lib/lazy-result.js +47 -37
- package/dist/web/standalone/node_modules/postcss/lib/map-generator.js +26 -9
- package/dist/web/standalone/node_modules/postcss/lib/no-work-result.js +57 -55
- package/dist/web/standalone/node_modules/postcss/lib/node.js +99 -31
- package/dist/web/standalone/node_modules/postcss/lib/parse.js +1 -1
- package/dist/web/standalone/node_modules/postcss/lib/parser.js +10 -9
- package/dist/web/standalone/node_modules/postcss/lib/postcss.js +12 -12
- package/dist/web/standalone/node_modules/postcss/lib/previous-map.js +30 -11
- 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 +69 -28
- package/dist/web/standalone/node_modules/postcss/lib/tokenize.js +6 -2
- package/dist/web/standalone/node_modules/postcss/package.json +48 -48
- package/package.json +2 -2
- 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/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 +10 -5
- package/packages/mcp-server/dist/cli.js.map +1 -1
- package/packages/mcp-server/dist/moonshot-tool-schema.d.ts +29 -0
- package/packages/mcp-server/dist/moonshot-tool-schema.d.ts.map +1 -0
- package/packages/mcp-server/dist/moonshot-tool-schema.js +50 -0
- package/packages/mcp-server/dist/moonshot-tool-schema.js.map +1 -0
- package/packages/mcp-server/dist/server.d.ts.map +1 -1
- package/packages/mcp-server/dist/server.js +4 -0
- package/packages/mcp-server/dist/server.js.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.d.ts +18 -18
- package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.js +99 -38
- package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
- package/packages/mcp-server/package.json +5 -4
- 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/README.md +1 -0
- package/packages/pi-ai/dist/image-models.generated.d.ts +2 -2
- package/packages/pi-ai/dist/image-models.generated.js +6 -6
- package/packages/pi-ai/dist/image-models.generated.js.map +1 -1
- package/packages/pi-ai/dist/index.d.ts +2 -0
- package/packages/pi-ai/dist/index.d.ts.map +1 -1
- package/packages/pi-ai/dist/index.js +2 -0
- package/packages/pi-ai/dist/index.js.map +1 -1
- package/packages/pi-ai/dist/models.generated.d.ts +419 -221
- package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
- package/packages/pi-ai/dist/models.generated.js +460 -261
- package/packages/pi-ai/dist/models.generated.js.map +1 -1
- package/packages/pi-ai/dist/providers/anthropic.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/anthropic.js +12 -7
- package/packages/pi-ai/dist/providers/anthropic.js.map +1 -1
- package/packages/pi-ai/dist/providers/google-shared.d.ts +5 -0
- package/packages/pi-ai/dist/providers/google-shared.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/google-shared.js +12 -3
- package/packages/pi-ai/dist/providers/google-shared.js.map +1 -1
- package/packages/pi-ai/dist/providers/openai-completions.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/openai-completions.js +7 -3
- package/packages/pi-ai/dist/providers/openai-completions.js.map +1 -1
- package/packages/pi-ai/dist/utils/moonshot-tool-schema.d.ts +9 -0
- package/packages/pi-ai/dist/utils/moonshot-tool-schema.d.ts.map +1 -0
- package/packages/pi-ai/dist/utils/moonshot-tool-schema.js +34 -0
- package/packages/pi-ai/dist/utils/moonshot-tool-schema.js.map +1 -0
- package/packages/pi-ai/dist/utils/oauth/github-copilot.d.ts.map +1 -1
- package/packages/pi-ai/dist/utils/oauth/github-copilot.js +6 -2
- package/packages/pi-ai/dist/utils/oauth/github-copilot.js.map +1 -1
- package/packages/pi-ai/package.json +3 -2
- 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/package.json +2 -2
- package/packages/rpc-client/package.json +2 -2
- package/pkg/package.json +1 -1
- package/src/resources/GSD-WORKFLOW.md +5 -4
- 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/browser-tools/tests/gsd-browser-launch-config.test.mjs +40 -1
- package/src/resources/extensions/gsd/auto/custom-verify-retry-store.ts +21 -3
- package/src/resources/extensions/gsd/auto/detect-stuck.ts +32 -9
- package/src/resources/extensions/gsd/auto/dispatch-history.ts +152 -0
- package/src/resources/extensions/gsd/auto/dispatch-key.ts +39 -0
- package/src/resources/extensions/gsd/auto/loop.ts +4 -1
- package/src/resources/extensions/gsd/auto/orchestrator.ts +98 -56
- package/src/resources/extensions/gsd/auto/phases.ts +65 -26
- package/src/resources/extensions/gsd/auto/session.ts +3 -0
- package/src/resources/extensions/gsd/auto-direct-dispatch.ts +18 -48
- package/src/resources/extensions/gsd/auto-dispatch.ts +48 -61
- package/src/resources/extensions/gsd/auto-model-selection.ts +41 -12
- package/src/resources/extensions/gsd/auto-post-unit.ts +33 -12
- package/src/resources/extensions/gsd/auto-prompts.ts +115 -35
- package/src/resources/extensions/gsd/auto-start.ts +36 -18
- package/src/resources/extensions/gsd/auto-unit-closeout.ts +83 -28
- package/src/resources/extensions/gsd/auto-unit-tool-scope.ts +4 -4
- package/src/resources/extensions/gsd/auto-verification.ts +26 -28
- package/src/resources/extensions/gsd/auto-worktree.ts +14 -1
- package/src/resources/extensions/gsd/auto.ts +44 -1
- package/src/resources/extensions/gsd/blocked-models.ts +49 -0
- package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +34 -5
- package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +23 -6
- package/src/resources/extensions/gsd/bootstrap/exec-tools.ts +2 -2
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +163 -55
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +350 -86
- package/src/resources/extensions/gsd/browser-daemon-auto-prep.ts +108 -0
- package/src/resources/extensions/gsd/closeout-wizard.ts +102 -0
- package/src/resources/extensions/gsd/commands/context.ts +16 -2
- package/src/resources/extensions/gsd/commands-handlers.ts +46 -3
- package/src/resources/extensions/gsd/consent-question.ts +431 -0
- package/src/resources/extensions/gsd/consent-verdict.ts +86 -0
- package/src/resources/extensions/gsd/constants.ts +0 -3
- package/src/resources/extensions/gsd/crash-recovery.ts +10 -2
- package/src/resources/extensions/gsd/db/queries.ts +37 -0
- package/src/resources/extensions/gsd/db-writer.ts +11 -19
- package/src/resources/extensions/gsd/dispatch-guard.ts +8 -31
- package/src/resources/extensions/gsd/doctor-engine-checks.ts +5 -4
- package/src/resources/extensions/gsd/doctor-git-checks.ts +2 -19
- package/src/resources/extensions/gsd/engine-hook-contract.ts +79 -0
- package/src/resources/extensions/gsd/exec-sandbox.ts +49 -9
- package/src/resources/extensions/gsd/files.ts +33 -12
- package/src/resources/extensions/gsd/gsd-command-home.ts +13 -3
- package/src/resources/extensions/gsd/gsd-db.ts +4 -3
- package/src/resources/extensions/gsd/guidance.ts +78 -0
- package/src/resources/extensions/gsd/guided-flow.ts +21 -26
- package/src/resources/extensions/gsd/markdown-renderer.ts +11 -0
- package/src/resources/extensions/gsd/milestone-closeout.ts +109 -24
- package/src/resources/extensions/gsd/milestone-planning-persistence.ts +2 -2
- package/src/resources/extensions/gsd/milestone-reopen-events.ts +3 -6
- package/src/resources/extensions/gsd/parsers-legacy.ts +16 -4
- package/src/resources/extensions/gsd/preferences-models.ts +2 -1
- package/src/resources/extensions/gsd/projection-flush.ts +20 -0
- package/src/resources/extensions/gsd/prompts/complete-slice.md +3 -3
- package/src/resources/extensions/gsd/prompts/execute-task.md +1 -1
- package/src/resources/extensions/gsd/prompts/plan-milestone.md +1 -1
- package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/quick-task.md +1 -1
- package/src/resources/extensions/gsd/prompts/reassess-roadmap.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/research-milestone.md +1 -1
- package/src/resources/extensions/gsd/prompts/research-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/rewrite-docs.md +1 -1
- package/src/resources/extensions/gsd/prompts/run-uat.md +7 -5
- package/src/resources/extensions/gsd/prompts/system.md +5 -2
- package/src/resources/extensions/gsd/prompts/triage-captures.md +1 -1
- package/src/resources/extensions/gsd/prompts/validate-milestone.md +1 -1
- package/src/resources/extensions/gsd/reactive-graph.ts +11 -1
- package/src/resources/extensions/gsd/roadmap-slices.ts +28 -3
- package/src/resources/extensions/gsd/safety/destructive-confirmation.ts +134 -0
- package/src/resources/extensions/gsd/session-lock.ts +1 -1
- package/src/resources/extensions/gsd/state.ts +5 -0
- package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +97 -1
- package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +198 -26
- package/src/resources/extensions/gsd/tests/auto-remote-session-lock-cleanup.test.ts +65 -3
- package/src/resources/extensions/gsd/tests/auto-start-orphan-bootstrap.test.ts +236 -0
- package/src/resources/extensions/gsd/tests/blocked-models.test.ts +19 -0
- package/src/resources/extensions/gsd/tests/browser-daemon-auto-prep.test.ts +144 -0
- package/src/resources/extensions/gsd/tests/complete-slice-verification-gate.test.ts +42 -0
- package/src/resources/extensions/gsd/tests/consent-question.test.ts +351 -0
- package/src/resources/extensions/gsd/tests/custom-verify-retry-store.test.ts +67 -0
- package/src/resources/extensions/gsd/tests/db-writer.test.ts +15 -4
- package/src/resources/extensions/gsd/tests/deep-project-auto-loop.test.ts +10 -10
- package/src/resources/extensions/gsd/tests/destructive-confirmation.test.ts +303 -0
- package/src/resources/extensions/gsd/tests/discuss-routing-fixes.test.ts +12 -2
- package/src/resources/extensions/gsd/tests/dispatch-history.test.ts +273 -0
- package/src/resources/extensions/gsd/tests/doctor-git-checks-terminal.test.ts +73 -0
- package/src/resources/extensions/gsd/tests/dynamic-bash-no-cap.test.ts +132 -0
- package/src/resources/extensions/gsd/tests/engine-hook-contract.test.ts +148 -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/gsd-command-home.test.ts +120 -0
- package/src/resources/extensions/gsd/tests/gsd-db.test.ts +27 -0
- package/src/resources/extensions/gsd/tests/guidance.test.ts +23 -0
- package/src/resources/extensions/gsd/tests/guided-dispatch-root.test.ts +2 -6
- package/src/resources/extensions/gsd/tests/integration/run-uat.test.ts +199 -0
- package/src/resources/extensions/gsd/tests/mcp-project-config.test.ts +3 -1
- package/src/resources/extensions/gsd/tests/milestone-closeout.test.ts +95 -4
- package/src/resources/extensions/gsd/tests/model-unittype-mapping.test.ts +32 -1
- package/src/resources/extensions/gsd/tests/oauth-api-model-routing.test.ts +167 -0
- package/src/resources/extensions/gsd/tests/parallel-research-dispatch.test.ts +18 -0
- package/src/resources/extensions/gsd/tests/parsers-legacy-importers.test.ts +138 -0
- package/src/resources/extensions/gsd/tests/phases-terminal-complete-idempotent.test.ts +242 -0
- package/src/resources/extensions/gsd/tests/post-exec-retry-bypass.test.ts +63 -2
- package/src/resources/extensions/gsd/tests/prompt-db.test.ts +124 -6
- package/src/resources/extensions/gsd/tests/roadmap-slices.test.ts +68 -0
- package/src/resources/extensions/gsd/tests/runtime-invariant-modules.test.ts +19 -1
- package/src/resources/extensions/gsd/tests/teardown-chdir-failure-clears-registry.test.ts +17 -0
- package/src/resources/extensions/gsd/tests/token-tool-gating.test.ts +41 -0
- package/src/resources/extensions/gsd/tests/tool-unavailable-retry.test.ts +33 -0
- package/src/resources/extensions/gsd/tests/transport-gate-double-complete.test.ts +139 -0
- package/src/resources/extensions/gsd/tests/uat-policy.test.ts +88 -0
- package/src/resources/extensions/gsd/tests/unit-context-composer.test.ts +44 -0
- package/src/resources/extensions/gsd/tests/uok-audit-unified.test.ts +8 -0
- package/src/resources/extensions/gsd/tests/verification-verdict.test.ts +2 -0
- package/src/resources/extensions/gsd/tests/workflow-events.test.ts +19 -0
- package/src/resources/extensions/gsd/tests/workflow-reconcile.test.ts +20 -0
- package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +273 -38
- package/src/resources/extensions/gsd/tests/worktree-teardown-safety.test.ts +22 -0
- package/src/resources/extensions/gsd/tests/worktree.test.ts +18 -0
- package/src/resources/extensions/gsd/tests/write-gate-seam.test.ts +358 -0
- package/src/resources/extensions/gsd/tests/write-gate.test.ts +67 -1
- package/src/resources/extensions/gsd/tool-contract.ts +38 -3
- package/src/resources/extensions/gsd/tool-presentation-plan.ts +4 -4
- package/src/resources/extensions/gsd/tools/complete-milestone.ts +3 -2
- package/src/resources/extensions/gsd/tools/complete-slice.ts +22 -12
- package/src/resources/extensions/gsd/tools/complete-task.ts +3 -2
- package/src/resources/extensions/gsd/tools/exec-tool.ts +4 -0
- package/src/resources/extensions/gsd/tools/plan-slice.ts +2 -2
- package/src/resources/extensions/gsd/tools/plan-task.ts +2 -2
- package/src/resources/extensions/gsd/tools/reassess-roadmap.ts +2 -2
- package/src/resources/extensions/gsd/tools/reopen-milestone.ts +2 -2
- package/src/resources/extensions/gsd/tools/reopen-slice.ts +2 -2
- package/src/resources/extensions/gsd/tools/reopen-task.ts +2 -2
- package/src/resources/extensions/gsd/tools/replan-slice.ts +2 -2
- package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +81 -2
- package/src/resources/extensions/gsd/uat-policy.ts +60 -15
- package/src/resources/extensions/gsd/unit-context-composer.ts +99 -0
- package/src/resources/extensions/gsd/verdict-parser.ts +1 -1
- package/src/resources/extensions/gsd/verification-verdict.ts +4 -2
- package/src/resources/extensions/gsd/workflow-event-ledger.ts +131 -0
- package/src/resources/extensions/gsd/workflow-event-vocabulary.ts +59 -0
- package/src/resources/extensions/gsd/workflow-events.ts +12 -20
- package/src/resources/extensions/gsd/workflow-reconcile.ts +29 -62
- package/src/resources/extensions/gsd/worktree-lifecycle.ts +3 -8
- package/src/resources/extensions/gsd/worktree-manager.ts +6 -1
- package/src/resources/extensions/gsd/worktree.ts +7 -1
- package/src/resources/extensions/shared/gsd-browser-cli.ts +54 -3
- package/src/resources/shared/gsd-browser-path-sync.ts +273 -0
- package/src/resources/shared/package-manager-detection.ts +1 -1
- package/src/resources/shared/package.json +3 -0
- package/src/resources/skills/create-skill/SKILL.md +3 -0
- package/src/resources/skills/create-skill/references/skill-structure.md +1 -0
- package/dist/resources/extensions/gsd/user-input-boundary.js +0 -218
- package/dist/resources/skills/gsd-browser/SKILL.md +0 -41
- package/src/resources/extensions/gsd/tests/user-input-boundary.test.ts +0 -173
- package/src/resources/extensions/gsd/user-input-boundary.ts +0 -216
- package/src/resources/skills/gsd-browser/SKILL.md +0 -41
- /package/dist/web/standalone/.next/static/{AOpDeK_gJHU8OZjRo31gQ → FBNo5cT_chy7YNoAQsU3o}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{AOpDeK_gJHU8OZjRo31gQ → FBNo5cT_chy7YNoAQsU3o}/_ssgManifest.js +0 -0
|
@@ -18,6 +18,7 @@ import { ensureGsdSymlink, isInheritedRepo, validateProjectId } from "./repo-ide
|
|
|
18
18
|
import { migrateToExternalState, recoverFailedMigration } from "./migrate-external.js";
|
|
19
19
|
import { collectSecretsFromManifest } from "../get-secrets-from-user.js";
|
|
20
20
|
import { gsdRoot, resolveMilestoneFile } from "./paths.js";
|
|
21
|
+
import { milestoneEntryBlockedGuidance } from "./guidance.js";
|
|
21
22
|
import { invalidateAllCaches } from "./cache.js";
|
|
22
23
|
import { writeLock, clearLock, readCrashLock, isLockProcessAlive } from "./crash-recovery.js";
|
|
23
24
|
import { acquireSessionLock, releaseSessionLock, updateSessionLock, } from "./session-lock.js";
|
|
@@ -741,12 +742,14 @@ export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, reques
|
|
|
741
742
|
// phase-specific planning model for a discuss turn (#2829).
|
|
742
743
|
//
|
|
743
744
|
// Precedence:
|
|
744
|
-
// 1) Explicit session override via /gsd model (this session)
|
|
745
|
-
// 2)
|
|
746
|
-
// 3)
|
|
745
|
+
// 1) Explicit session override via /gsd model or /gsd auto --model (this session)
|
|
746
|
+
// 2) GSD model preferences from PREFERENCES.md (validated against live auth)
|
|
747
|
+
// 3) Current session model from settings/session restore (if provider ready)
|
|
747
748
|
//
|
|
748
|
-
//
|
|
749
|
-
//
|
|
749
|
+
// PREFERENCES.md wins over the ambient session default (#3517) so /gsd auto
|
|
750
|
+
// does not stick on claude-code/claude-sonnet-4-6 when the user configured
|
|
751
|
+
// models via /gsd workflow-preferences or PREFERENCES.md. Custom providers
|
|
752
|
+
// still skip PREFERENCES.md entirely (#4122).
|
|
750
753
|
//
|
|
751
754
|
// Exception (#4122): when the session provider is a custom provider declared
|
|
752
755
|
// in ~/.gsd/agent/models.json (Ollama, vLLM, OpenAI-compatible proxy, etc.),
|
|
@@ -758,7 +761,7 @@ export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, reques
|
|
|
758
761
|
const sessionProviderIsCustom = isCustomProvider(ctx.model?.provider);
|
|
759
762
|
const preferredModel = sessionProviderIsCustom
|
|
760
763
|
? null
|
|
761
|
-
: resolveDefaultSessionModel(ctx.model?.provider);
|
|
764
|
+
: resolveDefaultSessionModel(ctx.model?.provider, base);
|
|
762
765
|
// Validate the preferred model against the live registry + provider auth so
|
|
763
766
|
// an unconfigured PREFERENCES.md entry (no API key / OAuth) can't become the
|
|
764
767
|
// start-model snapshot. Without this, every subsequent unit would try to
|
|
@@ -781,8 +784,8 @@ export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, reques
|
|
|
781
784
|
: null;
|
|
782
785
|
const startThinkingSnapshot = pi.getThinkingLevel();
|
|
783
786
|
const startModelSnapshot = manualSessionOverride
|
|
784
|
-
?? currentSessionModel
|
|
785
787
|
?? validatedPreferredModel
|
|
788
|
+
?? currentSessionModel
|
|
786
789
|
?? null;
|
|
787
790
|
try {
|
|
788
791
|
// Validate GSD_PROJECT_ID early so the user gets immediate feedback
|
|
@@ -973,9 +976,26 @@ export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, reques
|
|
|
973
976
|
state = await deriveState(wtPath);
|
|
974
977
|
}
|
|
975
978
|
}
|
|
976
|
-
const
|
|
977
|
-
|
|
978
|
-
|
|
979
|
+
const requestedMilestoneLock = process.env.GSD_MILESTONE_LOCK?.trim() || null;
|
|
980
|
+
const lockedActiveMilestone = requestedMilestoneLock && state.activeMilestone?.id === requestedMilestoneLock;
|
|
981
|
+
let blockingStrandedRecoveryAction;
|
|
982
|
+
if (lockedActiveMilestone) {
|
|
983
|
+
// Parallel worker or explicit `/gsd auto Mxxx`: sibling milestones'
|
|
984
|
+
// stranded work must not block this milestone's resumption, and the
|
|
985
|
+
// downstream `strandedRecoveryAction` (used for currentMilestoneId,
|
|
986
|
+
// setActiveMilestoneId, and adoptStrandedMilestone) must be scoped to
|
|
987
|
+
// the locked milestone only. Falling back to the first sibling action
|
|
988
|
+
// would mis-target adoption (#742).
|
|
989
|
+
const lockMatch = strandedRecoveryActions.find((action) => action.milestoneId === requestedMilestoneLock) ?? null;
|
|
990
|
+
blockingStrandedRecoveryAction = lockMatch;
|
|
991
|
+
strandedRecoveryAction = lockMatch;
|
|
992
|
+
}
|
|
993
|
+
else if (state.activeMilestone) {
|
|
994
|
+
blockingStrandedRecoveryAction = strandedRecoveryActions.find((action) => action.milestoneId !== state.activeMilestone?.id) ?? strandedRecoveryAction;
|
|
995
|
+
}
|
|
996
|
+
else {
|
|
997
|
+
blockingStrandedRecoveryAction = strandedRecoveryAction;
|
|
998
|
+
}
|
|
979
999
|
if (blockingStrandedRecoveryAction) {
|
|
980
1000
|
if (!state.activeMilestone) {
|
|
981
1001
|
ctx.ui.notify(formatStrandedWorkBlockerMessage(blockingStrandedRecoveryAction, null), "error");
|
|
@@ -988,6 +1008,9 @@ export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, reques
|
|
|
988
1008
|
strandedRecoveryAction = blockingStrandedRecoveryAction;
|
|
989
1009
|
ctx.ui.notify(formatStrandedWorkRecoveryMessage(strandedRecoveryAction), "info");
|
|
990
1010
|
}
|
|
1011
|
+
else if (lockedActiveMilestone) {
|
|
1012
|
+
strandedRecoveryAction = null;
|
|
1013
|
+
}
|
|
991
1014
|
if (process.env.GSD_HEADLESS === "1" &&
|
|
992
1015
|
orphanAuditRecovered &&
|
|
993
1016
|
!state.activeMilestone &&
|
|
@@ -1270,11 +1293,8 @@ export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, reques
|
|
|
1270
1293
|
if (enterResult.reason === "lease-conflict") {
|
|
1271
1294
|
ctx.ui.notify(`Cannot enter milestone ${s.currentMilestoneId}: lease is held by another worker.`, "error");
|
|
1272
1295
|
}
|
|
1273
|
-
else if (enterResult.reason === "creation-failed") {
|
|
1274
|
-
ctx.ui.notify(
|
|
1275
|
-
}
|
|
1276
|
-
else if (enterResult.reason === "isolation-degraded") {
|
|
1277
|
-
ctx.ui.notify(`Cannot enter milestone ${s.currentMilestoneId}: isolation is degraded from a prior worktree failure. Close processes locking the worktree and retry, or run /gsd doctor fix.`, "error");
|
|
1296
|
+
else if (enterResult.reason === "creation-failed" || enterResult.reason === "isolation-degraded") {
|
|
1297
|
+
ctx.ui.notify(milestoneEntryBlockedGuidance(s.currentMilestoneId, enterResult.reason), "error");
|
|
1278
1298
|
}
|
|
1279
1299
|
else if (enterResult.reason === "invalid-milestone-id") {
|
|
1280
1300
|
ctx.ui.notify(`Cannot enter milestone ${s.currentMilestoneId}: milestone id is invalid.`, "error");
|
|
@@ -36,17 +36,17 @@ export function isSuspiciousGhostCompletion(ctx, startedAt, maxElapsedMs = GHOST
|
|
|
36
36
|
activity.assistantMessages === 0);
|
|
37
37
|
}
|
|
38
38
|
/**
|
|
39
|
-
* Snapshot metrics, save activity log,
|
|
40
|
-
* for a completed unit.
|
|
39
|
+
* Snapshot metrics, save activity log, extract memories, and record the git
|
|
40
|
+
* transaction for a completed auto-mode unit.
|
|
41
41
|
*/
|
|
42
|
-
export async function
|
|
43
|
-
const modelId = ctx.model?.id ?? "unknown";
|
|
44
|
-
snapshotUnitMetrics(ctx, unitType, unitId, startedAt, modelId, opts);
|
|
45
|
-
const activityFile = saveActivityLog(ctx, basePath, unitType, unitId);
|
|
42
|
+
export async function closeoutAutoUnit(request) {
|
|
43
|
+
const modelId = request.ctx.model?.id ?? "unknown";
|
|
44
|
+
snapshotUnitMetrics(request.ctx, request.unitType, request.unitId, request.startedAt, modelId, request.opts);
|
|
45
|
+
const activityFile = saveActivityLog(request.ctx, request.basePath, request.unitType, request.unitId);
|
|
46
46
|
if (activityFile) {
|
|
47
47
|
try {
|
|
48
|
-
const { buildMemoryLLMCall, extractMemoriesFromUnit } = await import(
|
|
49
|
-
const llmCallFn = buildMemoryLLMCall(ctx);
|
|
48
|
+
const { buildMemoryLLMCall, extractMemoriesFromUnit } = await import("./memory-extractor.js");
|
|
49
|
+
const llmCallFn = buildMemoryLLMCall(request.ctx);
|
|
50
50
|
if (llmCallFn) {
|
|
51
51
|
// Awaited: a fire-and-forget here lets memory-extractor writes land in
|
|
52
52
|
// .gsd/ after closeoutUnit returns but before the milestone merge
|
|
@@ -55,10 +55,10 @@ export async function closeoutUnit(ctx, basePath, unitType, unitId, startedAt, o
|
|
|
55
55
|
// bounded by the extractor's LLM call, which is the acceptable price
|
|
56
56
|
// for not racing the merge boundary.
|
|
57
57
|
try {
|
|
58
|
-
await extractMemoriesFromUnit(activityFile, unitType, unitId, llmCallFn);
|
|
58
|
+
await extractMemoriesFromUnit(activityFile, request.unitType, request.unitId, llmCallFn);
|
|
59
59
|
}
|
|
60
60
|
catch (err) {
|
|
61
|
-
logWarning("engine", `memory extraction failed for ${unitType}/${unitId}: ${err.message}`);
|
|
61
|
+
logWarning("engine", `memory extraction failed for ${request.unitType}/${request.unitId}: ${err.message}`);
|
|
62
62
|
}
|
|
63
63
|
}
|
|
64
64
|
}
|
|
@@ -66,22 +66,46 @@ export async function closeoutUnit(ctx, basePath, unitType, unitId, startedAt, o
|
|
|
66
66
|
logWarning("engine", `operation failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
67
67
|
}
|
|
68
68
|
}
|
|
69
|
-
|
|
69
|
+
const gitTransaction = resolveGitTransactionOptions(request.opts);
|
|
70
|
+
if (gitTransaction) {
|
|
70
71
|
writeTurnGitTransaction({
|
|
71
|
-
basePath,
|
|
72
|
-
traceId:
|
|
73
|
-
turnId:
|
|
74
|
-
unitType,
|
|
75
|
-
unitId,
|
|
72
|
+
basePath: request.basePath,
|
|
73
|
+
traceId: gitTransaction.traceId,
|
|
74
|
+
turnId: gitTransaction.turnId,
|
|
75
|
+
unitType: request.unitType,
|
|
76
|
+
unitId: request.unitId,
|
|
76
77
|
stage: "record",
|
|
77
|
-
action:
|
|
78
|
-
push:
|
|
79
|
-
status:
|
|
80
|
-
error:
|
|
78
|
+
action: gitTransaction.gitAction,
|
|
79
|
+
push: gitTransaction.gitPush === true,
|
|
80
|
+
status: gitTransaction.gitStatus,
|
|
81
|
+
error: gitTransaction.gitError,
|
|
81
82
|
metadata: {
|
|
82
83
|
activityFile,
|
|
83
84
|
},
|
|
84
85
|
});
|
|
85
86
|
}
|
|
86
|
-
return
|
|
87
|
+
return {
|
|
88
|
+
...(activityFile ? { activityFile } : {}),
|
|
89
|
+
gitTransactionRecorded: Boolean(gitTransaction),
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
function resolveGitTransactionOptions(opts) {
|
|
93
|
+
if (!opts?.traceId || !opts.turnId || !opts.gitAction || !opts.gitStatus)
|
|
94
|
+
return null;
|
|
95
|
+
return {
|
|
96
|
+
traceId: opts.traceId,
|
|
97
|
+
turnId: opts.turnId,
|
|
98
|
+
gitAction: opts.gitAction,
|
|
99
|
+
gitStatus: opts.gitStatus,
|
|
100
|
+
gitPush: opts.gitPush,
|
|
101
|
+
gitError: opts.gitError,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Compatibility wrapper for existing auto-loop callers. New code should prefer
|
|
106
|
+
* closeoutAutoUnit so the closeout request and result stay explicit.
|
|
107
|
+
*/
|
|
108
|
+
export async function closeoutUnit(ctx, basePath, unitType, unitId, startedAt, opts) {
|
|
109
|
+
const result = await closeoutAutoUnit({ ctx, basePath, unitType, unitId, startedAt, opts });
|
|
110
|
+
return result.activityFile;
|
|
87
111
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { parseUnitId } from "./unit-id.js";
|
|
2
2
|
import { AUTO_UNIT_SCOPED_TOOLS, getForbiddenGsdToolReason, } from "./unit-tool-contracts.js";
|
|
3
|
-
import { WORKFLOW_TOOL_ALIAS_PAIRS,
|
|
3
|
+
import { WORKFLOW_TOOL_ALIAS_PAIRS, isWorkflowSurfaceAliasTool, stripMcpToolPrefix, } from "./workflow-tool-surface.js";
|
|
4
|
+
import { canonicalWorkflowToolName } from "./engine-hook-contract.js";
|
|
4
5
|
export { AUTO_UNIT_SCOPED_TOOLS, RUN_UAT_BROWSER_TOOL_NAMES, } from "./unit-tool-contracts.js";
|
|
5
6
|
// Scope-class membership is declared per unit in the Unit Registry (ADR-033).
|
|
6
7
|
// EXECUTE_TASK_UNIT_TYPES = scopeClass "execute-task"; the section-close gate
|
|
@@ -22,9 +23,9 @@ const SCOPED_GSD_LIFECYCLE_TOOLS = new Set([
|
|
|
22
23
|
.map(canonicalWorkflowToolName));
|
|
23
24
|
export const GSD_PHASE_SCOPE_DISPLAY_REASON = "This GSD phase only allows its scoped workflow tools.";
|
|
24
25
|
export const GSD_SECTION_CLOSE_GATE_DISPLAY_REASON = "Gates here close by writing summary sections — gsd_save_gate_result isn't needed.";
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
}
|
|
26
|
+
// Normalizer seam lives in engine-hook-contract.ts; re-exported here for
|
|
27
|
+
// existing scope importers.
|
|
28
|
+
export { canonicalWorkflowToolName };
|
|
28
29
|
export function isWorkflowAliasTool(toolName) {
|
|
29
30
|
return isWorkflowSurfaceAliasTool(toolName);
|
|
30
31
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// Project/App: gsd-pi
|
|
2
2
|
// File Purpose: Post-unit verification gate for GSD auto-mode units.
|
|
3
3
|
import { existsSync, mkdirSync, readFileSync, readdirSync, writeFileSync } from "node:fs";
|
|
4
|
-
import { gsdProjectionRoot, resolveSlicePath
|
|
4
|
+
import { gsdProjectionRoot, resolveSlicePath } from "./paths.js";
|
|
5
5
|
import { resolveMilestoneValidationVerdict } from "./milestone-validation-verdict.js";
|
|
6
6
|
import { resolveCanonicalMilestoneRoot } from "./worktree-manager.js";
|
|
7
7
|
import { parseUnitId } from "./unit-id.js";
|
|
@@ -9,8 +9,6 @@ import { isDbAvailable, getTask, getSliceTasks, getMilestoneSlices } from "./gsd
|
|
|
9
9
|
import { loadEffectiveGSDPreferences } from "./preferences.js";
|
|
10
10
|
import { isClosedStatus } from "./status-guards.js";
|
|
11
11
|
import { loadFile } from "./files.js";
|
|
12
|
-
import { parseRoadmap } from "./parsers-legacy.js";
|
|
13
|
-
import { isMilestoneComplete } from "./state.js";
|
|
14
12
|
import { runVerificationGate, runVerificationGateForTargets, formatFailureContext, captureRuntimeErrors, runDependencyAudit, } from "./verification-gate.js";
|
|
15
13
|
import { writeVerificationJSON } from "./verification-evidence.js";
|
|
16
14
|
import { logWarning } from "./workflow-logger.js";
|
|
@@ -25,6 +23,7 @@ import { getSlice } from "./gsd-db.js";
|
|
|
25
23
|
import { getLedger } from "./metrics.js";
|
|
26
24
|
import { getUnitCostSpikeAction, resolveUnitCostSpikeMultiplier } from "./auto-budget.js";
|
|
27
25
|
import { formatPostUnitStatusCard } from "./auto-status-message.js";
|
|
26
|
+
import { detectWebApp } from "./web-app-uat.js";
|
|
28
27
|
function getCurrentUnitCostStats(unitId) {
|
|
29
28
|
const ledger = getLedger();
|
|
30
29
|
if (!ledger || !Array.isArray(ledger.units) || ledger.units.length === 0) {
|
|
@@ -274,32 +273,15 @@ async function runValidateMilestonePostCheck(vctx, pauseAuto) {
|
|
|
274
273
|
* DB-backed projects are authoritative (#4094 peer review); falls back to
|
|
275
274
|
* roadmap parsing only when the DB is unavailable.
|
|
276
275
|
*/
|
|
277
|
-
async function countIncompleteSlices(
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
// No DB rows — treat as "unknown", do not pause.
|
|
282
|
-
return 1;
|
|
283
|
-
}
|
|
284
|
-
return slices.filter((slice) => !isClosedStatus(slice.status)).length;
|
|
285
|
-
}
|
|
286
|
-
// Filesystem fallback: parse the roadmap markdown.
|
|
287
|
-
try {
|
|
288
|
-
const roadmapFile = resolveMilestoneFile(basePath, milestoneId, "ROADMAP");
|
|
289
|
-
if (!roadmapFile)
|
|
290
|
-
return 1;
|
|
291
|
-
const roadmapContent = await loadFile(roadmapFile);
|
|
292
|
-
if (!roadmapContent)
|
|
293
|
-
return 1;
|
|
294
|
-
const roadmap = parseRoadmap(roadmapContent);
|
|
295
|
-
if (roadmap.slices.length === 0)
|
|
296
|
-
return 1;
|
|
297
|
-
return isMilestoneComplete(roadmap) ? 0 : 1;
|
|
298
|
-
}
|
|
299
|
-
catch {
|
|
300
|
-
// Parsing failures should not cause false-positive pauses.
|
|
276
|
+
async function countIncompleteSlices(_basePath, milestoneId) {
|
|
277
|
+
// DB-authoritative (ADR-017): no markdown fallback. DB unavailable or no
|
|
278
|
+
// rows means "unknown" — do not pause.
|
|
279
|
+
if (!isDbAvailable())
|
|
301
280
|
return 1;
|
|
302
|
-
|
|
281
|
+
const slices = getMilestoneSlices(milestoneId);
|
|
282
|
+
if (slices.length === 0)
|
|
283
|
+
return 1;
|
|
284
|
+
return slices.filter((slice) => !isClosedStatus(slice.status)).length;
|
|
303
285
|
}
|
|
304
286
|
/**
|
|
305
287
|
* Run the verification gate for the current execute-task unit.
|
|
@@ -636,14 +618,25 @@ export async function runPostUnitVerification(vctx, pauseAuto) {
|
|
|
636
618
|
s.pendingVerificationRetry = null;
|
|
637
619
|
return "continue";
|
|
638
620
|
}
|
|
621
|
+
else if (verdict.reason === "no-host-checks" &&
|
|
622
|
+
taskAlreadyComplete &&
|
|
623
|
+
detectWebApp(s.basePath) &&
|
|
624
|
+
!result.runtimeErrors?.some((e) => e.blocking)) {
|
|
625
|
+
s.verificationRetryCount.delete(retryKey);
|
|
626
|
+
s.verificationRetryFailureHashes.delete(retryKey);
|
|
627
|
+
s.pendingVerificationRetry = null;
|
|
628
|
+
ctx.ui.notify("No task-level host verification command was found for a completed browser-facing task; continuing so slice UAT can verify the UI with browser tools.", "warning");
|
|
629
|
+
return "continue";
|
|
630
|
+
}
|
|
639
631
|
else if (verdict.reason === "no-host-checks") {
|
|
640
632
|
s.verificationRetryCount.delete(retryKey);
|
|
641
633
|
s.verificationRetryFailureHashes.delete(retryKey);
|
|
642
634
|
s.pendingVerificationRetry = null;
|
|
643
|
-
|
|
635
|
+
const pauseMessage = `Verification failed: ${verdict.failureContext}`;
|
|
636
|
+
ctx.ui.notify(`Verification gate FAILED — ${verdict.failureContext}`, "error");
|
|
644
637
|
process.stderr.write(`verification-gate: ${verdict.failureContext}\n`);
|
|
645
638
|
await pauseAuto(ctx, pi, {
|
|
646
|
-
message:
|
|
639
|
+
message: pauseMessage,
|
|
647
640
|
category: "unknown",
|
|
648
641
|
});
|
|
649
642
|
return "pause";
|
|
@@ -800,6 +800,14 @@ function _resolveIntegrationBranchForReuse(basePath, milestoneId) {
|
|
|
800
800
|
return null;
|
|
801
801
|
}
|
|
802
802
|
}
|
|
803
|
+
function safeCwd(fallback) {
|
|
804
|
+
try {
|
|
805
|
+
return process.cwd();
|
|
806
|
+
}
|
|
807
|
+
catch {
|
|
808
|
+
return fallback;
|
|
809
|
+
}
|
|
810
|
+
}
|
|
803
811
|
/**
|
|
804
812
|
* When reusing an existing milestone branch, fast-forward it onto the
|
|
805
813
|
* integration branch when that's safe (branch is a strict ancestor of
|
|
@@ -949,7 +957,7 @@ export function teardownAutoWorktree(originalBasePath, milestoneId, opts = {}) {
|
|
|
949
957
|
originalBasePath = resolveWorktreeProjectRoot(originalBasePath);
|
|
950
958
|
const branch = autoWorktreeBranch(milestoneId);
|
|
951
959
|
const { preserveBranch = false, preserveWorktree = false } = opts;
|
|
952
|
-
const previousCwd =
|
|
960
|
+
const previousCwd = safeCwd(originalBasePath);
|
|
953
961
|
// Wrap the entire teardown body in a single try/finally so activeWorkspace
|
|
954
962
|
// is ALWAYS cleared — even if process.chdir throws (e.g. originalBasePath
|
|
955
963
|
// was deleted before teardown ran). Previously the finally only covered
|
|
@@ -1901,6 +1909,11 @@ export function mergeMilestoneToMain(originalBasePath_, milestoneId, roadmapCont
|
|
|
1901
1909
|
}
|
|
1902
1910
|
catch (err) {
|
|
1903
1911
|
logWarning("worktree", `chdir to project root after merge failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
1912
|
+
debugLog("mergeMilestoneToMain", {
|
|
1913
|
+
phase: "post-merge-chdir-failed",
|
|
1914
|
+
target: originalBasePath_,
|
|
1915
|
+
error: err instanceof Error ? err.message : String(err),
|
|
1916
|
+
});
|
|
1904
1917
|
}
|
|
1905
1918
|
};
|
|
1906
1919
|
let shouldCleanup = false;
|
|
@@ -557,6 +557,13 @@ export function getAutoModeStartModel() {
|
|
|
557
557
|
export function setCurrentDispatchedModelId(model) {
|
|
558
558
|
s.currentDispatchedModelId = model ? `${model.provider}/${model.id}` : null;
|
|
559
559
|
}
|
|
560
|
+
/**
|
|
561
|
+
* Update the active unit model after runtime recovery switches models mid-unit.
|
|
562
|
+
* The next session restore path reads this field before dispatching again.
|
|
563
|
+
*/
|
|
564
|
+
export function setCurrentUnitModelForRecovery(model) {
|
|
565
|
+
s.currentUnitModel = model;
|
|
566
|
+
}
|
|
560
567
|
// Tool tracking — delegates to auto-tool-tracking.ts
|
|
561
568
|
export function markToolStart(toolCallId, toolName) {
|
|
562
569
|
_markToolStart(toolCallId, s.active, toolName);
|
|
@@ -623,6 +630,35 @@ export function stopAutoRemote(projectRoot) {
|
|
|
623
630
|
return { found: false, error: err.message };
|
|
624
631
|
}
|
|
625
632
|
}
|
|
633
|
+
/**
|
|
634
|
+
* Force-stop a remote auto-mode session before stealing its lock.
|
|
635
|
+
* The normal stop path stays SIGTERM-only so cooperative sessions can clean up;
|
|
636
|
+
* this path is only for the explicit "Force start" action.
|
|
637
|
+
*/
|
|
638
|
+
export function forceStopAutoRemote(projectRoot) {
|
|
639
|
+
const lock = readCrashLock(projectRoot);
|
|
640
|
+
if (!lock)
|
|
641
|
+
return { found: false };
|
|
642
|
+
if (lock.pid === process.pid) {
|
|
643
|
+
clearLock(projectRoot);
|
|
644
|
+
return { found: false };
|
|
645
|
+
}
|
|
646
|
+
if (!isLockProcessAlive(lock)) {
|
|
647
|
+
clearLock(projectRoot);
|
|
648
|
+
return { found: false };
|
|
649
|
+
}
|
|
650
|
+
try {
|
|
651
|
+
process.kill(lock.pid, "SIGTERM");
|
|
652
|
+
if (isLockProcessAlive(lock)) {
|
|
653
|
+
process.kill(lock.pid, "SIGKILL");
|
|
654
|
+
}
|
|
655
|
+
clearLock(projectRoot);
|
|
656
|
+
return { found: true, pid: lock.pid };
|
|
657
|
+
}
|
|
658
|
+
catch (err) {
|
|
659
|
+
return { found: false, error: err.message };
|
|
660
|
+
}
|
|
661
|
+
}
|
|
626
662
|
/**
|
|
627
663
|
* Check if a remote auto-mode session is running (from a different process).
|
|
628
664
|
* Reads the crash lock, checks PID liveness, and returns session details.
|
|
@@ -1824,7 +1860,7 @@ export async function startAuto(ctx, pi, base, verboseMode, options) {
|
|
|
1824
1860
|
if (freshStartAssessment.classification === "running") {
|
|
1825
1861
|
const pid = freshStartAssessment.lock?.pid;
|
|
1826
1862
|
ctx.ui.notify(pid
|
|
1827
|
-
? `Another auto-mode session (PID ${pid}) appears to be running.\
|
|
1863
|
+
? `Another auto-mode session (PID ${pid}) appears to be running.\nRun \`/gsd stop\` for graceful shutdown, or choose "Force start" from \`/gsd auto\` to terminate it.`
|
|
1828
1864
|
: "Another auto-mode session appears to be running.", "error");
|
|
1829
1865
|
return;
|
|
1830
1866
|
}
|
|
@@ -9,12 +9,16 @@ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
|
9
9
|
import { dirname, join } from "node:path";
|
|
10
10
|
import { gsdRoot } from "./paths.js";
|
|
11
11
|
import { withFileLockSync } from "./file-lock.js";
|
|
12
|
+
const temporaryBlockedModels = new Map();
|
|
12
13
|
function blockedModelsPath(basePath) {
|
|
13
14
|
return join(gsdRoot(basePath), "runtime", "blocked-models.json");
|
|
14
15
|
}
|
|
15
16
|
function modelKey(provider, id) {
|
|
16
17
|
return `${provider.toLowerCase()}/${id.toLowerCase()}`;
|
|
17
18
|
}
|
|
19
|
+
function temporaryModelKey(basePath, provider, id) {
|
|
20
|
+
return `${basePath}:${modelKey(provider, id)}`;
|
|
21
|
+
}
|
|
18
22
|
function readFileSafe(path) {
|
|
19
23
|
if (!existsSync(path))
|
|
20
24
|
return { version: 1, blocked: [] };
|
|
@@ -41,6 +45,30 @@ export function isModelBlocked(basePath, provider, id) {
|
|
|
41
45
|
const target = modelKey(provider, id);
|
|
42
46
|
return loadBlockedModels(basePath).some((e) => modelKey(e.provider, e.id) === target);
|
|
43
47
|
}
|
|
48
|
+
export function blockModelUntil(basePath, provider, id, blockedUntil, reason) {
|
|
49
|
+
const key = temporaryModelKey(basePath, provider, id);
|
|
50
|
+
if (blockedUntil <= Date.now()) {
|
|
51
|
+
temporaryBlockedModels.delete(key);
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
temporaryBlockedModels.set(key, { provider, id, reason, blockedUntil });
|
|
55
|
+
}
|
|
56
|
+
export function isModelTemporarilyUnavailable(basePath, provider, id, now = Date.now()) {
|
|
57
|
+
if (!provider || !id)
|
|
58
|
+
return false;
|
|
59
|
+
const key = temporaryModelKey(basePath, provider, id);
|
|
60
|
+
const entry = temporaryBlockedModels.get(key);
|
|
61
|
+
if (!entry)
|
|
62
|
+
return false;
|
|
63
|
+
if (entry.blockedUntil <= now) {
|
|
64
|
+
temporaryBlockedModels.delete(key);
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
return true;
|
|
68
|
+
}
|
|
69
|
+
export function clearTemporaryModelBlocksForTest() {
|
|
70
|
+
temporaryBlockedModels.clear();
|
|
71
|
+
}
|
|
44
72
|
export function blockModel(basePath, provider, id, reason) {
|
|
45
73
|
const path = blockedModelsPath(basePath);
|
|
46
74
|
mkdirSync(dirname(path), { recursive: true });
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { logWarning } from "../workflow-logger.js";
|
|
3
3
|
import { checkDeepProjectSetupAfterTurn, checkAutoStartAfterDiscuss, maybeHandleReadyPhraseWithoutFiles, maybeHandleEmptyIntentTurn, resetEmptyTurnCounter, } from "../guided-flow.js";
|
|
4
4
|
import { clearPathCache } from "../paths.js";
|
|
5
|
-
import { getAutoDashboardData, getAutoModeStartModel, isAutoActive, isAutoCompletionStopInProgress, pauseAuto, setCurrentDispatchedModelId, } from "../auto.js";
|
|
5
|
+
import { getAutoDashboardData, getAutoModeStartModel, isAutoActive, isAutoCompletionStopInProgress, pauseAuto, setCurrentDispatchedModelId, setCurrentUnitModelForRecovery, } from "../auto.js";
|
|
6
6
|
import { getNextFallbackModel, resolveModelWithFallbacksForUnit } from "../preferences.js";
|
|
7
7
|
import { pauseAutoForProviderError } from "../provider-error-pause.js";
|
|
8
8
|
import { isSessionSwitchAbortGraceActive, isSessionSwitchInFlight, resolveAgentEnd, resolveAgentEndCancelled, } from "../auto/resolve.js";
|
|
@@ -13,7 +13,7 @@ import { clearDiscussionFlowState } from "./write-gate.js";
|
|
|
13
13
|
import { clearGuidedUnitContext } from "../guided-unit-context.js";
|
|
14
14
|
import { resumeAutoAfterProviderDelay } from "./provider-error-resume.js";
|
|
15
15
|
import { classifyError, createRetryState, resetRetryState, isTransient, } from "../error-classifier.js";
|
|
16
|
-
import { blockModel, isModelBlocked } from "../blocked-models.js";
|
|
16
|
+
import { blockModel, blockModelUntil, isModelBlocked, isModelTemporarilyUnavailable } from "../blocked-models.js";
|
|
17
17
|
import { getProjectGSDPreferencesPath } from "../preferences.js";
|
|
18
18
|
import { resolveProviderErrorGuidance } from "../provider-error-guidance.js";
|
|
19
19
|
import { formatGuidance } from "../guidance.js";
|
|
@@ -96,9 +96,12 @@ async function tryProviderModelFallback(params) {
|
|
|
96
96
|
if (!nextModelId)
|
|
97
97
|
break;
|
|
98
98
|
const candidate = resolveModelId(nextModelId, availableModels, rejectedProvider);
|
|
99
|
-
if (candidate &&
|
|
99
|
+
if (candidate &&
|
|
100
|
+
!isModelBlocked(basePath, candidate.provider, candidate.id) &&
|
|
101
|
+
!isModelTemporarilyUnavailable(basePath, candidate.provider, candidate.id)) {
|
|
100
102
|
const ok = await pi.setModel(candidate, { persist: false });
|
|
101
103
|
if (ok) {
|
|
104
|
+
setCurrentUnitModelForRecovery(candidate);
|
|
102
105
|
setCurrentDispatchedModelId({ provider: candidate.provider, id: candidate.id });
|
|
103
106
|
switchedNotify(`${candidate.provider}/${candidate.id}`);
|
|
104
107
|
pi.sendMessage({ customType: "gsd-auto-timeout-recovery", content: "Continue execution.", display: false }, { triggerTurn: true });
|
|
@@ -111,11 +114,13 @@ async function tryProviderModelFallback(params) {
|
|
|
111
114
|
const sessionModel = getAutoModeStartModel();
|
|
112
115
|
if (sessionModel &&
|
|
113
116
|
!(sessionModel.provider === rejectedProvider && sessionModel.id === rejectedId) &&
|
|
114
|
-
!isModelBlocked(basePath, sessionModel.provider, sessionModel.id)
|
|
117
|
+
!isModelBlocked(basePath, sessionModel.provider, sessionModel.id) &&
|
|
118
|
+
!isModelTemporarilyUnavailable(basePath, sessionModel.provider, sessionModel.id)) {
|
|
115
119
|
const startModel = availableModels.find((m) => m.provider === sessionModel.provider && m.id === sessionModel.id);
|
|
116
120
|
if (startModel) {
|
|
117
121
|
const ok = await pi.setModel(startModel, { persist: false });
|
|
118
122
|
if (ok) {
|
|
123
|
+
setCurrentUnitModelForRecovery(startModel);
|
|
119
124
|
setCurrentDispatchedModelId({ provider: startModel.provider, id: startModel.id });
|
|
120
125
|
switchedNotify(`${startModel.provider}/${startModel.id}`);
|
|
121
126
|
pi.sendMessage({ customType: "gsd-auto-timeout-recovery", content: "Continue execution.", display: false }, { triggerTurn: true });
|
|
@@ -533,6 +538,10 @@ export async function handleAgentEnd(pi, event, ctx) {
|
|
|
533
538
|
if (currentProvider === "openai-codex" || currentProvider === "google-gemini-cli") {
|
|
534
539
|
cls.retryAfterMs = Math.min(cls.retryAfterMs, 30_000);
|
|
535
540
|
}
|
|
541
|
+
const dash = getAutoDashboardData();
|
|
542
|
+
if (dash.basePath && ctx.model?.provider && ctx.model?.id) {
|
|
543
|
+
blockModelUntil(dash.basePath, ctx.model.provider, ctx.model.id, Date.now() + cls.retryAfterMs, rawErrorMsg || displayMsg || "rate limit");
|
|
544
|
+
}
|
|
536
545
|
}
|
|
537
546
|
// ── 2. Decide & Act ──────────────────────────────────────────────────
|
|
538
547
|
// --- Network errors: same-model retry with backoff ---
|
|
@@ -572,9 +581,14 @@ export async function handleAgentEnd(pi, event, ctx) {
|
|
|
572
581
|
retryState.networkRetryCount = 0;
|
|
573
582
|
retryState.currentRetryModelId = undefined;
|
|
574
583
|
const modelToSet = resolveModelId(nextModelId, availableModels, ctx.model?.provider);
|
|
575
|
-
|
|
584
|
+
const modelUnavailable = dash.basePath && modelToSet
|
|
585
|
+
? isModelBlocked(dash.basePath, modelToSet.provider, modelToSet.id) ||
|
|
586
|
+
isModelTemporarilyUnavailable(dash.basePath, modelToSet.provider, modelToSet.id)
|
|
587
|
+
: false;
|
|
588
|
+
if (modelToSet && !modelUnavailable) {
|
|
576
589
|
const ok = await pi.setModel(modelToSet, { persist: false });
|
|
577
590
|
if (ok) {
|
|
591
|
+
setCurrentUnitModelForRecovery(modelToSet);
|
|
578
592
|
setCurrentDispatchedModelId({ provider: modelToSet.provider, id: modelToSet.id });
|
|
579
593
|
ctx.ui.notify(`Model error${errorDetail}. Switched to fallback: ${nextModelId} and resuming.`, "warning");
|
|
580
594
|
pi.sendMessage({ customType: "gsd-auto-timeout-recovery", content: "Continue execution.", display: false }, { triggerTurn: true });
|
|
@@ -587,11 +601,17 @@ export async function handleAgentEnd(pi, event, ctx) {
|
|
|
587
601
|
// Try restoring session model
|
|
588
602
|
const sessionModel = getAutoModeStartModel();
|
|
589
603
|
if (sessionModel) {
|
|
590
|
-
|
|
604
|
+
const dash = getAutoDashboardData();
|
|
605
|
+
const sessionModelUnavailable = dash.basePath
|
|
606
|
+
? isModelBlocked(dash.basePath, sessionModel.provider, sessionModel.id) ||
|
|
607
|
+
isModelTemporarilyUnavailable(dash.basePath, sessionModel.provider, sessionModel.id)
|
|
608
|
+
: false;
|
|
609
|
+
if (!sessionModelUnavailable && (ctx.model?.id !== sessionModel.id || ctx.model?.provider !== sessionModel.provider)) {
|
|
591
610
|
const startModel = ctx.modelRegistry.getAvailable().find((m) => m.provider === sessionModel.provider && m.id === sessionModel.id);
|
|
592
611
|
if (startModel) {
|
|
593
612
|
const ok = await pi.setModel(startModel, { persist: false });
|
|
594
613
|
if (ok) {
|
|
614
|
+
setCurrentUnitModelForRecovery(startModel);
|
|
595
615
|
setCurrentDispatchedModelId({ provider: startModel.provider, id: startModel.id });
|
|
596
616
|
retryState.networkRetryCount = 0;
|
|
597
617
|
retryState.currentRetryModelId = undefined;
|
|
@@ -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);
|
|
@@ -114,8 +114,8 @@ export function registerExecTools(pi) {
|
|
|
114
114
|
],
|
|
115
115
|
parameters: Type.Object({
|
|
116
116
|
query: Type.Optional(Type.String({ description: "Substring matched against id and purpose (case-insensitive)." })),
|
|
117
|
-
runtime: Type.Optional(Type.
|
|
118
|
-
description: "Restrict to one runtime.",
|
|
117
|
+
runtime: Type.Optional(Type.String({
|
|
118
|
+
description: "Restrict to one runtime: bash, node, or python.",
|
|
119
119
|
})),
|
|
120
120
|
failing_only: Type.Optional(Type.Boolean({ description: "Only non-zero exit codes and timeouts." })),
|
|
121
121
|
limit: Type.Optional(Type.Number({ description: "Max results (default 20, cap 200)", minimum: 1, maximum: 200 })),
|