gsd-pi 2.80.0-dev.3065f7bfa → 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 +32 -8
- package/dist/resources/extensions/gsd/auto/resolve.js +12 -0
- package/dist/resources/extensions/gsd/auto/run-unit.js +3 -1
- 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-post-unit.js +81 -76
- package/dist/resources/extensions/gsd/auto-start.js +41 -6
- package/dist/resources/extensions/gsd/auto-worktree.js +98 -80
- package/dist/resources/extensions/gsd/auto.js +84 -29
- package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +62 -13
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +20 -26
- package/dist/resources/extensions/gsd/bootstrap/dynamic-tools.js +29 -12
- package/dist/resources/extensions/gsd/bootstrap/exec-tools.js +6 -9
- package/dist/resources/extensions/gsd/bootstrap/journal-tools.js +4 -7
- package/dist/resources/extensions/gsd/bootstrap/memory-tools.js +6 -10
- package/dist/resources/extensions/gsd/bootstrap/query-tools.js +5 -9
- package/dist/resources/extensions/gsd/bootstrap/register-extension.js +1 -1
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +60 -26
- package/dist/resources/extensions/gsd/bootstrap/sanitize-complete-milestone.js +4 -0
- 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/dashboard-overlay.js +1 -1
- package/dist/resources/extensions/gsd/db/unit-dispatches.js +53 -0
- package/dist/resources/extensions/gsd/git-service.js +37 -1
- package/dist/resources/extensions/gsd/guided-flow.js +14 -4
- package/dist/resources/extensions/gsd/init-wizard.js +4 -1
- package/dist/resources/extensions/gsd/prompts/complete-milestone.md +6 -4
- 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/worktree-resolver.js +22 -1
- 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 +17 -17
- 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/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 +17 -17
- 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/welcome-screen.d.ts +2 -0
- package/dist/welcome-screen.js +9 -7
- package/package.json +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/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/types.d.ts +2 -2
- 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/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/chat-controller-ordering.test.ts +3 -1
- package/packages/pi-coding-agent/src/core/extensions/types.ts +2 -1
- 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.ts +84 -8
- package/src/resources/extensions/gsd/auto/phases.ts +43 -8
- package/src/resources/extensions/gsd/auto/resolve.ts +19 -0
- package/src/resources/extensions/gsd/auto/run-unit.ts +3 -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-post-unit.ts +93 -78
- package/src/resources/extensions/gsd/auto-start.ts +56 -6
- package/src/resources/extensions/gsd/auto-worktree.ts +118 -72
- package/src/resources/extensions/gsd/auto.ts +121 -29
- package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +76 -12
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +20 -26
- package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +27 -12
- package/src/resources/extensions/gsd/bootstrap/exec-tools.ts +7 -9
- package/src/resources/extensions/gsd/bootstrap/journal-tools.ts +4 -7
- package/src/resources/extensions/gsd/bootstrap/memory-tools.ts +6 -10
- package/src/resources/extensions/gsd/bootstrap/query-tools.ts +5 -9
- package/src/resources/extensions/gsd/bootstrap/register-extension.ts +1 -1
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +64 -26
- package/src/resources/extensions/gsd/bootstrap/sanitize-complete-milestone.ts +4 -0
- 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/dashboard-overlay.ts +1 -1
- package/src/resources/extensions/gsd/db/unit-dispatches.ts +66 -0
- package/src/resources/extensions/gsd/git-service.ts +41 -2
- package/src/resources/extensions/gsd/guided-flow.ts +19 -4
- package/src/resources/extensions/gsd/init-wizard.ts +5 -1
- package/src/resources/extensions/gsd/prompts/complete-milestone.md +6 -4
- 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 +15 -0
- 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 +1 -217
- 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/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.test.ts +140 -0
- 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/crash-handler-secondary.test.ts +35 -31
- 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/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 -59
- 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/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/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/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 +113 -0
- 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-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-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 -90
- 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/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 +61 -1
- 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/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/token-profile.test.ts +84 -309
- 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 +6 -101
- 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-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-main-branch.test.ts +20 -18
- package/src/resources/extensions/gsd/tests/worktree-resolver.test.ts +36 -0
- 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/worktree-resolver.ts +34 -1
- 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/{O2WvnXROue6l7nAp_4dhC → G68KoLv5claox_Dyd4pZn}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{O2WvnXROue6l7nAp_4dhC → G68KoLv5claox_Dyd4pZn}/_ssgManifest.js +0 -0
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
import { existsSync, cpSync, readFileSync, readdirSync, mkdirSync, realpathSync, rmSync, unlinkSync, statSync, lstatSync as lstatSyncFn, } from "node:fs";
|
|
11
11
|
import { isAbsolute, join, relative, sep as pathSep } from "node:path";
|
|
12
12
|
import { GSDError, GSD_IO_ERROR, GSD_GIT_ERROR } from "./errors.js";
|
|
13
|
-
import { reconcileWorktreeDb, isDbAvailable, getMilestone, getMilestoneSlices, closeDatabase, openDatabase, getDbPath, } from "./gsd-db.js";
|
|
13
|
+
import { reconcileWorktreeDb, isDbAvailable, getMilestone, getMilestoneSlices, getSliceTasks, closeDatabase, openDatabase, getDbPath, } from "./gsd-db.js";
|
|
14
14
|
import { execFileSync } from "node:child_process";
|
|
15
15
|
import { safeCopy, safeCopyRecursive } from "./safe-fs.js";
|
|
16
16
|
import { gsdRoot, resolveGsdPathContract } from "./paths.js";
|
|
@@ -135,6 +135,35 @@ function isSamePath(a, b) {
|
|
|
135
135
|
return false;
|
|
136
136
|
}
|
|
137
137
|
}
|
|
138
|
+
export function _isSamePathForTest(a, b) {
|
|
139
|
+
return isSamePath(a, b);
|
|
140
|
+
}
|
|
141
|
+
export function _resolveAutoWorktreeStartPointForTest(integrationBranch, gitMainBranch, branchExists) {
|
|
142
|
+
if (integrationBranch)
|
|
143
|
+
return integrationBranch;
|
|
144
|
+
return gitMainBranch &&
|
|
145
|
+
typeof gitMainBranch === "string" &&
|
|
146
|
+
gitMainBranch.length > 0 &&
|
|
147
|
+
branchExists(gitMainBranch)
|
|
148
|
+
? gitMainBranch
|
|
149
|
+
: undefined;
|
|
150
|
+
}
|
|
151
|
+
export function _shouldReconcileWorktreeDbForTest(worktreeDbPath, mainDbPath, pathExists = existsSync, samePath = isSamePath) {
|
|
152
|
+
return pathExists(worktreeDbPath) && !samePath(worktreeDbPath, mainDbPath);
|
|
153
|
+
}
|
|
154
|
+
export function _isExpectedWorktreeUnlinkErrorForTest(code) {
|
|
155
|
+
return code === "ENOENT" || code === "EISDIR";
|
|
156
|
+
}
|
|
157
|
+
function stripGsdDisplayPrefix(value, id) {
|
|
158
|
+
const raw = String(value ?? "").trim();
|
|
159
|
+
if (!raw)
|
|
160
|
+
return undefined;
|
|
161
|
+
const lower = raw.toLowerCase();
|
|
162
|
+
const idLower = id.toLowerCase();
|
|
163
|
+
if (lower.startsWith(`${idLower}:`))
|
|
164
|
+
return raw.slice(id.length + 1).trim() || undefined;
|
|
165
|
+
return raw;
|
|
166
|
+
}
|
|
138
167
|
// ─── ASSESSMENT Force-Sync Helper (#2821) ─────────────────────────────────
|
|
139
168
|
/** Regex matching YAML frontmatter `verdict:` field. */
|
|
140
169
|
const VERDICT_RE = /verdict:\s*[\w-]+/i;
|
|
@@ -288,7 +317,7 @@ function clearProjectRootStateFiles(basePath, milestoneId) {
|
|
|
288
317
|
catch (err) {
|
|
289
318
|
// ENOENT/EISDIR are expected for already-removed or directory entries (#3597)
|
|
290
319
|
const code = err.code;
|
|
291
|
-
if (code
|
|
320
|
+
if (!_isExpectedWorktreeUnlinkErrorForTest(code)) {
|
|
292
321
|
logWarning("worktree", `untracked file unlink failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
293
322
|
}
|
|
294
323
|
}
|
|
@@ -317,6 +346,44 @@ export const SAFE_AUTO_RESOLVE_PATTERNS = [
|
|
|
317
346
|
* Covers `.gsd/` state files and common build artifacts. */
|
|
318
347
|
export const isSafeToAutoResolve = (filePath) => filePath.startsWith(".gsd/") ||
|
|
319
348
|
SAFE_AUTO_RESOLVE_PATTERNS.some((re) => re.test(filePath));
|
|
349
|
+
function removeMergeStateFiles(basePath, contextLabel) {
|
|
350
|
+
try {
|
|
351
|
+
const gitDir_ = resolveGitDir(basePath);
|
|
352
|
+
for (const f of ["SQUASH_MSG", "MERGE_MSG", "MERGE_HEAD"]) {
|
|
353
|
+
const p = join(gitDir_, f);
|
|
354
|
+
if (existsSync(p))
|
|
355
|
+
unlinkSync(p);
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
catch (err) {
|
|
359
|
+
logError("worktree", `${contextLabel} merge state cleanup failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
function cleanupSquashConflictState(basePath) {
|
|
363
|
+
// `git merge --squash` conflicts can leave unmerged index entries without
|
|
364
|
+
// MERGE_HEAD, so merge-abort alone is not enough. Reset the merge index, then
|
|
365
|
+
// remove merge message files that native/libgit2 paths may have created.
|
|
366
|
+
try {
|
|
367
|
+
nativeMergeAbort(basePath);
|
|
368
|
+
}
|
|
369
|
+
catch (err) {
|
|
370
|
+
// Expected for squash conflicts when MERGE_HEAD was never written.
|
|
371
|
+
debugLog("squash-conflict-cleanup:merge-abort-skipped", {
|
|
372
|
+
error: err instanceof Error ? err.message : String(err),
|
|
373
|
+
});
|
|
374
|
+
}
|
|
375
|
+
try {
|
|
376
|
+
execFileSync("git", ["reset", "--merge"], {
|
|
377
|
+
cwd: basePath,
|
|
378
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
379
|
+
encoding: "utf-8",
|
|
380
|
+
});
|
|
381
|
+
}
|
|
382
|
+
catch (err) {
|
|
383
|
+
logError("worktree", `git reset --merge failed after squash conflict: ${err instanceof Error ? err.message : String(err)}`);
|
|
384
|
+
}
|
|
385
|
+
removeMergeStateFiles(basePath, "squash conflict");
|
|
386
|
+
}
|
|
320
387
|
// ─── Dispatch-Level Sync (project root ↔ worktree) ──────────────────────────
|
|
321
388
|
/**
|
|
322
389
|
* Sync milestone artifacts from project root INTO worktree before deriveState.
|
|
@@ -945,17 +1012,7 @@ export function enterBranchModeForMilestone(basePath, milestoneId) {
|
|
|
945
1012
|
// Create the milestone branch from the integration branch start-point.
|
|
946
1013
|
const integrationBranch = readIntegrationBranch(basePath, milestoneId) ?? undefined;
|
|
947
1014
|
const gitPrefs = loadEffectiveGSDPreferences()?.preferences?.git;
|
|
948
|
-
|
|
949
|
-
// a stale preference (e.g. "master" when repo uses "main") would cause
|
|
950
|
-
// nativeBranchForceReset to fail with a bad start-point reference.
|
|
951
|
-
const validatedPrefBranch = gitPrefs?.main_branch &&
|
|
952
|
-
typeof gitPrefs.main_branch === "string" &&
|
|
953
|
-
gitPrefs.main_branch.length > 0 &&
|
|
954
|
-
nativeBranchExists(basePath, gitPrefs.main_branch)
|
|
955
|
-
? gitPrefs.main_branch
|
|
956
|
-
: undefined;
|
|
957
|
-
const startPoint = integrationBranch ??
|
|
958
|
-
validatedPrefBranch ??
|
|
1015
|
+
const startPoint = _resolveAutoWorktreeStartPointForTest(integrationBranch, gitPrefs?.main_branch, (branchName) => nativeBranchExists(basePath, branchName)) ??
|
|
959
1016
|
nativeDetectMainBranch(basePath);
|
|
960
1017
|
// TOCTOU ancestry guard (Issue #4980 HIGH-3).
|
|
961
1018
|
//
|
|
@@ -1161,13 +1218,7 @@ export function createAutoWorktree(basePath, milestoneId) {
|
|
|
1161
1218
|
// would fork worktrees from the wrong (stale) branch.
|
|
1162
1219
|
const integrationBranch = readIntegrationBranch(basePath, milestoneId) ?? undefined;
|
|
1163
1220
|
const gitPrefs = loadEffectiveGSDPreferences()?.preferences?.git;
|
|
1164
|
-
const
|
|
1165
|
-
typeof gitPrefs.main_branch === "string" &&
|
|
1166
|
-
gitPrefs.main_branch.length > 0 &&
|
|
1167
|
-
nativeBranchExists(basePath, gitPrefs.main_branch)
|
|
1168
|
-
? gitPrefs.main_branch
|
|
1169
|
-
: undefined;
|
|
1170
|
-
const startPoint = integrationBranch ?? validatedPrefBranch ?? undefined;
|
|
1221
|
+
const startPoint = _resolveAutoWorktreeStartPointForTest(integrationBranch, gitPrefs?.main_branch, (branchName) => nativeBranchExists(basePath, branchName));
|
|
1171
1222
|
info = createWorktree(basePath, milestoneId, {
|
|
1172
1223
|
branch,
|
|
1173
1224
|
startPoint,
|
|
@@ -1244,7 +1295,7 @@ export function teardownAutoWorktree(originalBasePath, milestoneId, opts = {}) {
|
|
|
1244
1295
|
const contract = resolveGsdPathContract(previousCwd, originalBasePath);
|
|
1245
1296
|
const worktreeDbPath = join(contract.worktreeGsd ?? join(previousCwd, ".gsd"), "gsd.db");
|
|
1246
1297
|
const mainDbPath = contract.projectDb;
|
|
1247
|
-
if (
|
|
1298
|
+
if (_shouldReconcileWorktreeDbForTest(worktreeDbPath, mainDbPath)) {
|
|
1248
1299
|
reconcileWorktreeDb(mainDbPath, worktreeDbPath);
|
|
1249
1300
|
}
|
|
1250
1301
|
}
|
|
@@ -1494,7 +1545,7 @@ export function mergeMilestoneToMain(originalBasePath_, milestoneId, roadmapCont
|
|
|
1494
1545
|
const contract = resolveGsdPathContract(worktreeCwd, originalBasePath_);
|
|
1495
1546
|
const worktreeDbPath = join(contract.worktreeGsd ?? join(worktreeCwd, ".gsd"), "gsd.db");
|
|
1496
1547
|
const mainDbPath = contract.projectDb;
|
|
1497
|
-
if (
|
|
1548
|
+
if (_shouldReconcileWorktreeDbForTest(worktreeDbPath, mainDbPath)) {
|
|
1498
1549
|
reconcileWorktreeDb(mainDbPath, worktreeDbPath);
|
|
1499
1550
|
}
|
|
1500
1551
|
}
|
|
@@ -1508,14 +1559,23 @@ export function mergeMilestoneToMain(originalBasePath_, milestoneId, roadmapCont
|
|
|
1508
1559
|
if (isDbAvailable()) {
|
|
1509
1560
|
completedSlices = getMilestoneSlices(milestoneId)
|
|
1510
1561
|
.filter(s => s.status === "complete")
|
|
1511
|
-
.map(s => ({
|
|
1562
|
+
.map(s => ({
|
|
1563
|
+
id: s.id,
|
|
1564
|
+
title: stripGsdDisplayPrefix(s.title, s.id) ?? s.id,
|
|
1565
|
+
tasks: getSliceTasks(milestoneId, s.id)
|
|
1566
|
+
.filter((task) => task.status === "complete")
|
|
1567
|
+
.map((task) => ({
|
|
1568
|
+
id: task.id,
|
|
1569
|
+
title: stripGsdDisplayPrefix(task.title, task.id) ?? task.id,
|
|
1570
|
+
})),
|
|
1571
|
+
}));
|
|
1512
1572
|
}
|
|
1513
1573
|
// Fallback: parse roadmap content when DB is unavailable
|
|
1514
1574
|
if (completedSlices.length === 0 && roadmapContent) {
|
|
1515
1575
|
const sliceRe = /- \[x\] \*\*(\w+):\s*(.+?)\*\*/gi;
|
|
1516
1576
|
let m;
|
|
1517
1577
|
while ((m = sliceRe.exec(roadmapContent)) !== null) {
|
|
1518
|
-
completedSlices.push({ id: m[1], title: m[2] });
|
|
1578
|
+
completedSlices.push({ id: m[1], title: m[2], tasks: [] });
|
|
1519
1579
|
}
|
|
1520
1580
|
}
|
|
1521
1581
|
// 3. chdir to original base
|
|
@@ -1572,7 +1632,7 @@ export function mergeMilestoneToMain(originalBasePath_, milestoneId, roadmapCont
|
|
|
1572
1632
|
}
|
|
1573
1633
|
// 6. Build rich commit message
|
|
1574
1634
|
const dbMilestone = getMilestone(milestoneId);
|
|
1575
|
-
let milestoneTitle = (dbMilestone?.title ?? ""
|
|
1635
|
+
let milestoneTitle = stripGsdDisplayPrefix(dbMilestone?.title, milestoneId) ?? "";
|
|
1576
1636
|
// Fallback: parse title from roadmap content header (e.g. "# M020: Backend foundation")
|
|
1577
1637
|
if (!milestoneTitle && roadmapContent) {
|
|
1578
1638
|
const titleMatch = roadmapContent.match(new RegExp(`^#\\s+${milestoneId}:\\s*(.+)`, "m"));
|
|
@@ -1581,15 +1641,22 @@ export function mergeMilestoneToMain(originalBasePath_, milestoneId, roadmapCont
|
|
|
1581
1641
|
}
|
|
1582
1642
|
milestoneTitle = milestoneTitle || milestoneId;
|
|
1583
1643
|
const subject = `feat: ${milestoneTitle}`;
|
|
1644
|
+
const milestoneContext = milestoneTitle === milestoneId
|
|
1645
|
+
? `Milestone: ${milestoneId}`
|
|
1646
|
+
: `Milestone: ${milestoneId} - ${milestoneTitle}`;
|
|
1584
1647
|
let body = "";
|
|
1585
1648
|
if (completedSlices.length > 0) {
|
|
1586
1649
|
const sliceLines = completedSlices
|
|
1587
1650
|
.map((s) => `- ${s.id}: ${s.title}`)
|
|
1588
1651
|
.join("\n");
|
|
1589
|
-
|
|
1652
|
+
const taskLines = completedSlices
|
|
1653
|
+
.flatMap((s) => s.tasks.map((task) => `- ${s.id}/${task.id}: ${task.title}`))
|
|
1654
|
+
.join("\n");
|
|
1655
|
+
const taskBlock = taskLines ? `\n\nCompleted tasks:\n${taskLines}` : "";
|
|
1656
|
+
body = `\n\nCompleted slices:\n${sliceLines}${taskBlock}\n\n${milestoneContext}\nGSD-Milestone: ${milestoneId}\nBranch: ${milestoneBranch}`;
|
|
1590
1657
|
}
|
|
1591
1658
|
else {
|
|
1592
|
-
body = `\n\nGSD-Milestone: ${milestoneId}\nBranch: ${milestoneBranch}`;
|
|
1659
|
+
body = `\n\n${milestoneContext}\nGSD-Milestone: ${milestoneId}\nBranch: ${milestoneBranch}`;
|
|
1593
1660
|
}
|
|
1594
1661
|
const commitMessage = subject + body;
|
|
1595
1662
|
// 6b. Reconcile worktree HEAD with milestone branch ref (#1846).
|
|
@@ -1790,17 +1857,7 @@ export function mergeMilestoneToMain(originalBasePath_, milestoneId, roadmapCont
|
|
|
1790
1857
|
// or interrupted operation) causes `git merge --squash` to refuse with
|
|
1791
1858
|
// "fatal: You have not concluded your merge (MERGE_HEAD exists)".
|
|
1792
1859
|
// Defensively remove merge artifacts before starting.
|
|
1793
|
-
|
|
1794
|
-
const gitDir_ = resolveGitDir(originalBasePath_);
|
|
1795
|
-
for (const f of ["SQUASH_MSG", "MERGE_MSG", "MERGE_HEAD"]) {
|
|
1796
|
-
const p = join(gitDir_, f);
|
|
1797
|
-
if (existsSync(p))
|
|
1798
|
-
unlinkSync(p);
|
|
1799
|
-
}
|
|
1800
|
-
}
|
|
1801
|
-
catch (err) { /* best-effort */
|
|
1802
|
-
logError("worktree", `merge state cleanup failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
1803
|
-
}
|
|
1860
|
+
removeMergeStateFiles(originalBasePath_, "pre-merge");
|
|
1804
1861
|
// 8. Squash merge — auto-resolve .gsd/ state file conflicts (#530)
|
|
1805
1862
|
const mergeResult = nativeMergeSquash(originalBasePath_, milestoneBranch);
|
|
1806
1863
|
if (!mergeResult.success) {
|
|
@@ -1810,17 +1867,7 @@ export function mergeMilestoneToMain(originalBasePath_, milestoneId, roadmapCont
|
|
|
1810
1867
|
if (mergeResult.conflicts.includes("__dirty_working_tree__")) {
|
|
1811
1868
|
// Defensively clean merge state — the native path may leave MERGE_HEAD
|
|
1812
1869
|
// even when the merge is rejected (#2912).
|
|
1813
|
-
|
|
1814
|
-
const gitDir_ = resolveGitDir(originalBasePath_);
|
|
1815
|
-
for (const f of ["SQUASH_MSG", "MERGE_MSG", "MERGE_HEAD"]) {
|
|
1816
|
-
const p = join(gitDir_, f);
|
|
1817
|
-
if (existsSync(p))
|
|
1818
|
-
unlinkSync(p);
|
|
1819
|
-
}
|
|
1820
|
-
}
|
|
1821
|
-
catch (err) { /* best-effort */
|
|
1822
|
-
logError("worktree", `merge state cleanup failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
1823
|
-
}
|
|
1870
|
+
removeMergeStateFiles(originalBasePath_, "dirty-tree rejection");
|
|
1824
1871
|
// Pop stash before throwing so local work is not lost.
|
|
1825
1872
|
if (stashed) {
|
|
1826
1873
|
try {
|
|
@@ -1869,26 +1916,7 @@ export function mergeMilestoneToMain(originalBasePath_, milestoneId, roadmapCont
|
|
|
1869
1916
|
}
|
|
1870
1917
|
// If there are still real code conflicts, escalate
|
|
1871
1918
|
if (codeConflicts.length > 0) {
|
|
1872
|
-
|
|
1873
|
-
// libgit2's merge creates MERGE_HEAD even for squash merges; if left
|
|
1874
|
-
// dangling, subsequent merges fail and doctor reports corrupt state.
|
|
1875
|
-
try {
|
|
1876
|
-
nativeMergeAbort(originalBasePath_);
|
|
1877
|
-
}
|
|
1878
|
-
catch (err) { /* best-effort */
|
|
1879
|
-
logError("worktree", `git merge-abort failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
1880
|
-
}
|
|
1881
|
-
try {
|
|
1882
|
-
const gitDir_ = resolveGitDir(originalBasePath_);
|
|
1883
|
-
for (const f of ["SQUASH_MSG", "MERGE_MSG", "MERGE_HEAD"]) {
|
|
1884
|
-
const p = join(gitDir_, f);
|
|
1885
|
-
if (existsSync(p))
|
|
1886
|
-
unlinkSync(p);
|
|
1887
|
-
}
|
|
1888
|
-
}
|
|
1889
|
-
catch (err) { /* best-effort */
|
|
1890
|
-
logError("worktree", `merge state file cleanup failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
1891
|
-
}
|
|
1919
|
+
cleanupSquashConflictState(originalBasePath_);
|
|
1892
1920
|
// Pop stash before throwing so local work is not lost (#2151).
|
|
1893
1921
|
if (stashed) {
|
|
1894
1922
|
try {
|
|
@@ -1919,17 +1947,7 @@ export function mergeMilestoneToMain(originalBasePath_, milestoneId, roadmapCont
|
|
|
1919
1947
|
// of which trigger git's SQUASH_MSG cleanup. MERGE_HEAD is created by
|
|
1920
1948
|
// libgit2's merge even in squash mode and is not removed by nativeCommit.
|
|
1921
1949
|
// If left on disk, doctor reports `corrupt_merge_state` on every subsequent run.
|
|
1922
|
-
|
|
1923
|
-
const gitDir_ = resolveGitDir(originalBasePath_);
|
|
1924
|
-
for (const f of ["SQUASH_MSG", "MERGE_MSG", "MERGE_HEAD"]) {
|
|
1925
|
-
const p = join(gitDir_, f);
|
|
1926
|
-
if (existsSync(p))
|
|
1927
|
-
unlinkSync(p);
|
|
1928
|
-
}
|
|
1929
|
-
}
|
|
1930
|
-
catch (err) { /* best-effort */
|
|
1931
|
-
logError("worktree", `post-commit merge state cleanup failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
1932
|
-
}
|
|
1950
|
+
removeMergeStateFiles(originalBasePath_, "post-commit");
|
|
1933
1951
|
// 9a-ii. Restore stashed files now that the merge+commit is complete (#2151).
|
|
1934
1952
|
// Pop after commit so stashed changes do not interfere with the squash merge
|
|
1935
1953
|
// or the commit content. Conflict on pop is non-fatal — the stash entry is
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
// Project/App: GSD-2
|
|
2
|
+
// File Purpose: Auto-mode orchestration, session lifecycle, and stop handling.
|
|
1
3
|
/**
|
|
2
4
|
* GSD Auto Mode — Fresh Session Per Unit
|
|
3
5
|
*
|
|
@@ -162,6 +164,12 @@ function restoreProjectRootEnv() {
|
|
|
162
164
|
s.hadProjectRootEnv = false;
|
|
163
165
|
s.projectRootEnvCaptured = false;
|
|
164
166
|
}
|
|
167
|
+
export function _captureProjectRootEnvForTest(projectRoot) {
|
|
168
|
+
captureProjectRootEnv(projectRoot);
|
|
169
|
+
}
|
|
170
|
+
export function _restoreProjectRootEnvForTest() {
|
|
171
|
+
restoreProjectRootEnv();
|
|
172
|
+
}
|
|
165
173
|
function captureMilestoneLockEnv(milestoneId) {
|
|
166
174
|
if (!s.milestoneLockEnvCaptured) {
|
|
167
175
|
s.hadMilestoneLockEnv = Object.prototype.hasOwnProperty.call(process.env, "GSD_MILESTONE_LOCK");
|
|
@@ -239,6 +247,11 @@ function synthesizePausedSessionRecovery(basePath, unitType, unitId, sessionFile
|
|
|
239
247
|
export function _synthesizePausedSessionRecoveryForTest(basePath, unitType, unitId, sessionFile) {
|
|
240
248
|
return synthesizePausedSessionRecovery(basePath, unitType, unitId, sessionFile);
|
|
241
249
|
}
|
|
250
|
+
export function _resolvePausedResumeBasePathForTest(basePath, pausedWorktreePath, pathExists = existsSync) {
|
|
251
|
+
return pausedWorktreePath && pathExists(pausedWorktreePath)
|
|
252
|
+
? pausedWorktreePath
|
|
253
|
+
: basePath;
|
|
254
|
+
}
|
|
242
255
|
const DETACHED_AUTO_KEEPALIVE_INTERVAL_MS = 30_000;
|
|
243
256
|
function withDetachedAutoKeepalive(run) {
|
|
244
257
|
const keepAlive = setInterval(() => { }, DETACHED_AUTO_KEEPALIVE_INTERVAL_MS);
|
|
@@ -415,6 +428,20 @@ export function _warnIfWorktreeMissingForTest(worktreePath, milestoneId) {
|
|
|
415
428
|
export function isAutoPaused() {
|
|
416
429
|
return s.paused;
|
|
417
430
|
}
|
|
431
|
+
export async function refreshResumeResourcesAndDb(basePath, deps = {}) {
|
|
432
|
+
const env = deps.env ?? process.env;
|
|
433
|
+
const importModule = deps.importModule ?? ((specifier) => import(specifier));
|
|
434
|
+
const agentDir = env.GSD_CODING_AGENT_DIR || join(gsdHome(), "agent");
|
|
435
|
+
const pkgRoot = env.GSD_PKG_ROOT;
|
|
436
|
+
const resourceLoaderPath = pkgRoot
|
|
437
|
+
? pathToFileURL(join(pkgRoot, "dist", "resource-loader.js")).href
|
|
438
|
+
: new URL("../../../resource-loader.js", import.meta.url).href;
|
|
439
|
+
const { initResources } = await importModule(resourceLoaderPath);
|
|
440
|
+
initResources(agentDir);
|
|
441
|
+
const { primeCache } = await importModule("./prompt-loader.js");
|
|
442
|
+
primeCache();
|
|
443
|
+
await (deps.openProjectDb ?? openProjectDbIfPresent)(basePath);
|
|
444
|
+
}
|
|
418
445
|
export function setActiveEngineId(id) {
|
|
419
446
|
s.activeEngineId = id;
|
|
420
447
|
}
|
|
@@ -618,7 +645,21 @@ function handleLostSessionLock(ctx, lockStatus) {
|
|
|
618
645
|
* the stale unit state, progress widget, status badge, and restores CWD so
|
|
619
646
|
* the dashboard does not show an orphaned timer and the shell is usable.
|
|
620
647
|
*/
|
|
621
|
-
function
|
|
648
|
+
export async function rerootCommandSession(cmdCtx, workspaceRoot) {
|
|
649
|
+
if (!cmdCtx || !workspaceRoot)
|
|
650
|
+
return { status: "skipped" };
|
|
651
|
+
try {
|
|
652
|
+
const result = await cmdCtx.newSession({ workspaceRoot });
|
|
653
|
+
return result.cancelled ? { status: "cancelled" } : { status: "ok" };
|
|
654
|
+
}
|
|
655
|
+
catch (err) {
|
|
656
|
+
return {
|
|
657
|
+
status: "failed",
|
|
658
|
+
error: err instanceof Error ? err.message : String(err),
|
|
659
|
+
};
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
export async function cleanupAfterLoopExit(ctx) {
|
|
622
663
|
s.currentUnit = null;
|
|
623
664
|
s.active = false;
|
|
624
665
|
deactivateGSD();
|
|
@@ -657,6 +698,26 @@ function cleanupAfterLoopExit(ctx) {
|
|
|
657
698
|
logWarning("engine", `chdir failed: ${err instanceof Error ? err.message : String(err)}`, { file: "auto.ts" });
|
|
658
699
|
}
|
|
659
700
|
}
|
|
701
|
+
if (s.originalBasePath && s.cmdCtx) {
|
|
702
|
+
const result = await rerootCommandSession(s.cmdCtx, s.basePath);
|
|
703
|
+
if (result.status === "cancelled") {
|
|
704
|
+
logWarning("engine", "post-loop session re-root was cancelled", { file: "auto.ts", basePath: s.basePath });
|
|
705
|
+
}
|
|
706
|
+
else if (result.status === "failed") {
|
|
707
|
+
logWarning("engine", `post-loop session re-root failed: ${result.error ?? "unknown"}`, { file: "auto.ts", basePath: s.basePath });
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
export function _cleanupAfterLoopExitForTest(ctx) {
|
|
712
|
+
return cleanupAfterLoopExit(ctx);
|
|
713
|
+
}
|
|
714
|
+
export function _resolveAutoWorktreeExitActionForTest(currentMilestoneId, milestoneMergedInPhases, milestoneComplete) {
|
|
715
|
+
const action = _selectStopAutoWorktreeExit({
|
|
716
|
+
currentMilestoneId: currentMilestoneId ?? null,
|
|
717
|
+
milestoneComplete,
|
|
718
|
+
milestoneMergedInPhases,
|
|
719
|
+
});
|
|
720
|
+
return action === "none" ? "skip" : action;
|
|
660
721
|
}
|
|
661
722
|
export async function stopAuto(ctx, pi, reason) {
|
|
662
723
|
if (!s.active && !s.paused)
|
|
@@ -797,11 +858,16 @@ export async function stopAuto(ctx, pi, reason) {
|
|
|
797
858
|
// Non-fatal — fall through to preserveBranch path
|
|
798
859
|
logWarning("engine", `milestone summary check failed: ${err instanceof Error ? err.message : String(err)}`, { file: "auto.ts" });
|
|
799
860
|
}
|
|
800
|
-
|
|
861
|
+
const exitAction = _selectStopAutoWorktreeExit({
|
|
862
|
+
currentMilestoneId: s.currentMilestoneId,
|
|
863
|
+
milestoneComplete,
|
|
864
|
+
milestoneMergedInPhases: s.milestoneMergedInPhases,
|
|
865
|
+
});
|
|
866
|
+
if (exitAction === "merge") {
|
|
801
867
|
// Milestone is complete — merge worktree branch back to main
|
|
802
868
|
resolver.mergeAndExit(s.currentMilestoneId, notifyCtx);
|
|
803
869
|
}
|
|
804
|
-
else {
|
|
870
|
+
else if (exitAction === "preserve") {
|
|
805
871
|
// Milestone still in progress — preserve branch for later resumption
|
|
806
872
|
resolver.exitMilestone(s.currentMilestoneId, notifyCtx, {
|
|
807
873
|
preserveBranch: true,
|
|
@@ -810,6 +876,7 @@ export async function stopAuto(ctx, pi, reason) {
|
|
|
810
876
|
}
|
|
811
877
|
}
|
|
812
878
|
catch (e) {
|
|
879
|
+
ctx?.ui.notify(`Worktree cleanup failed for ${s.currentMilestoneId ?? "current milestone"}: ${e instanceof Error ? e.message : String(e)}. Resolve the preserved branch/worktree and run /gsd auto to resume.`, "warning");
|
|
813
880
|
debugLog("stop-cleanup-worktree", { error: e instanceof Error ? e.message : String(e) });
|
|
814
881
|
}
|
|
815
882
|
// ── Step 5: Rebuild state while DB is still open (#3599) ──
|
|
@@ -860,14 +927,12 @@ export async function stopAuto(ctx, pi, reason) {
|
|
|
860
927
|
// its own cwd for tools and system prompt; refresh it before returning to the
|
|
861
928
|
// user so follow-up commands do not target a removed milestone worktree.
|
|
862
929
|
if (s.originalBasePath && ctx && s.cmdCtx) {
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
logWarning("engine", "post-stop session re-root was cancelled", { file: "auto.ts", basePath: s.basePath });
|
|
867
|
-
}
|
|
930
|
+
const result = await rerootCommandSession(s.cmdCtx, s.basePath);
|
|
931
|
+
if (result.status === "cancelled") {
|
|
932
|
+
logWarning("engine", "post-stop session re-root was cancelled", { file: "auto.ts", basePath: s.basePath });
|
|
868
933
|
}
|
|
869
|
-
|
|
870
|
-
logWarning("engine", `post-stop session re-root failed: ${
|
|
934
|
+
else if (result.status === "failed") {
|
|
935
|
+
logWarning("engine", `post-stop session re-root failed: ${result.error ?? "unknown"}`, { file: "auto.ts", basePath: s.basePath });
|
|
871
936
|
}
|
|
872
937
|
}
|
|
873
938
|
// ── Step 8: Ledger notification ──
|
|
@@ -995,6 +1060,11 @@ export async function stopAuto(ctx, pi, reason) {
|
|
|
995
1060
|
s.reset();
|
|
996
1061
|
}
|
|
997
1062
|
}
|
|
1063
|
+
export function _selectStopAutoWorktreeExit(args) {
|
|
1064
|
+
if (!args.currentMilestoneId || args.milestoneMergedInPhases)
|
|
1065
|
+
return "none";
|
|
1066
|
+
return args.milestoneComplete ? "merge" : "preserve";
|
|
1067
|
+
}
|
|
998
1068
|
/**
|
|
999
1069
|
* Pause auto-mode without destroying state. Context is preserved.
|
|
1000
1070
|
* The user can interact with the agent, then `/gsd auto` resumes
|
|
@@ -1585,9 +1655,7 @@ export async function startAuto(ctx, pi, base, verboseMode, options) {
|
|
|
1585
1655
|
if (resumeWorktreePath && !existsSync(resumeWorktreePath)) {
|
|
1586
1656
|
logWarning("session", `Worktree was expected at ${resumeWorktreePath} but is missing. Continuing in project-root mode. To restart with a fresh worktree, run /gsd-debug or recreate the milestone.`, { file: "auto.ts", milestoneId: s.currentMilestoneId ?? "" });
|
|
1587
1657
|
}
|
|
1588
|
-
|
|
1589
|
-
s.basePath = resumeWorktreePath;
|
|
1590
|
-
}
|
|
1658
|
+
s.basePath = _resolvePausedResumeBasePathForTest(base, resumeWorktreePath);
|
|
1591
1659
|
// Rebuild scope now that s.basePath reflects the actual worktree (or project root).
|
|
1592
1660
|
rebuildScope(s.basePath, s.currentMilestoneId);
|
|
1593
1661
|
// Ensure the workflow-logger audit log is pinned to the project root
|
|
@@ -1632,20 +1700,7 @@ export async function startAuto(ctx, pi, base, verboseMode, options) {
|
|
|
1632
1700
|
// tree; deployed extensions live at ~/.gsd/agent/extensions/gsd/ where the
|
|
1633
1701
|
// relative path resolves to ~/.gsd/agent/resource-loader.js which doesn't exist.
|
|
1634
1702
|
// Using GSD_PKG_ROOT constructs a correct absolute path in both contexts (#3949).
|
|
1635
|
-
|
|
1636
|
-
const pkgRoot = process.env.GSD_PKG_ROOT;
|
|
1637
|
-
const resourceLoaderPath = pkgRoot
|
|
1638
|
-
? pathToFileURL(join(pkgRoot, "dist", "resource-loader.js")).href
|
|
1639
|
-
: new URL("../../../resource-loader.js", import.meta.url).href;
|
|
1640
|
-
const { initResources } = await import(resourceLoaderPath);
|
|
1641
|
-
initResources(agentDir);
|
|
1642
|
-
// initResources() uses synchronous fs APIs, so the prompt-template cache
|
|
1643
|
-
// can be primed immediately — no need for the legacy 1s setTimeout deferral.
|
|
1644
|
-
const { primeCache } = await import("./prompt-loader.js");
|
|
1645
|
-
primeCache();
|
|
1646
|
-
// Open the project DB before rebuild/derive so resume uses DB-backed
|
|
1647
|
-
// state instead of falling back to stale markdown parsing (#2940).
|
|
1648
|
-
await openProjectDbIfPresent(s.basePath);
|
|
1703
|
+
await refreshResumeResourcesAndDb(s.basePath);
|
|
1649
1704
|
try {
|
|
1650
1705
|
await rebuildState(s.basePath);
|
|
1651
1706
|
pi.events.emit(CMUX_CHANNELS.SIDEBAR, { action: "sync", preferences: loadEffectiveGSDPreferences(s.basePath || undefined)?.preferences, state: await deriveState(s.basePath) });
|
|
@@ -1698,7 +1753,7 @@ export async function startAuto(ctx, pi, base, verboseMode, options) {
|
|
|
1698
1753
|
runKernelLoop: runUokKernelLoop,
|
|
1699
1754
|
runLegacyLoop: runLegacyAutoLoop,
|
|
1700
1755
|
});
|
|
1701
|
-
cleanupAfterLoopExit(ctx);
|
|
1756
|
+
await cleanupAfterLoopExit(ctx);
|
|
1702
1757
|
return;
|
|
1703
1758
|
}
|
|
1704
1759
|
// ── Fresh start path — delegated to auto-start.ts ──
|
|
@@ -1745,7 +1800,7 @@ export async function startAuto(ctx, pi, base, verboseMode, options) {
|
|
|
1745
1800
|
runKernelLoop: runUokKernelLoop,
|
|
1746
1801
|
runLegacyLoop: runLegacyAutoLoop,
|
|
1747
1802
|
});
|
|
1748
|
-
cleanupAfterLoopExit(ctx);
|
|
1803
|
+
await cleanupAfterLoopExit(ctx);
|
|
1749
1804
|
}
|
|
1750
1805
|
// describeNextUnit is imported from auto-dashboard.ts and re-exported
|
|
1751
1806
|
export { describeNextUnit } from "./auto-dashboard.js";
|
|
@@ -5,7 +5,7 @@ import { clearPathCache } from "../paths.js";
|
|
|
5
5
|
import { getAutoDashboardData, getAutoModeStartModel, isAutoActive, pauseAuto, setCurrentDispatchedModelId } from "../auto.js";
|
|
6
6
|
import { getNextFallbackModel, resolveModelWithFallbacksForUnit } from "../preferences.js";
|
|
7
7
|
import { pauseAutoForProviderError } from "../provider-error-pause.js";
|
|
8
|
-
import { isSessionSwitchInFlight, resolveAgentEnd, resolveAgentEndCancelled } from "../auto/resolve.js";
|
|
8
|
+
import { isSessionSwitchAbortGraceActive, isSessionSwitchInFlight, resolveAgentEnd, resolveAgentEndCancelled, } from "../auto/resolve.js";
|
|
9
9
|
import { resolveModelId } from "../auto-model-selection.js";
|
|
10
10
|
import { resolveProjectRoot } from "../worktree.js";
|
|
11
11
|
import { clearDiscussionFlowState } from "./write-gate.js";
|
|
@@ -53,6 +53,41 @@ export function isUserInitiatedAbortMessage(message) {
|
|
|
53
53
|
return false;
|
|
54
54
|
return /\b(?:claude code process aborted by user|request aborted by user|process aborted by user)\b/i.test(message);
|
|
55
55
|
}
|
|
56
|
+
function isBareClaudeCodeSessionSwitchAbortMarker(message) {
|
|
57
|
+
if (!message)
|
|
58
|
+
return false;
|
|
59
|
+
const normalized = message.trim().replace(/\s+/g, " ").toLowerCase();
|
|
60
|
+
return normalized === "claude code process aborted by user"
|
|
61
|
+
|| normalized === "request aborted by user"
|
|
62
|
+
|| normalized === "process aborted by user"
|
|
63
|
+
|| normalized === "claude code stream aborted by caller";
|
|
64
|
+
}
|
|
65
|
+
function readAssistantTextContent(content) {
|
|
66
|
+
if (!Array.isArray(content))
|
|
67
|
+
return "";
|
|
68
|
+
return content
|
|
69
|
+
.map((block) => {
|
|
70
|
+
if (!block || typeof block !== "object")
|
|
71
|
+
return "";
|
|
72
|
+
const text = block.text;
|
|
73
|
+
return typeof text === "string" ? text : "";
|
|
74
|
+
})
|
|
75
|
+
.filter(Boolean)
|
|
76
|
+
.join("\n");
|
|
77
|
+
}
|
|
78
|
+
export function isClaudeCodeSessionSwitchAbortMessage(lastMsg) {
|
|
79
|
+
if (!lastMsg || typeof lastMsg !== "object")
|
|
80
|
+
return false;
|
|
81
|
+
const m = lastMsg;
|
|
82
|
+
const carriers = [
|
|
83
|
+
m.errorMessage ? String(m.errorMessage) : "",
|
|
84
|
+
readAssistantTextContent(m.content),
|
|
85
|
+
].filter((value) => value.trim().length > 0);
|
|
86
|
+
if ((m.stopReason === "error" || m.stopReason === "aborted") && carriers.length > 0) {
|
|
87
|
+
return carriers.every(isBareClaudeCodeSessionSwitchAbortMarker);
|
|
88
|
+
}
|
|
89
|
+
return false;
|
|
90
|
+
}
|
|
56
91
|
/**
|
|
57
92
|
* Resolve an agent_end event observed while a session switch is in flight.
|
|
58
93
|
*
|
|
@@ -65,18 +100,23 @@ export function isUserInitiatedAbortMessage(message) {
|
|
|
65
100
|
* "Auto-mode stopped — Unit aborted: Claude Code process aborted by user"
|
|
66
101
|
* even though no user input occurred.
|
|
67
102
|
*
|
|
68
|
-
*
|
|
69
|
-
* the session-switch is in flight: the abort is the expected side-effect
|
|
70
|
-
* the transition, not a user signal. Other branches (genuine `stopReason
|
|
71
|
-
* "aborted"` with content/errorMessage) preserve the prior
|
|
103
|
+
* Claude Code abort markers are intentionally ignored when the abort fires
|
|
104
|
+
* while the session-switch is in flight: the abort is the expected side-effect
|
|
105
|
+
* of the transition, not a user signal. Other branches (genuine `stopReason
|
|
106
|
+
* === "aborted"` with diagnostic content/errorMessage) preserve the prior
|
|
107
|
+
* behavior.
|
|
72
108
|
*/
|
|
73
109
|
export function _handleSessionSwitchAgentEnd(lastMsg, resolveCancelled) {
|
|
74
110
|
if (!lastMsg || typeof lastMsg !== "object")
|
|
75
111
|
return;
|
|
76
112
|
const m = lastMsg;
|
|
113
|
+
if (isClaudeCodeSessionSwitchAbortMessage(m)) {
|
|
114
|
+
// Internal abort from in-flight session transition — drop on the floor.
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
77
117
|
if (m.stopReason === "error") {
|
|
78
118
|
const rawErrorMsg = m.errorMessage ? String(m.errorMessage) : "";
|
|
79
|
-
if (
|
|
119
|
+
if (isBareClaudeCodeSessionSwitchAbortMarker(rawErrorMsg)) {
|
|
80
120
|
// Internal abort from in-flight session transition — drop on the floor.
|
|
81
121
|
return;
|
|
82
122
|
}
|
|
@@ -91,6 +131,15 @@ export function _handleSessionSwitchAgentEnd(lastMsg, resolveCancelled) {
|
|
|
91
131
|
}
|
|
92
132
|
}
|
|
93
133
|
}
|
|
134
|
+
export function resolveAgentEndErrorDisplay(rawErrorMsg, content) {
|
|
135
|
+
const isUseless = !rawErrorMsg || /^(success|ok|true|error|unknown)$/i.test(rawErrorMsg.trim());
|
|
136
|
+
if (isUseless && Array.isArray(content)) {
|
|
137
|
+
const textBlock = content.find((b) => b.type === "text" && b.text);
|
|
138
|
+
if (textBlock)
|
|
139
|
+
return textBlock.text.slice(0, 300);
|
|
140
|
+
}
|
|
141
|
+
return rawErrorMsg;
|
|
142
|
+
}
|
|
94
143
|
async function pauseTransientWithBackoff(cls, pi, ctx, errorDetail, isRateLimit) {
|
|
95
144
|
retryState.consecutiveTransientCount += 1;
|
|
96
145
|
const baseRetryAfterMs = "retryAfterMs" in cls ? cls.retryAfterMs : 15_000;
|
|
@@ -161,6 +210,12 @@ export async function handleAgentEnd(pi, event, ctx) {
|
|
|
161
210
|
_handleSessionSwitchAgentEnd(lastMsg, resolveAgentEndCancelled);
|
|
162
211
|
return;
|
|
163
212
|
}
|
|
213
|
+
if (isSessionSwitchAbortGraceActive() && isClaudeCodeSessionSwitchAbortMessage(lastMsg)) {
|
|
214
|
+
// Claude Code can report the abort from `newSession()` a few hundred ms
|
|
215
|
+
// after the guard drops. That event belongs to the old turn; do not let it
|
|
216
|
+
// cancel the freshly-dispatched unit.
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
164
219
|
if (lastMsg && "stopReason" in lastMsg && lastMsg.stopReason === "aborted") {
|
|
165
220
|
// Empty content with aborted stopReason is a non-fatal agent stop (the LLM
|
|
166
221
|
// chose to end without producing output). Only pause on genuine fatal aborts
|
|
@@ -204,16 +259,10 @@ export async function handleAgentEnd(pi, event, ctx) {
|
|
|
204
259
|
});
|
|
205
260
|
return;
|
|
206
261
|
}
|
|
207
|
-
const isUseless = !rawErrorMsg || /^(success|ok|true|error|unknown)$/i.test(rawErrorMsg.trim());
|
|
208
262
|
// #3588: When errorMessage is uninformative, extract the real error from
|
|
209
263
|
// the assistant message text content for display purposes only.
|
|
210
264
|
// Classification still uses rawErrorMsg to avoid false positives from prose.
|
|
211
|
-
|
|
212
|
-
if (isUseless && "content" in lastMsg && Array.isArray(lastMsg.content)) {
|
|
213
|
-
const textBlock = lastMsg.content.find((b) => b.type === "text" && b.text);
|
|
214
|
-
if (textBlock)
|
|
215
|
-
displayMsg = textBlock.text.slice(0, 300);
|
|
216
|
-
}
|
|
265
|
+
const displayMsg = resolveAgentEndErrorDisplay(rawErrorMsg, "content" in lastMsg ? lastMsg.content : undefined);
|
|
217
266
|
const errorDetail = displayMsg ? `: ${displayMsg}` : "";
|
|
218
267
|
const explicitRetryAfterMs = ("retryAfterMs" in lastMsg && typeof lastMsg.retryAfterMs === "number") ? lastMsg.retryAfterMs : undefined;
|
|
219
268
|
// ── 1. Classify using rawErrorMsg to avoid prose false-positives ────
|