gsd-pi 2.80.0-dev.42bd34838 → 2.80.0-dev.488219eb6
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/claude-cli-check.d.ts +30 -0
- package/dist/claude-cli-check.js +18 -7
- package/dist/cli.js +0 -19
- package/dist/headless-query.d.ts +10 -0
- package/dist/headless-query.js +6 -4
- package/dist/loader-entrypoint.d.ts +8 -0
- package/dist/loader-entrypoint.js +27 -0
- package/dist/loader.js +2 -11
- package/dist/mcp-server.d.ts +1 -0
- package/dist/mcp-server.js +6 -3
- package/dist/resources/.managed-resources-content-hash +1 -1
- package/dist/resources/extensions/claude-code-cli/readiness.js +18 -7
- package/dist/resources/extensions/claude-code-cli/stream-adapter.js +29 -0
- package/dist/resources/extensions/github-sync/sync.js +4 -1
- package/dist/resources/extensions/gsd/auto/loop.js +71 -8
- package/dist/resources/extensions/gsd/auto/phases.js +179 -99
- package/dist/resources/extensions/gsd/auto/resolve.js +12 -0
- package/dist/resources/extensions/gsd/auto/run-unit.js +10 -30
- package/dist/resources/extensions/gsd/auto/session.js +8 -0
- package/dist/resources/extensions/gsd/auto/workflow-dispatch-claim.js +33 -1
- package/dist/resources/extensions/gsd/auto/workflow-worker-heartbeat.js +9 -1
- package/dist/resources/extensions/gsd/auto-direct-dispatch.js +5 -32
- package/dist/resources/extensions/gsd/auto-dispatch.js +16 -0
- package/dist/resources/extensions/gsd/auto-post-unit.js +94 -76
- package/dist/resources/extensions/gsd/auto-prompts.js +90 -15
- package/dist/resources/extensions/gsd/auto-start.js +238 -12
- package/dist/resources/extensions/gsd/auto-worktree.js +209 -81
- package/dist/resources/extensions/gsd/auto.js +95 -44
- package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +96 -26
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +44 -37
- package/dist/resources/extensions/gsd/bootstrap/dynamic-tools.js +37 -10
- package/dist/resources/extensions/gsd/bootstrap/exec-tools.js +6 -3
- package/dist/resources/extensions/gsd/bootstrap/journal-tools.js +4 -1
- package/dist/resources/extensions/gsd/bootstrap/memory-tools.js +6 -4
- package/dist/resources/extensions/gsd/bootstrap/query-tools.js +5 -3
- package/dist/resources/extensions/gsd/bootstrap/register-extension.js +1 -1
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +298 -54
- package/dist/resources/extensions/gsd/bootstrap/sanitize-complete-milestone.js +4 -0
- package/dist/resources/extensions/gsd/bootstrap/system-context.js +82 -23
- package/dist/resources/extensions/gsd/clean-root-preflight.js +24 -6
- package/dist/resources/extensions/gsd/commands/handlers/ops.js +2 -2
- package/dist/resources/extensions/gsd/commands-config.js +1 -1
- package/dist/resources/extensions/gsd/commands-eval-review.js +2 -2
- package/dist/resources/extensions/gsd/commands-handlers.js +23 -9
- package/dist/resources/extensions/gsd/dashboard-overlay.js +1 -1
- package/dist/resources/extensions/gsd/db/unit-dispatches.js +53 -0
- package/dist/resources/extensions/gsd/ecosystem/gsd-extension-api.js +2 -0
- package/dist/resources/extensions/gsd/git-service.js +37 -1
- package/dist/resources/extensions/gsd/guided-flow.js +61 -32
- package/dist/resources/extensions/gsd/init-wizard.js +4 -1
- package/dist/resources/extensions/gsd/native-git-bridge.js +32 -8
- package/dist/resources/extensions/gsd/orphan-stash-audit.js +101 -0
- package/dist/resources/extensions/gsd/parallel-orchestrator.js +13 -3
- package/dist/resources/extensions/gsd/pre-execution-checks.js +22 -0
- package/dist/resources/extensions/gsd/prompts/complete-milestone.md +8 -4
- package/dist/resources/extensions/gsd/prompts/complete-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/execute-task.md +4 -2
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/replan-slice.md +2 -2
- package/dist/resources/extensions/gsd/slice-cadence.js +45 -2
- package/dist/resources/extensions/gsd/slice-parallel-orchestrator.js +15 -9
- package/dist/resources/extensions/gsd/tools/complete-milestone.js +6 -7
- package/dist/resources/extensions/gsd/tools/complete-task.js +1 -1
- package/dist/resources/extensions/gsd/workflow-protocol.js +131 -0
- package/dist/resources/extensions/gsd/worktree-resolver.js +57 -5
- package/dist/resources/skills/web-quality-audit/scripts/analyze.sh +0 -0
- package/dist/tsconfig.extensions.tsbuildinfo +1 -1
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +11 -11
- 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 +2 -2
- package/dist/web/standalone/.next/required-server-files.json +1 -1
- package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +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/page_client-reference-manifest.js +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/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +2 -2
- package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
- package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +2 -2
- 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/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +11 -11
- 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/middleware.js +3 -3
- 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/8359.e059d86b255fce1c.js +10 -0
- package/dist/web/standalone/.next/static/chunks/app/{page-fab3ebb85b006001.js → page-752f1e2ebdaa3e45.js} +1 -1
- package/dist/web/standalone/.next/static/chunks/{webpack-0481f1221120a7c6.js → webpack-de742b64187e13fe.js} +1 -1
- package/dist/web/standalone/server.js +1 -1
- package/dist/welcome-screen.d.ts +2 -0
- package/dist/welcome-screen.js +9 -7
- package/package.json +1 -1
- package/packages/pi-agent-core/dist/agent-loop.d.ts.map +1 -1
- package/packages/pi-agent-core/dist/agent-loop.js +4 -1
- package/packages/pi-agent-core/dist/agent-loop.js.map +1 -1
- package/packages/pi-agent-core/dist/agent.d.ts +5 -0
- package/packages/pi-agent-core/dist/agent.d.ts.map +1 -1
- package/packages/pi-agent-core/dist/agent.js +2 -0
- package/packages/pi-agent-core/dist/agent.js.map +1 -1
- package/packages/pi-agent-core/dist/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 +2 -0
- package/packages/pi-agent-core/dist/index.js.map +1 -1
- package/packages/pi-agent-core/dist/token-audit.d.ts +47 -0
- package/packages/pi-agent-core/dist/token-audit.d.ts.map +1 -0
- package/packages/pi-agent-core/dist/token-audit.js +221 -0
- package/packages/pi-agent-core/dist/token-audit.js.map +1 -0
- package/packages/pi-agent-core/dist/types.d.ts +9 -0
- package/packages/pi-agent-core/dist/types.d.ts.map +1 -1
- package/packages/pi-agent-core/dist/types.js.map +1 -1
- package/packages/pi-agent-core/src/agent-loop.test.ts +128 -0
- package/packages/pi-agent-core/src/agent-loop.ts +4 -1
- package/packages/pi-agent-core/src/agent.ts +8 -0
- package/packages/pi-agent-core/src/index.ts +2 -0
- package/packages/pi-agent-core/src/token-audit.test.ts +189 -0
- package/packages/pi-agent-core/src/token-audit.ts +287 -0
- package/packages/pi-agent-core/src/types.ts +14 -0
- package/packages/pi-agent-core/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-ai/dist/providers/anthropic-auth.test.js +35 -13
- package/packages/pi-ai/dist/providers/anthropic-auth.test.js.map +1 -1
- package/packages/pi-ai/dist/providers/anthropic-bearer-auth.test.js +21 -11
- package/packages/pi-ai/dist/providers/anthropic-bearer-auth.test.js.map +1 -1
- package/packages/pi-ai/dist/providers/anthropic.d.ts +7 -0
- package/packages/pi-ai/dist/providers/anthropic.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/anthropic.js +9 -7
- package/packages/pi-ai/dist/providers/anthropic.js.map +1 -1
- package/packages/pi-ai/dist/providers/minimax-tool-name.test.js +23 -14
- package/packages/pi-ai/dist/providers/minimax-tool-name.test.js.map +1 -1
- package/packages/pi-ai/dist/utils/oauth/github-copilot.test.js +48 -21
- package/packages/pi-ai/dist/utils/oauth/github-copilot.test.js.map +1 -1
- package/packages/pi-ai/dist/utils/oauth/google-antigravity.test.js +22 -21
- package/packages/pi-ai/dist/utils/oauth/google-antigravity.test.js.map +1 -1
- package/packages/pi-ai/dist/utils/oauth/google-gemini-cli.test.js +22 -21
- package/packages/pi-ai/dist/utils/oauth/google-gemini-cli.test.js.map +1 -1
- package/packages/pi-ai/src/providers/anthropic-auth.test.ts +39 -25
- package/packages/pi-ai/src/providers/anthropic-bearer-auth.test.ts +26 -22
- package/packages/pi-ai/src/providers/anthropic.ts +22 -9
- package/packages/pi-ai/src/providers/minimax-tool-name.test.ts +34 -21
- package/packages/pi-ai/src/utils/oauth/github-copilot.test.ts +56 -22
- package/packages/pi-ai/src/utils/oauth/google-antigravity.test.ts +24 -28
- package/packages/pi-ai/src/utils/oauth/google-gemini-cli.test.ts +24 -28
- package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session-tool-refresh.test.js +18 -0
- package/packages/pi-coding-agent/dist/core/agent-session-tool-refresh.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session.d.ts +12 -0
- package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session.js +36 -7
- package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js +3 -1
- package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/loader.js +8 -0
- package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/runner.js +3 -6
- package/packages/pi-coding-agent/dist/core/extensions/runner.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/runner.test.js +3 -3
- package/packages/pi-coding-agent/dist/core/extensions/runner.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/types.d.ts +34 -3
- package/packages/pi-coding-agent/dist/core/extensions/types.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/types.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/hooks-runner.test.js +2 -0
- package/packages/pi-coding-agent/dist/core/hooks-runner.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/sdk-tool-filter.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/sdk-tool-filter.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/sdk-tool-filter.test.js +46 -0
- package/packages/pi-coding-agent/dist/core/sdk-tool-filter.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/sdk.d.ts +10 -2
- package/packages/pi-coding-agent/dist/core/sdk.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/sdk.js +74 -2
- package/packages/pi-coding-agent/dist/core/sdk.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/skill-tool.test.js +22 -0
- package/packages/pi-coding-agent/dist/core/skill-tool.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/system-prompt.d.ts +6 -7
- package/packages/pi-coding-agent/dist/core/system-prompt.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/system-prompt.js +2 -3
- package/packages/pi-coding-agent/dist/core/system-prompt.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/bash-spawn-windows.test.js +22 -56
- package/packages/pi-coding-agent/dist/core/tools/bash-spawn-windows.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/bash.d.ts +1 -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 +3 -1
- package/packages/pi-coding-agent/dist/core/tools/bash.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/edit.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/tools/edit.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/edit.js +12 -1
- package/packages/pi-coding-agent/dist/core/tools/edit.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/find.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/tools/find.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/find.js +14 -6
- package/packages/pi-coding-agent/dist/core/tools/find.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/grep.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/tools/grep.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/grep.js +12 -3
- package/packages/pi-coding-agent/dist/core/tools/grep.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/hashline-read.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/tools/hashline-read.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/hashline-read.js +3 -1
- package/packages/pi-coding-agent/dist/core/tools/hashline-read.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/index.d.ts +2 -1
- package/packages/pi-coding-agent/dist/core/tools/index.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/index.js +1 -0
- package/packages/pi-coding-agent/dist/core/tools/index.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/ls.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/tools/ls.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/ls.js +10 -3
- package/packages/pi-coding-agent/dist/core/tools/ls.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/read.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/tools/read.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/read.js +3 -1
- package/packages/pi-coding-agent/dist/core/tools/read.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/spawn-shell-windows.test.js +7 -62
- package/packages/pi-coding-agent/dist/core/tools/spawn-shell-windows.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/tool-target-metadata.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/tools/tool-target-metadata.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/tools/tool-target-metadata.test.js +115 -0
- package/packages/pi-coding-agent/dist/core/tools/tool-target-metadata.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/tools/tool-target.d.ts +19 -0
- package/packages/pi-coding-agent/dist/core/tools/tool-target.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/tools/tool-target.js +20 -0
- package/packages/pi-coding-agent/dist/core/tools/tool-target.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/tools/write.d.ts +4 -0
- package/packages/pi-coding-agent/dist/core/tools/write.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/write.js +9 -1
- package/packages/pi-coding-agent/dist/core/tools/write.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js +89 -2
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-card-cleanup-and-success-runtime.test.js +25 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-card-cleanup-and-success-runtime.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts +5 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +153 -8
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +18 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.test.js +23 -5
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts +2 -0
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +19 -0
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/packages/pi-coding-agent/dist/resources/extensions/memory/storage-safety-guard.test.js +23 -5
- package/packages/pi-coding-agent/dist/resources/extensions/memory/storage-safety-guard.test.js.map +1 -1
- package/packages/pi-coding-agent/src/core/agent-session-tool-refresh.test.ts +25 -0
- package/packages/pi-coding-agent/src/core/agent-session.ts +40 -7
- package/packages/pi-coding-agent/src/core/chat-controller-ordering.test.ts +3 -1
- package/packages/pi-coding-agent/src/core/extensions/loader.ts +10 -0
- package/packages/pi-coding-agent/src/core/extensions/runner.test.ts +3 -3
- package/packages/pi-coding-agent/src/core/extensions/runner.ts +5 -5
- package/packages/pi-coding-agent/src/core/extensions/types.ts +37 -2
- package/packages/pi-coding-agent/src/core/hooks-runner.test.ts +2 -0
- package/packages/pi-coding-agent/src/core/sdk-tool-filter.test.ts +60 -0
- package/packages/pi-coding-agent/src/core/sdk.ts +85 -3
- package/packages/pi-coding-agent/src/core/skill-tool.test.ts +28 -0
- package/packages/pi-coding-agent/src/core/system-prompt.ts +8 -10
- package/packages/pi-coding-agent/src/core/tools/bash-spawn-windows.test.ts +22 -66
- package/packages/pi-coding-agent/src/core/tools/bash.ts +4 -1
- package/packages/pi-coding-agent/src/core/tools/edit.ts +13 -1
- package/packages/pi-coding-agent/src/core/tools/find.ts +15 -6
- package/packages/pi-coding-agent/src/core/tools/grep.ts +13 -3
- package/packages/pi-coding-agent/src/core/tools/hashline-read.ts +4 -1
- package/packages/pi-coding-agent/src/core/tools/index.ts +8 -0
- package/packages/pi-coding-agent/src/core/tools/ls.ts +11 -3
- package/packages/pi-coding-agent/src/core/tools/read.ts +4 -1
- package/packages/pi-coding-agent/src/core/tools/spawn-shell-windows.test.ts +11 -72
- package/packages/pi-coding-agent/src/core/tools/tool-target-metadata.test.ts +127 -0
- package/packages/pi-coding-agent/src/core/tools/tool-target.ts +48 -0
- package/packages/pi-coding-agent/src/core/tools/write.ts +14 -2
- package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/tool-execution.test.ts +119 -2
- package/packages/pi-coding-agent/src/modes/interactive/components/tool-card-cleanup-and-success-runtime.test.ts +31 -1
- package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +177 -8
- package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.test.ts +24 -5
- package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +17 -1
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +21 -0
- package/packages/pi-coding-agent/src/resources/extensions/memory/storage-safety-guard.test.ts +25 -8
- package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
- package/src/resources/extensions/claude-code-cli/readiness.ts +25 -7
- package/src/resources/extensions/claude-code-cli/stream-adapter.ts +30 -0
- package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +26 -0
- package/src/resources/extensions/github-sync/sync.ts +8 -1
- package/src/resources/extensions/github-sync/tests/sync-source.test.ts +6 -18
- package/src/resources/extensions/gsd/auto/loop-deps.ts +2 -2
- package/src/resources/extensions/gsd/auto/loop.ts +84 -8
- package/src/resources/extensions/gsd/auto/phases.ts +258 -159
- package/src/resources/extensions/gsd/auto/resolve.ts +19 -0
- package/src/resources/extensions/gsd/auto/run-unit.ts +10 -29
- package/src/resources/extensions/gsd/auto/session.ts +8 -0
- package/src/resources/extensions/gsd/auto/workflow-dispatch-claim.ts +63 -1
- package/src/resources/extensions/gsd/auto/workflow-worker-heartbeat.ts +14 -1
- package/src/resources/extensions/gsd/auto-direct-dispatch.ts +8 -34
- package/src/resources/extensions/gsd/auto-dispatch.ts +16 -0
- package/src/resources/extensions/gsd/auto-post-unit.ts +107 -78
- package/src/resources/extensions/gsd/auto-prompts.ts +95 -14
- package/src/resources/extensions/gsd/auto-start.ts +286 -15
- package/src/resources/extensions/gsd/auto-worktree.ts +241 -72
- package/src/resources/extensions/gsd/auto.ts +132 -40
- package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +116 -24
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +45 -37
- package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +36 -10
- package/src/resources/extensions/gsd/bootstrap/exec-tools.ts +8 -3
- package/src/resources/extensions/gsd/bootstrap/journal-tools.ts +5 -1
- package/src/resources/extensions/gsd/bootstrap/memory-tools.ts +7 -4
- package/src/resources/extensions/gsd/bootstrap/query-tools.ts +6 -3
- package/src/resources/extensions/gsd/bootstrap/register-extension.ts +1 -1
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +347 -54
- package/src/resources/extensions/gsd/bootstrap/sanitize-complete-milestone.ts +4 -0
- package/src/resources/extensions/gsd/bootstrap/system-context.ts +90 -22
- package/src/resources/extensions/gsd/clean-root-preflight.ts +32 -7
- package/src/resources/extensions/gsd/commands/handlers/ops.ts +4 -2
- package/src/resources/extensions/gsd/commands-config.ts +1 -1
- package/src/resources/extensions/gsd/commands-eval-review.ts +2 -2
- package/src/resources/extensions/gsd/commands-handlers.ts +34 -15
- package/src/resources/extensions/gsd/dashboard-overlay.ts +1 -1
- package/src/resources/extensions/gsd/db/unit-dispatches.ts +66 -0
- package/src/resources/extensions/gsd/ecosystem/gsd-extension-api.ts +3 -0
- package/src/resources/extensions/gsd/git-service.ts +41 -2
- package/src/resources/extensions/gsd/guided-flow.ts +71 -39
- package/src/resources/extensions/gsd/init-wizard.ts +5 -1
- package/src/resources/extensions/gsd/native-git-bridge.ts +39 -6
- package/src/resources/extensions/gsd/orphan-stash-audit.ts +117 -0
- package/src/resources/extensions/gsd/parallel-orchestrator.ts +13 -3
- package/src/resources/extensions/gsd/pre-execution-checks.ts +23 -0
- package/src/resources/extensions/gsd/prompts/complete-milestone.md +8 -4
- package/src/resources/extensions/gsd/prompts/complete-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/execute-task.md +4 -2
- package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/replan-slice.md +2 -2
- package/src/resources/extensions/gsd/slice-cadence.ts +49 -2
- package/src/resources/extensions/gsd/slice-parallel-orchestrator.ts +23 -9
- package/src/resources/extensions/gsd/tests/agent-end-retry.test.ts +59 -89
- package/src/resources/extensions/gsd/tests/artifact-retry-cap.test.ts +47 -172
- package/src/resources/extensions/gsd/tests/artifacts-table-preserved-on-cache-invalidate.test.ts +0 -35
- package/src/resources/extensions/gsd/tests/auto-dashboard.test.ts +35 -9
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +361 -10
- package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +80 -59
- package/src/resources/extensions/gsd/tests/auto-paused-session-validation.test.ts +3 -47
- package/src/resources/extensions/gsd/tests/auto-paused-ui-cleanup.test.ts +76 -18
- package/src/resources/extensions/gsd/tests/auto-phases-lifecycle.test.ts +106 -0
- package/src/resources/extensions/gsd/tests/auto-pr-bugs.test.ts +54 -95
- package/src/resources/extensions/gsd/tests/auto-project-root-env.test.ts +67 -26
- package/src/resources/extensions/gsd/tests/auto-remediate-slice-status.test.ts +32 -30
- package/src/resources/extensions/gsd/tests/auto-start-bootstrap-await-3420.test.ts +32 -128
- package/src/resources/extensions/gsd/tests/auto-start-clean-runtime-db-gated.test.ts +20 -54
- package/src/resources/extensions/gsd/tests/auto-start-cold-db-bootstrap.test.ts +20 -30
- package/src/resources/extensions/gsd/tests/auto-start-index-lock.test.ts +17 -29
- package/src/resources/extensions/gsd/tests/auto-start-orphan-bootstrap.test.ts +138 -0
- package/src/resources/extensions/gsd/tests/auto-start-time-persistence.test.ts +21 -39
- package/src/resources/extensions/gsd/tests/auto-start-worktree-db-path.test.ts +15 -24
- package/src/resources/extensions/gsd/tests/auto-thinking-restore.test.ts +44 -29
- package/src/resources/extensions/gsd/tests/auto-warning-noise-regression.test.ts +39 -51
- package/src/resources/extensions/gsd/tests/auto-wrapup-inflight-guard.test.ts +159 -213
- package/src/resources/extensions/gsd/tests/bootstrap-derive-state-db-open.test.ts +15 -32
- package/src/resources/extensions/gsd/tests/browser-teardown.test.ts +0 -41
- package/src/resources/extensions/gsd/tests/clean-root-preflight.test.ts +15 -6
- package/src/resources/extensions/gsd/tests/clear-stale-autostart.test.ts +34 -27
- package/src/resources/extensions/gsd/tests/cmux.test.ts +51 -53
- package/src/resources/extensions/gsd/tests/cold-resume-db-reopen.test.ts +39 -61
- package/src/resources/extensions/gsd/tests/commands-config.test.ts +26 -19
- package/src/resources/extensions/gsd/tests/complete-milestone-excerpt.test.ts +31 -0
- package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +140 -0
- package/src/resources/extensions/gsd/tests/complete-slice-composer.test.ts +3 -2
- package/src/resources/extensions/gsd/tests/complete-task-normalize-lists.test.ts +29 -33
- package/src/resources/extensions/gsd/tests/completed-units-metrics-sync.test.ts +45 -108
- package/src/resources/extensions/gsd/tests/context-store.test.ts +7 -1
- package/src/resources/extensions/gsd/tests/crash-handler-secondary.test.ts +35 -31
- package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +5 -1
- package/src/resources/extensions/gsd/tests/cwd-fallback-hardening.test.ts +138 -0
- package/src/resources/extensions/gsd/tests/dashboard-custom-engine.test.ts +4 -68
- package/src/resources/extensions/gsd/tests/deep-project-auto-loop.test.ts +4 -9
- package/src/resources/extensions/gsd/tests/deferred-milestone-dir-4996.test.ts +14 -65
- package/src/resources/extensions/gsd/tests/discuss-tool-scoping.test.ts +44 -37
- package/src/resources/extensions/gsd/tests/dispatch-complete-milestone-guard.test.ts +58 -40
- package/src/resources/extensions/gsd/tests/dispatch-guard-closed-status.test.ts +25 -15
- package/src/resources/extensions/gsd/tests/dispatcher-stuck-planning.test.ts +35 -17
- package/src/resources/extensions/gsd/tests/error-success-mask.test.ts +16 -21
- package/src/resources/extensions/gsd/tests/est-annotation-timeout.test.ts +15 -82
- package/src/resources/extensions/gsd/tests/execute-task-rendering.test.ts +5 -2
- package/src/resources/extensions/gsd/tests/fast-forward-reused-milestone-branch.test.ts +219 -0
- package/src/resources/extensions/gsd/tests/finalize-survivor-branch.test.ts +132 -0
- package/src/resources/extensions/gsd/tests/flat-rate-routing-guard.test.ts +2 -20
- package/src/resources/extensions/gsd/tests/frontmatter-parse-noise.test.ts +18 -26
- package/src/resources/extensions/gsd/tests/init-skip-git.test.ts +9 -12
- package/src/resources/extensions/gsd/tests/integration/auto-worktree-milestone-merge.test.ts +40 -0
- package/src/resources/extensions/gsd/tests/integration/commands-eval-review.integration.test.ts +4 -2
- package/src/resources/extensions/gsd/tests/integration/git-locale.test.ts +31 -20
- package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +12 -0
- package/src/resources/extensions/gsd/tests/integration/milestone-transition-worktree.test.ts +0 -47
- package/src/resources/extensions/gsd/tests/interactive-routing-bypass.test.ts +60 -202
- package/src/resources/extensions/gsd/tests/isolation-none-branch-guard.test.ts +13 -56
- package/src/resources/extensions/gsd/tests/journal-integration.test.ts +5 -1
- package/src/resources/extensions/gsd/tests/journal-query-tool.test.ts +32 -0
- package/src/resources/extensions/gsd/tests/knowledge.test.ts +47 -0
- package/src/resources/extensions/gsd/tests/lazy-pi-tui-import.test.ts +44 -6
- package/src/resources/extensions/gsd/tests/memory-pressure-stuck-state.test.ts +21 -35
- package/src/resources/extensions/gsd/tests/merge-conflict-stops-loop.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/milestone-merge-stash-restore.test.ts +242 -0
- package/src/resources/extensions/gsd/tests/milestone-transition-state-rebuild.test.ts +79 -98
- package/src/resources/extensions/gsd/tests/model-unittype-mapping.test.ts +70 -278
- package/src/resources/extensions/gsd/tests/native-git-bridge-exec-fallback.test.ts +34 -2
- package/src/resources/extensions/gsd/tests/needs-remediation-revalidation.test.ts +37 -30
- package/src/resources/extensions/gsd/tests/note-captures-executed.test.ts +32 -28
- package/src/resources/extensions/gsd/tests/originalbase-path-comparison.test.ts +3 -0
- package/src/resources/extensions/gsd/tests/orphan-merge-bootstrap.test.ts +133 -0
- package/src/resources/extensions/gsd/tests/orphan-stash-audit.test.ts +201 -0
- package/src/resources/extensions/gsd/tests/parallel-orchestrator-fast-forward.test.ts +113 -0
- package/src/resources/extensions/gsd/tests/phantom-ghost-detection.test.ts +24 -37
- package/src/resources/extensions/gsd/tests/phantom-milestone-default-queued.test.ts +9 -24
- package/src/resources/extensions/gsd/tests/phases-merge-error-stops-auto.test.ts +91 -75
- package/src/resources/extensions/gsd/tests/post-unit-state-rebuild.test.ts +36 -22
- package/src/resources/extensions/gsd/tests/pre-exec-backtick-strip.test.ts +36 -30
- package/src/resources/extensions/gsd/tests/pre-execution-checks.test.ts +45 -5
- package/src/resources/extensions/gsd/tests/pre-execution-pause-wiring.test.ts +74 -4
- package/src/resources/extensions/gsd/tests/preferences-worktree-sync.test.ts +20 -22
- package/src/resources/extensions/gsd/tests/prefs-wizard-coverage.test.ts +130 -32
- package/src/resources/extensions/gsd/tests/project-root-cwd-crash.test.ts +18 -36
- package/src/resources/extensions/gsd/tests/projection-no-plan-overwrite.test.ts +35 -73
- package/src/resources/extensions/gsd/tests/prompt-budget-enforcement.test.ts +76 -138
- package/src/resources/extensions/gsd/tests/prompt-duplication-cuts.test.ts +230 -0
- package/src/resources/extensions/gsd/tests/prompt-step-ordering.test.ts +70 -125
- package/src/resources/extensions/gsd/tests/provider-errors.test.ts +59 -161
- package/src/resources/extensions/gsd/tests/query-tools-db-open.test.ts +33 -29
- package/src/resources/extensions/gsd/tests/queue-auto-guard.test.ts +22 -196
- package/src/resources/extensions/gsd/tests/quick-auto-guard.test.ts +23 -93
- package/src/resources/extensions/gsd/tests/quick-turn-end-cleanup.test.ts +50 -79
- package/src/resources/extensions/gsd/tests/reassess-default-optin.test.ts +27 -13
- package/src/resources/extensions/gsd/tests/remote-questions.test.ts +151 -251
- package/src/resources/extensions/gsd/tests/resource-loader-import-path.test.ts +41 -29
- package/src/resources/extensions/gsd/tests/restore-tools-after-discuss.test.ts +58 -69
- package/src/resources/extensions/gsd/tests/resume-dispatch-worktree.test.ts +32 -164
- package/src/resources/extensions/gsd/tests/run-uat-replay-cap.test.ts +57 -41
- package/src/resources/extensions/gsd/tests/select-resumable-milestone.test.ts +96 -0
- package/src/resources/extensions/gsd/tests/session-model-override.test.ts +14 -9
- package/src/resources/extensions/gsd/tests/session-start-footer.test.ts +77 -0
- package/src/resources/extensions/gsd/tests/session-switch-abort-misclassification.test.ts +166 -0
- package/src/resources/extensions/gsd/tests/show-config-command.test.ts +44 -42
- package/src/resources/extensions/gsd/tests/skip-slice-state-rebuild.test.ts +56 -24
- package/src/resources/extensions/gsd/tests/skipped-validation-db-atomicity.test.ts +51 -11
- package/src/resources/extensions/gsd/tests/slice-cadence.test.ts +23 -0
- package/src/resources/extensions/gsd/tests/slice-context-injection.test.ts +66 -50
- package/src/resources/extensions/gsd/tests/slice-parallel-orchestrator.test.ts +68 -107
- package/src/resources/extensions/gsd/tests/slice-sequence-insert.test.ts +115 -42
- package/src/resources/extensions/gsd/tests/smart-entry-complete.test.ts +21 -97
- package/src/resources/extensions/gsd/tests/smart-entry-draft.test.ts +25 -116
- package/src/resources/extensions/gsd/tests/sqlite-unavailable-gate.test.ts +21 -57
- package/src/resources/extensions/gsd/tests/stale-dirlistcache-4648.test.ts +29 -76
- package/src/resources/extensions/gsd/tests/stale-lockfile-recovery.test.ts +33 -24
- package/src/resources/extensions/gsd/tests/stale-slice-rows.test.ts +39 -30
- package/src/resources/extensions/gsd/tests/state-corruption-2945.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/status-db-open.test.ts +33 -47
- package/src/resources/extensions/gsd/tests/stop-auto-merge-back.test.ts +48 -46
- package/src/resources/extensions/gsd/tests/stop-auto-race-null-unit.test.ts +14 -102
- package/src/resources/extensions/gsd/tests/subagent-model-dispatch.test.ts +78 -232
- package/src/resources/extensions/gsd/tests/sync-worktree-skip-current.test.ts +32 -35
- package/src/resources/extensions/gsd/tests/system-context-memory.test.ts +112 -0
- package/src/resources/extensions/gsd/tests/system-context-message-routing.test.ts +7 -9
- package/src/resources/extensions/gsd/tests/token-profile.test.ts +84 -309
- package/src/resources/extensions/gsd/tests/token-tool-gating.test.ts +291 -0
- package/src/resources/extensions/gsd/tests/triage-dispatch.test.ts +134 -341
- package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +8 -25
- package/src/resources/extensions/gsd/tests/unit-dispatches.test.ts +50 -1
- package/src/resources/extensions/gsd/tests/unstructured-continue-context-injection.test.ts +5 -99
- package/src/resources/extensions/gsd/tests/uok-plan-v2-wiring.test.ts +43 -36
- package/src/resources/extensions/gsd/tests/visualizer-data.test.ts +84 -444
- package/src/resources/extensions/gsd/tests/workflow-dispatch-claim.test.ts +142 -0
- package/src/resources/extensions/gsd/tests/workflow-logger-wiring.test.ts +44 -189
- package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +2 -57
- package/src/resources/extensions/gsd/tests/workflow-protocol-excerpt.test.ts +99 -0
- package/src/resources/extensions/gsd/tests/workflow-worker-heartbeat.test.ts +32 -1
- package/src/resources/extensions/gsd/tests/worktree-db-same-file.test.ts +21 -44
- package/src/resources/extensions/gsd/tests/worktree-expected-warnings.test.ts +27 -26
- package/src/resources/extensions/gsd/tests/worktree-health-dispatch.test.ts +14 -13
- package/src/resources/extensions/gsd/tests/worktree-journal-events.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/worktree-main-branch.test.ts +20 -18
- package/src/resources/extensions/gsd/tests/worktree-path-injection.test.ts +22 -19
- package/src/resources/extensions/gsd/tests/worktree-project-root-degrade.test.ts +66 -0
- package/src/resources/extensions/gsd/tests/worktree-resolver.test.ts +140 -3
- package/src/resources/extensions/gsd/tests/zero-slice-roadmap-guided.test.ts +19 -13
- package/src/resources/extensions/gsd/tools/complete-milestone.ts +14 -15
- package/src/resources/extensions/gsd/tools/complete-task.ts +1 -1
- package/src/resources/extensions/gsd/workflow-protocol.ts +160 -0
- package/src/resources/extensions/gsd/worktree-resolver.ts +83 -5
- package/src/resources/skills/create-gsd-extension/templates/templates.test.ts +86 -40
- package/src/resources/skills/web-quality-audit/scripts/analyze.sh +0 -0
- package/dist/web/standalone/.next/static/chunks/8336.631939fb583761fa.js +0 -10
- /package/dist/web/standalone/.next/static/{tht0ltP8EIjsohPOA_WZf → G68KoLv5claox_Dyd4pZn}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{tht0ltP8EIjsohPOA_WZf → G68KoLv5claox_Dyd4pZn}/_ssgManifest.js +0 -0
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
// Project/App: GSD-2
|
|
2
|
+
// File Purpose: Auto-loop pipeline phases, merge closeout, and finalize handling.
|
|
1
3
|
/**
|
|
2
4
|
* auto/phases.ts — Pipeline phases for the auto-loop.
|
|
3
5
|
*
|
|
@@ -42,6 +44,11 @@ import { getWorkflowTransportSupportError, getRequiredWorkflowToolsForAutoUnit,
|
|
|
42
44
|
function isSamePathLocal(a, b) {
|
|
43
45
|
return normalizeWorktreePathForCompare(a) === normalizeWorktreePathForCompare(b);
|
|
44
46
|
}
|
|
47
|
+
export function shouldDegradeEmptyWorktreeToProjectRoot(worktreeClassification, projectRootClassification) {
|
|
48
|
+
return (worktreeClassification.kind === "greenfield" &&
|
|
49
|
+
projectRootClassification.kind !== "greenfield" &&
|
|
50
|
+
projectRootClassification.kind !== "invalid-repo");
|
|
51
|
+
}
|
|
45
52
|
// ─── Session timeout auto-resume state ────────────────────────────────────────
|
|
46
53
|
let consecutiveSessionTimeouts = 0;
|
|
47
54
|
const MAX_SESSION_TIMEOUT_AUTO_RESUMES = 3;
|
|
@@ -71,9 +78,15 @@ const PLAN_V2_GATE_PHASES = new Set([
|
|
|
71
78
|
"validating-milestone",
|
|
72
79
|
"completing-milestone",
|
|
73
80
|
]);
|
|
74
|
-
function shouldRunPlanV2Gate(phase) {
|
|
81
|
+
export function shouldRunPlanV2Gate(phase) {
|
|
75
82
|
return PLAN_V2_GATE_PHASES.has(phase);
|
|
76
83
|
}
|
|
84
|
+
export function _shouldProceedWithInvalidRepoClassificationForTest(reason, hasGit) {
|
|
85
|
+
return reason === "missing .git" && hasGit;
|
|
86
|
+
}
|
|
87
|
+
export function _resolveCurrentUnitStartedAtForTest(currentUnit) {
|
|
88
|
+
return currentUnit?.startedAt;
|
|
89
|
+
}
|
|
77
90
|
/**
|
|
78
91
|
* Generate and write an HTML milestone report snapshot.
|
|
79
92
|
* Extracted from the milestone-transition block in autoLoop.
|
|
@@ -129,6 +142,85 @@ async function closeoutAndStop(ctx, pi, s, deps, reason) {
|
|
|
129
142
|
}
|
|
130
143
|
await deps.stopAuto(ctx, pi, reason);
|
|
131
144
|
}
|
|
145
|
+
async function stopOnPostflightRecoveryNeeded(ic, result, milestoneId) {
|
|
146
|
+
if (!result.needsManualRecovery)
|
|
147
|
+
return null;
|
|
148
|
+
const { ctx, pi, deps } = ic;
|
|
149
|
+
const reason = `Post-merge stash restore failed for milestone ${milestoneId}`;
|
|
150
|
+
ctx.ui.notify(`${reason}. Resolve the working tree before resuming auto-mode. ${result.message}`, "error");
|
|
151
|
+
await deps.stopAuto(ctx, pi, reason);
|
|
152
|
+
return { action: "break", reason: "postflight-stash-restore-failed" };
|
|
153
|
+
}
|
|
154
|
+
async function restorePreflightStashOrStop(ic, preflight, milestoneId) {
|
|
155
|
+
if (!preflight.stashPushed)
|
|
156
|
+
return null;
|
|
157
|
+
const { ctx, s, deps } = ic;
|
|
158
|
+
const result = deps.postflightPopStash(s.originalBasePath || s.basePath, milestoneId, preflight.stashMarker, ctx.ui.notify.bind(ctx.ui));
|
|
159
|
+
return stopOnPostflightRecoveryNeeded(ic, result, milestoneId);
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Run a milestone merge surrounded by preflight stash + always-on postflight
|
|
163
|
+
* pop. The previous code popped the stash only after a successful merge, which
|
|
164
|
+
* leaked `gsd-preflight-stash:M00x:*` entries whenever `mergeAndExit` threw —
|
|
165
|
+
* leaving the user's pre-merge working tree silently stashed away after a
|
|
166
|
+
* merge-conflict or other merge error. This helper restores the stash on
|
|
167
|
+
* every exit path, then surfaces the merge or stash failure (in priority
|
|
168
|
+
* order) as the loop's stop reason.
|
|
169
|
+
*
|
|
170
|
+
* Returns a `break` action when auto-mode must stop, or `null` when the merge
|
|
171
|
+
* succeeded and the stash (if any) was restored cleanly.
|
|
172
|
+
*/
|
|
173
|
+
export async function _runMilestoneMergeWithStashRestore(ic, milestoneId) {
|
|
174
|
+
const { ctx, pi, s, deps } = ic;
|
|
175
|
+
const preflight = deps.preflightCleanRoot(s.originalBasePath || s.basePath, milestoneId, ctx.ui.notify.bind(ctx.ui));
|
|
176
|
+
let mergeError = null;
|
|
177
|
+
try {
|
|
178
|
+
deps.resolver.mergeAndExit(milestoneId, ctx.ui);
|
|
179
|
+
s.milestoneMergedInPhases = true;
|
|
180
|
+
}
|
|
181
|
+
catch (mergeErr) {
|
|
182
|
+
mergeError = mergeErr;
|
|
183
|
+
}
|
|
184
|
+
// Always attempt to restore the stashed working tree, even on merge error.
|
|
185
|
+
// postflightPopStash itself does not throw; failures surface via the
|
|
186
|
+
// PostflightResult.needsManualRecovery flag.
|
|
187
|
+
let stashResult = null;
|
|
188
|
+
if (preflight.stashPushed) {
|
|
189
|
+
stashResult = deps.postflightPopStash(s.originalBasePath || s.basePath, milestoneId, preflight.stashMarker, ctx.ui.notify.bind(ctx.ui));
|
|
190
|
+
}
|
|
191
|
+
// Merge failure takes priority over stash recovery — the merge is the
|
|
192
|
+
// authoritative gate. If the stash also needed manual recovery, the user
|
|
193
|
+
// already saw the postflightPopStash notify above.
|
|
194
|
+
if (mergeError) {
|
|
195
|
+
if (mergeError instanceof MergeConflictError) {
|
|
196
|
+
ctx.ui.notify(`Merge conflict: ${mergeError.conflictedFiles.join(", ")}. Resolve conflicts manually and run /gsd auto to resume.`, "error");
|
|
197
|
+
await deps.stopAuto(ctx, pi, `Merge conflict on milestone ${milestoneId}`);
|
|
198
|
+
return { action: "break", reason: "merge-conflict" };
|
|
199
|
+
}
|
|
200
|
+
logError("engine", "Milestone merge failed with non-conflict error", {
|
|
201
|
+
milestone: milestoneId,
|
|
202
|
+
error: String(mergeError),
|
|
203
|
+
});
|
|
204
|
+
ctx.ui.notify(`Merge failed: ${mergeError instanceof Error ? mergeError.message : String(mergeError)}. Resolve and run /gsd auto to resume.`, "error");
|
|
205
|
+
await deps.stopAuto(ctx, pi, `Merge error on milestone ${milestoneId}: ${String(mergeError)}`);
|
|
206
|
+
return { action: "break", reason: "merge-failed" };
|
|
207
|
+
}
|
|
208
|
+
if (stashResult) {
|
|
209
|
+
return stopOnPostflightRecoveryNeeded(ic, stashResult, milestoneId);
|
|
210
|
+
}
|
|
211
|
+
return null;
|
|
212
|
+
}
|
|
213
|
+
export async function _runMilestoneMergeOnceWithStashRestore(ic, milestoneId) {
|
|
214
|
+
if (ic.s.milestoneMergedInPhases) {
|
|
215
|
+
debugLog("autoLoop", {
|
|
216
|
+
phase: "milestone-merge-skip",
|
|
217
|
+
reason: "already-merged-in-phases",
|
|
218
|
+
milestoneId,
|
|
219
|
+
});
|
|
220
|
+
return null;
|
|
221
|
+
}
|
|
222
|
+
return _runMilestoneMergeWithStashRestore(ic, milestoneId);
|
|
223
|
+
}
|
|
132
224
|
async function emitCancelledUnitEnd(ic, unitType, unitId, unitStartSeq, errorContext) {
|
|
133
225
|
ic.deps.emitJournalEvent({
|
|
134
226
|
ts: new Date().toISOString(),
|
|
@@ -470,28 +562,12 @@ export async function runPreDispatch(ic, loopState) {
|
|
|
470
562
|
s.unitLifetimeDispatches.clear();
|
|
471
563
|
loopState.recentUnits.length = 0;
|
|
472
564
|
loopState.stuckRecoveryAttempts = 0;
|
|
473
|
-
// Worktree lifecycle on milestone transition — merge current, enter next
|
|
474
|
-
// #2909: preflight
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
catch (mergeErr) {
|
|
480
|
-
if (mergeErr instanceof MergeConflictError) {
|
|
481
|
-
// Real code conflicts — stop the loop instead of retrying forever (#2330)
|
|
482
|
-
ctx.ui.notify(`Merge conflict: ${mergeErr.conflictedFiles.join(", ")}. Resolve conflicts manually and run /gsd auto to resume.`, "error");
|
|
483
|
-
await deps.stopAuto(ctx, pi, `Merge conflict on milestone ${s.currentMilestoneId}`);
|
|
484
|
-
return { action: "break", reason: "merge-conflict" };
|
|
485
|
-
}
|
|
486
|
-
// Non-conflict merge errors — stop auto to avoid advancing with unmerged work
|
|
487
|
-
logError("engine", "Milestone merge failed with non-conflict error", { milestone: s.currentMilestoneId, error: String(mergeErr) });
|
|
488
|
-
ctx.ui.notify(`Merge failed: ${mergeErr instanceof Error ? mergeErr.message : String(mergeErr)}. Resolve and run /gsd auto to resume.`, "error");
|
|
489
|
-
await deps.stopAuto(ctx, pi, `Merge error on milestone ${s.currentMilestoneId}: ${String(mergeErr)}`);
|
|
490
|
-
return { action: "break", reason: "merge-failed" };
|
|
491
|
-
}
|
|
492
|
-
// #2909: postflight — restore stashed changes after successful merge
|
|
493
|
-
if (preflightTransition.stashPushed) {
|
|
494
|
-
deps.postflightPopStash(s.originalBasePath || s.basePath, s.currentMilestoneId, preflightTransition.stashMarker, ctx.ui.notify.bind(ctx.ui));
|
|
565
|
+
// Worktree lifecycle on milestone transition — merge current, enter next.
|
|
566
|
+
// #2909 / #5538-followup: preflight stash + always-on postflight pop.
|
|
567
|
+
{
|
|
568
|
+
const stop = await _runMilestoneMergeOnceWithStashRestore(ic, s.currentMilestoneId);
|
|
569
|
+
if (stop)
|
|
570
|
+
return stop;
|
|
495
571
|
}
|
|
496
572
|
// PR creation (auto_pr) is handled inside mergeMilestoneToMain (#2302)
|
|
497
573
|
deps.invalidateAllCaches();
|
|
@@ -545,30 +621,12 @@ export async function runPreDispatch(ic, loopState) {
|
|
|
545
621
|
}
|
|
546
622
|
const incomplete = state.registry.filter((m) => m.status !== "complete" && m.status !== "parked");
|
|
547
623
|
if (incomplete.length === 0 && state.registry.length > 0) {
|
|
548
|
-
// All milestones complete — merge milestone branch before stopping
|
|
624
|
+
// All milestones complete — merge milestone branch before stopping.
|
|
549
625
|
if (s.currentMilestoneId) {
|
|
550
|
-
// #2909: preflight
|
|
551
|
-
const
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
// Prevent stopAuto from attempting the same merge (#2645)
|
|
555
|
-
s.milestoneMergedInPhases = true;
|
|
556
|
-
}
|
|
557
|
-
catch (mergeErr) {
|
|
558
|
-
if (mergeErr instanceof MergeConflictError) {
|
|
559
|
-
ctx.ui.notify(`Merge conflict: ${mergeErr.conflictedFiles.join(", ")}. Resolve conflicts manually and run /gsd auto to resume.`, "error");
|
|
560
|
-
await deps.stopAuto(ctx, pi, `Merge conflict on milestone ${s.currentMilestoneId}`);
|
|
561
|
-
return { action: "break", reason: "merge-conflict" };
|
|
562
|
-
}
|
|
563
|
-
logError("engine", "Milestone merge failed with non-conflict error", { milestone: s.currentMilestoneId, error: String(mergeErr) });
|
|
564
|
-
ctx.ui.notify(`Merge failed: ${mergeErr instanceof Error ? mergeErr.message : String(mergeErr)}. Resolve and run /gsd auto to resume.`, "error");
|
|
565
|
-
await deps.stopAuto(ctx, pi, `Merge error on milestone ${s.currentMilestoneId}: ${String(mergeErr)}`);
|
|
566
|
-
return { action: "break", reason: "merge-failed" };
|
|
567
|
-
}
|
|
568
|
-
// #2909: postflight — restore stashed changes after successful merge
|
|
569
|
-
if (preflightAllComplete.stashPushed) {
|
|
570
|
-
deps.postflightPopStash(s.originalBasePath || s.basePath, s.currentMilestoneId, preflightAllComplete.stashMarker, ctx.ui.notify.bind(ctx.ui));
|
|
571
|
-
}
|
|
626
|
+
// #2909 / #5538-followup: preflight stash + always-on postflight pop.
|
|
627
|
+
const stop = await _runMilestoneMergeOnceWithStashRestore(ic, s.currentMilestoneId);
|
|
628
|
+
if (stop)
|
|
629
|
+
return stop;
|
|
572
630
|
// PR creation (auto_pr) is handled inside mergeMilestoneToMain (#2302)
|
|
573
631
|
}
|
|
574
632
|
deps.sendDesktopNotification("GSD", "All milestones complete!", "success", "milestone", basename(s.originalBasePath || s.basePath));
|
|
@@ -631,30 +689,12 @@ export async function runPreDispatch(ic, loopState) {
|
|
|
631
689
|
}
|
|
632
690
|
// Terminal: complete
|
|
633
691
|
if (state.phase === "complete") {
|
|
634
|
-
// Milestone merge on complete (before closeout so branch state is clean)
|
|
692
|
+
// Milestone merge on complete (before closeout so branch state is clean).
|
|
635
693
|
if (s.currentMilestoneId) {
|
|
636
|
-
// #2909: preflight
|
|
637
|
-
const
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
// Prevent stopAuto from attempting the same merge (#2645)
|
|
641
|
-
s.milestoneMergedInPhases = true;
|
|
642
|
-
}
|
|
643
|
-
catch (mergeErr) {
|
|
644
|
-
if (mergeErr instanceof MergeConflictError) {
|
|
645
|
-
ctx.ui.notify(`Merge conflict: ${mergeErr.conflictedFiles.join(", ")}. Resolve conflicts manually and run /gsd auto to resume.`, "error");
|
|
646
|
-
await deps.stopAuto(ctx, pi, `Merge conflict on milestone ${s.currentMilestoneId}`);
|
|
647
|
-
return { action: "break", reason: "merge-conflict" };
|
|
648
|
-
}
|
|
649
|
-
logError("engine", "Milestone merge failed with non-conflict error", { milestone: s.currentMilestoneId, error: String(mergeErr) });
|
|
650
|
-
ctx.ui.notify(`Merge failed: ${mergeErr instanceof Error ? mergeErr.message : String(mergeErr)}. Resolve and run /gsd auto to resume.`, "error");
|
|
651
|
-
await deps.stopAuto(ctx, pi, `Merge error on milestone ${s.currentMilestoneId}: ${String(mergeErr)}`);
|
|
652
|
-
return { action: "break", reason: "merge-failed" };
|
|
653
|
-
}
|
|
654
|
-
// #2909: postflight — restore stashed changes after successful merge
|
|
655
|
-
if (preflightComplete.stashPushed) {
|
|
656
|
-
deps.postflightPopStash(s.originalBasePath || s.basePath, s.currentMilestoneId, preflightComplete.stashMarker, ctx.ui.notify.bind(ctx.ui));
|
|
657
|
-
}
|
|
694
|
+
// #2909 / #5538-followup: preflight stash + always-on postflight pop.
|
|
695
|
+
const stop = await _runMilestoneMergeOnceWithStashRestore(ic, s.currentMilestoneId);
|
|
696
|
+
if (stop)
|
|
697
|
+
return stop;
|
|
658
698
|
// PR creation (auto_pr) is handled inside mergeMilestoneToMain (#2302)
|
|
659
699
|
}
|
|
660
700
|
deps.sendDesktopNotification("GSD", `Milestone ${mid} complete!`, "success", "milestone", basename(s.originalBasePath || s.basePath));
|
|
@@ -747,6 +787,48 @@ export async function runDispatch(ic, preData, loopState) {
|
|
|
747
787
|
let unitId = dispatchResult.unitId;
|
|
748
788
|
let prompt = dispatchResult.prompt;
|
|
749
789
|
const pauseAfterUatDispatch = dispatchResult.pauseAfterDispatch ?? false;
|
|
790
|
+
// Resolve hooks and prior-slice gating before health/stuck accounting so
|
|
791
|
+
// those checks run against the final dispatch unit.
|
|
792
|
+
const preDispatchResult = deps.runPreDispatchHooks(unitType, unitId, prompt, s.basePath);
|
|
793
|
+
if (preDispatchResult.firedHooks.length > 0) {
|
|
794
|
+
ctx.ui.notify(`Pre-dispatch hook${preDispatchResult.firedHooks.length > 1 ? "s" : ""}: ${preDispatchResult.firedHooks.join(", ")}`, "info");
|
|
795
|
+
deps.emitJournalEvent({ ts: new Date().toISOString(), flowId: ic.flowId, seq: ic.nextSeq(), eventType: "pre-dispatch-hook", data: { firedHooks: preDispatchResult.firedHooks, action: preDispatchResult.action } });
|
|
796
|
+
}
|
|
797
|
+
if (preDispatchResult.action === "skip") {
|
|
798
|
+
ctx.ui.notify(`Skipping ${unitType} ${unitId} (pre-dispatch hook).`, "info");
|
|
799
|
+
await new Promise((r) => setImmediate(r));
|
|
800
|
+
return { action: "continue" };
|
|
801
|
+
}
|
|
802
|
+
if (preDispatchResult.action === "replace") {
|
|
803
|
+
prompt = preDispatchResult.prompt ?? prompt;
|
|
804
|
+
if (preDispatchResult.unitType)
|
|
805
|
+
unitType = preDispatchResult.unitType;
|
|
806
|
+
}
|
|
807
|
+
else if (preDispatchResult.prompt) {
|
|
808
|
+
prompt = preDispatchResult.prompt;
|
|
809
|
+
}
|
|
810
|
+
const guardBasePath = _resolveDispatchGuardBasePath(s);
|
|
811
|
+
const priorSliceBlocker = deps.getPriorSliceCompletionBlocker(guardBasePath, deps.getMainBranch(guardBasePath), unitType, unitId);
|
|
812
|
+
if (priorSliceBlocker) {
|
|
813
|
+
await deps.stopAuto(ctx, pi, priorSliceBlocker);
|
|
814
|
+
debugLog("autoLoop", { phase: "exit", reason: "prior-slice-blocker" });
|
|
815
|
+
return { action: "break", reason: "prior-slice-blocker" };
|
|
816
|
+
}
|
|
817
|
+
// Execute-task needs a real writable checkout. The same health check also
|
|
818
|
+
// exists in runUnitPhase, but the stuck-window detector runs before that
|
|
819
|
+
// phase. Check here too so repeated derivations of a broken worktree stop
|
|
820
|
+
// with the actionable worktree error instead of the generic stuck-loop error.
|
|
821
|
+
if (s.basePath && unitType === "execute-task") {
|
|
822
|
+
const gitMarker = join(s.basePath, ".git");
|
|
823
|
+
const hasGit = deps.existsSync(gitMarker);
|
|
824
|
+
if (!hasGit) {
|
|
825
|
+
const msg = `Worktree health check failed: ${s.basePath} has no .git — refusing to dispatch ${unitType} ${unitId}`;
|
|
826
|
+
debugLog("autoLoop", { phase: "dispatch-worktree-health-fail", basePath: s.basePath, hasGit });
|
|
827
|
+
ctx.ui.notify(msg, "error");
|
|
828
|
+
await deps.stopAuto(ctx, pi, msg);
|
|
829
|
+
return { action: "break", reason: "worktree-invalid" };
|
|
830
|
+
}
|
|
831
|
+
}
|
|
750
832
|
// ── Sliding-window stuck detection with graduated recovery ──
|
|
751
833
|
const derivedKey = `${unitType}/${unitId}`;
|
|
752
834
|
// Always record this dispatch in the sliding window so detectStuck() has
|
|
@@ -863,32 +945,6 @@ export async function runDispatch(ic, preData, loopState) {
|
|
|
863
945
|
}
|
|
864
946
|
}
|
|
865
947
|
}
|
|
866
|
-
// Pre-dispatch hooks
|
|
867
|
-
const preDispatchResult = deps.runPreDispatchHooks(unitType, unitId, prompt, s.basePath);
|
|
868
|
-
if (preDispatchResult.firedHooks.length > 0) {
|
|
869
|
-
ctx.ui.notify(`Pre-dispatch hook${preDispatchResult.firedHooks.length > 1 ? "s" : ""}: ${preDispatchResult.firedHooks.join(", ")}`, "info");
|
|
870
|
-
deps.emitJournalEvent({ ts: new Date().toISOString(), flowId: ic.flowId, seq: ic.nextSeq(), eventType: "pre-dispatch-hook", data: { firedHooks: preDispatchResult.firedHooks, action: preDispatchResult.action } });
|
|
871
|
-
}
|
|
872
|
-
if (preDispatchResult.action === "skip") {
|
|
873
|
-
ctx.ui.notify(`Skipping ${unitType} ${unitId} (pre-dispatch hook).`, "info");
|
|
874
|
-
await new Promise((r) => setImmediate(r));
|
|
875
|
-
return { action: "continue" };
|
|
876
|
-
}
|
|
877
|
-
if (preDispatchResult.action === "replace") {
|
|
878
|
-
prompt = preDispatchResult.prompt ?? prompt;
|
|
879
|
-
if (preDispatchResult.unitType)
|
|
880
|
-
unitType = preDispatchResult.unitType;
|
|
881
|
-
}
|
|
882
|
-
else if (preDispatchResult.prompt) {
|
|
883
|
-
prompt = preDispatchResult.prompt;
|
|
884
|
-
}
|
|
885
|
-
const guardBasePath = _resolveDispatchGuardBasePath(s);
|
|
886
|
-
const priorSliceBlocker = deps.getPriorSliceCompletionBlocker(guardBasePath, deps.getMainBranch(guardBasePath), unitType, unitId);
|
|
887
|
-
if (priorSliceBlocker) {
|
|
888
|
-
await deps.stopAuto(ctx, pi, priorSliceBlocker);
|
|
889
|
-
debugLog("autoLoop", { phase: "exit", reason: "prior-slice-blocker" });
|
|
890
|
-
return { action: "break", reason: "prior-slice-blocker" };
|
|
891
|
-
}
|
|
892
948
|
return {
|
|
893
949
|
action: "next",
|
|
894
950
|
data: {
|
|
@@ -1108,7 +1164,7 @@ export async function runUnitPhase(ic, iterData, loopState, sidecarItem) {
|
|
|
1108
1164
|
if (projectClassification.kind === "invalid-repo") {
|
|
1109
1165
|
const msg = `Worktree health check failed: ${s.basePath} classified as invalid-repo (${projectClassification.reason}) — refusing to dispatch ${unitType} ${unitId}`;
|
|
1110
1166
|
debugLog("runUnitPhase", { phase: "worktree-health-invalid-repo", basePath: s.basePath, classification: projectClassification });
|
|
1111
|
-
if (projectClassification.reason
|
|
1167
|
+
if (_shouldProceedWithInvalidRepoClassificationForTest(projectClassification.reason, hasGit)) {
|
|
1112
1168
|
ctx.ui.notify(`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`, "warning");
|
|
1113
1169
|
}
|
|
1114
1170
|
else {
|
|
@@ -1118,6 +1174,25 @@ export async function runUnitPhase(ic, iterData, loopState, sidecarItem) {
|
|
|
1118
1174
|
}
|
|
1119
1175
|
}
|
|
1120
1176
|
else if (projectClassification.kind === "greenfield") {
|
|
1177
|
+
const projectRoot = s.canonicalProjectRoot;
|
|
1178
|
+
if (!isSamePathLocal(s.basePath, projectRoot)) {
|
|
1179
|
+
const projectRootClassification = classifyProject(projectRoot);
|
|
1180
|
+
if (shouldDegradeEmptyWorktreeToProjectRoot(projectClassification, projectRootClassification)) {
|
|
1181
|
+
debugLog("runUnitPhase", {
|
|
1182
|
+
phase: "worktree-health-degrade-to-project-root",
|
|
1183
|
+
worktreePath: s.basePath,
|
|
1184
|
+
projectRoot,
|
|
1185
|
+
worktreeClassification: projectClassification,
|
|
1186
|
+
projectRootClassification,
|
|
1187
|
+
});
|
|
1188
|
+
ctx.ui.notify(`Warning: ${s.basePath} has no project content, but ${projectRoot} does. Continuing in project root because the milestone worktree cannot represent untracked project files.`, "warning");
|
|
1189
|
+
s.basePath = projectRoot;
|
|
1190
|
+
s.isolationDegraded = true;
|
|
1191
|
+
projectClassification = projectRootClassification;
|
|
1192
|
+
}
|
|
1193
|
+
}
|
|
1194
|
+
}
|
|
1195
|
+
if (projectClassification.kind === "greenfield") {
|
|
1121
1196
|
debugLog("runUnitPhase", { phase: "worktree-health-greenfield", basePath: s.basePath, classification: projectClassification });
|
|
1122
1197
|
ctx.ui.notify(`Warning: ${s.basePath} has no project content yet — proceeding as greenfield project`, "warning");
|
|
1123
1198
|
}
|
|
@@ -1471,7 +1546,7 @@ export async function runUnitPhase(ic, iterData, loopState, sidecarItem) {
|
|
|
1471
1546
|
{
|
|
1472
1547
|
const currentLedger = deps.getLedger();
|
|
1473
1548
|
if (currentLedger?.units) {
|
|
1474
|
-
const lastUnit = [...currentLedger.units].reverse().find((u) => u.type === unitType && u.id === unitId && u.startedAt === s.currentUnit
|
|
1549
|
+
const lastUnit = [...currentLedger.units].reverse().find((u) => u.type === unitType && u.id === unitId && u.startedAt === _resolveCurrentUnitStartedAtForTest(s.currentUnit));
|
|
1475
1550
|
if (lastUnit && lastUnit.toolCalls === 0) {
|
|
1476
1551
|
if (USER_DRIVEN_DEEP_UNITS.has(unitType) && isAwaitingUserInput(s.lastUnitAgentEndMessages ?? undefined)) {
|
|
1477
1552
|
debugLog("runUnitPhase", {
|
|
@@ -1490,7 +1565,7 @@ export async function runUnitPhase(ic, iterData, loopState, sidecarItem) {
|
|
|
1490
1565
|
ctx.ui.notify(`${unitType} ${unitId} completed with 0 tool calls — context exhaustion, will retry`, "warning");
|
|
1491
1566
|
// Fall through to next iteration where dispatch will re-derive
|
|
1492
1567
|
// and re-dispatch this unit.
|
|
1493
|
-
return { action: "next", data: { unitStartedAt: s.currentUnit
|
|
1568
|
+
return { action: "next", data: { unitStartedAt: _resolveCurrentUnitStartedAtForTest(s.currentUnit), requestDispatchedAt: unitResult.requestDispatchedAt } };
|
|
1494
1569
|
}
|
|
1495
1570
|
}
|
|
1496
1571
|
}
|
|
@@ -1544,7 +1619,7 @@ export async function runUnitPhase(ic, iterData, loopState, sidecarItem) {
|
|
|
1544
1619
|
}
|
|
1545
1620
|
s.checkpointSha = null;
|
|
1546
1621
|
}
|
|
1547
|
-
return { action: "next", data: { unitStartedAt: s.currentUnit
|
|
1622
|
+
return { action: "next", data: { unitStartedAt: _resolveCurrentUnitStartedAtForTest(s.currentUnit), requestDispatchedAt: unitResult.requestDispatchedAt } };
|
|
1548
1623
|
}
|
|
1549
1624
|
// ─── runFinalize ──────────────────────────────────────────────────────────────
|
|
1550
1625
|
/**
|
|
@@ -1677,6 +1752,11 @@ export async function runFinalize(ic, iterData, loopState, sidecarItem) {
|
|
|
1677
1752
|
debugLog("autoLoop", { phase: "exit", reason: "step-wizard" });
|
|
1678
1753
|
return { action: "break", reason: "step-wizard" };
|
|
1679
1754
|
}
|
|
1755
|
+
if (preUnitSnapshot?.type === "complete-milestone" && s.currentMilestoneId) {
|
|
1756
|
+
const stop = await _runMilestoneMergeOnceWithStashRestore(ic, s.currentMilestoneId);
|
|
1757
|
+
if (stop)
|
|
1758
|
+
return stop;
|
|
1759
|
+
}
|
|
1680
1760
|
// Both pre and post verification completed without timeout — reset counter
|
|
1681
1761
|
loopState.consecutiveFinalizeTimeouts = 0;
|
|
1682
1762
|
if (preUnitSnapshot) {
|
|
@@ -18,6 +18,8 @@ import { bumpTurnGeneration } from "./turn-epoch.js";
|
|
|
18
18
|
let _currentResolve = null;
|
|
19
19
|
let _sessionSwitchInFlight = false;
|
|
20
20
|
let _pendingSwitchCancellation = null;
|
|
21
|
+
let _sessionSwitchAbortGraceUntil = 0;
|
|
22
|
+
const DEFAULT_SESSION_SWITCH_ABORT_GRACE_MS = 2_000;
|
|
21
23
|
// ─── Setters (needed for cross-module mutation) ─────────────────────────────
|
|
22
24
|
export function _setCurrentResolve(fn) {
|
|
23
25
|
_currentResolve = fn;
|
|
@@ -25,6 +27,15 @@ export function _setCurrentResolve(fn) {
|
|
|
25
27
|
export function _setSessionSwitchInFlight(v) {
|
|
26
28
|
_sessionSwitchInFlight = v;
|
|
27
29
|
}
|
|
30
|
+
export function _markSessionSwitchAbortGraceWindow(durationMs = DEFAULT_SESSION_SWITCH_ABORT_GRACE_MS) {
|
|
31
|
+
_sessionSwitchAbortGraceUntil = Math.max(_sessionSwitchAbortGraceUntil, Date.now() + durationMs);
|
|
32
|
+
}
|
|
33
|
+
export function _clearSessionSwitchAbortGraceWindow() {
|
|
34
|
+
_sessionSwitchAbortGraceUntil = 0;
|
|
35
|
+
}
|
|
36
|
+
export function isSessionSwitchAbortGraceActive(now = Date.now()) {
|
|
37
|
+
return now < _sessionSwitchAbortGraceUntil;
|
|
38
|
+
}
|
|
28
39
|
export function _clearCurrentResolve() {
|
|
29
40
|
_currentResolve = null;
|
|
30
41
|
}
|
|
@@ -118,6 +129,7 @@ export function _resetPendingResolve() {
|
|
|
118
129
|
_currentResolve = null;
|
|
119
130
|
_sessionSwitchInFlight = false;
|
|
120
131
|
_pendingSwitchCancellation = null;
|
|
132
|
+
_sessionSwitchAbortGraceUntil = 0;
|
|
121
133
|
}
|
|
122
134
|
export function _hasPendingResolveForTest() {
|
|
123
135
|
return _currentResolve !== null;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// GSD-2 + src/resources/extensions/gsd/auto/run-unit.ts - Runs one GSD auto-mode unit from session creation through agent completion.
|
|
2
2
|
import { NEW_SESSION_TIMEOUT_MS } from "./session.js";
|
|
3
|
-
import { _clearCurrentResolve, _consumePendingSwitchCancellation, _setCurrentResolve, _setSessionSwitchInFlight, } from "./resolve.js";
|
|
3
|
+
import { _clearCurrentResolve, _consumePendingSwitchCancellation, _markSessionSwitchAbortGraceWindow, _setCurrentResolve, _setSessionSwitchInFlight, } from "./resolve.js";
|
|
4
4
|
import { getCurrentTurnGeneration, runWithTurnGeneration, } from "./turn-epoch.js";
|
|
5
5
|
import { debugLog } from "../debug-logger.js";
|
|
6
6
|
import { logWarning } from "../workflow-logger.js";
|
|
@@ -19,44 +19,23 @@ let sessionSwitchGeneration = 0;
|
|
|
19
19
|
*/
|
|
20
20
|
export async function runUnit(ctx, pi, s, unitType, unitId, prompt) {
|
|
21
21
|
debugLog("runUnit", { phase: "start", unitType, unitId });
|
|
22
|
-
// Ensure cwd matches basePath BEFORE newSession() captures it. The new
|
|
23
|
-
// session reads process.cwd() during construction to anchor its tool
|
|
24
|
-
// runtime and system prompt; if cwd has drifted (async_bash, background
|
|
25
|
-
// jobs, prior unit cleanup), the session would otherwise be rooted to
|
|
26
|
-
// the wrong directory. Must be synchronous — no awaits between chdir
|
|
27
|
-
// and newSession (#1389, #4762 follow-up).
|
|
28
|
-
try {
|
|
29
|
-
if (process.cwd() !== s.basePath) {
|
|
30
|
-
process.chdir(s.basePath);
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
catch (e) {
|
|
34
|
-
const msg = `Failed to chdir to basePath before newSession (basePath: ${s.basePath}): ${String(e)}`;
|
|
35
|
-
logWarning("engine", msg, { basePath: s.basePath, error: String(e) });
|
|
36
|
-
return {
|
|
37
|
-
status: "cancelled",
|
|
38
|
-
errorContext: {
|
|
39
|
-
message: msg,
|
|
40
|
-
category: "session-failed",
|
|
41
|
-
isTransient: true,
|
|
42
|
-
},
|
|
43
|
-
};
|
|
44
|
-
}
|
|
45
22
|
// ── Session creation with timeout ──
|
|
46
23
|
debugLog("runUnit", { phase: "session-create", unitType, unitId });
|
|
47
24
|
let sessionResult;
|
|
48
25
|
let sessionTimeoutHandle;
|
|
49
26
|
const mySessionSwitchGeneration = ++sessionSwitchGeneration;
|
|
50
|
-
// #3731: Cancellation controller for newSession(). When
|
|
51
|
-
//
|
|
52
|
-
//
|
|
53
|
-
// it from capturing the (now-root) process.cwd() and rebuilding the tool
|
|
54
|
-
// runtime with the wrong cwd.
|
|
27
|
+
// #3731: Cancellation controller for newSession(). When session creation
|
|
28
|
+
// times out, abort before a late session switch can rebuild the tool runtime
|
|
29
|
+
// against a stale workspace root.
|
|
55
30
|
const sessionAbortController = new AbortController();
|
|
56
31
|
_setSessionSwitchInFlight(true);
|
|
57
32
|
try {
|
|
58
|
-
const sessionPromise = s.cmdCtx.newSession({
|
|
33
|
+
const sessionPromise = s.cmdCtx.newSession({
|
|
34
|
+
abortSignal: sessionAbortController.signal,
|
|
35
|
+
workspaceRoot: s.basePath,
|
|
36
|
+
}).finally(() => {
|
|
59
37
|
if (sessionSwitchGeneration === mySessionSwitchGeneration) {
|
|
38
|
+
_markSessionSwitchAbortGraceWindow();
|
|
60
39
|
_setSessionSwitchInFlight(false);
|
|
61
40
|
}
|
|
62
41
|
});
|
|
@@ -111,6 +90,7 @@ export async function runUnit(ctx, pi, s, unitType, unitId, prompt) {
|
|
|
111
90
|
// ── Create the agent_end promise (per-unit one-shot) ──
|
|
112
91
|
// This happens after newSession completes so session-switch agent_end events
|
|
113
92
|
// from the previous session cannot resolve the new unit.
|
|
93
|
+
_markSessionSwitchAbortGraceWindow();
|
|
114
94
|
_setSessionSwitchInFlight(false);
|
|
115
95
|
const unitPromise = new Promise((resolve) => {
|
|
116
96
|
_setCurrentResolve(resolve);
|
|
@@ -106,6 +106,13 @@ export class AutoSession {
|
|
|
106
106
|
* stale context bleeding into unrelated slices.
|
|
107
107
|
*/
|
|
108
108
|
lastPreExecFailure = null;
|
|
109
|
+
/**
|
|
110
|
+
* Tracks how many consecutive times each slice unit has failed pre-execution
|
|
111
|
+
* checks. Keyed by unitId (e.g. "M001/S01"). Used to break the infinite
|
|
112
|
+
* plan-slice → pre-exec fail → re-dispatch loop when the planner cannot fix
|
|
113
|
+
* the issues after MAX_PRE_EXEC_RETRIES re-attempts.
|
|
114
|
+
*/
|
|
115
|
+
preExecRetryCount = new Map();
|
|
109
116
|
// ── Tool invocation errors (#2883) ──────────────────────────────────
|
|
110
117
|
/** Set when a GSD tool execution ends with isError due to malformed/truncated
|
|
111
118
|
* JSON arguments. Checked by postUnitPreVerification to break retry loops. */
|
|
@@ -258,6 +265,7 @@ export class AutoSession {
|
|
|
258
265
|
this.rewriteAttemptCount = 0;
|
|
259
266
|
this.consecutiveCompleteBootstraps = 0;
|
|
260
267
|
this.lastPreExecFailure = null;
|
|
268
|
+
this.preExecRetryCount.clear();
|
|
261
269
|
this.lastToolInvocationError = null;
|
|
262
270
|
this.lastUnitAgentEndMessages = null;
|
|
263
271
|
this.lastGitActionFailure = null;
|
|
@@ -1,7 +1,39 @@
|
|
|
1
1
|
// Project/App: GSD-2
|
|
2
2
|
// File Purpose: Best-effort unit dispatch claim adapter for auto-mode loop.
|
|
3
|
+
export function ensureDispatchLease(s, milestoneId, deps, opts = {}) {
|
|
4
|
+
if (!s.workerId)
|
|
5
|
+
return { kind: "degraded", reason: "missing-worker" };
|
|
6
|
+
if (!milestoneId)
|
|
7
|
+
return { kind: "degraded", reason: "missing-milestone" };
|
|
8
|
+
if (!opts.forceReclaim && typeof s.milestoneLeaseToken === "number") {
|
|
9
|
+
return { kind: "ready", token: s.milestoneLeaseToken, recovered: false };
|
|
10
|
+
}
|
|
11
|
+
s.milestoneLeaseToken = null;
|
|
12
|
+
try {
|
|
13
|
+
const claim = deps.claimMilestoneLease(s.workerId, milestoneId);
|
|
14
|
+
if (!claim.ok) {
|
|
15
|
+
const reason = `Milestone ${milestoneId} is held by worker ${claim.byWorker} until ${claim.expiresAt}.`;
|
|
16
|
+
deps.logLeaseRecoveryFailed({ milestoneId, workerId: s.workerId, reason });
|
|
17
|
+
return { kind: "blocked", reason };
|
|
18
|
+
}
|
|
19
|
+
s.currentMilestoneId = milestoneId;
|
|
20
|
+
s.milestoneLeaseToken = claim.token;
|
|
21
|
+
deps.logLeaseRecovered({
|
|
22
|
+
milestoneId,
|
|
23
|
+
workerId: s.workerId,
|
|
24
|
+
token: claim.token,
|
|
25
|
+
recovered: opts.forceReclaim === true,
|
|
26
|
+
});
|
|
27
|
+
return { kind: "ready", token: claim.token, recovered: opts.forceReclaim === true };
|
|
28
|
+
}
|
|
29
|
+
catch (err) {
|
|
30
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
31
|
+
deps.logLeaseRecoveryFailed({ milestoneId, workerId: s.workerId, reason });
|
|
32
|
+
return { kind: "failed", reason };
|
|
33
|
+
}
|
|
34
|
+
}
|
|
3
35
|
export function openDispatchClaim(s, flowId, turnId, iterData, deps) {
|
|
4
|
-
if (!s.workerId || s.milestoneLeaseToken
|
|
36
|
+
if (!s.workerId || typeof s.milestoneLeaseToken !== "number")
|
|
5
37
|
return { kind: "degraded" };
|
|
6
38
|
const mid = iterData.mid;
|
|
7
39
|
if (!mid)
|
|
@@ -6,7 +6,15 @@ export function maintainWorkerHeartbeat(session, deps) {
|
|
|
6
6
|
try {
|
|
7
7
|
deps.heartbeatAutoWorker(session.workerId);
|
|
8
8
|
if (session.currentMilestoneId && session.milestoneLeaseToken) {
|
|
9
|
-
deps.refreshMilestoneLease(session.workerId, session.currentMilestoneId, session.milestoneLeaseToken);
|
|
9
|
+
const refreshed = deps.refreshMilestoneLease(session.workerId, session.currentMilestoneId, session.milestoneLeaseToken);
|
|
10
|
+
if (!refreshed) {
|
|
11
|
+
deps.logLeaseRefreshMiss?.({
|
|
12
|
+
workerId: session.workerId,
|
|
13
|
+
milestoneId: session.currentMilestoneId,
|
|
14
|
+
fencingToken: session.milestoneLeaseToken,
|
|
15
|
+
});
|
|
16
|
+
session.milestoneLeaseToken = null;
|
|
17
|
+
}
|
|
10
18
|
}
|
|
11
19
|
}
|
|
12
20
|
catch (err) {
|
|
@@ -11,7 +11,6 @@ import { buildResearchSlicePrompt, buildResearchMilestonePrompt, buildPlanSliceP
|
|
|
11
11
|
import { loadEffectiveGSDPreferences } from "./preferences.js";
|
|
12
12
|
import { pauseAuto } from "./auto.js";
|
|
13
13
|
import { resolveCanonicalMilestoneRoot } from "./worktree-manager.js";
|
|
14
|
-
import { logWarning } from "./workflow-logger.js";
|
|
15
14
|
import { getWorkflowTransportSupportError, getRequiredWorkflowToolsForAutoUnit, } from "./workflow-mcp.js";
|
|
16
15
|
export async function dispatchDirectPhase(ctx, pi, phase, base) {
|
|
17
16
|
const state = await deriveState(base);
|
|
@@ -231,36 +230,10 @@ export async function dispatchDirectPhase(ctx, pi, phase, base) {
|
|
|
231
230
|
return;
|
|
232
231
|
}
|
|
233
232
|
ctx.ui.notify(`Dispatching ${unitType} for ${unitId}...`, "info");
|
|
234
|
-
const
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
try {
|
|
239
|
-
if (process.cwd() !== dispatchBase) {
|
|
240
|
-
process.chdir(dispatchBase);
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
catch (err) {
|
|
244
|
-
const msg = `Failed to chdir before direct-dispatch newSession (basePath: ${dispatchBase}): ${err instanceof Error ? err.message : String(err)}`;
|
|
245
|
-
logWarning("engine", msg, { file: "auto-direct-dispatch.ts", basePath: dispatchBase, error: err instanceof Error ? err.message : String(err) });
|
|
246
|
-
ctx.ui.notify(`${msg}. Cancelling dispatch to avoid running in the wrong directory.`, "error");
|
|
247
|
-
return;
|
|
248
|
-
}
|
|
249
|
-
const result = await ctx.newSession();
|
|
250
|
-
if (result.cancelled) {
|
|
251
|
-
ctx.ui.notify("Session creation cancelled.", "warning");
|
|
252
|
-
return;
|
|
253
|
-
}
|
|
254
|
-
pi.sendMessage({ customType: "gsd-dispatch", content: prompt, display: false }, { triggerTurn: true });
|
|
255
|
-
}
|
|
256
|
-
finally {
|
|
257
|
-
try {
|
|
258
|
-
if (process.cwd() !== originalCwd) {
|
|
259
|
-
process.chdir(originalCwd);
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
catch (err) {
|
|
263
|
-
logWarning("engine", `Failed to restore cwd after direct dispatch: ${err instanceof Error ? err.message : String(err)}`, { file: "auto-direct-dispatch.ts", basePath: originalCwd });
|
|
264
|
-
}
|
|
233
|
+
const result = await ctx.newSession({ workspaceRoot: dispatchBase });
|
|
234
|
+
if (result.cancelled) {
|
|
235
|
+
ctx.ui.notify("Session creation cancelled.", "warning");
|
|
236
|
+
return;
|
|
265
237
|
}
|
|
238
|
+
pi.sendMessage({ customType: "gsd-dispatch", content: prompt, display: false }, { triggerTurn: true });
|
|
266
239
|
}
|
|
@@ -791,6 +791,22 @@ export const DISPATCH_RULES = [
|
|
|
791
791
|
const unitId = `${mid}/${sid}`;
|
|
792
792
|
let priorPreExecFailure;
|
|
793
793
|
if (session?.lastPreExecFailure?.unitId === unitId) {
|
|
794
|
+
// Circuit breaker: stop re-dispatching after 2 failed retries. The
|
|
795
|
+
// planner has had multiple attempts with injected failure context and
|
|
796
|
+
// still cannot produce a valid plan — human review is required.
|
|
797
|
+
const MAX_PRE_EXEC_RETRIES = 2;
|
|
798
|
+
const retryCount = session.preExecRetryCount?.get(unitId) ?? 0;
|
|
799
|
+
if (retryCount >= MAX_PRE_EXEC_RETRIES) {
|
|
800
|
+
const findings = session.lastPreExecFailure.blockingFindings.join("; ");
|
|
801
|
+
session.lastPreExecFailure = null;
|
|
802
|
+
session.preExecRetryCount?.delete(unitId);
|
|
803
|
+
return {
|
|
804
|
+
action: "stop",
|
|
805
|
+
reason: `Pre-execution checks failed ${retryCount} times for ${unitId} — manual intervention required. Blocking findings: ${findings}. Fix the plan manually, then run /gsd auto to resume.`,
|
|
806
|
+
level: "error",
|
|
807
|
+
matchedRule: "planning → plan-slice",
|
|
808
|
+
};
|
|
809
|
+
}
|
|
794
810
|
priorPreExecFailure = {
|
|
795
811
|
blockingFindings: session.lastPreExecFailure.blockingFindings,
|
|
796
812
|
verdictExcerpt: session.lastPreExecFailure.verdictExcerpt,
|