gsd-pi 2.80.0-dev.2848d9009 → 2.80.0-dev.3065f7bfa
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/README.md +4 -2
- package/dist/resources/.managed-resources-content-hash +1 -1
- package/dist/resources/extensions/gsd/auto/loop.js +32 -1
- package/dist/resources/extensions/gsd/auto/phases.js +178 -108
- package/dist/resources/extensions/gsd/auto/resolve.js +17 -0
- package/dist/resources/extensions/gsd/auto/run-unit.js +20 -30
- package/dist/resources/extensions/gsd/auto/session.js +8 -0
- 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 +17 -4
- package/dist/resources/extensions/gsd/auto-prompts.js +103 -16
- package/dist/resources/extensions/gsd/auto-recovery.js +43 -1
- package/dist/resources/extensions/gsd/auto-start.js +197 -6
- package/dist/resources/extensions/gsd/auto-supervisor.js +8 -1
- package/dist/resources/extensions/gsd/auto-timeout-recovery.js +2 -2
- package/dist/resources/extensions/gsd/auto-worktree.js +111 -1
- package/dist/resources/extensions/gsd/auto.js +86 -26
- package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +42 -2
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +49 -36
- package/dist/resources/extensions/gsd/bootstrap/dynamic-tools.js +15 -5
- package/dist/resources/extensions/gsd/bootstrap/exec-tools.js +33 -20
- package/dist/resources/extensions/gsd/bootstrap/journal-tools.js +7 -1
- package/dist/resources/extensions/gsd/bootstrap/memory-tools.js +9 -3
- package/dist/resources/extensions/gsd/bootstrap/query-tools.js +8 -2
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +259 -28
- 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.js +23 -9
- package/dist/resources/extensions/gsd/context-budget.js +37 -2
- package/dist/resources/extensions/gsd/crash-recovery.js +56 -10
- package/dist/resources/extensions/gsd/db/unit-dispatches.js +39 -0
- package/dist/resources/extensions/gsd/db-base-schema.js +4 -2
- package/dist/resources/extensions/gsd/db-migration-steps.js +6 -0
- package/dist/resources/extensions/gsd/ecosystem/gsd-extension-api.js +2 -0
- package/dist/resources/extensions/gsd/git-service.js +36 -4
- package/dist/resources/extensions/gsd/gsd-db.js +46 -13
- package/dist/resources/extensions/gsd/guided-flow.js +99 -38
- package/dist/resources/extensions/gsd/memory-store.js +69 -12
- package/dist/resources/extensions/gsd/migrate/command.js +40 -1
- package/dist/resources/extensions/gsd/migration-auto-check.js +87 -0
- 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/planning-path-scope.js +26 -0
- package/dist/resources/extensions/gsd/pre-execution-checks.js +22 -0
- package/dist/resources/extensions/gsd/prompt-loader.js +28 -2
- package/dist/resources/extensions/gsd/prompts/complete-milestone.md +16 -13
- 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/parallel-research-slices.md +1 -1
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/quick-task.md +1 -5
- package/dist/resources/extensions/gsd/prompts/replan-slice.md +2 -2
- package/dist/resources/extensions/gsd/prompts/validate-milestone.md +2 -2
- package/dist/resources/extensions/gsd/quick.js +34 -2
- package/dist/resources/extensions/gsd/tools/context-mode-tool-result.js +15 -0
- package/dist/resources/extensions/gsd/tools/exec-search-tool.js +5 -0
- package/dist/resources/extensions/gsd/tools/exec-tool.js +3 -15
- package/dist/resources/extensions/gsd/tools/memory-tools.js +1 -0
- package/dist/resources/extensions/gsd/tools/plan-slice.js +9 -0
- package/dist/resources/extensions/gsd/tools/plan-task.js +9 -0
- package/dist/resources/extensions/gsd/tools/resume-tool.js +5 -0
- package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +1 -1
- package/dist/resources/extensions/gsd/unit-context-composer.js +12 -3
- package/dist/resources/extensions/gsd/unit-runtime.js +22 -0
- package/dist/resources/extensions/gsd/workflow-protocol.js +131 -0
- package/dist/resources/extensions/gsd/worktree-resolver.js +68 -21
- 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 +15 -15
- package/dist/web/standalone/.next/build-manifest.json +2 -2
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +15 -15
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/pages/404.html +1 -1
- package/dist/web/standalone/.next/server/pages/500.html +1 -1
- package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
- package/package.json +3 -3
- package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.js +22 -17
- package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
- package/packages/mcp-server/src/workflow-tools.test.ts +75 -2
- package/packages/mcp-server/src/workflow-tools.ts +30 -16
- package/packages/mcp-server/tsconfig.tsbuildinfo +1 -1
- package/packages/native/tsconfig.tsbuildinfo +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-coding-agent/dist/core/agent-session-abort-order.test.js +32 -0
- package/packages/pi-coding-agent/dist/core/agent-session-abort-order.test.js.map +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 +44 -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/compaction/compaction.d.ts +11 -0
- package/packages/pi-coding-agent/dist/core/compaction/compaction.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/compaction/compaction.js +9 -0
- package/packages/pi-coding-agent/dist/core/compaction/compaction.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/compaction-threshold.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/compaction-threshold.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/compaction-threshold.test.js +103 -0
- package/packages/pi-coding-agent/dist/core/compaction-threshold.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/db-snapshot.d.ts +15 -0
- package/packages/pi-coding-agent/dist/core/db-snapshot.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/db-snapshot.js +66 -0
- package/packages/pi-coding-agent/dist/core/db-snapshot.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/db-snapshot.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/db-snapshot.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/db-snapshot.test.js +24 -0
- package/packages/pi-coding-agent/dist/core/db-snapshot.test.js.map +1 -0
- 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 +3 -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 +6 -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 +5 -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 +39 -1
- 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/settings-manager.d.ts +20 -0
- package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.js +25 -0
- package/packages/pi-coding-agent/dist/core/settings-manager.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/modes/interactive/components/tool-execution.d.ts +1 -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 +3 -0
- 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 +13 -5
- 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 +53 -0
- 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.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +3 -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.d.ts +2 -0
- package/packages/pi-coding-agent/dist/resources/extensions/memory/storage-safety-guard.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/resources/extensions/memory/storage-safety-guard.test.js +10 -0
- package/packages/pi-coding-agent/dist/resources/extensions/memory/storage-safety-guard.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.js +3 -2
- package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.js.map +1 -1
- package/packages/pi-coding-agent/src/core/agent-session-abort-order.test.ts +36 -0
- 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 +48 -7
- package/packages/pi-coding-agent/src/core/chat-controller-ordering.test.ts +3 -1
- package/packages/pi-coding-agent/src/core/compaction/compaction.ts +18 -0
- package/packages/pi-coding-agent/src/core/compaction-threshold.test.ts +121 -0
- package/packages/pi-coding-agent/src/core/db-snapshot.test.ts +32 -0
- package/packages/pi-coding-agent/src/core/db-snapshot.ts +66 -0
- package/packages/pi-coding-agent/src/core/extensions/loader.ts +10 -0
- package/packages/pi-coding-agent/src/core/extensions/runner.test.ts +5 -3
- package/packages/pi-coding-agent/src/core/extensions/runner.ts +8 -5
- package/packages/pi-coding-agent/src/core/extensions/types.ts +42 -1
- 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/settings-manager.ts +39 -1
- 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/modes/interactive/components/tool-execution.ts +4 -0
- package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.test.ts +56 -0
- package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +22 -7
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +3 -0
- package/packages/pi-coding-agent/src/resources/extensions/memory/storage-safety-guard.test.ts +14 -0
- package/packages/pi-coding-agent/src/resources/extensions/memory/storage.ts +3 -2
- package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-tui/dist/tui.d.ts.map +1 -1
- package/packages/pi-tui/dist/tui.js +18 -8
- package/packages/pi-tui/dist/tui.js.map +1 -1
- package/packages/pi-tui/src/tui.ts +20 -8
- package/packages/pi-tui/tsconfig.tsbuildinfo +1 -1
- package/src/resources/extensions/gsd/auto/loop-deps.ts +2 -2
- package/src/resources/extensions/gsd/auto/loop.ts +50 -8
- package/src/resources/extensions/gsd/auto/phases.ts +251 -172
- package/src/resources/extensions/gsd/auto/resolve.ts +23 -1
- package/src/resources/extensions/gsd/auto/run-unit.ts +25 -30
- package/src/resources/extensions/gsd/auto/session.ts +8 -0
- 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 +18 -4
- package/src/resources/extensions/gsd/auto-prompts.ts +112 -15
- package/src/resources/extensions/gsd/auto-recovery.ts +54 -0
- package/src/resources/extensions/gsd/auto-start.ts +230 -9
- package/src/resources/extensions/gsd/auto-supervisor.ts +7 -0
- package/src/resources/extensions/gsd/auto-timeout-recovery.ts +2 -2
- package/src/resources/extensions/gsd/auto-worktree.ts +123 -0
- package/src/resources/extensions/gsd/auto.ts +98 -21
- package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +49 -1
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +50 -36
- package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +16 -5
- package/src/resources/extensions/gsd/bootstrap/exec-tools.ts +34 -19
- package/src/resources/extensions/gsd/bootstrap/journal-tools.ts +8 -1
- package/src/resources/extensions/gsd/bootstrap/memory-tools.ts +10 -3
- package/src/resources/extensions/gsd/bootstrap/query-tools.ts +9 -2
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +305 -28
- 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.ts +34 -15
- package/src/resources/extensions/gsd/context-budget.ts +44 -2
- package/src/resources/extensions/gsd/crash-recovery.ts +67 -10
- package/src/resources/extensions/gsd/db/unit-dispatches.ts +41 -0
- package/src/resources/extensions/gsd/db-base-schema.ts +4 -2
- package/src/resources/extensions/gsd/db-migration-steps.ts +8 -0
- package/src/resources/extensions/gsd/ecosystem/gsd-extension-api.ts +3 -0
- package/src/resources/extensions/gsd/git-service.ts +46 -8
- package/src/resources/extensions/gsd/gsd-db.ts +50 -13
- package/src/resources/extensions/gsd/guided-flow.ts +123 -45
- package/src/resources/extensions/gsd/memory-store.ts +77 -12
- package/src/resources/extensions/gsd/migrate/command.ts +47 -1
- package/src/resources/extensions/gsd/migration-auto-check.ts +129 -0
- 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/planning-path-scope.ts +35 -0
- package/src/resources/extensions/gsd/pre-execution-checks.ts +23 -0
- package/src/resources/extensions/gsd/preferences-types.ts +1 -1
- package/src/resources/extensions/gsd/prompt-loader.ts +27 -2
- package/src/resources/extensions/gsd/prompts/complete-milestone.md +16 -13
- 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/parallel-research-slices.md +1 -1
- package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/quick-task.md +1 -5
- package/src/resources/extensions/gsd/prompts/replan-slice.md +2 -2
- package/src/resources/extensions/gsd/prompts/validate-milestone.md +2 -2
- package/src/resources/extensions/gsd/quick.ts +37 -2
- package/src/resources/extensions/gsd/tests/artifact-retry-cap.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +417 -10
- package/src/resources/extensions/gsd/tests/auto-phases-lifecycle.test.ts +56 -13
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +14 -1
- package/src/resources/extensions/gsd/tests/auto-wrapup-inflight-guard.test.ts +168 -6
- package/src/resources/extensions/gsd/tests/clean-root-preflight.test.ts +15 -6
- package/src/resources/extensions/gsd/tests/compaction-snapshot.test.ts +14 -1
- package/src/resources/extensions/gsd/tests/complete-milestone-excerpt.test.ts +31 -0
- package/src/resources/extensions/gsd/tests/complete-slice-composer.test.ts +3 -2
- package/src/resources/extensions/gsd/tests/context-budget.test.ts +10 -1
- package/src/resources/extensions/gsd/tests/context-store.test.ts +7 -1
- package/src/resources/extensions/gsd/tests/crash-handler-secondary.test.ts +55 -0
- package/src/resources/extensions/gsd/tests/crash-recovery-via-db.test.ts +22 -0
- package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +5 -1
- package/src/resources/extensions/gsd/tests/dispatch-rule-coverage.test.ts +313 -0
- package/src/resources/extensions/gsd/tests/exec-history.test.ts +15 -0
- package/src/resources/extensions/gsd/tests/exec-sandbox.test.ts +65 -0
- 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/integration/git-service.test.ts +54 -0
- package/src/resources/extensions/gsd/tests/isolation-none-branch-guard.test.ts +6 -3
- package/src/resources/extensions/gsd/tests/journal-integration.test.ts +239 -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/memory-decay-factor.test.ts +90 -0
- package/src/resources/extensions/gsd/tests/merge-conflict-stops-loop.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/migrate-writer-integration.test.ts +48 -0
- package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +127 -0
- package/src/resources/extensions/gsd/tests/milestone-merge-stash-restore.test.ts +242 -0
- package/src/resources/extensions/gsd/tests/native-git-bridge-exec-fallback.test.ts +34 -2
- 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/plan-slice.test.ts +50 -0
- package/src/resources/extensions/gsd/tests/plan-task.test.ts +21 -0
- package/src/resources/extensions/gsd/tests/pre-execution-checks.test.ts +45 -5
- package/src/resources/extensions/gsd/tests/prompt-duplication-cuts.test.ts +230 -0
- package/src/resources/extensions/gsd/tests/prompt-path-audit.test.ts +40 -0
- package/src/resources/extensions/gsd/tests/prompt-step-ordering.test.ts +19 -0
- package/src/resources/extensions/gsd/tests/query-tools-db-open.test.ts +3 -3
- package/src/resources/extensions/gsd/tests/quick-external-gsd.test.ts +40 -0
- package/src/resources/extensions/gsd/tests/restore-tools-after-discuss.test.ts +38 -17
- package/src/resources/extensions/gsd/tests/schema-v27-v28-sequence.test.ts +156 -0
- package/src/resources/extensions/gsd/tests/select-resumable-milestone.test.ts +96 -0
- package/src/resources/extensions/gsd/tests/session-switch-abort-misclassification.test.ts +106 -0
- package/src/resources/extensions/gsd/tests/signal-handlers.test.ts +27 -0
- package/src/resources/extensions/gsd/tests/smart-entry-complete.test.ts +20 -0
- package/src/resources/extensions/gsd/tests/stalled-tool-recovery.test.ts +49 -1
- package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +55 -0
- package/src/resources/extensions/gsd/tests/state-corruption-2945.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/status-db-open.test.ts +9 -0
- 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-tool-gating.test.ts +291 -0
- package/src/resources/extensions/gsd/tests/unit-context-composer.test.ts +136 -4
- package/src/resources/extensions/gsd/tests/unit-dispatches.test.ts +30 -0
- package/src/resources/extensions/gsd/tests/unit-runtime.test.ts +37 -0
- package/src/resources/extensions/gsd/tests/unstructured-continue-context-injection.test.ts +5 -4
- package/src/resources/extensions/gsd/tests/workflow-protocol-excerpt.test.ts +99 -0
- package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +3 -0
- package/src/resources/extensions/gsd/tests/worktree-journal-events.test.ts +1 -0
- 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 +167 -4
- package/src/resources/extensions/gsd/tools/context-mode-tool-result.ts +25 -0
- package/src/resources/extensions/gsd/tools/exec-search-tool.ts +7 -7
- package/src/resources/extensions/gsd/tools/exec-tool.ts +4 -23
- package/src/resources/extensions/gsd/tools/memory-tools.ts +1 -0
- package/src/resources/extensions/gsd/tools/plan-slice.ts +13 -0
- package/src/resources/extensions/gsd/tools/plan-task.ts +10 -0
- package/src/resources/extensions/gsd/tools/resume-tool.ts +7 -7
- package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +1 -1
- package/src/resources/extensions/gsd/unit-context-composer.ts +19 -4
- package/src/resources/extensions/gsd/unit-runtime.ts +25 -0
- package/src/resources/extensions/gsd/workflow-protocol.ts +160 -0
- package/src/resources/extensions/gsd/worktree-resolver.ts +85 -19
- package/src/resources/extensions/gsd/tests/phases-merge-error-stops-auto.test.ts +0 -97
- /package/dist/web/standalone/.next/static/{vaQ47E8aNlbbNEDoeME6G → O2WvnXROue6l7nAp_4dhC}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{vaQ47E8aNlbbNEDoeME6G → O2WvnXROue6l7nAp_4dhC}/_ssgManifest.js +0 -0
|
@@ -65,6 +65,7 @@ import { snapshotSkills } from "./skill-discovery.js";
|
|
|
65
65
|
import { isDbAvailable, getMilestone, openDatabase, getDbStatus } from "./gsd-db.js";
|
|
66
66
|
import { isClosedStatus } from "./status-guards.js";
|
|
67
67
|
import { classifyMilestoneSummaryContent } from "./milestone-summary-classifier.js";
|
|
68
|
+
import { auditOrphanedPreflightStashes } from "./orphan-stash-audit.js";
|
|
68
69
|
|
|
69
70
|
import {
|
|
70
71
|
debugLog,
|
|
@@ -332,6 +333,165 @@ export function auditOrphanedMilestoneBranches(
|
|
|
332
333
|
return { recovered, warnings };
|
|
333
334
|
}
|
|
334
335
|
|
|
336
|
+
/**
|
|
337
|
+
* Pure decision function for picking which orphan milestone the auto-loop
|
|
338
|
+
* should resume the merge transition for. Extracted so it can be unit-tested
|
|
339
|
+
* without spinning up a git repo or a SQLite DB.
|
|
340
|
+
*
|
|
341
|
+
* Returns the lexicographically-greatest milestone id (e.g. "M002" beats
|
|
342
|
+
* "M001") whose branch is unmerged AND has commits ahead of main AND whose
|
|
343
|
+
* status is `complete`. Lex-ordering matches the project's M00x convention,
|
|
344
|
+
* which is the most-recently-completed milestone in practice.
|
|
345
|
+
* `isComplete` errors propagate; `commitsAhead` errors are treated as 0.
|
|
346
|
+
*/
|
|
347
|
+
export function _selectResumableMilestone(
|
|
348
|
+
branchNames: readonly string[],
|
|
349
|
+
mergedBranches: ReadonlySet<string>,
|
|
350
|
+
isComplete: (milestoneId: string) => boolean,
|
|
351
|
+
commitsAhead: (branch: string) => number,
|
|
352
|
+
): string | null {
|
|
353
|
+
const candidates: string[] = [];
|
|
354
|
+
for (const branch of branchNames) {
|
|
355
|
+
if (!branch.startsWith("milestone/")) continue;
|
|
356
|
+
const milestoneId = branch.slice("milestone/".length);
|
|
357
|
+
if (mergedBranches.has(branch)) continue;
|
|
358
|
+
if (!isComplete(milestoneId)) continue;
|
|
359
|
+
let ahead = 0;
|
|
360
|
+
try {
|
|
361
|
+
ahead = commitsAhead(branch);
|
|
362
|
+
} catch {
|
|
363
|
+
continue;
|
|
364
|
+
}
|
|
365
|
+
if (ahead <= 0) continue;
|
|
366
|
+
candidates.push(milestoneId);
|
|
367
|
+
}
|
|
368
|
+
if (candidates.length === 0) return null;
|
|
369
|
+
candidates.sort();
|
|
370
|
+
return candidates[candidates.length - 1];
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
/**
|
|
374
|
+
* Find the most-recent completed milestone whose branch still has unmerged
|
|
375
|
+
* commits ahead of the integration branch. Used by `bootstrapAutoSession`
|
|
376
|
+
* to seed `s.currentMilestoneId` so the auto-loop's transition guard at
|
|
377
|
+
* `phases.ts:730` fires on the first iteration after a process restart —
|
|
378
|
+
* without this, the in-memory-only `s.currentMilestoneId` is `null` after
|
|
379
|
+
* restart, the guard short-circuits, and the orphaned milestone branch
|
|
380
|
+
* never gets merged into main (#5538-followup).
|
|
381
|
+
*
|
|
382
|
+
* Returns null when isolation is `none`, the DB is unavailable, or no
|
|
383
|
+
* orphan candidate exists. All git failures degrade silently — startup
|
|
384
|
+
* must never block on this defensive lookup.
|
|
385
|
+
*/
|
|
386
|
+
export function findUnmergedCompletedMilestone(
|
|
387
|
+
basePath: string,
|
|
388
|
+
isolationMode: "worktree" | "branch" | "none",
|
|
389
|
+
): string | null {
|
|
390
|
+
if (isolationMode === "none") return null;
|
|
391
|
+
if (!isDbAvailable()) return null;
|
|
392
|
+
|
|
393
|
+
let milestoneBranches: string[];
|
|
394
|
+
try {
|
|
395
|
+
milestoneBranches = nativeBranchList(basePath, "milestone/*");
|
|
396
|
+
} catch {
|
|
397
|
+
return null;
|
|
398
|
+
}
|
|
399
|
+
if (milestoneBranches.length === 0) return null;
|
|
400
|
+
|
|
401
|
+
let mainBranch: string;
|
|
402
|
+
try {
|
|
403
|
+
mainBranch = nativeDetectMainBranch(basePath);
|
|
404
|
+
} catch {
|
|
405
|
+
mainBranch = "main";
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
let mergedBranches: Set<string>;
|
|
409
|
+
try {
|
|
410
|
+
mergedBranches = new Set(
|
|
411
|
+
nativeBranchListMerged(basePath, mainBranch, "milestone/*"),
|
|
412
|
+
);
|
|
413
|
+
} catch {
|
|
414
|
+
mergedBranches = new Set();
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
return _selectResumableMilestone(
|
|
418
|
+
milestoneBranches,
|
|
419
|
+
mergedBranches,
|
|
420
|
+
(milestoneId) => {
|
|
421
|
+
const row = getMilestone(milestoneId);
|
|
422
|
+
return !!row && row.status === "complete";
|
|
423
|
+
},
|
|
424
|
+
(branch) => nativeCommitCountBetween(basePath, mainBranch, branch),
|
|
425
|
+
);
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
/**
|
|
429
|
+
* Run `mergeAndExit` for a milestone whose worktree/branch finalization
|
|
430
|
+
* never completed in a prior session — the active-milestone in phase
|
|
431
|
+
* `complete` with a survivor `milestone/<id>` branch still around.
|
|
432
|
+
*
|
|
433
|
+
* Wraps the call in try/catch so a thrown error from `_mergeBranchMode`
|
|
434
|
+
* (made fail-loud in commit 68ef58a3c) is converted into a user-facing
|
|
435
|
+
* error notify instead of an unhandled exception that propagates through
|
|
436
|
+
* `bootstrapAutoSession` to the slash-command caller's `.catch` block.
|
|
437
|
+
*
|
|
438
|
+
* Returns `{ merged: true }` on success; `{ merged: false, error }` on
|
|
439
|
+
* throw — caller decides whether to abort bootstrap.
|
|
440
|
+
*/
|
|
441
|
+
export function _finalizeSurvivorBranch(
|
|
442
|
+
resolver: WorktreeResolver,
|
|
443
|
+
milestoneId: string,
|
|
444
|
+
ui: { notify: (msg: string, level?: "info" | "warning" | "error" | "success") => void },
|
|
445
|
+
): { merged: boolean; error?: unknown } {
|
|
446
|
+
ui.notify(
|
|
447
|
+
`Milestone ${milestoneId} is complete but branch/worktree was not finalized. Running merge now.`,
|
|
448
|
+
"info",
|
|
449
|
+
);
|
|
450
|
+
try {
|
|
451
|
+
resolver.mergeAndExit(milestoneId, { notify: ui.notify.bind(ui) });
|
|
452
|
+
return { merged: true };
|
|
453
|
+
} catch (err) {
|
|
454
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
455
|
+
ui.notify(
|
|
456
|
+
`Survivor-branch finalization for ${milestoneId} failed: ${msg}. Resolve manually and re-run /gsd auto.`,
|
|
457
|
+
"error",
|
|
458
|
+
);
|
|
459
|
+
return { merged: false, error: err };
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
/**
|
|
464
|
+
* Merge a milestone whose DB row is `complete` but whose branch is still
|
|
465
|
+
* unmerged into the integration branch. Called from `bootstrapAutoSession`
|
|
466
|
+
* for orphans surfaced by `findUnmergedCompletedMilestone`.
|
|
467
|
+
*
|
|
468
|
+
* Notifies the user before and after, swallowing errors so a transient git
|
|
469
|
+
* failure never blocks bootstrap. Returns `{ merged: true }` when the
|
|
470
|
+
* underlying `mergeAndExit` completes; `{ merged: false, error }` on throw.
|
|
471
|
+
*
|
|
472
|
+
* Extracted to keep `bootstrapAutoSession` testable: the merge call and the
|
|
473
|
+
* notify shape are exercised against a mock resolver in
|
|
474
|
+
* `tests/orphan-merge-bootstrap.test.ts`.
|
|
475
|
+
*/
|
|
476
|
+
export function _mergeOrphanCompletedMilestone(
|
|
477
|
+
resolver: WorktreeResolver,
|
|
478
|
+
orphanId: string,
|
|
479
|
+
ui: { notify: (msg: string, level?: "info" | "warning" | "error" | "success") => void },
|
|
480
|
+
): { merged: boolean; error?: unknown } {
|
|
481
|
+
ui.notify(`Detected unmerged completed milestone ${orphanId}. Merging now.`, "info");
|
|
482
|
+
try {
|
|
483
|
+
resolver.mergeAndExit(orphanId, { notify: ui.notify.bind(ui) });
|
|
484
|
+
return { merged: true };
|
|
485
|
+
} catch (err) {
|
|
486
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
487
|
+
ui.notify(
|
|
488
|
+
`Could not merge orphan milestone ${orphanId}: ${msg}. Resolve manually and re-run /gsd auto.`,
|
|
489
|
+
"warning",
|
|
490
|
+
);
|
|
491
|
+
return { merged: false, error: err };
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
|
|
335
495
|
export async function bootstrapAutoSession(
|
|
336
496
|
s: AutoSession,
|
|
337
497
|
ctx: ExtensionCommandContext,
|
|
@@ -577,6 +737,39 @@ export async function bootstrapAutoSession(
|
|
|
577
737
|
logWarning("bootstrap", `orphaned milestone branch audit failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
578
738
|
}
|
|
579
739
|
|
|
740
|
+
// ── Orphaned preflight-stash audit (#5538-followup) ──
|
|
741
|
+
// Reapplies pre-merge stashes whose milestone is now complete but whose
|
|
742
|
+
// postflight pop was skipped by an interrupted merge in a prior session.
|
|
743
|
+
// Uses `git stash apply` (not pop) so the entry remains as a backup.
|
|
744
|
+
try {
|
|
745
|
+
if (isDbAvailable()) {
|
|
746
|
+
const stashAudit = auditOrphanedPreflightStashes(base, (milestoneId) => {
|
|
747
|
+
const row = getMilestone(milestoneId);
|
|
748
|
+
return !!row && isClosedStatus(row.status);
|
|
749
|
+
});
|
|
750
|
+
for (const entry of stashAudit.applied) {
|
|
751
|
+
ctx.ui.notify(
|
|
752
|
+
`Orphan audit: applied preflight stash ${entry.stashRef} for completed milestone ${entry.milestoneId}. The stash entry is preserved as a backup.`,
|
|
753
|
+
"info",
|
|
754
|
+
);
|
|
755
|
+
}
|
|
756
|
+
for (const msg of stashAudit.warnings) {
|
|
757
|
+
ctx.ui.notify(`Orphan audit: ${msg}`, "warning");
|
|
758
|
+
}
|
|
759
|
+
if (stashAudit.applied.length > 0) {
|
|
760
|
+
debugLog("orphan-stash-audit", {
|
|
761
|
+
applied: stashAudit.applied,
|
|
762
|
+
warnings: stashAudit.warnings,
|
|
763
|
+
});
|
|
764
|
+
}
|
|
765
|
+
}
|
|
766
|
+
} catch (err) {
|
|
767
|
+
logWarning(
|
|
768
|
+
"bootstrap",
|
|
769
|
+
`orphaned preflight-stash audit failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
770
|
+
);
|
|
771
|
+
}
|
|
772
|
+
|
|
580
773
|
let state = await deriveState(base);
|
|
581
774
|
|
|
582
775
|
// Stale worktree state recovery (#654)
|
|
@@ -649,20 +842,48 @@ export async function bootstrapAutoSession(
|
|
|
649
842
|
// hasSurvivorBranch after a successful promotion.
|
|
650
843
|
if (decideSurvivorAction(hasSurvivorBranch, state.phase) === "finalize") {
|
|
651
844
|
const mid = state.activeMilestone!.id;
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
845
|
+
// Commit 68ef58a3c made `_mergeBranchMode` throw on wrong-branch
|
|
846
|
+
// instead of returning false silently. Wrap the call so the throw is
|
|
847
|
+
// converted into an error notify + clean bootstrap abort, not an
|
|
848
|
+
// unhandled exception propagating to the slash-command caller (#5549
|
|
849
|
+
// post-merge audit, R2).
|
|
850
|
+
const finalize = _finalizeSurvivorBranch(buildResolver(), mid, ctx.ui);
|
|
851
|
+
if (!finalize.merged) {
|
|
852
|
+
return releaseLockAndReturn();
|
|
853
|
+
}
|
|
660
854
|
invalidateAllCaches();
|
|
661
855
|
state = await deriveState(base);
|
|
662
856
|
// Clear survivor flag — finalization is done
|
|
663
857
|
hasSurvivorBranch = false;
|
|
664
858
|
}
|
|
665
859
|
|
|
860
|
+
// ── Orphan-completed-milestone merge (#5538-followup) ──
|
|
861
|
+
// A process killed between `complete-milestone` (DB flip + SUMMARY write)
|
|
862
|
+
// and the loop's transition-guard merge strands the milestone branch
|
|
863
|
+
// forever: `s.currentMilestoneId` is in-memory only, so on the next
|
|
864
|
+
// bootstrap the guard at phases.ts:730 sees `mid === s.currentMilestoneId`
|
|
865
|
+
// and short-circuits.
|
|
866
|
+
//
|
|
867
|
+
// The earlier attempt at this fix seeded `s.currentMilestoneId` to the
|
|
868
|
+
// orphan id pre-state-derivation, but the unconditional assignment at
|
|
869
|
+
// line 948 (`s.currentMilestoneId = state.activeMilestone?.id ?? null`)
|
|
870
|
+
// immediately overwrote the seed. Active-merge is the more durable fix:
|
|
871
|
+
// call `mergeAndExit` directly during bootstrap, then re-derive state so
|
|
872
|
+
// the loop's normal flow continues without an in-memory hint.
|
|
873
|
+
//
|
|
874
|
+
// Mirrors the survivor-finalize block above. Failures degrade to a
|
|
875
|
+
// warning notify so a transient git error doesn't block bootstrap.
|
|
876
|
+
{
|
|
877
|
+
const orphan = findUnmergedCompletedMilestone(base, getIsolationMode(base));
|
|
878
|
+
if (orphan && orphan !== state.activeMilestone?.id) {
|
|
879
|
+
const result = _mergeOrphanCompletedMilestone(buildResolver(), orphan, ctx.ui);
|
|
880
|
+
if (result.merged) {
|
|
881
|
+
invalidateAllCaches();
|
|
882
|
+
state = await deriveState(base);
|
|
883
|
+
}
|
|
884
|
+
}
|
|
885
|
+
}
|
|
886
|
+
|
|
666
887
|
const effectivePrefs = loadEffectiveGSDPreferences(base)?.preferences;
|
|
667
888
|
const { shouldRunDeepProjectSetup } = await import("./auto-dispatch.js");
|
|
668
889
|
const deepProjectStagePending = shouldRunDeepProjectSetup(
|
|
@@ -790,7 +1011,7 @@ export async function bootstrapAutoSession(
|
|
|
790
1011
|
s.resourceVersionOnStart = readResourceVersion();
|
|
791
1012
|
s.pendingQuickTasks = [];
|
|
792
1013
|
s.currentUnit = null;
|
|
793
|
-
s.currentMilestoneId
|
|
1014
|
+
s.currentMilestoneId ??= deepProjectStagePending ? null : state.activeMilestone?.id ?? null;
|
|
794
1015
|
s.originalModelId = startModelSnapshot?.id ?? ctx.model?.id ?? null;
|
|
795
1016
|
s.originalModelProvider = startModelSnapshot?.provider ?? ctx.model?.provider ?? null;
|
|
796
1017
|
s.originalThinkingLevel = startThinkingSnapshot ?? null;
|
|
@@ -32,6 +32,7 @@ let _currentSigtermHandler: (() => void) | null = null;
|
|
|
32
32
|
export function registerSigtermHandler(
|
|
33
33
|
currentBasePath: string,
|
|
34
34
|
previousHandler: (() => void) | null,
|
|
35
|
+
onSignalCleanup?: () => void,
|
|
35
36
|
): () => void {
|
|
36
37
|
// Remove the explicitly-passed previous handler
|
|
37
38
|
if (previousHandler) {
|
|
@@ -43,6 +44,12 @@ export function registerSigtermHandler(
|
|
|
43
44
|
for (const sig of CLEANUP_SIGNALS) process.off(sig, _currentSigtermHandler);
|
|
44
45
|
}
|
|
45
46
|
const handler = () => {
|
|
47
|
+
try {
|
|
48
|
+
onSignalCleanup?.();
|
|
49
|
+
} catch {
|
|
50
|
+
void 0;
|
|
51
|
+
// Signal cleanup is best-effort; lock cleanup and process exit still run.
|
|
52
|
+
}
|
|
46
53
|
clearLock(currentBasePath);
|
|
47
54
|
releaseSessionLock(currentBasePath);
|
|
48
55
|
process.exit(0);
|
|
@@ -71,14 +71,14 @@ export async function recoverTimedOutUnit(
|
|
|
71
71
|
recovery: status,
|
|
72
72
|
});
|
|
73
73
|
|
|
74
|
-
const durableComplete = status.summaryExists && status.taskChecked && status.nextActionAdvanced;
|
|
74
|
+
const durableComplete = status.dbComplete || (status.summaryExists && status.taskChecked && status.nextActionAdvanced);
|
|
75
75
|
if (durableComplete) {
|
|
76
76
|
writeUnitRuntimeRecord(basePath, unitType, unitId, currentUnitStartedAt, {
|
|
77
77
|
phase: "finalized",
|
|
78
78
|
recovery: status,
|
|
79
79
|
});
|
|
80
80
|
ctx.ui.notify(
|
|
81
|
-
`${reason === "idle" ? "Idle" : "Timeout"} recovery: ${unitType} ${unitId} already completed
|
|
81
|
+
`${reason === "idle" ? "Idle" : "Timeout"} recovery: ${unitType} ${unitId} already completed. Continuing auto-mode. (attempt ${attemptNumber})`,
|
|
82
82
|
"info",
|
|
83
83
|
);
|
|
84
84
|
unitRecoveryCount.delete(recoveryKey);
|
|
@@ -78,6 +78,7 @@ import {
|
|
|
78
78
|
nativeUpdateRef,
|
|
79
79
|
nativeIsAncestor,
|
|
80
80
|
nativeMergeAbort,
|
|
81
|
+
nativeWorktreeList,
|
|
81
82
|
} from "./native-git-bridge.js";
|
|
82
83
|
import { gsdHome } from "./gsd-home.js";
|
|
83
84
|
import { type MilestoneScope, type GsdWorkspace, createWorkspace } from "./workspace.js";
|
|
@@ -1180,6 +1181,122 @@ export function enterBranchModeForMilestone(
|
|
|
1180
1181
|
* (both formerly here) became dead.
|
|
1181
1182
|
*/
|
|
1182
1183
|
|
|
1184
|
+
/**
|
|
1185
|
+
* True when `branch` is checked out in any worktree listed by
|
|
1186
|
+
* `git worktree list --porcelain`. Used to gate ref updates that would
|
|
1187
|
+
* otherwise leave a concurrent worktree's HEAD inconsistent with its
|
|
1188
|
+
* index/working tree (Codex peer-review of #5538-followup).
|
|
1189
|
+
*
|
|
1190
|
+
* Best-effort: a `nativeWorktreeList` failure returns true so we err on
|
|
1191
|
+
* the side of NOT moving the ref. Better to skip a fast-forward than to
|
|
1192
|
+
* silently corrupt another worktree.
|
|
1193
|
+
*/
|
|
1194
|
+
export function _isBranchCheckedOutElsewhere(
|
|
1195
|
+
basePath: string,
|
|
1196
|
+
branch: string,
|
|
1197
|
+
): boolean {
|
|
1198
|
+
try {
|
|
1199
|
+
const entries = nativeWorktreeList(basePath);
|
|
1200
|
+
return entries.some((entry) => entry.branch === branch);
|
|
1201
|
+
} catch {
|
|
1202
|
+
return true;
|
|
1203
|
+
}
|
|
1204
|
+
}
|
|
1205
|
+
|
|
1206
|
+
/**
|
|
1207
|
+
* Resolve the integration branch using the same 3-tier fallback as the
|
|
1208
|
+
* fresh-create path: META.json → git.main_branch preference → detected
|
|
1209
|
+
* main branch. Returns null when no usable target exists.
|
|
1210
|
+
*/
|
|
1211
|
+
function _resolveIntegrationBranchForReuse(
|
|
1212
|
+
basePath: string,
|
|
1213
|
+
milestoneId: string,
|
|
1214
|
+
): string | null {
|
|
1215
|
+
const fromMeta = readIntegrationBranch(basePath, milestoneId);
|
|
1216
|
+
if (fromMeta) return fromMeta;
|
|
1217
|
+
|
|
1218
|
+
const gitPrefs = loadEffectiveGSDPreferences()?.preferences?.git;
|
|
1219
|
+
const fromPref = gitPrefs?.main_branch &&
|
|
1220
|
+
typeof gitPrefs.main_branch === "string" &&
|
|
1221
|
+
gitPrefs.main_branch.length > 0 &&
|
|
1222
|
+
nativeBranchExists(basePath, gitPrefs.main_branch)
|
|
1223
|
+
? gitPrefs.main_branch
|
|
1224
|
+
: null;
|
|
1225
|
+
if (fromPref) return fromPref;
|
|
1226
|
+
|
|
1227
|
+
try {
|
|
1228
|
+
return nativeDetectMainBranch(basePath);
|
|
1229
|
+
} catch {
|
|
1230
|
+
return null;
|
|
1231
|
+
}
|
|
1232
|
+
}
|
|
1233
|
+
|
|
1234
|
+
/**
|
|
1235
|
+
* When reusing an existing milestone branch, fast-forward it onto the
|
|
1236
|
+
* integration branch when that's safe (branch is a strict ancestor of
|
|
1237
|
+
* integration — no commits would be lost). Skips when the branch has its
|
|
1238
|
+
* own commits ahead of integration, when the integration branch can't be
|
|
1239
|
+
* resolved, or when any git operation fails — the merge gate at milestone
|
|
1240
|
+
* completion will surface real divergence as a conflict.
|
|
1241
|
+
*
|
|
1242
|
+
* The previous behavior re-attached the worktree to whatever stale tip
|
|
1243
|
+
* the branch held, which caused new milestone work to fork from a base
|
|
1244
|
+
* missing prior milestones' merges (#5538-followup).
|
|
1245
|
+
*/
|
|
1246
|
+
export function fastForwardReusedMilestoneBranchIfSafe(
|
|
1247
|
+
basePath: string,
|
|
1248
|
+
milestoneId: string,
|
|
1249
|
+
branch: string,
|
|
1250
|
+
): void {
|
|
1251
|
+
try {
|
|
1252
|
+
const integrationBranch = _resolveIntegrationBranchForReuse(basePath, milestoneId);
|
|
1253
|
+
if (!integrationBranch || integrationBranch === branch) return;
|
|
1254
|
+
if (!nativeBranchExists(basePath, integrationBranch)) return;
|
|
1255
|
+
|
|
1256
|
+
// Pure fast-forward only: branch must be a strict ancestor of integration.
|
|
1257
|
+
// If the branch has its own commits ahead, leave it alone.
|
|
1258
|
+
if (!nativeIsAncestor(basePath, branch, integrationBranch)) {
|
|
1259
|
+
debugLog("createAutoWorktree", {
|
|
1260
|
+
phase: "skip-ff-branch-not-ancestor",
|
|
1261
|
+
milestoneId,
|
|
1262
|
+
branch,
|
|
1263
|
+
integration: integrationBranch,
|
|
1264
|
+
});
|
|
1265
|
+
return;
|
|
1266
|
+
}
|
|
1267
|
+
|
|
1268
|
+
// Codex peer-review: `nativeUpdateRef` succeeds even when the branch is
|
|
1269
|
+
// currently checked out in another worktree, leaving that worktree's HEAD
|
|
1270
|
+
// inconsistent with its index/work tree. Skip the fast-forward if any
|
|
1271
|
+
// listed worktree has this branch checked out — the merge gate at
|
|
1272
|
+
// milestone-completion will surface stale-base divergence as a conflict
|
|
1273
|
+
// instead of silently corrupting the other worktree's state.
|
|
1274
|
+
if (_isBranchCheckedOutElsewhere(basePath, branch)) {
|
|
1275
|
+
debugLog("createAutoWorktree", {
|
|
1276
|
+
phase: "skip-ff-branch-checked-out-elsewhere",
|
|
1277
|
+
milestoneId,
|
|
1278
|
+
branch,
|
|
1279
|
+
});
|
|
1280
|
+
return;
|
|
1281
|
+
}
|
|
1282
|
+
|
|
1283
|
+
nativeUpdateRef(basePath, `refs/heads/${branch}`, integrationBranch);
|
|
1284
|
+
debugLog("createAutoWorktree", {
|
|
1285
|
+
phase: "fast-forward-reused-branch",
|
|
1286
|
+
milestoneId,
|
|
1287
|
+
branch,
|
|
1288
|
+
integration: integrationBranch,
|
|
1289
|
+
});
|
|
1290
|
+
} catch (err) {
|
|
1291
|
+
debugLog("createAutoWorktree", {
|
|
1292
|
+
phase: "fast-forward-reused-branch-failed",
|
|
1293
|
+
milestoneId,
|
|
1294
|
+
branch,
|
|
1295
|
+
error: err instanceof Error ? err.message : String(err),
|
|
1296
|
+
});
|
|
1297
|
+
}
|
|
1298
|
+
}
|
|
1299
|
+
|
|
1183
1300
|
export function createAutoWorktree(
|
|
1184
1301
|
basePath: string,
|
|
1185
1302
|
milestoneId: string,
|
|
@@ -1206,6 +1323,12 @@ export function createAutoWorktree(
|
|
|
1206
1323
|
|
|
1207
1324
|
let info: { name: string; path: string; branch: string; exists: boolean };
|
|
1208
1325
|
if (branchExists) {
|
|
1326
|
+
// #5538-followup: fast-forward the reused branch onto the integration
|
|
1327
|
+
// branch when safe so the next milestone forks from up-to-date code.
|
|
1328
|
+
// Without this, a milestone that was created before another milestone
|
|
1329
|
+
// merged into main would carry a stale base into its worktree.
|
|
1330
|
+
fastForwardReusedMilestoneBranchIfSafe(basePath, milestoneId, branch);
|
|
1331
|
+
|
|
1209
1332
|
// Re-attach worktree to the existing milestone branch (preserving commits)
|
|
1210
1333
|
info = createWorktree(basePath, milestoneId, {
|
|
1211
1334
|
branch,
|
|
@@ -59,6 +59,7 @@ import {
|
|
|
59
59
|
isLockProcessAlive,
|
|
60
60
|
formatCrashInfo,
|
|
61
61
|
emitCrashRecoveredUnitEnd,
|
|
62
|
+
emitOpenUnitEndForUnit,
|
|
62
63
|
} from "./crash-recovery.js";
|
|
63
64
|
import {
|
|
64
65
|
acquireSessionLock,
|
|
@@ -150,6 +151,7 @@ import {
|
|
|
150
151
|
resolveProjectRoot,
|
|
151
152
|
} from "./worktree.js";
|
|
152
153
|
import { GitServiceImpl } from "./git-service.js";
|
|
154
|
+
import { nativeCheckoutBranch } from "./native-git-bridge.js";
|
|
153
155
|
import { getPriorSliceCompletionBlocker } from "./dispatch-guard.js";
|
|
154
156
|
import {
|
|
155
157
|
createAutoWorktree,
|
|
@@ -200,6 +202,8 @@ import {
|
|
|
200
202
|
detectWorkingTreeActivity,
|
|
201
203
|
} from "./auto-supervisor.js";
|
|
202
204
|
import { isDbAvailable, getMilestone } from "./gsd-db.js";
|
|
205
|
+
import { markLatestActiveForWorkerCanceled } from "./db/unit-dispatches.js";
|
|
206
|
+
import { writeUnitRuntimeRecord } from "./unit-runtime.js";
|
|
203
207
|
import { countPendingCaptures } from "./captures.js";
|
|
204
208
|
import { CMUX_CHANNELS, type CmuxLogLevel } from "../shared/cmux-events.js";
|
|
205
209
|
import { ensureDbOpen } from "./bootstrap/dynamic-tools.js";
|
|
@@ -242,6 +246,20 @@ import {
|
|
|
242
246
|
type WorktreeResolverDeps,
|
|
243
247
|
} from "./worktree-resolver.js";
|
|
244
248
|
import { reorderForCaching } from "./prompt-ordering.js";
|
|
249
|
+
import { initTokenCounter } from "./token-counter.js";
|
|
250
|
+
|
|
251
|
+
// Warm the tiktoken encoder at extension startup so context-budget computations
|
|
252
|
+
// can use accurate token counts via countTokensSync without paying the load
|
|
253
|
+
// cost mid-prompt-build. Fire-and-forget — failure falls back to the
|
|
254
|
+
// provider-aware char-ratio estimator already used by getCharsPerToken().
|
|
255
|
+
// Catch rejections explicitly: an unhandled rejection at module-import time
|
|
256
|
+
// can destabilize startup before the engine logger is configured.
|
|
257
|
+
void initTokenCounter().catch((err) => {
|
|
258
|
+
logWarning(
|
|
259
|
+
"engine",
|
|
260
|
+
`token counter warm-up failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
261
|
+
);
|
|
262
|
+
});
|
|
245
263
|
|
|
246
264
|
// ─── Session State ─────────────────────────────────────────────────────────
|
|
247
265
|
|
|
@@ -293,11 +311,15 @@ const STATE_REBUILD_MIN_INTERVAL_MS = 30_000;
|
|
|
293
311
|
* the DB is unavailable (e.g. fresh project before init) we skip registration
|
|
294
312
|
* silently rather than blocking session start.
|
|
295
313
|
*/
|
|
296
|
-
function registerAutoWorkerForSession(
|
|
314
|
+
function registerAutoWorkerForSession(
|
|
315
|
+
session: AutoSession,
|
|
316
|
+
projectRootOverride?: string,
|
|
317
|
+
): void {
|
|
297
318
|
if (session.workerId) return; // already registered (e.g. resume re-runs)
|
|
298
319
|
try {
|
|
299
320
|
const projectRootRealpath = normalizeRealPath(
|
|
300
|
-
|
|
321
|
+
projectRootOverride
|
|
322
|
+
?? session.scope?.workspace.projectRoot
|
|
301
323
|
?? (session.originalBasePath || session.basePath),
|
|
302
324
|
);
|
|
303
325
|
session.workerId = registerAutoWorker({ projectRootRealpath });
|
|
@@ -501,9 +523,54 @@ export {
|
|
|
501
523
|
getBudgetEnforcementAction,
|
|
502
524
|
} from "./auto-budget.js";
|
|
503
525
|
|
|
526
|
+
function closeOutSignalInterruptedUnit(currentBasePath: string): void {
|
|
527
|
+
const currentUnit = s.currentUnit;
|
|
528
|
+
if (!currentUnit) return;
|
|
529
|
+
|
|
530
|
+
const reason = "Auto-mode process received a termination signal";
|
|
531
|
+
const errorContext: ErrorContext = {
|
|
532
|
+
message: reason,
|
|
533
|
+
category: "aborted",
|
|
534
|
+
isTransient: false,
|
|
535
|
+
};
|
|
536
|
+
const basePath = s.basePath || currentBasePath;
|
|
537
|
+
|
|
538
|
+
try {
|
|
539
|
+
emitOpenUnitEndForUnit(basePath, currentUnit.type, currentUnit.id, "cancelled", errorContext);
|
|
540
|
+
} catch (err) {
|
|
541
|
+
logWarning("engine", `signal unit-end cleanup failed: ${getErrorMessage(err)}`, { file: "auto.ts" });
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
try {
|
|
545
|
+
writeUnitRuntimeRecord(basePath, currentUnit.type, currentUnit.id, currentUnit.startedAt, {
|
|
546
|
+
phase: "crashed",
|
|
547
|
+
lastProgressAt: Date.now(),
|
|
548
|
+
lastProgressKind: "signal",
|
|
549
|
+
});
|
|
550
|
+
} catch (err) {
|
|
551
|
+
logWarning("engine", `signal runtime cleanup failed: ${getErrorMessage(err)}`, { file: "auto.ts" });
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
try {
|
|
555
|
+
if (s.workerId) markLatestActiveForWorkerCanceled(s.workerId, "signal-exit");
|
|
556
|
+
} catch (err) {
|
|
557
|
+
logWarning("engine", `signal dispatch cleanup failed: ${getErrorMessage(err)}`, { file: "auto.ts" });
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
try {
|
|
561
|
+
resolveAgentEndCancelled(errorContext);
|
|
562
|
+
} catch (err) {
|
|
563
|
+
logWarning("engine", `signal resolve cleanup failed: ${getErrorMessage(err)}`, { file: "auto.ts" });
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
|
|
504
567
|
/** Wrapper: register SIGTERM handler and store reference. */
|
|
505
568
|
function registerSigtermHandler(currentBasePath: string): void {
|
|
506
|
-
s.sigtermHandler = _registerSigtermHandler(
|
|
569
|
+
s.sigtermHandler = _registerSigtermHandler(
|
|
570
|
+
currentBasePath,
|
|
571
|
+
s.sigtermHandler,
|
|
572
|
+
() => closeOutSignalInterruptedUnit(currentBasePath),
|
|
573
|
+
);
|
|
507
574
|
}
|
|
508
575
|
|
|
509
576
|
/** Wrapper: deregister SIGTERM handler and clear reference. */
|
|
@@ -968,6 +1035,8 @@ export async function stopAuto(
|
|
|
968
1035
|
if (s.workerId) {
|
|
969
1036
|
markWorkerStopping(s.workerId);
|
|
970
1037
|
}
|
|
1038
|
+
s.workerId = null;
|
|
1039
|
+
s.milestoneLeaseToken = null;
|
|
971
1040
|
} catch (e) {
|
|
972
1041
|
debugLog("stop-cleanup-coordination", { error: e instanceof Error ? e.message : String(e) });
|
|
973
1042
|
}
|
|
@@ -1105,6 +1174,21 @@ export async function stopAuto(
|
|
|
1105
1174
|
debugLog("stop-cleanup-basepath", { error: e instanceof Error ? e.message : String(e) });
|
|
1106
1175
|
}
|
|
1107
1176
|
|
|
1177
|
+
// Re-root the active command session/tool runtime after worktree teardown.
|
|
1178
|
+
// mergeAndExit restores process.cwd(), but AgentSession has already captured
|
|
1179
|
+
// its own cwd for tools and system prompt; refresh it before returning to the
|
|
1180
|
+
// user so follow-up commands do not target a removed milestone worktree.
|
|
1181
|
+
if (s.originalBasePath && ctx && s.cmdCtx) {
|
|
1182
|
+
try {
|
|
1183
|
+
const result = await s.cmdCtx.newSession({ workspaceRoot: s.basePath });
|
|
1184
|
+
if (result.cancelled) {
|
|
1185
|
+
logWarning("engine", "post-stop session re-root was cancelled", { file: "auto.ts", basePath: s.basePath });
|
|
1186
|
+
}
|
|
1187
|
+
} catch (err) {
|
|
1188
|
+
logWarning("engine", `post-stop session re-root failed: ${err instanceof Error ? err.message : String(err)}`, { file: "auto.ts", basePath: s.basePath });
|
|
1189
|
+
}
|
|
1190
|
+
}
|
|
1191
|
+
|
|
1108
1192
|
// ── Step 8: Ledger notification ──
|
|
1109
1193
|
try {
|
|
1110
1194
|
const ledger = getLedger();
|
|
@@ -1368,6 +1452,7 @@ function buildResolverDeps(): WorktreeResolverDeps {
|
|
|
1368
1452
|
getAutoWorktreePath,
|
|
1369
1453
|
autoCommitCurrentBranch,
|
|
1370
1454
|
getCurrentBranch,
|
|
1455
|
+
checkoutBranch: nativeCheckoutBranch,
|
|
1371
1456
|
autoWorktreeBranch,
|
|
1372
1457
|
resolveMilestoneFile,
|
|
1373
1458
|
readFileSync: (path: string, encoding: string) =>
|
|
@@ -1971,6 +2056,10 @@ export async function startAuto(
|
|
|
1971
2056
|
: new URL("../../../resource-loader.js", import.meta.url).href;
|
|
1972
2057
|
const { initResources } = await import(resourceLoaderPath);
|
|
1973
2058
|
initResources(agentDir);
|
|
2059
|
+
// initResources() uses synchronous fs APIs, so the prompt-template cache
|
|
2060
|
+
// can be primed immediately — no need for the legacy 1s setTimeout deferral.
|
|
2061
|
+
const { primeCache } = await import("./prompt-loader.js");
|
|
2062
|
+
primeCache();
|
|
1974
2063
|
// Open the project DB before rebuild/derive so resume uses DB-backed
|
|
1975
2064
|
// state instead of falling back to stale markdown parsing (#2940).
|
|
1976
2065
|
await openProjectDbIfPresent(s.basePath);
|
|
@@ -2057,6 +2146,11 @@ export async function startAuto(
|
|
|
2057
2146
|
buildResolver,
|
|
2058
2147
|
};
|
|
2059
2148
|
|
|
2149
|
+
// Register the worker before bootstrap enters a milestone worktree.
|
|
2150
|
+
// This ensures enterMilestone can claim a lease and seed dispatch claims
|
|
2151
|
+
// for crash-recovery fidelity (#5405).
|
|
2152
|
+
registerAutoWorkerForSession(s, base);
|
|
2153
|
+
|
|
2060
2154
|
const ready = await bootstrapAutoSession(
|
|
2061
2155
|
s,
|
|
2062
2156
|
ctx,
|
|
@@ -2224,24 +2318,7 @@ export async function dispatchHookUnit(
|
|
|
2224
2318
|
startedAt: hookStartedAt,
|
|
2225
2319
|
};
|
|
2226
2320
|
|
|
2227
|
-
|
|
2228
|
-
// newSession() snapshots process.cwd() during construction; chdir-ing
|
|
2229
|
-
// afterward leaves the session rooted to whatever cwd was when the call
|
|
2230
|
-
// was made. Must be synchronous — no awaits between chdir and newSession.
|
|
2231
|
-
try { if (process.cwd() !== s.basePath) process.chdir(s.basePath); } catch (err) {
|
|
2232
|
-
const msg = `Failed to chdir before hook newSession (basePath: ${s.basePath}): ${err instanceof Error ? err.message : String(err)}`;
|
|
2233
|
-
logWarning("engine", msg, { file: "auto.ts", basePath: s.basePath, error: err instanceof Error ? err.message : String(err) });
|
|
2234
|
-
ctx.ui.notify(`${msg}. Cancelling hook dispatch to avoid running in the wrong directory.`, "error");
|
|
2235
|
-
if (wasActive) {
|
|
2236
|
-
s.basePath = previousBasePath;
|
|
2237
|
-
s.currentUnit = previousCurrentUnit;
|
|
2238
|
-
} else {
|
|
2239
|
-
s.reset();
|
|
2240
|
-
}
|
|
2241
|
-
return false;
|
|
2242
|
-
}
|
|
2243
|
-
|
|
2244
|
-
const result = await s.cmdCtx!.newSession();
|
|
2321
|
+
const result = await s.cmdCtx!.newSession({ workspaceRoot: s.basePath });
|
|
2245
2322
|
if (result.cancelled) {
|
|
2246
2323
|
await stopAuto(ctx, pi);
|
|
2247
2324
|
return false;
|