@opengsd/gsd-pi 1.2.0-dev.5457a158 → 1.2.0-dev.6ccd27b3
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-model-override.d.ts +15 -0
- package/dist/cli-model-override.js +21 -0
- package/dist/cli.js +1 -18
- package/dist/headless-events.js +7 -5
- package/dist/loader.js +6 -4
- package/dist/mcp-server.js +2 -1
- package/dist/register-agent-bundles.d.ts +11 -2
- package/dist/register-agent-bundles.js +18 -4
- 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/ask-user-questions.js +3 -2
- 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/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 +450 -217
- package/dist/resources/extensions/claude-code-cli/turn-assembler.js +33 -1
- package/dist/resources/extensions/gsd/auto/closeout.js +215 -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 +120 -0
- package/dist/resources/extensions/gsd/auto/dispatch-key.js +37 -0
- package/dist/resources/extensions/gsd/auto/dispatch.js +365 -0
- package/dist/resources/extensions/gsd/auto/finalize.js +347 -0
- package/dist/resources/extensions/gsd/auto/loop.js +7 -1
- package/dist/resources/extensions/gsd/auto/milestone-lease-reclaim.js +56 -0
- package/dist/resources/extensions/gsd/auto/orchestrator.js +174 -69
- package/dist/resources/extensions/gsd/auto/phase-helpers.js +146 -0
- package/dist/resources/extensions/gsd/auto/phases.js +17 -2329
- package/dist/resources/extensions/gsd/auto/pre-dispatch.js +534 -0
- package/dist/resources/extensions/gsd/auto/session.js +3 -0
- package/dist/resources/extensions/gsd/auto/unit-phase.js +694 -0
- package/dist/resources/extensions/gsd/auto/workflow-unit-dispatch.js +1 -1
- package/dist/resources/extensions/gsd/auto/worktree-safety-phase.js +125 -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 +15 -2
- package/dist/resources/extensions/gsd/auto.js +41 -2
- 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 +60 -13
- package/dist/resources/extensions/gsd/bootstrap/exec-tools.js +2 -2
- package/dist/resources/extensions/gsd/bootstrap/register-extension.js +19 -0
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +172 -59
- 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/browser-evidence.js +8 -2
- 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/commands-mcp-status.js +2 -2
- package/dist/resources/extensions/gsd/commands-workflow-templates.js +9 -2
- 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 +56 -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-environment.js +256 -125
- 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 +93 -4
- package/dist/resources/extensions/gsd/health-widget.js +87 -28
- package/dist/resources/extensions/gsd/markdown-renderer.js +10 -0
- package/dist/resources/extensions/gsd/mcp-bridge.js +10 -0
- package/dist/resources/extensions/gsd/mcp-filter.js +2 -19
- 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/milestone-settlement.js +2 -2
- package/dist/resources/extensions/gsd/notifications.js +12 -7
- 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 +4 -4
- package/dist/resources/extensions/gsd/prompts/execute-task.md +3 -2
- 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 +9 -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/prompts/workflow-start.md +2 -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/skill-activation.js +3 -6
- package/dist/resources/extensions/gsd/state.js +11 -2
- 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/tool-surface-readiness.js +83 -31
- 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 +65 -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 +42 -16
- package/dist/resources/extensions/gsd/unit-context-composer.js +65 -0
- package/dist/resources/extensions/gsd/unit-registry.js +41 -24
- 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/web-app-uat.js +45 -8
- 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-mcp-auto-prep.js +2 -0
- package/dist/resources/extensions/gsd/workflow-mcp-readiness-cache.js +105 -0
- 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-safety.js +28 -26
- package/dist/resources/extensions/gsd/worktree.js +8 -1
- package/dist/resources/extensions/mcp-client/manager.js +6 -1
- 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 +116 -6
- 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/executable-code.md +1 -1
- package/dist/resources/skills/create-skill/references/skill-structure.md +1 -0
- 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/runtime-checks.d.ts +10 -0
- package/dist/runtime-checks.js +27 -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 +12 -12
- 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 +12 -12
- 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/package.json +1 -1
- package/package.json +3 -3
- 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/dist/sdk.d.ts.map +1 -1
- package/packages/gsd-agent-core/dist/sdk.js +6 -4
- package/packages/gsd-agent-core/dist/sdk.js.map +1 -1
- package/packages/gsd-agent-core/package.json +5 -5
- package/packages/gsd-agent-modes/dist/modes/interactive/components/settings-selector.d.ts +2 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/settings-selector.js +10 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.d.ts +13 -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 +55 -6
- package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.d.ts +2 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.js +34 -5
- package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.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-mode.d.ts +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode.js +12 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-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/interactive/interactive-selectors-settings.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-settings.js +4 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-settings.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/README.md +12 -3
- package/packages/mcp-server/dist/cli-runner.d.ts +40 -0
- package/packages/mcp-server/dist/cli-runner.d.ts.map +1 -0
- package/packages/mcp-server/dist/cli-runner.js +137 -0
- package/packages/mcp-server/dist/cli-runner.js.map +1 -0
- package/packages/mcp-server/dist/cli.js +2 -53
- 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/pid-registry.d.ts +46 -0
- package/packages/mcp-server/dist/pid-registry.d.ts.map +1 -0
- package/packages/mcp-server/dist/pid-registry.js +452 -0
- package/packages/mcp-server/dist/pid-registry.js.map +1 -0
- package/packages/mcp-server/dist/probe-mode.d.ts +4 -0
- package/packages/mcp-server/dist/probe-mode.d.ts.map +1 -0
- package/packages/mcp-server/dist/probe-mode.js +10 -0
- package/packages/mcp-server/dist/probe-mode.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/stdio-watchdog.d.ts +8 -0
- package/packages/mcp-server/dist/stdio-watchdog.d.ts.map +1 -0
- package/packages/mcp-server/dist/stdio-watchdog.js +40 -0
- package/packages/mcp-server/dist/stdio-watchdog.js.map +1 -0
- 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 +161 -81
- 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/agent-loop.js +43 -2
- package/packages/pi-agent-core/dist/agent-loop.js.map +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 +239 -153
- package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
- package/packages/pi-ai/dist/models.generated.js +256 -145
- 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/settings-manager.d.ts +3 -0
- package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.js +11 -0
- package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/bash.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/theme/theme.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/theme/theme.js +45 -17
- package/packages/pi-coding-agent/dist/theme/theme.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/index.d.ts +1 -1
- package/packages/pi-tui/dist/index.d.ts.map +1 -1
- package/packages/pi-tui/dist/index.js +1 -1
- package/packages/pi-tui/dist/index.js.map +1 -1
- package/packages/pi-tui/dist/terminal-image.d.ts +33 -0
- package/packages/pi-tui/dist/terminal-image.d.ts.map +1 -1
- package/packages/pi-tui/dist/terminal-image.js +54 -2
- package/packages/pi-tui/dist/terminal-image.js.map +1 -1
- package/packages/pi-tui/dist/tui.d.ts +8 -0
- package/packages/pi-tui/dist/tui.d.ts.map +1 -1
- package/packages/pi-tui/dist/tui.js +72 -18
- package/packages/pi-tui/dist/tui.js.map +1 -1
- package/packages/pi-tui/dist/utils.d.ts.map +1 -1
- package/packages/pi-tui/dist/utils.js +110 -36
- package/packages/pi-tui/dist/utils.js.map +1 -1
- package/packages/pi-tui/package.json +2 -2
- package/packages/rpc-client/package.json +2 -2
- package/pkg/dist/theme/theme.d.ts.map +1 -1
- package/pkg/dist/theme/theme.js +45 -17
- package/pkg/dist/theme/theme.js.map +1 -1
- package/pkg/package.json +1 -1
- package/src/resources/GSD-WORKFLOW.md +5 -4
- package/src/resources/extensions/ask-user-questions.ts +7 -2
- 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/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 +40 -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 +534 -228
- package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +672 -7
- package/src/resources/extensions/claude-code-cli/turn-assembler.ts +38 -1
- package/src/resources/extensions/gsd/auto/closeout.ts +309 -0
- 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 +168 -0
- package/src/resources/extensions/gsd/auto/dispatch-key.ts +39 -0
- package/src/resources/extensions/gsd/auto/dispatch.ts +449 -0
- package/src/resources/extensions/gsd/auto/finalize.ts +445 -0
- package/src/resources/extensions/gsd/auto/loop.ts +7 -1
- package/src/resources/extensions/gsd/auto/milestone-lease-reclaim.ts +74 -0
- package/src/resources/extensions/gsd/auto/orchestrator.ts +193 -71
- package/src/resources/extensions/gsd/auto/phase-helpers.ts +199 -0
- package/src/resources/extensions/gsd/auto/phases.ts +58 -3022
- package/src/resources/extensions/gsd/auto/pre-dispatch.ts +704 -0
- package/src/resources/extensions/gsd/auto/session.ts +3 -0
- package/src/resources/extensions/gsd/auto/unit-phase.ts +910 -0
- package/src/resources/extensions/gsd/auto/workflow-unit-dispatch.ts +1 -1
- package/src/resources/extensions/gsd/auto/worktree-safety-phase.ts +149 -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 +15 -2
- package/src/resources/extensions/gsd/auto.ts +49 -2
- 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 +79 -12
- package/src/resources/extensions/gsd/bootstrap/exec-tools.ts +2 -2
- package/src/resources/extensions/gsd/bootstrap/register-extension.ts +24 -0
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +211 -59
- 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/browser-evidence.ts +18 -2
- 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/commands-mcp-status.ts +2 -2
- package/src/resources/extensions/gsd/commands-workflow-templates.ts +11 -4
- 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 +66 -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-environment.ts +267 -142
- 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 +145 -24
- package/src/resources/extensions/gsd/health-widget.ts +91 -27
- package/src/resources/extensions/gsd/markdown-renderer.ts +11 -0
- package/src/resources/extensions/gsd/mcp-bridge.ts +39 -0
- package/src/resources/extensions/gsd/mcp-filter.ts +2 -23
- 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/milestone-settlement.ts +2 -2
- package/src/resources/extensions/gsd/notifications.ts +13 -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 +4 -4
- package/src/resources/extensions/gsd/prompts/execute-task.md +3 -2
- 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 +9 -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/prompts/workflow-start.md +2 -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/skill-activation.ts +3 -6
- package/src/resources/extensions/gsd/state.ts +12 -1
- package/src/resources/extensions/gsd/tests/auto-abort-pause-regression.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/auto-blocked-remediation-message.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +206 -22
- package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +97 -1
- package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +273 -37
- package/src/resources/extensions/gsd/tests/auto-pause-double-entry-guard.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/auto-paused-ui-cleanup.test.ts +51 -0
- package/src/resources/extensions/gsd/tests/auto-phases-lifecycle.test.ts +2 -1
- 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/auto-unit-closeout.test.ts +169 -1
- package/src/resources/extensions/gsd/tests/blocked-models.test.ts +19 -0
- 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/complete-slice-verification-gate.test.ts +42 -0
- package/src/resources/extensions/gsd/tests/complete-task.test.ts +141 -5
- 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 +12 -11
- package/src/resources/extensions/gsd/tests/derive-state-helpers.test.ts +36 -0
- 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 +328 -0
- package/src/resources/extensions/gsd/tests/dispatch-run-uat-browser-tools.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/dist-redirect.mjs +8 -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/engine-interfaces-contract.test.ts +117 -91
- package/src/resources/extensions/gsd/tests/ensure-db-open.test.ts +113 -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/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 +18 -6
- package/src/resources/extensions/gsd/tests/integration/auto-worktree-milestone-merge.test.ts +7 -11
- package/src/resources/extensions/gsd/tests/integration/auto-worktree.test.ts +35 -58
- package/src/resources/extensions/gsd/tests/integration/doctor-environment-async.test.ts +104 -0
- package/src/resources/extensions/gsd/tests/integration/gsd-integration-fixture.ts +80 -0
- package/src/resources/extensions/gsd/tests/integration/run-uat.test.ts +217 -0
- package/src/resources/extensions/gsd/tests/journal-integration.test.ts +47 -16
- package/src/resources/extensions/gsd/tests/mcp-project-config.test.ts +3 -1
- package/src/resources/extensions/gsd/tests/mcp-readiness-preflight.test.ts +205 -0
- package/src/resources/extensions/gsd/tests/mcp-status.test.ts +6 -5
- package/src/resources/extensions/gsd/tests/milestone-closeout.test.ts +95 -4
- package/src/resources/extensions/gsd/tests/milestone-merge-stash-restore.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/milestone-report-path.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/milestone-settlement.test.ts +92 -0
- package/src/resources/extensions/gsd/tests/milestone-transition-state-rebuild.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/model-unittype-mapping.test.ts +32 -1
- package/src/resources/extensions/gsd/tests/notifications.test.ts +64 -9
- 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/parallel-skill-prompt-integration.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/parsers-legacy-importers.test.ts +143 -0
- package/src/resources/extensions/gsd/tests/phases-merge-error-stops-auto.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/phases-terminal-complete-idempotent.test.ts +242 -0
- package/src/resources/extensions/gsd/tests/plan-gate-failed-doctor-heal-hint.test.ts +3 -3
- package/src/resources/extensions/gsd/tests/post-exec-retry-bypass.test.ts +63 -2
- package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +10 -2
- package/src/resources/extensions/gsd/tests/prompt-db.test.ts +124 -6
- package/src/resources/extensions/gsd/tests/provider-errors.test.ts +2 -4
- package/src/resources/extensions/gsd/tests/remote-notification-from-desktop.test.ts +31 -81
- package/src/resources/extensions/gsd/tests/roadmap-slices.test.ts +68 -0
- package/src/resources/extensions/gsd/tests/runtime-invariant-modules.test.ts +26 -2
- package/src/resources/extensions/gsd/tests/skill-activation.test.ts +20 -17
- package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +7 -3
- package/src/resources/extensions/gsd/tests/stop-auto-race-null-unit.test.ts +1 -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 +80 -2
- package/src/resources/extensions/gsd/tests/tool-surface-readiness.test.ts +184 -10
- 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 +112 -29
- 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/uok-plan-v2-wiring.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/verification-verdict.test.ts +2 -0
- package/src/resources/extensions/gsd/tests/web-app-uat.test.ts +44 -1
- package/src/resources/extensions/gsd/tests/workflow-events.test.ts +19 -0
- package/src/resources/extensions/gsd/tests/workflow-mcp-readiness-cache.test.ts +119 -0
- package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +65 -2
- package/src/resources/extensions/gsd/tests/workflow-phase-contract-matrix.test.ts +332 -0
- package/src/resources/extensions/gsd/tests/workflow-reconcile.test.ts +20 -0
- package/src/resources/extensions/gsd/tests/workflow-templates.test.ts +92 -0
- package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +273 -38
- package/src/resources/extensions/gsd/tests/worktree-health-dispatch.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/worktree-project-root-degrade.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/worktree-safety-phase.test.ts +100 -0
- package/src/resources/extensions/gsd/tests/worktree-safety.test.ts +72 -0
- 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/tool-surface-readiness.ts +126 -19
- 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 +90 -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 +62 -16
- package/src/resources/extensions/gsd/unit-context-composer.ts +99 -0
- package/src/resources/extensions/gsd/unit-registry.ts +41 -24
- 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/web-app-uat.ts +51 -8
- 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-mcp-auto-prep.ts +2 -0
- package/src/resources/extensions/gsd/workflow-mcp-readiness-cache.ts +150 -0
- 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-safety.ts +41 -39
- package/src/resources/extensions/gsd/worktree.ts +7 -1
- package/src/resources/extensions/mcp-client/manager.ts +7 -1
- 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 +141 -6
- 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/executable-code.md +1 -1
- package/src/resources/skills/create-skill/references/skill-structure.md +1 -0
- 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/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/{2p9Rv9pQflAxCBbGVI2vb → avEtvPrImYTq2gGe-hVNp}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{2p9Rv9pQflAxCBbGVI2vb → avEtvPrImYTq2gGe-hVNp}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,910 @@
|
|
|
1
|
+
// Project/App: gsd-pi
|
|
2
|
+
// File Purpose: Auto-loop unit execution phase.
|
|
3
|
+
|
|
4
|
+
import { importExtensionModule } from "@gsd/pi-coding-agent";
|
|
5
|
+
import type { SidecarItem, AutoSession } from "./session.js";
|
|
6
|
+
import { resetEvidence, loadEvidenceFromDisk } from "../safety/evidence-collector.js";
|
|
7
|
+
import { captureRootDirtySnapshot } from "../root-write-leak-guard.js";
|
|
8
|
+
import {
|
|
9
|
+
USER_DRIVEN_DEEP_UNITS,
|
|
10
|
+
isAwaitingUserInput,
|
|
11
|
+
} from "../auto-post-unit.js";
|
|
12
|
+
import { lastAssistantText } from "../consent-question.js";
|
|
13
|
+
import { classifyProject } from "../detection.js";
|
|
14
|
+
import { debugLog } from "../debug-logger.js";
|
|
15
|
+
import { pauseAutoForProviderError } from "../provider-error-pause.js";
|
|
16
|
+
import { resumeAutoAfterProviderDelay } from "../bootstrap/provider-error-resume.js";
|
|
17
|
+
import { join } from "node:path";
|
|
18
|
+
import { logWarning, _resetLogs } from "../workflow-logger.js";
|
|
19
|
+
import {
|
|
20
|
+
verifyExpectedArtifact,
|
|
21
|
+
diagnoseExpectedArtifact,
|
|
22
|
+
buildLoopRemediationSteps,
|
|
23
|
+
refreshRecoveryDbForArtifact,
|
|
24
|
+
} from "../auto-recovery.js";
|
|
25
|
+
import { writeUnitRuntimeRecord } from "../unit-runtime.js";
|
|
26
|
+
import { isDbAvailable, getTask } from "../gsd-db.js";
|
|
27
|
+
import { getLatestForUnit } from "../db/unit-dispatches.js";
|
|
28
|
+
import type { MinimalModelRegistry } from "../context-budget.js";
|
|
29
|
+
import { parseUnitId } from "../unit-id.js";
|
|
30
|
+
import { createCheckpoint, cleanupCheckpoint, rollbackToCheckpoint } from "../safety/git-checkpoint.js";
|
|
31
|
+
import { resolveSafetyHarnessConfig } from "../safety/safety-harness.js";
|
|
32
|
+
import { getUnitWorkflowDispatchReadinessError } from "../tool-contract.js";
|
|
33
|
+
import { prepareWorkflowMcpForProject } from "../workflow-mcp-auto-prep.js";
|
|
34
|
+
import {
|
|
35
|
+
applyThinkingLevelForModel,
|
|
36
|
+
floorThinkingLevelForUnit,
|
|
37
|
+
} from "../auto-model-selection.js";
|
|
38
|
+
import { isSuspiciousGhostCompletion } from "../auto-unit-closeout.js";
|
|
39
|
+
import { classifyError, isTransient } from "../error-classifier.js";
|
|
40
|
+
import { setCurrentPhase, clearCurrentPhase } from "../../shared/gsd-phase-state.js";
|
|
41
|
+
import { setAutoActiveStatus } from "../auto-dashboard.js";
|
|
42
|
+
import { runUnit } from "./run-unit.js";
|
|
43
|
+
import { validateSourceWriteWorktreeSafety } from "./worktree-safety-phase.js";
|
|
44
|
+
import {
|
|
45
|
+
isIsolatedWorktreeSession,
|
|
46
|
+
_resolveCurrentUnitStartedAtForTest,
|
|
47
|
+
emitCancelledUnitEnd,
|
|
48
|
+
_buildCancelledUnitStopReason,
|
|
49
|
+
_isPauseOriginCancelledResult,
|
|
50
|
+
rememberRetryDispatch,
|
|
51
|
+
} from "./phase-helpers.js";
|
|
52
|
+
import type { IterationContext, IterationData, LoopState, PhaseResult } from "./types.js";
|
|
53
|
+
import { MAX_RECOVERY_CHARS } from "./types.js";
|
|
54
|
+
|
|
55
|
+
const ZERO_TOOL_PROVIDER_ERROR_PREFIX_RE =
|
|
56
|
+
/^(?:api error(?::|$|\s*\()|provider error(?::|$|\s*\()|request failed\b|(?:http\s*)?(?:429|500|502|503)\b|\b(?:econnreset|etimedout|econnrefused|epipe)\b|socket hang up\b|fetch failed\b|(?:network|connection|server) error(?::|$)|connection (?:reset|refused)(?::|$|\s+by\b)|dns\b.*(?:fail|error|timeout)|unexpected eof\b|stream idle timeout\b|partial response received\b|stream_exhausted\b|terminated(?::|$)|(?:connection|stream|request)\b.{0,40}\bterminated\b|other side closed\b|rate.?limit(?:ed| exceeded| reached| error)|too many requests\b|you(?:'ve| have) (?:hit|reached) your (?:\w+ )?limit\b|.*\b(?:usage|session|weekly|daily|monthly|quota) limit\b|limit\b.{0,40}\bresets?\b|out of extra usage\b|service.?unavailable\b|internal(?: server)? error(?::|$)|internal(?:[_-]server)?[_-]error\b|server[_-]error\b|(?:provider|server|api|model|codex|claude|openai|anthropic|gemini)\b.{0,80}\boverloaded\b|overloaded\b.{0,80}\b(?:provider|server|api|model)\b|context (?:window|length) exceed|context window exceed)/i;
|
|
57
|
+
const ZERO_TOOL_PROVIDER_ERROR_SIGNAL_RE =
|
|
58
|
+
/(?:\b(?:http|status(?: code)?|code|error:)\s*(?:429|500|502|503)\b|\b(?:api|provider) error\s*[:(]?\s*(?:429|500|502|503)\b|\b(?:typeerror|error):\s*(?:fetch failed\b|socket hang up\b|terminated(?::|$)|connection (?:reset|refused)(?::|$|\s+by\b)|(?:network|connection|server) error(?::|$)|stream idle timeout\b|partial response received\b|unexpected eof\b)|\b(?:server_error|api_error|stream_exhausted(?:_without_result)?)\b|\b(?:econnreset|etimedout|econnrefused|epipe)\b|context (?:window|length) exceed|context window exceed)/i;
|
|
59
|
+
|
|
60
|
+
function classifyZeroToolProviderMessage(message: string): ReturnType<typeof classifyError> | null {
|
|
61
|
+
const firstLine = message.trim().split(/\r?\n/, 1)[0]?.trim() ?? "";
|
|
62
|
+
if (
|
|
63
|
+
!firstLine ||
|
|
64
|
+
(!ZERO_TOOL_PROVIDER_ERROR_PREFIX_RE.test(firstLine) &&
|
|
65
|
+
!ZERO_TOOL_PROVIDER_ERROR_SIGNAL_RE.test(firstLine))
|
|
66
|
+
) return null;
|
|
67
|
+
return classifyError(firstLine);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export const _classifyZeroToolProviderMessageForTest = classifyZeroToolProviderMessage;
|
|
71
|
+
|
|
72
|
+
export function resolveDispatchRecoveryAttempts(
|
|
73
|
+
unitRecoveryCount: Map<string, number>,
|
|
74
|
+
unitType: string,
|
|
75
|
+
unitId: string,
|
|
76
|
+
): number | undefined {
|
|
77
|
+
return (unitRecoveryCount.get(`${unitType}/${unitId}`) ?? 0) > 0
|
|
78
|
+
? 0
|
|
79
|
+
: undefined;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export function _shouldProceedWithInvalidRepoClassificationForTest(
|
|
83
|
+
reason: string | undefined,
|
|
84
|
+
hasGit: boolean,
|
|
85
|
+
): boolean {
|
|
86
|
+
return reason === "missing .git" && hasGit;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// ─── Session timeout auto-resume state ────────────────────────────────────────
|
|
90
|
+
|
|
91
|
+
let consecutiveSessionTimeouts = 0;
|
|
92
|
+
const MAX_SESSION_TIMEOUT_AUTO_RESUMES = 3;
|
|
93
|
+
/** Maximum zero-tool-call retries before pausing — context exhaustion is deterministic. */
|
|
94
|
+
const MAX_ZERO_TOOL_RETRIES = 1;
|
|
95
|
+
|
|
96
|
+
export function resetSessionTimeoutState(): void {
|
|
97
|
+
consecutiveSessionTimeouts = 0;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Phase 4: Unit execution — dispatch prompt, await agent_end, closeout, artifact verify.
|
|
102
|
+
* Returns break or next with unitStartedAt for downstream phases.
|
|
103
|
+
*/
|
|
104
|
+
export async function runUnitPhase(
|
|
105
|
+
ic: IterationContext,
|
|
106
|
+
iterData: IterationData,
|
|
107
|
+
loopState: LoopState,
|
|
108
|
+
sidecarItem?: SidecarItem,
|
|
109
|
+
): Promise<PhaseResult<{ unitStartedAt?: number; requestDispatchedAt?: number }>> {
|
|
110
|
+
const { ctx, pi, s, deps, prefs } = ic;
|
|
111
|
+
const { unitType, unitId, prompt, state, mid } = iterData;
|
|
112
|
+
|
|
113
|
+
debugLog("autoLoop", {
|
|
114
|
+
phase: "unit-execution",
|
|
115
|
+
iteration: ic.iteration,
|
|
116
|
+
unitType,
|
|
117
|
+
unitId,
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
const worktreeSafetyBlock = await validateSourceWriteWorktreeSafety(
|
|
121
|
+
ic,
|
|
122
|
+
unitType,
|
|
123
|
+
unitId,
|
|
124
|
+
mid,
|
|
125
|
+
"unit-execution",
|
|
126
|
+
);
|
|
127
|
+
if (worktreeSafetyBlock) return worktreeSafetyBlock;
|
|
128
|
+
|
|
129
|
+
// ── Project classification notice (#1833, #1843) ─────────────────────
|
|
130
|
+
// Worktree Safety owns source-write root validity. Classification now only
|
|
131
|
+
// shapes user/model guidance for valid roots.
|
|
132
|
+
let projectClassification: ReturnType<typeof classifyProject> | null = null;
|
|
133
|
+
if (s.basePath && unitType === "execute-task") {
|
|
134
|
+
projectClassification = classifyProject(s.basePath);
|
|
135
|
+
if (projectClassification.kind === "invalid-repo") {
|
|
136
|
+
const msg = `Worktree health check failed: ${s.basePath} classified as invalid-repo (${projectClassification.reason}) — refusing to dispatch ${unitType} ${unitId}`;
|
|
137
|
+
debugLog("runUnitPhase", { phase: "worktree-health-invalid-repo", basePath: s.basePath, classification: projectClassification });
|
|
138
|
+
const hasGit = deps.existsSync(join(s.basePath, ".git"));
|
|
139
|
+
if (_shouldProceedWithInvalidRepoClassificationForTest(projectClassification.reason, hasGit)) {
|
|
140
|
+
ctx.ui.notify(
|
|
141
|
+
`Warning: ${s.basePath} project classification could not confirm .git; assuming it has no project content yet — proceeding as greenfield project because worktree health reported .git present`,
|
|
142
|
+
"warning",
|
|
143
|
+
);
|
|
144
|
+
} else {
|
|
145
|
+
ctx.ui.notify(msg, "error");
|
|
146
|
+
await deps.stopAuto(ctx, pi, msg);
|
|
147
|
+
return { action: "break", reason: "worktree-invalid" };
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
if (projectClassification.kind === "greenfield") {
|
|
152
|
+
debugLog("runUnitPhase", { phase: "worktree-health-greenfield", basePath: s.basePath, classification: projectClassification });
|
|
153
|
+
ctx.ui.notify(`Warning: ${s.basePath} has no project content yet — proceeding as greenfield project`, "warning");
|
|
154
|
+
} else if (projectClassification.kind === "untyped-existing") {
|
|
155
|
+
debugLog("runUnitPhase", { phase: "worktree-health-untyped-existing", basePath: s.basePath, classification: projectClassification });
|
|
156
|
+
ctx.ui.notify(
|
|
157
|
+
`Notice: ${s.basePath} has existing project content but no recognized tooling markers — using generic file-level workflow guidance`,
|
|
158
|
+
"info",
|
|
159
|
+
);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// Detect retry and capture previous tier for escalation
|
|
164
|
+
const isRetry = !!(
|
|
165
|
+
s.currentUnit &&
|
|
166
|
+
s.currentUnit.type === unitType &&
|
|
167
|
+
s.currentUnit.id === unitId
|
|
168
|
+
);
|
|
169
|
+
const previousTier = s.currentUnitRouting?.tier;
|
|
170
|
+
const dispatchKey = `${unitType}/${unitId}`;
|
|
171
|
+
const nextDispatchCount = (s.unitDispatchCount.get(dispatchKey) ?? 0) + 1;
|
|
172
|
+
|
|
173
|
+
// Status bar (widget + preconditions deferred until after model selection — see #2899)
|
|
174
|
+
setAutoActiveStatus(ctx, s.stepMode ? "next" : "auto");
|
|
175
|
+
if (mid)
|
|
176
|
+
deps.updateSliceProgressCache(s.basePath, mid, state.activeSlice?.id);
|
|
177
|
+
|
|
178
|
+
// ── Safety harness: reset evidence + create checkpoint ──
|
|
179
|
+
const safetyConfig = resolveSafetyHarnessConfig(
|
|
180
|
+
prefs?.safety_harness as Record<string, unknown> | undefined,
|
|
181
|
+
);
|
|
182
|
+
if (safetyConfig.enabled && safetyConfig.evidence_collection) {
|
|
183
|
+
resetEvidence();
|
|
184
|
+
// Restore persisted evidence so session-restart resumes don't produce
|
|
185
|
+
// false-positive "no bash calls" warnings (Bug #4385).
|
|
186
|
+
if (s.basePath && unitType === "execute-task") {
|
|
187
|
+
const { milestone: eMid, slice: eSid, task: eTid } = parseUnitId(unitId);
|
|
188
|
+
if (eMid && eSid && eTid) {
|
|
189
|
+
loadEvidenceFromDisk(s.basePath, eMid, eSid, eTid);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
// Only checkpoint code-executing units (not lifecycle/planning units)
|
|
194
|
+
if (safetyConfig.enabled && safetyConfig.checkpoints && unitType === "execute-task") {
|
|
195
|
+
s.checkpointSha = createCheckpoint(s.basePath, unitId);
|
|
196
|
+
if (s.checkpointSha) {
|
|
197
|
+
debugLog("runUnitPhase", { phase: "checkpoint-created", unitId, sha: s.checkpointSha.slice(0, 8) });
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// Prompt injection
|
|
202
|
+
let finalPrompt = prompt;
|
|
203
|
+
|
|
204
|
+
if (unitType === "execute-task") {
|
|
205
|
+
projectClassification ??= classifyProject(s.basePath);
|
|
206
|
+
if (projectClassification.kind === "untyped-existing") {
|
|
207
|
+
const samples = projectClassification.contentFiles.slice(0, 8).join(", ") || "project files";
|
|
208
|
+
finalPrompt +=
|
|
209
|
+
"\n\n**Project classification:** Existing untyped project. No recognized build/tooling markers were detected, " +
|
|
210
|
+
"so use generic file-level workflow guidance. Task plans and completion summaries must list every concrete " +
|
|
211
|
+
`project file changed in \`files\` or \`expected_output\`. Detected content sample: ${samples}.`;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
if (s.pendingVerificationRetry && s.pendingVerificationRetry.unitId === unitId) {
|
|
216
|
+
const retryCtx = s.pendingVerificationRetry;
|
|
217
|
+
s.pendingVerificationRetry = null;
|
|
218
|
+
const capped =
|
|
219
|
+
retryCtx.failureContext.length > MAX_RECOVERY_CHARS
|
|
220
|
+
? retryCtx.failureContext.slice(0, MAX_RECOVERY_CHARS) +
|
|
221
|
+
"\n\n[...failure context truncated]"
|
|
222
|
+
: retryCtx.failureContext;
|
|
223
|
+
finalPrompt = `**VERIFICATION FAILED — AUTO-FIX ATTEMPT ${retryCtx.attempt}**\n\nThe verification gate ran after your previous attempt and found failures. Fix these issues before completing the task.\n\n${capped}\n\n---\n\n${finalPrompt}`;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
if (s.pendingCrashRecovery) {
|
|
227
|
+
const capped =
|
|
228
|
+
s.pendingCrashRecovery.length > MAX_RECOVERY_CHARS
|
|
229
|
+
? s.pendingCrashRecovery.slice(0, MAX_RECOVERY_CHARS) +
|
|
230
|
+
"\n\n[...recovery briefing truncated to prevent memory exhaustion]"
|
|
231
|
+
: s.pendingCrashRecovery;
|
|
232
|
+
finalPrompt = `${capped}\n\n---\n\n${finalPrompt}`;
|
|
233
|
+
s.pendingCrashRecovery = null;
|
|
234
|
+
} else if (nextDispatchCount > 1) {
|
|
235
|
+
const diagnostic = deps.getDeepDiagnostic(s.basePath);
|
|
236
|
+
if (diagnostic) {
|
|
237
|
+
const cappedDiag =
|
|
238
|
+
diagnostic.length > MAX_RECOVERY_CHARS
|
|
239
|
+
? diagnostic.slice(0, MAX_RECOVERY_CHARS) +
|
|
240
|
+
"\n\n[...diagnostic truncated to prevent memory exhaustion]"
|
|
241
|
+
: diagnostic;
|
|
242
|
+
const retryInstruction =
|
|
243
|
+
unitType === "execute-task"
|
|
244
|
+
? "The required artifact is `T##-SUMMARY.md`. Do NOT manually write this file. Call `gsd_task_complete` with `milestoneId`, `sliceId`, `taskId`, and the required completion fields. Do not re-run implementation work — call the tool."
|
|
245
|
+
: "Fix whatever went wrong and make sure you write the required file this time.";
|
|
246
|
+
finalPrompt = `**RETRY — your previous attempt did not produce the required artifact.**\n\nDiagnostic from previous attempt:\n${cappedDiag}\n\n${retryInstruction}\n\n---\n\n${finalPrompt}`;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// Prompt char measurement
|
|
251
|
+
s.lastPromptCharCount = finalPrompt.length;
|
|
252
|
+
s.lastBaselineCharCount = undefined;
|
|
253
|
+
if (deps.isDbAvailable()) {
|
|
254
|
+
try {
|
|
255
|
+
const { inlineGsdRootFile } = await importExtensionModule<typeof import("../auto-prompts.js")>(import.meta.url, "../auto-prompts.js");
|
|
256
|
+
const [decisionsContent, requirementsContent, projectContent] =
|
|
257
|
+
await Promise.all([
|
|
258
|
+
inlineGsdRootFile(s.basePath, "decisions.md", "Decisions"),
|
|
259
|
+
inlineGsdRootFile(s.basePath, "requirements.md", "Requirements"),
|
|
260
|
+
inlineGsdRootFile(s.basePath, "project.md", "Project"),
|
|
261
|
+
]);
|
|
262
|
+
s.lastBaselineCharCount =
|
|
263
|
+
(decisionsContent?.length ?? 0) +
|
|
264
|
+
(requirementsContent?.length ?? 0) +
|
|
265
|
+
(projectContent?.length ?? 0);
|
|
266
|
+
} catch (e) {
|
|
267
|
+
logWarning("engine", "Baseline char count measurement failed", { error: String(e) });
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
// Cache-optimize prompt section ordering
|
|
272
|
+
try {
|
|
273
|
+
finalPrompt = deps.reorderForCaching(finalPrompt);
|
|
274
|
+
} catch (reorderErr) {
|
|
275
|
+
const msg =
|
|
276
|
+
reorderErr instanceof Error ? reorderErr.message : String(reorderErr);
|
|
277
|
+
logWarning("engine", "Prompt reorder failed", { error: msg });
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
// Select and apply model (with tier escalation on retry — normal units only)
|
|
281
|
+
const prevUnitRouting = s.currentUnitRouting;
|
|
282
|
+
const prevUnitModel = s.currentUnitModel;
|
|
283
|
+
const prevDispatchedModelId = s.currentDispatchedModelId;
|
|
284
|
+
const prevSessionModel = ctx.model;
|
|
285
|
+
const prevSessionThinkingLevel = pi.getThinkingLevel();
|
|
286
|
+
const modelResult = await deps.selectAndApplyModel(
|
|
287
|
+
ctx,
|
|
288
|
+
pi,
|
|
289
|
+
unitType,
|
|
290
|
+
unitId,
|
|
291
|
+
s.basePath,
|
|
292
|
+
prefs,
|
|
293
|
+
s.verbose,
|
|
294
|
+
s.autoModeStartModel,
|
|
295
|
+
sidecarItem ? undefined : { isRetry, previousTier },
|
|
296
|
+
undefined,
|
|
297
|
+
s.manualSessionModelOverride,
|
|
298
|
+
s.autoModeStartThinkingLevel,
|
|
299
|
+
);
|
|
300
|
+
s.currentUnitRouting =
|
|
301
|
+
modelResult.routing as AutoSession["currentUnitRouting"];
|
|
302
|
+
s.currentUnitModel =
|
|
303
|
+
modelResult.appliedModel as AutoSession["currentUnitModel"];
|
|
304
|
+
|
|
305
|
+
// Apply sidecar/pre-dispatch hook model override (takes priority over standard model selection)
|
|
306
|
+
const hookModelOverride = sidecarItem?.model ?? iterData.hookModelOverride;
|
|
307
|
+
if (hookModelOverride) {
|
|
308
|
+
const availableModels = ctx.modelRegistry.getAvailable();
|
|
309
|
+
const match = deps.resolveModelId(hookModelOverride, availableModels, ctx.model?.provider);
|
|
310
|
+
if (match) {
|
|
311
|
+
const ok = await pi.setModel(match, { persist: false });
|
|
312
|
+
if (ok) {
|
|
313
|
+
// Apply the per-phase reasoning effort selectAndApplyModel resolved for
|
|
314
|
+
// this unit — not the auto-start session snapshot — but route it through
|
|
315
|
+
// the same floor + capability-clamp pipeline against the *hook* model
|
|
316
|
+
// (ADR-026). The hook override can pick a different model family than the
|
|
317
|
+
// one selectAndApplyModel clamped against, so re-clamping here prevents
|
|
318
|
+
// sending an unsupported level; the floor fills in when no phase level
|
|
319
|
+
// resolved so a hook-overridden execute-task still meets the floor.
|
|
320
|
+
const hookThinkingBase = modelResult.appliedThinkingLevel
|
|
321
|
+
?? floorThinkingLevelForUnit(unitType, s.autoModeStartThinkingLevel);
|
|
322
|
+
applyThinkingLevelForModel(pi, hookThinkingBase, match, ctx);
|
|
323
|
+
s.currentUnitModel = match as AutoSession["currentUnitModel"];
|
|
324
|
+
ctx.ui.notify(`Hook model override: ${match.provider}/${match.id}`, "info");
|
|
325
|
+
} else {
|
|
326
|
+
ctx.ui.notify(
|
|
327
|
+
`Hook model "${hookModelOverride}" found but setModel failed. Using default.`,
|
|
328
|
+
"warning",
|
|
329
|
+
);
|
|
330
|
+
}
|
|
331
|
+
} else {
|
|
332
|
+
ctx.ui.notify(
|
|
333
|
+
`Hook model "${hookModelOverride}" not found in available models. Falling back to current session model. ` +
|
|
334
|
+
`Ensure the model is defined in models.json and has auth configured.`,
|
|
335
|
+
"warning",
|
|
336
|
+
);
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
// Store the final dispatched model ID so the dashboard can read it (#2899).
|
|
341
|
+
// This accounts for hook model overrides applied after selectAndApplyModel.
|
|
342
|
+
s.currentDispatchedModelId = s.currentUnitModel
|
|
343
|
+
? `${(s.currentUnitModel as any).provider ?? ""}/${(s.currentUnitModel as any).id ?? ""}`
|
|
344
|
+
: null;
|
|
345
|
+
|
|
346
|
+
const compatibilityError = getUnitWorkflowDispatchReadinessError({
|
|
347
|
+
provider: s.currentUnitModel?.provider ?? ctx.model?.provider,
|
|
348
|
+
projectRoot: s.basePath,
|
|
349
|
+
surface: "auto-mode",
|
|
350
|
+
unitType,
|
|
351
|
+
authMode: s.currentUnitModel?.provider
|
|
352
|
+
? ctx.modelRegistry.getProviderAuthMode(s.currentUnitModel.provider)
|
|
353
|
+
: ctx.model?.provider
|
|
354
|
+
? ctx.modelRegistry.getProviderAuthMode(ctx.model.provider)
|
|
355
|
+
: undefined,
|
|
356
|
+
baseUrl: (s.currentUnitModel as any)?.baseUrl ?? ctx.model?.baseUrl,
|
|
357
|
+
activeTools: typeof pi.getActiveTools === "function" ? pi.getActiveTools() : [],
|
|
358
|
+
});
|
|
359
|
+
const workflowMcpPrepModel = s.currentUnitModel;
|
|
360
|
+
if (compatibilityError) {
|
|
361
|
+
s.currentUnitRouting = prevUnitRouting;
|
|
362
|
+
s.currentUnitModel = prevUnitModel;
|
|
363
|
+
s.currentDispatchedModelId = prevDispatchedModelId;
|
|
364
|
+
if (s.checkpointSha) {
|
|
365
|
+
cleanupCheckpoint(s.basePath, unitId);
|
|
366
|
+
s.checkpointSha = null;
|
|
367
|
+
}
|
|
368
|
+
if (prevSessionModel) {
|
|
369
|
+
const ok = await pi.setModel(prevSessionModel, { persist: false });
|
|
370
|
+
if (!ok) {
|
|
371
|
+
ctx.ui.notify("Failed to restore previous session model after compatibility check failure.", "warning");
|
|
372
|
+
}
|
|
373
|
+
if (prevSessionThinkingLevel) {
|
|
374
|
+
pi.setThinkingLevel(prevSessionThinkingLevel);
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
const workflowMcpPrep = prepareWorkflowMcpForProject(ctx, s.basePath, workflowMcpPrepModel);
|
|
379
|
+
if (workflowMcpPrep && workflowMcpPrep.status !== "unchanged") {
|
|
380
|
+
const pauseMsg =
|
|
381
|
+
"GSD workflow MCP config has been written. Restart Claude Code (or reload MCP servers), then run /gsd auto to continue.";
|
|
382
|
+
ctx.ui.notify(pauseMsg, "warning");
|
|
383
|
+
await deps.pauseAuto(ctx, pi, {
|
|
384
|
+
category: "provider",
|
|
385
|
+
isTransient: true,
|
|
386
|
+
message: pauseMsg,
|
|
387
|
+
});
|
|
388
|
+
return { action: "break", reason: "workflow-capability" };
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
ctx.ui.notify(compatibilityError, "error");
|
|
392
|
+
await deps.stopAuto(ctx, pi, compatibilityError);
|
|
393
|
+
return { action: "break", reason: "workflow-capability" };
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
// Scope workflow-logger buffer to this unit so post-finalize drains are
|
|
397
|
+
// per-unit. Without this, the module-level _buffer accumulates across every
|
|
398
|
+
// unit in the same Node process (see workflow-logger.ts module header).
|
|
399
|
+
_resetLogs();
|
|
400
|
+
const unitStartedAt = Date.now();
|
|
401
|
+
s.unitDispatchCount.set(dispatchKey, nextDispatchCount);
|
|
402
|
+
s.setCurrentUnit({ type: unitType, id: unitId, startedAt: unitStartedAt, workspaceRoot: s.basePath });
|
|
403
|
+
if (unitType === "execute-task") {
|
|
404
|
+
const { milestone, slice, task } = parseUnitId(unitId);
|
|
405
|
+
if (milestone && slice && task && isDbAvailable()) {
|
|
406
|
+
try {
|
|
407
|
+
const taskRow = getTask(milestone, slice, task);
|
|
408
|
+
if (taskRow) s.sourceObservations.observePlanTask(taskRow);
|
|
409
|
+
} catch (err) {
|
|
410
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
411
|
+
logWarning("prompt", `failed to preload source observations for ${unitId}: ${message}`);
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
s.rootWriteBaseline = isIsolatedWorktreeSession(s)
|
|
416
|
+
? captureRootDirtySnapshot(s.originalBasePath)
|
|
417
|
+
: null;
|
|
418
|
+
s.lastGitActionFailure = null;
|
|
419
|
+
s.lastGitActionStatus = null;
|
|
420
|
+
s.lastUnitAgentEndMessages = null;
|
|
421
|
+
setCurrentPhase(unitType, {
|
|
422
|
+
basePath: s.basePath,
|
|
423
|
+
traceId: ic.flowId,
|
|
424
|
+
turnId: `iter-${ic.iteration}`,
|
|
425
|
+
causedBy: "unit-start",
|
|
426
|
+
});
|
|
427
|
+
s.lastToolInvocationError = null; // #2883: clear stale error from previous unit
|
|
428
|
+
if (nextDispatchCount <= 1) {
|
|
429
|
+
s.toolUnavailableRetries = 0;
|
|
430
|
+
}
|
|
431
|
+
const unitStartSeq = ic.nextSeq();
|
|
432
|
+
deps.emitJournalEvent({ ts: new Date().toISOString(), flowId: ic.flowId, seq: unitStartSeq, eventType: "unit-start", data: { unitType, unitId } });
|
|
433
|
+
deps.captureAvailableSkills();
|
|
434
|
+
writeUnitRuntimeRecord(
|
|
435
|
+
s.basePath,
|
|
436
|
+
unitType,
|
|
437
|
+
unitId,
|
|
438
|
+
unitStartedAt,
|
|
439
|
+
{
|
|
440
|
+
phase: "dispatched",
|
|
441
|
+
wrapupWarningSent: false,
|
|
442
|
+
timeoutAt: null,
|
|
443
|
+
lastProgressAt: unitStartedAt,
|
|
444
|
+
progressCount: 0,
|
|
445
|
+
lastProgressKind: "dispatch",
|
|
446
|
+
recoveryAttempts: resolveDispatchRecoveryAttempts(s.unitRecoveryCount, unitType, unitId),
|
|
447
|
+
},
|
|
448
|
+
);
|
|
449
|
+
|
|
450
|
+
// Progress widget + preconditions — deferred to after model selection so the
|
|
451
|
+
// widget's first render tick shows the correct model (#2899).
|
|
452
|
+
deps.updateProgressWidget(ctx, unitType, unitId, state);
|
|
453
|
+
deps.ensurePreconditions(unitType, unitId, s.basePath, state);
|
|
454
|
+
|
|
455
|
+
// Start unit supervision
|
|
456
|
+
deps.clearUnitTimeout();
|
|
457
|
+
deps.startUnitSupervision({
|
|
458
|
+
s,
|
|
459
|
+
ctx,
|
|
460
|
+
pi,
|
|
461
|
+
unitType,
|
|
462
|
+
unitId,
|
|
463
|
+
prefs,
|
|
464
|
+
buildSnapshotOpts: () => deps.buildSnapshotOpts(unitType, unitId),
|
|
465
|
+
buildRecoveryContext: () => ({
|
|
466
|
+
basePath: s.basePath,
|
|
467
|
+
verbose: s.verbose,
|
|
468
|
+
currentUnitStartedAt: s.currentUnit?.startedAt ?? Date.now(),
|
|
469
|
+
unitRecoveryCount: s.unitRecoveryCount,
|
|
470
|
+
}),
|
|
471
|
+
pauseAuto: deps.pauseAuto,
|
|
472
|
+
});
|
|
473
|
+
|
|
474
|
+
// Write preliminary lock (no session path yet — runUnit creates a new session).
|
|
475
|
+
// Crash recovery can still identify the in-flight unit from this lock.
|
|
476
|
+
deps.writeLock(
|
|
477
|
+
deps.lockBase(),
|
|
478
|
+
unitType,
|
|
479
|
+
unitId,
|
|
480
|
+
);
|
|
481
|
+
|
|
482
|
+
debugLog("autoLoop", {
|
|
483
|
+
phase: "runUnit-start",
|
|
484
|
+
iteration: ic.iteration,
|
|
485
|
+
unitType,
|
|
486
|
+
unitId,
|
|
487
|
+
});
|
|
488
|
+
const pausedBeforeRun = s.paused;
|
|
489
|
+
const unitResult = await runUnit(
|
|
490
|
+
ctx,
|
|
491
|
+
pi,
|
|
492
|
+
s,
|
|
493
|
+
unitType,
|
|
494
|
+
unitId,
|
|
495
|
+
finalPrompt,
|
|
496
|
+
);
|
|
497
|
+
s.lastUnitAgentEndMessages = unitResult.event?.messages ?? null;
|
|
498
|
+
debugLog("autoLoop", {
|
|
499
|
+
phase: "runUnit-end",
|
|
500
|
+
iteration: ic.iteration,
|
|
501
|
+
unitType,
|
|
502
|
+
unitId,
|
|
503
|
+
status: unitResult.status,
|
|
504
|
+
});
|
|
505
|
+
|
|
506
|
+
if (
|
|
507
|
+
unitResult.status === "completed" &&
|
|
508
|
+
s.currentUnit &&
|
|
509
|
+
(unitResult.event?.messages?.length ?? 0) === 0 &&
|
|
510
|
+
isSuspiciousGhostCompletion(ctx, unitResult.requestDispatchedAt ?? s.currentUnit.startedAt)
|
|
511
|
+
) {
|
|
512
|
+
const message =
|
|
513
|
+
`${unitType} ${unitId} completed without assistant output or tool calls; treating as a stale ghost completion.`;
|
|
514
|
+
debugLog("autoLoop", {
|
|
515
|
+
phase: "ghost-completion",
|
|
516
|
+
iteration: ic.iteration,
|
|
517
|
+
unitType,
|
|
518
|
+
unitId,
|
|
519
|
+
elapsedMs: Date.now() - (unitResult.requestDispatchedAt ?? s.currentUnit.startedAt),
|
|
520
|
+
});
|
|
521
|
+
logWarning("engine", message);
|
|
522
|
+
ctx.ui.notify(`${message} Pausing auto-mode before closeout side effects.`, "warning");
|
|
523
|
+
await emitCancelledUnitEnd(ic, unitType, unitId, unitStartSeq, {
|
|
524
|
+
message,
|
|
525
|
+
category: "unknown",
|
|
526
|
+
isTransient: true,
|
|
527
|
+
});
|
|
528
|
+
s.clearCurrentUnit();
|
|
529
|
+
await deps.pauseAuto(ctx, pi);
|
|
530
|
+
return { action: "break", reason: "ghost-completion" };
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
// Now that runUnit has called newSession(), the session file path is correct.
|
|
534
|
+
const sessionFile = deps.getSessionFile(ctx);
|
|
535
|
+
deps.updateSessionLock(
|
|
536
|
+
deps.lockBase(),
|
|
537
|
+
unitType,
|
|
538
|
+
unitId,
|
|
539
|
+
sessionFile,
|
|
540
|
+
);
|
|
541
|
+
deps.writeLock(
|
|
542
|
+
deps.lockBase(),
|
|
543
|
+
unitType,
|
|
544
|
+
unitId,
|
|
545
|
+
sessionFile,
|
|
546
|
+
);
|
|
547
|
+
|
|
548
|
+
// Tag the most recent window entry with error info for stuck detection
|
|
549
|
+
const lastEntry = loopState.recentUnits[loopState.recentUnits.length - 1];
|
|
550
|
+
if (lastEntry) {
|
|
551
|
+
if (unitResult.errorContext) {
|
|
552
|
+
lastEntry.error = `${unitResult.errorContext.category}:${unitResult.errorContext.message}`.slice(0, 200);
|
|
553
|
+
} else if (unitResult.status === "error" || unitResult.status === "cancelled") {
|
|
554
|
+
lastEntry.error = `${unitResult.status}:${unitType}/${unitId}`;
|
|
555
|
+
} else if (unitResult.event?.messages?.length) {
|
|
556
|
+
const lastMsg = unitResult.event.messages[unitResult.event.messages.length - 1];
|
|
557
|
+
const msgStr = typeof lastMsg === "string" ? lastMsg : JSON.stringify(lastMsg);
|
|
558
|
+
if (/error|fail|exception/i.test(msgStr)) {
|
|
559
|
+
lastEntry.error = msgStr.slice(0, 200);
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
if (unitResult.status === "cancelled") {
|
|
565
|
+
if (_isPauseOriginCancelledResult(s.paused, unitResult.errorContext)) {
|
|
566
|
+
if (!pausedBeforeRun) {
|
|
567
|
+
const pauseContext = {
|
|
568
|
+
message: "Auto-mode paused during unit setup",
|
|
569
|
+
category: "aborted" as const,
|
|
570
|
+
isTransient: true,
|
|
571
|
+
};
|
|
572
|
+
await deps.autoCommitUnit?.(s.basePath, unitType, unitId, ctx);
|
|
573
|
+
await emitCancelledUnitEnd(ic, unitType, unitId, unitStartSeq, pauseContext);
|
|
574
|
+
return { action: "break", reason: "pause-during-setup" };
|
|
575
|
+
}
|
|
576
|
+
debugLog("autoLoop", { phase: "cancelled-after-pause", unitType, unitId });
|
|
577
|
+
return { action: "break", reason: "paused" };
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
const errorCategory = unitResult.errorContext?.category;
|
|
581
|
+
// Provider-error pause: agent_end recovery normally pauses before this
|
|
582
|
+
// branch. Provider readiness failures happen before dispatch, so pause here
|
|
583
|
+
// if nothing upstream already did.
|
|
584
|
+
if (errorCategory === "provider") {
|
|
585
|
+
if (!s.paused) {
|
|
586
|
+
const detail = unitResult.errorContext?.message ?? `Provider unavailable for ${unitType} ${unitId}`;
|
|
587
|
+
const isTransient = Boolean(unitResult.errorContext?.isTransient);
|
|
588
|
+
const retryAfterMs = unitResult.errorContext?.retryAfterMs ?? (isTransient ? 30_000 : undefined);
|
|
589
|
+
await pauseAutoForProviderError(
|
|
590
|
+
ctx.ui,
|
|
591
|
+
detail,
|
|
592
|
+
() => deps.pauseAuto(ctx, pi),
|
|
593
|
+
{
|
|
594
|
+
isRateLimit: false,
|
|
595
|
+
isTransient,
|
|
596
|
+
retryAfterMs,
|
|
597
|
+
resume: isTransient
|
|
598
|
+
? () => {
|
|
599
|
+
void resumeAutoAfterProviderDelay(pi, ctx).catch((err) => {
|
|
600
|
+
logWarning("engine", `Provider error auto-resume failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
601
|
+
});
|
|
602
|
+
}
|
|
603
|
+
: undefined,
|
|
604
|
+
},
|
|
605
|
+
);
|
|
606
|
+
}
|
|
607
|
+
await emitCancelledUnitEnd(ic, unitType, unitId, unitStartSeq, unitResult.errorContext);
|
|
608
|
+
debugLog("autoLoop", { phase: "exit", reason: "provider-pause", isTransient: unitResult.errorContext?.isTransient });
|
|
609
|
+
return { action: "break", reason: "provider-pause" };
|
|
610
|
+
}
|
|
611
|
+
// Timeout category covers two distinct scenarios:
|
|
612
|
+
// 1. Session creation timeout (120s) — transient, auto-resume with backoff
|
|
613
|
+
// 2. Unit hard timeout (30min+) — stuck agent, pause for manual review
|
|
614
|
+
// Transient session-failed covers recoverable newSession failures and should
|
|
615
|
+
// pause instead of hard-stopping.
|
|
616
|
+
// Structural errors (TypeError, is not a function) are NOT transient
|
|
617
|
+
// and must hard-stop to avoid infinite retry loops.
|
|
618
|
+
if (
|
|
619
|
+
unitResult.errorContext?.isTransient &&
|
|
620
|
+
errorCategory === "timeout"
|
|
621
|
+
) {
|
|
622
|
+
const isSessionCreationTimeout = unitResult.errorContext.message?.includes("Session creation timed out");
|
|
623
|
+
|
|
624
|
+
if (isSessionCreationTimeout) {
|
|
625
|
+
consecutiveSessionTimeouts += 1;
|
|
626
|
+
const baseRetryAfterMs = 30_000;
|
|
627
|
+
const retryAfterMs = baseRetryAfterMs * 2 ** Math.max(0, consecutiveSessionTimeouts - 1);
|
|
628
|
+
const allowAutoResume = consecutiveSessionTimeouts <= MAX_SESSION_TIMEOUT_AUTO_RESUMES;
|
|
629
|
+
|
|
630
|
+
if (!allowAutoResume) {
|
|
631
|
+
ctx.ui.notify(
|
|
632
|
+
`Session creation timed out ${consecutiveSessionTimeouts} consecutive times for ${unitType} ${unitId}. Pausing for manual review.`,
|
|
633
|
+
"warning",
|
|
634
|
+
);
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
debugLog("autoLoop", {
|
|
638
|
+
phase: "session-timeout-pause",
|
|
639
|
+
unitType, unitId,
|
|
640
|
+
consecutiveSessionTimeouts,
|
|
641
|
+
retryAfterMs,
|
|
642
|
+
allowAutoResume,
|
|
643
|
+
});
|
|
644
|
+
|
|
645
|
+
const errorDetail = ` for ${unitType} ${unitId}`;
|
|
646
|
+
await pauseAutoForProviderError(
|
|
647
|
+
ctx.ui,
|
|
648
|
+
errorDetail,
|
|
649
|
+
() => deps.pauseAuto(ctx, pi),
|
|
650
|
+
{
|
|
651
|
+
isRateLimit: false,
|
|
652
|
+
isTransient: allowAutoResume,
|
|
653
|
+
retryAfterMs,
|
|
654
|
+
resume: allowAutoResume
|
|
655
|
+
? () => {
|
|
656
|
+
void resumeAutoAfterProviderDelay(pi, ctx).catch((err) => {
|
|
657
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
658
|
+
ctx.ui.notify(
|
|
659
|
+
`Session timeout recovery failed: ${message}`,
|
|
660
|
+
"error",
|
|
661
|
+
);
|
|
662
|
+
});
|
|
663
|
+
}
|
|
664
|
+
: undefined,
|
|
665
|
+
},
|
|
666
|
+
);
|
|
667
|
+
await deps.autoCommitUnit?.(s.basePath, unitType, unitId, ctx);
|
|
668
|
+
await emitCancelledUnitEnd(ic, unitType, unitId, unitStartSeq, unitResult.errorContext);
|
|
669
|
+
return { action: "break", reason: "session-timeout" };
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
// Unit hard timeout (30min+): pause without auto-resume — stuck agent
|
|
673
|
+
ctx.ui.notify(
|
|
674
|
+
`Unit timed out for ${unitType} ${unitId} (supervision may have failed). Pausing auto-mode.`,
|
|
675
|
+
"warning",
|
|
676
|
+
);
|
|
677
|
+
debugLog("autoLoop", { phase: "unit-hard-timeout-pause", unitType, unitId });
|
|
678
|
+
await deps.pauseAuto(ctx, pi);
|
|
679
|
+
await deps.autoCommitUnit?.(s.basePath, unitType, unitId, ctx);
|
|
680
|
+
await emitCancelledUnitEnd(ic, unitType, unitId, unitStartSeq, unitResult.errorContext);
|
|
681
|
+
return { action: "break", reason: "unit-hard-timeout" };
|
|
682
|
+
}
|
|
683
|
+
if (
|
|
684
|
+
unitResult.errorContext?.isTransient &&
|
|
685
|
+
errorCategory === "session-failed"
|
|
686
|
+
) {
|
|
687
|
+
ctx.ui.notify(
|
|
688
|
+
`Session creation failed transiently for ${unitType} ${unitId}: ${unitResult.errorContext?.message ?? "unknown"}. Pausing auto-mode (recoverable).`,
|
|
689
|
+
"warning",
|
|
690
|
+
);
|
|
691
|
+
debugLog("autoLoop", { phase: "session-start-transient-pause", unitType, unitId, category: errorCategory });
|
|
692
|
+
await deps.pauseAuto(ctx, pi);
|
|
693
|
+
await deps.autoCommitUnit?.(s.basePath, unitType, unitId, ctx);
|
|
694
|
+
await emitCancelledUnitEnd(ic, unitType, unitId, unitStartSeq, unitResult.errorContext);
|
|
695
|
+
return { action: "break", reason: "session-timeout" };
|
|
696
|
+
}
|
|
697
|
+
if (
|
|
698
|
+
unitResult.errorContext?.isTransient &&
|
|
699
|
+
errorCategory === "aborted"
|
|
700
|
+
) {
|
|
701
|
+
rememberRetryDispatch(s, { type: unitType, id: unitId }, iterData);
|
|
702
|
+
writeUnitRuntimeRecord(s.basePath, unitType, unitId, s.currentUnit?.startedAt ?? Date.now(), {
|
|
703
|
+
phase: "paused",
|
|
704
|
+
lastProgressAt: Date.now(),
|
|
705
|
+
lastProgressKind: "unit-aborted-pause",
|
|
706
|
+
});
|
|
707
|
+
ctx.ui.notify(
|
|
708
|
+
`Unit ${unitType} ${unitId} was aborted (transient). Pausing auto-mode (recoverable).`,
|
|
709
|
+
"warning",
|
|
710
|
+
);
|
|
711
|
+
debugLog("autoLoop", { phase: "unit-aborted-transient-pause", unitType, unitId, category: errorCategory });
|
|
712
|
+
await deps.pauseAuto(ctx, pi, unitResult.errorContext);
|
|
713
|
+
await deps.autoCommitUnit?.(s.basePath, unitType, unitId, ctx);
|
|
714
|
+
await emitCancelledUnitEnd(ic, unitType, unitId, unitStartSeq, unitResult.errorContext);
|
|
715
|
+
return { action: "break", reason: "unit-aborted-pause" };
|
|
716
|
+
}
|
|
717
|
+
// All other cancelled states (structural errors, non-transient failures): hard stop
|
|
718
|
+
if (s.currentUnit) {
|
|
719
|
+
await deps.closeoutUnit(
|
|
720
|
+
ctx,
|
|
721
|
+
s.basePath,
|
|
722
|
+
unitType,
|
|
723
|
+
unitId,
|
|
724
|
+
s.currentUnit.startedAt,
|
|
725
|
+
deps.buildSnapshotOpts(unitType, unitId),
|
|
726
|
+
);
|
|
727
|
+
}
|
|
728
|
+
await deps.autoCommitUnit?.(s.basePath, unitType, unitId, ctx);
|
|
729
|
+
await emitCancelledUnitEnd(ic, unitType, unitId, unitStartSeq, unitResult.errorContext);
|
|
730
|
+
|
|
731
|
+
const cancelledStop = _buildCancelledUnitStopReason(
|
|
732
|
+
unitType,
|
|
733
|
+
unitId,
|
|
734
|
+
unitResult.errorContext,
|
|
735
|
+
);
|
|
736
|
+
ctx.ui.notify(cancelledStop.notifyMessage, "warning");
|
|
737
|
+
await deps.stopAuto(ctx, pi, cancelledStop.stopReason);
|
|
738
|
+
debugLog("autoLoop", { phase: "exit", reason: cancelledStop.loopReason });
|
|
739
|
+
return { action: "break", reason: cancelledStop.loopReason };
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
// ── Immediate unit closeout (metrics, activity log, memory) ────────
|
|
743
|
+
// Run right after runUnit() returns so telemetry is never lost to a
|
|
744
|
+
// crash between iterations.
|
|
745
|
+
// Guard: stopAuto() may have nulled s.currentUnit via s.reset() while
|
|
746
|
+
// this coroutine was suspended at `await runUnit(...)` (#2939).
|
|
747
|
+
if (s.currentUnit) {
|
|
748
|
+
// Reset session timeout counter — any successful unit clears the slate
|
|
749
|
+
consecutiveSessionTimeouts = 0;
|
|
750
|
+
await deps.closeoutUnit(
|
|
751
|
+
ctx,
|
|
752
|
+
s.basePath,
|
|
753
|
+
unitType,
|
|
754
|
+
unitId,
|
|
755
|
+
s.currentUnit.startedAt,
|
|
756
|
+
deps.buildSnapshotOpts(unitType, unitId),
|
|
757
|
+
);
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
// ── Zero tool-call guard (#1833, #2653) ──────────────────────────
|
|
761
|
+
// Any unit that completes with 0 tool calls made no real progress —
|
|
762
|
+
// likely context exhaustion where all tool calls errored out. Treat
|
|
763
|
+
// as failed so the unit is retried in a fresh context instead of
|
|
764
|
+
// silently passing through to artifact verification (which loops
|
|
765
|
+
// forever when the unit never produced its artifact).
|
|
766
|
+
{
|
|
767
|
+
const currentLedger = deps.getLedger() as { units: Array<{ type: string; id: string; startedAt: number; toolCalls: number }> } | null;
|
|
768
|
+
if (currentLedger?.units) {
|
|
769
|
+
const lastUnit = [...currentLedger.units].reverse().find(
|
|
770
|
+
(u: { type: string; id: string; startedAt: number; toolCalls: number }) => u.type === unitType && u.id === unitId && u.startedAt === _resolveCurrentUnitStartedAtForTest(s.currentUnit),
|
|
771
|
+
);
|
|
772
|
+
if (lastUnit && lastUnit.toolCalls === 0) {
|
|
773
|
+
const lastAssistantMessage = lastAssistantText(s.lastUnitAgentEndMessages);
|
|
774
|
+
const providerMessageClass = classifyZeroToolProviderMessage(lastAssistantMessage);
|
|
775
|
+
if (providerMessageClass && isTransient(providerMessageClass)) {
|
|
776
|
+
const retryAfterMs = "retryAfterMs" in providerMessageClass ? providerMessageClass.retryAfterMs : 15_000;
|
|
777
|
+
await pauseAutoForProviderError(
|
|
778
|
+
ctx.ui,
|
|
779
|
+
` for ${unitType} ${unitId}`,
|
|
780
|
+
() => deps.pauseAuto(ctx, pi),
|
|
781
|
+
{
|
|
782
|
+
isRateLimit: providerMessageClass.kind === "rate-limit",
|
|
783
|
+
isTransient: true,
|
|
784
|
+
retryAfterMs,
|
|
785
|
+
resume: () => {
|
|
786
|
+
void resumeAutoAfterProviderDelay(pi, ctx).catch((err) => {
|
|
787
|
+
logWarning("engine", `Provider error auto-resume failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
788
|
+
});
|
|
789
|
+
},
|
|
790
|
+
},
|
|
791
|
+
);
|
|
792
|
+
await emitCancelledUnitEnd(ic, unitType, unitId, unitStartSeq, {
|
|
793
|
+
message: lastAssistantMessage.slice(0, 200),
|
|
794
|
+
category: "provider",
|
|
795
|
+
isTransient: true,
|
|
796
|
+
retryAfterMs,
|
|
797
|
+
});
|
|
798
|
+
return {
|
|
799
|
+
action: "break",
|
|
800
|
+
reason: providerMessageClass.kind === "rate-limit" ? "rate-limit" : "api-timeout",
|
|
801
|
+
};
|
|
802
|
+
}
|
|
803
|
+
if (USER_DRIVEN_DEEP_UNITS.has(unitType) && isAwaitingUserInput(s.lastUnitAgentEndMessages ?? undefined)) {
|
|
804
|
+
debugLog("runUnitPhase", {
|
|
805
|
+
phase: "zero-tool-calls-awaiting-user-input",
|
|
806
|
+
unitType,
|
|
807
|
+
unitId,
|
|
808
|
+
});
|
|
809
|
+
} else {
|
|
810
|
+
const zeroToolKey = `${unitType}/${unitId}`;
|
|
811
|
+
const attempt = (s.zeroToolRetryCount.get(zeroToolKey) ?? 0) + 1;
|
|
812
|
+
debugLog("runUnitPhase", {
|
|
813
|
+
phase: "zero-tool-calls",
|
|
814
|
+
unitType,
|
|
815
|
+
unitId,
|
|
816
|
+
attempt,
|
|
817
|
+
warning: "Unit completed with 0 tool calls — likely context exhaustion, marking as failed",
|
|
818
|
+
});
|
|
819
|
+
if (attempt > MAX_ZERO_TOOL_RETRIES) {
|
|
820
|
+
s.zeroToolRetryCount.delete(zeroToolKey);
|
|
821
|
+
ctx.ui.notify(
|
|
822
|
+
`${unitType} ${unitId} completed with 0 tool calls — context exhaustion, pausing auto-mode after ${MAX_ZERO_TOOL_RETRIES} retry.`,
|
|
823
|
+
"error",
|
|
824
|
+
);
|
|
825
|
+
await deps.pauseAuto(ctx, pi);
|
|
826
|
+
return { action: "break", reason: "zero-tool-calls-exhausted" };
|
|
827
|
+
}
|
|
828
|
+
s.zeroToolRetryCount.set(zeroToolKey, attempt);
|
|
829
|
+
ctx.ui.notify(
|
|
830
|
+
`${unitType} ${unitId} completed with 0 tool calls — context exhaustion, will retry (attempt ${attempt}/${MAX_ZERO_TOOL_RETRIES})`,
|
|
831
|
+
"warning",
|
|
832
|
+
);
|
|
833
|
+
return {
|
|
834
|
+
action: "retry",
|
|
835
|
+
reason: "zero-tool-calls",
|
|
836
|
+
data: {
|
|
837
|
+
unitStartedAt: _resolveCurrentUnitStartedAtForTest(s.currentUnit),
|
|
838
|
+
requestDispatchedAt: unitResult.requestDispatchedAt,
|
|
839
|
+
},
|
|
840
|
+
};
|
|
841
|
+
}
|
|
842
|
+
}
|
|
843
|
+
}
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
const skipArtifactVerification = unitType.startsWith("hook/") || unitType === "custom-step";
|
|
847
|
+
const artifactVerified =
|
|
848
|
+
skipArtifactVerification ||
|
|
849
|
+
verifyExpectedArtifact(unitType, unitId, s.basePath);
|
|
850
|
+
if (s.currentUnitRouting) {
|
|
851
|
+
deps.recordOutcome(
|
|
852
|
+
unitType,
|
|
853
|
+
s.currentUnitRouting.tier as "light" | "standard" | "heavy",
|
|
854
|
+
artifactVerified,
|
|
855
|
+
);
|
|
856
|
+
}
|
|
857
|
+
if (artifactVerified) {
|
|
858
|
+
s.unitDispatchCount.delete(dispatchKey);
|
|
859
|
+
s.unitRecoveryCount.delete(`${unitType}/${unitId}`);
|
|
860
|
+
s.zeroToolRetryCount.delete(dispatchKey);
|
|
861
|
+
}
|
|
862
|
+
|
|
863
|
+
// Write phase handoff anchor after successful research/planning completion
|
|
864
|
+
const anchorPhases = new Set(["research-milestone", "research-slice", "plan-milestone", "plan-slice"]);
|
|
865
|
+
if (artifactVerified && mid && anchorPhases.has(unitType)) {
|
|
866
|
+
try {
|
|
867
|
+
const { writePhaseAnchor } = await import("../phase-anchor.js");
|
|
868
|
+
writePhaseAnchor(s.basePath, mid, {
|
|
869
|
+
phase: unitType,
|
|
870
|
+
milestoneId: mid,
|
|
871
|
+
generatedAt: new Date().toISOString(),
|
|
872
|
+
intent: `Completed ${unitType} for ${unitId}`,
|
|
873
|
+
decisions: [],
|
|
874
|
+
blockers: [],
|
|
875
|
+
nextSteps: [],
|
|
876
|
+
});
|
|
877
|
+
} catch (err) { /* non-fatal — anchor is advisory */
|
|
878
|
+
logWarning("engine", `phase anchor failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
879
|
+
}
|
|
880
|
+
}
|
|
881
|
+
|
|
882
|
+
const unitEndStatus =
|
|
883
|
+
!artifactVerified && unitResult.status === "completed"
|
|
884
|
+
? "no-artifact"
|
|
885
|
+
: unitResult.status;
|
|
886
|
+
deps.emitJournalEvent({ ts: new Date().toISOString(), flowId: ic.flowId, seq: ic.nextSeq(), eventType: "unit-end", data: { unitType, unitId, status: unitEndStatus, artifactVerified, ...(unitResult.errorContext ? { errorContext: unitResult.errorContext } : {}) }, causedBy: { flowId: ic.flowId, seq: unitStartSeq } });
|
|
887
|
+
|
|
888
|
+
// ── Safety harness: checkpoint cleanup or rollback ──
|
|
889
|
+
if (s.checkpointSha) {
|
|
890
|
+
if (unitResult.status === "error" && safetyConfig.auto_rollback) {
|
|
891
|
+
const rolled = rollbackToCheckpoint(s.basePath, unitId, s.checkpointSha);
|
|
892
|
+
if (rolled) {
|
|
893
|
+
ctx.ui.notify(`Rolled back to pre-unit checkpoint for ${unitId}`, "info");
|
|
894
|
+
debugLog("runUnitPhase", { phase: "checkpoint-rollback", unitId });
|
|
895
|
+
}
|
|
896
|
+
} else if (unitResult.status === "error") {
|
|
897
|
+
ctx.ui.notify(
|
|
898
|
+
`Unit ${unitId} failed. Pre-unit checkpoint available at ${s.checkpointSha.slice(0, 8)}`,
|
|
899
|
+
"warning",
|
|
900
|
+
);
|
|
901
|
+
} else {
|
|
902
|
+
// Success — clean up checkpoint ref
|
|
903
|
+
cleanupCheckpoint(s.basePath, unitId);
|
|
904
|
+
debugLog("runUnitPhase", { phase: "checkpoint-cleaned", unitId });
|
|
905
|
+
}
|
|
906
|
+
s.checkpointSha = null;
|
|
907
|
+
}
|
|
908
|
+
|
|
909
|
+
return { action: "next", data: { unitStartedAt: _resolveCurrentUnitStartedAtForTest(s.currentUnit), requestDispatchedAt: unitResult.requestDispatchedAt } };
|
|
910
|
+
}
|