gsd-pi 2.80.0-dev.c5f2443b3 → 2.80.0-dev.e51d2c88c
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/GSD-WORKFLOW.md +2 -2
- package/dist/resources/extensions/github-sync/templates.js +39 -8
- package/dist/resources/extensions/gsd/auto/loop.js +48 -10
- package/dist/resources/extensions/gsd/auto/phases.js +66 -45
- package/dist/resources/extensions/gsd/auto/resolve.js +17 -0
- package/dist/resources/extensions/gsd/auto/run-unit.js +32 -16
- package/dist/resources/extensions/gsd/auto-dashboard.js +51 -15
- package/dist/resources/extensions/gsd/auto-dispatch.js +10 -0
- package/dist/resources/extensions/gsd/auto-post-unit.js +10 -10
- package/dist/resources/extensions/gsd/auto-prompts.js +124 -2
- package/dist/resources/extensions/gsd/auto-recovery.js +197 -9
- package/dist/resources/extensions/gsd/auto-start.js +2 -3
- 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.js +75 -5
- package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +36 -3
- package/dist/resources/extensions/gsd/bootstrap/exec-tools.js +27 -20
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +32 -1
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +129 -1
- package/dist/resources/extensions/gsd/clean-root-preflight.js +42 -4
- package/dist/resources/extensions/gsd/commands/dispatcher.js +5 -0
- package/dist/resources/extensions/gsd/commands-extract-learnings.js +17 -12
- 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/custom-workflow-engine.js +22 -2
- package/dist/resources/extensions/gsd/db/unit-dispatches.js +39 -0
- package/dist/resources/extensions/gsd/db-base-schema.js +18 -2
- package/dist/resources/extensions/gsd/db-migration-steps.js +22 -0
- package/dist/resources/extensions/gsd/detection.js +106 -0
- package/dist/resources/extensions/gsd/graph.js +9 -3
- package/dist/resources/extensions/gsd/gsd-db.js +146 -13
- package/dist/resources/extensions/gsd/guided-flow.js +82 -16
- 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/planning-path-scope.js +26 -0
- package/dist/resources/extensions/gsd/pr-evidence.js +57 -16
- package/dist/resources/extensions/gsd/prompt-loader.js +28 -2
- package/dist/resources/extensions/gsd/prompts/complete-milestone.md +19 -19
- package/dist/resources/extensions/gsd/prompts/parallel-research-slices.md +1 -1
- package/dist/resources/extensions/gsd/prompts/plan-milestone.md +3 -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/validate-milestone.md +2 -2
- package/dist/resources/extensions/gsd/quick.js +34 -2
- package/dist/resources/extensions/gsd/safety/evidence-collector.js +10 -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/working-output-messages.js +64 -0
- package/dist/resources/extensions/gsd/worktree-manager.js +16 -14
- package/dist/tsconfig.extensions.tsbuildinfo +1 -1
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +11 -11
- package/dist/web/standalone/.next/build-manifest.json +3 -3
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- package/dist/web/standalone/.next/react-loadable-manifest.json +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/api/onboarding/route.js +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 +11 -11
- package/dist/web/standalone/.next/server/chunks/6897.js +3 -3
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
- package/dist/web/standalone/.next/server/pages/404.html +1 -1
- package/dist/web/standalone/.next/server/pages/500.html +1 -1
- package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
- package/dist/web/standalone/.next/static/chunks/{8336.6f6f30e410419aff.js → 8336.631939fb583761fa.js} +1 -1
- package/dist/web/standalone/.next/static/chunks/{webpack-d82dbee6356c1733.js → webpack-0481f1221120a7c6.js} +1 -1
- package/package.json +12 -8
- package/packages/contracts/package.json +1 -1
- 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-ai/dist/models/fake-model.d.ts +12 -0
- package/packages/pi-ai/dist/models/fake-model.d.ts.map +1 -0
- package/packages/pi-ai/dist/models/fake-model.js +27 -0
- package/packages/pi-ai/dist/models/fake-model.js.map +1 -0
- package/packages/pi-ai/dist/models/index.d.ts.map +1 -1
- package/packages/pi-ai/dist/models/index.js +8 -0
- package/packages/pi-ai/dist/models/index.js.map +1 -1
- package/packages/pi-ai/dist/providers/fake.d.ts +42 -0
- package/packages/pi-ai/dist/providers/fake.d.ts.map +1 -0
- package/packages/pi-ai/dist/providers/fake.js +319 -0
- package/packages/pi-ai/dist/providers/fake.js.map +1 -0
- package/packages/pi-ai/dist/providers/register-builtins.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/register-builtins.js +24 -0
- package/packages/pi-ai/dist/providers/register-builtins.js.map +1 -1
- package/packages/pi-ai/src/models/fake-model.ts +30 -0
- package/packages/pi-ai/src/models/index.ts +9 -0
- package/packages/pi-ai/src/providers/fake.ts +376 -0
- package/packages/pi-ai/src/providers/register-builtins.ts +23 -0
- package/packages/pi-ai/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.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session.js +8 -0
- 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 +76 -0
- 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/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 +17 -1
- package/packages/pi-coding-agent/dist/core/extensions/runner.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/runner.test.js +99 -0
- 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 +7 -0
- 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/model-registry.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-registry.js +5 -0
- package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +24 -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 +33 -0
- package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/slash-commands.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/slash-commands.js +1 -0
- package/packages/pi-coding-agent/dist/core/slash-commands.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/chat-frame-compaction-tone.test.js +6 -4
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/chat-frame-compaction-tone.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js +54 -15
- 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/adaptive-layout.d.ts +26 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.js +112 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.test.js +51 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.js +10 -9
- package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.d.ts +3 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.js +11 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-card-cleanup-and-success-runtime.test.js +7 -6
- 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 +17 -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 +109 -17
- 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 +69 -2
- 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 +93 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.js +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts +3 -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 +26 -0
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.js +20 -0
- package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.test.js +79 -0
- package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-schema.d.ts +12 -0
- package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-schema.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-schema.js +13 -0
- package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-schema.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.d.ts +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.js +18 -1
- package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.js +36 -27
- package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.d.ts +11 -0
- package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.js +18 -0
- package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.test.js +48 -0
- package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.test.js.map +1 -0
- 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.ts +8 -0
- package/packages/pi-coding-agent/src/core/chat-controller-ordering.test.ts +89 -0
- 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/runner.test.ts +110 -0
- package/packages/pi-coding-agent/src/core/extensions/runner.ts +19 -1
- package/packages/pi-coding-agent/src/core/extensions/types.ts +7 -0
- package/packages/pi-coding-agent/src/core/model-registry.ts +4 -0
- package/packages/pi-coding-agent/src/core/settings-manager.ts +51 -1
- package/packages/pi-coding-agent/src/core/slash-commands.ts +1 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/chat-frame-compaction-tone.test.ts +7 -5
- package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/tool-execution.test.ts +78 -15
- package/packages/pi-coding-agent/src/modes/interactive/components/adaptive-layout.test.ts +59 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/adaptive-layout.ts +160 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/assistant-message.ts +1 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/chat-frame.ts +10 -9
- package/packages/pi-coding-agent/src/modes/interactive/components/settings-selector.ts +15 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/tool-card-cleanup-and-success-runtime.test.ts +10 -9
- package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +122 -17
- package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.test.ts +99 -1
- package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +92 -3
- package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.test.ts +1 -0
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode-state.ts +1 -1
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +28 -0
- package/packages/pi-coding-agent/src/modes/interactive/slash-command-handlers.test.ts +95 -0
- package/packages/pi-coding-agent/src/modes/interactive/slash-command-handlers.ts +24 -1
- package/packages/pi-coding-agent/src/modes/interactive/theme/theme-schema.ts +13 -0
- package/packages/pi-coding-agent/src/modes/interactive/theme/theme.ts +32 -2
- package/packages/pi-coding-agent/src/modes/interactive/theme/themes.ts +36 -27
- package/packages/pi-coding-agent/src/modes/interactive/tui-mode.test.ts +65 -0
- package/packages/pi-coding-agent/src/modes/interactive/tui-mode.ts +29 -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/__tests__/style.test.d.ts +2 -0
- package/packages/pi-tui/dist/__tests__/style.test.d.ts.map +1 -0
- package/packages/pi-tui/dist/__tests__/style.test.js +63 -0
- package/packages/pi-tui/dist/__tests__/style.test.js.map +1 -0
- package/packages/pi-tui/dist/__tests__/tui.test.js +24 -3
- package/packages/pi-tui/dist/__tests__/tui.test.js.map +1 -1
- package/packages/pi-tui/dist/index.d.ts +1 -0
- package/packages/pi-tui/dist/index.d.ts.map +1 -1
- package/packages/pi-tui/dist/index.js +2 -0
- package/packages/pi-tui/dist/index.js.map +1 -1
- package/packages/pi-tui/dist/style.d.ts +41 -0
- package/packages/pi-tui/dist/style.d.ts.map +1 -0
- package/packages/pi-tui/dist/style.js +158 -0
- package/packages/pi-tui/dist/style.js.map +1 -0
- package/packages/pi-tui/dist/tui.d.ts +0 -1
- package/packages/pi-tui/dist/tui.d.ts.map +1 -1
- package/packages/pi-tui/dist/tui.js +21 -16
- package/packages/pi-tui/dist/tui.js.map +1 -1
- package/packages/pi-tui/src/__tests__/style.test.ts +76 -0
- package/packages/pi-tui/src/__tests__/tui.test.ts +29 -3
- package/packages/pi-tui/src/index.ts +9 -0
- package/packages/pi-tui/src/style.ts +225 -0
- package/packages/pi-tui/src/tui.ts +23 -16
- package/packages/pi-tui/tsconfig.tsbuildinfo +1 -1
- package/pkg/dist/modes/interactive/theme/theme-schema.d.ts +12 -0
- package/pkg/dist/modes/interactive/theme/theme-schema.d.ts.map +1 -1
- package/pkg/dist/modes/interactive/theme/theme-schema.js +13 -0
- package/pkg/dist/modes/interactive/theme/theme-schema.js.map +1 -1
- package/pkg/dist/modes/interactive/theme/theme.d.ts +1 -1
- package/pkg/dist/modes/interactive/theme/theme.d.ts.map +1 -1
- package/pkg/dist/modes/interactive/theme/theme.js +18 -1
- package/pkg/dist/modes/interactive/theme/theme.js.map +1 -1
- package/pkg/dist/modes/interactive/theme/themes.d.ts.map +1 -1
- package/pkg/dist/modes/interactive/theme/themes.js +36 -27
- package/pkg/dist/modes/interactive/theme/themes.js.map +1 -1
- package/src/resources/GSD-WORKFLOW.md +2 -2
- package/src/resources/extensions/github-sync/templates.ts +38 -8
- package/src/resources/extensions/github-sync/tests/inline-code.test.ts +66 -0
- package/src/resources/extensions/gsd/auto/loop-deps.ts +1 -0
- package/src/resources/extensions/gsd/auto/loop.ts +67 -18
- package/src/resources/extensions/gsd/auto/phases.ts +77 -48
- package/src/resources/extensions/gsd/auto/resolve.ts +23 -1
- package/src/resources/extensions/gsd/auto/run-unit.ts +42 -15
- package/src/resources/extensions/gsd/auto-dashboard.ts +57 -8
- package/src/resources/extensions/gsd/auto-dispatch.ts +17 -0
- package/src/resources/extensions/gsd/auto-post-unit.ts +10 -10
- package/src/resources/extensions/gsd/auto-prompts.ts +133 -2
- package/src/resources/extensions/gsd/auto-recovery.ts +207 -7
- package/src/resources/extensions/gsd/auto-start.ts +7 -6
- 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.ts +90 -4
- package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +37 -2
- package/src/resources/extensions/gsd/bootstrap/exec-tools.ts +27 -19
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +39 -1
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +135 -1
- package/src/resources/extensions/gsd/clean-root-preflight.ts +41 -3
- package/src/resources/extensions/gsd/commands/dispatcher.ts +6 -0
- package/src/resources/extensions/gsd/commands-extract-learnings.ts +17 -12
- 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/custom-workflow-engine.ts +24 -1
- package/src/resources/extensions/gsd/db/unit-dispatches.ts +41 -0
- package/src/resources/extensions/gsd/db-base-schema.ts +19 -2
- package/src/resources/extensions/gsd/db-migration-steps.ts +25 -0
- package/src/resources/extensions/gsd/detection.ts +128 -0
- package/src/resources/extensions/gsd/graph.ts +12 -5
- package/src/resources/extensions/gsd/gsd-db.ts +168 -13
- package/src/resources/extensions/gsd/guided-flow.ts +98 -16
- 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/planning-path-scope.ts +35 -0
- package/src/resources/extensions/gsd/pr-evidence.ts +63 -5
- 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 +19 -19
- package/src/resources/extensions/gsd/prompts/parallel-research-slices.md +1 -1
- package/src/resources/extensions/gsd/prompts/plan-milestone.md +3 -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/validate-milestone.md +2 -2
- package/src/resources/extensions/gsd/quick.ts +37 -2
- package/src/resources/extensions/gsd/safety/evidence-collector.ts +11 -2
- package/src/resources/extensions/gsd/tests/auto-abort-pause-regression.test.ts +7 -1
- package/src/resources/extensions/gsd/tests/auto-dashboard.test.ts +33 -0
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +155 -5
- package/src/resources/extensions/gsd/tests/auto-phases-lifecycle.test.ts +56 -13
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +184 -2
- package/src/resources/extensions/gsd/tests/clean-root-preflight.test.ts +88 -2
- package/src/resources/extensions/gsd/tests/commands-extract-learnings.test.ts +9 -0
- package/src/resources/extensions/gsd/tests/compaction-snapshot.test.ts +14 -1
- package/src/resources/extensions/gsd/tests/context-budget.test.ts +10 -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 +112 -6
- package/src/resources/extensions/gsd/tests/custom-workflow-engine.test.ts +40 -2
- package/src/resources/extensions/gsd/tests/db-migration-steps.integration.test.ts +428 -0
- package/src/resources/extensions/gsd/tests/db-schema-metadata.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/detection.test.ts +140 -0
- 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/fixtures/pr-body/commands-ship-basic.md +52 -0
- package/src/resources/extensions/gsd/tests/fixtures/pr-body/commands-ship-empty-optionals.md +42 -0
- package/src/resources/extensions/gsd/tests/fixtures/pr-body/swarm-lane-no-blockers.md +55 -0
- package/src/resources/extensions/gsd/tests/fixtures/pr-body/swarm-lane-with-blockers.md +60 -0
- package/src/resources/extensions/gsd/tests/graph-operations.test.ts +10 -0
- package/src/resources/extensions/gsd/tests/gsd-db.test.ts +44 -0
- package/src/resources/extensions/gsd/tests/has-pending-deep-stage.test.ts +33 -1
- package/src/resources/extensions/gsd/tests/journal-integration.test.ts +234 -0
- package/src/resources/extensions/gsd/tests/memory-decay-factor.test.ts +90 -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/plan-slice.test.ts +50 -0
- package/src/resources/extensions/gsd/tests/plan-task.test.ts +21 -0
- package/src/resources/extensions/gsd/tests/pr-evidence-equivalence.test.ts +102 -0
- package/src/resources/extensions/gsd/tests/pr-evidence-hardening.test.ts +165 -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/quick-external-gsd.test.ts +40 -0
- package/src/resources/extensions/gsd/tests/right-sized-workflow-prompts.test.ts +192 -0
- package/src/resources/extensions/gsd/tests/safety-harness-false-positives.test.ts +29 -0
- package/src/resources/extensions/gsd/tests/schema-v27-v28-sequence.test.ts +156 -0
- package/src/resources/extensions/gsd/tests/signal-handlers.test.ts +27 -0
- package/src/resources/extensions/gsd/tests/smart-entry-complete.test.ts +38 -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 +101 -2
- package/src/resources/extensions/gsd/tests/status-db-open.test.ts +9 -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/uok-plan-v2-wiring.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +3 -0
- package/src/resources/extensions/gsd/tests/working-output-messages.test.ts +93 -0
- package/src/resources/extensions/gsd/tests/worktree-health-dispatch.test.ts +37 -6
- package/src/resources/extensions/gsd/tests/worktree-manager.test.ts +7 -0
- package/src/resources/extensions/gsd/tests/worktree-nested-git-safety.test.ts +9 -2
- package/src/resources/extensions/gsd/tests/worktree-write-gate.test.ts +179 -0
- 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/working-output-messages.ts +120 -0
- package/src/resources/extensions/gsd/worktree-manager.ts +15 -4
- package/packages/contracts/tsconfig.tsbuildinfo +0 -1
- /package/dist/web/standalone/.next/static/{bQDK5_LtkGVS64AirQgQG → 8F5YpnZNBaooIWGF4GBV3}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{bQDK5_LtkGVS64AirQgQG → 8F5YpnZNBaooIWGF4GBV3}/_ssgManifest.js +0 -0
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
import { loadFile, parseContinue, parseSummary, loadActiveOverrides, formatOverridesSection, parseTaskPlanFile } from "./files.js";
|
|
10
10
|
import type { Override, UatType } from "./files.js";
|
|
11
|
-
import { hasVerdict, getUatType } from "./verdict-parser.js";
|
|
11
|
+
import { hasVerdict, getUatType, extractVerdict } from "./verdict-parser.js";
|
|
12
12
|
import { loadPrompt, inlineTemplate } from "./prompt-loader.js";
|
|
13
13
|
import {
|
|
14
14
|
resolveMilestoneFile, resolveSliceFile, resolveSlicePath,
|
|
@@ -35,10 +35,12 @@ import {
|
|
|
35
35
|
import { formatDecisionsCompact, formatRequirementsCompact } from "./structured-data-formatter.js";
|
|
36
36
|
import { readPhaseAnchor, formatAnchorForPrompt } from "./phase-anchor.js";
|
|
37
37
|
import { composeContextModeInstructions, composeInlinedContext, type ArtifactResolver, type ContextModeRenderMode } from "./unit-context-composer.js";
|
|
38
|
+
import { readCompactionSnapshot } from "./compaction-snapshot.js";
|
|
38
39
|
import { logWarning } from "./workflow-logger.js";
|
|
39
40
|
import { inlineGraphSubgraph } from "./graph-context.js";
|
|
40
41
|
import { buildExtractionStepsBlock } from "./commands-extract-learnings.js";
|
|
41
42
|
import { resolveSkillManifest, warnIfManifestHasMissingSkills } from "./skill-manifest.js";
|
|
43
|
+
import { classifyProject, type ProjectClassification } from "./detection.js";
|
|
42
44
|
|
|
43
45
|
// ─── Preamble Cap ─────────────────────────────────────────────────────────────
|
|
44
46
|
|
|
@@ -80,6 +82,108 @@ function resolveSummaryBudgetChars(): number {
|
|
|
80
82
|
return resolvePromptBudgets().summaryBudgetChars;
|
|
81
83
|
}
|
|
82
84
|
|
|
85
|
+
function formatProjectClassificationForPlanning(classification: ProjectClassification): string {
|
|
86
|
+
const sampleFiles = classification.contentFiles.slice(0, 8);
|
|
87
|
+
const sample = sampleFiles.length > 0 ? sampleFiles.map((file) => `\`${file}\``).join(", ") : "(none)";
|
|
88
|
+
const lines = [
|
|
89
|
+
"### Project Classification",
|
|
90
|
+
"",
|
|
91
|
+
`- **Kind:** ${classification.kind}`,
|
|
92
|
+
`- **Content files:** ${classification.contentFiles.length}`,
|
|
93
|
+
`- **Sample files:** ${sample}`,
|
|
94
|
+
`- **Reason:** ${classification.reason}`,
|
|
95
|
+
"",
|
|
96
|
+
];
|
|
97
|
+
|
|
98
|
+
if (classification.kind === "untyped-existing") {
|
|
99
|
+
if (classification.contentFiles.length <= 2) {
|
|
100
|
+
lines.push(
|
|
101
|
+
"**Workflow sizing:** This is a tiny existing untyped project. Prefer exactly one slice unless the milestone request clearly spans multiple independent user-visible capabilities.",
|
|
102
|
+
);
|
|
103
|
+
} else if (classification.contentFiles.length <= 5) {
|
|
104
|
+
lines.push(
|
|
105
|
+
"**Workflow sizing:** This is a small existing untyped project. Prefer 1-2 slices unless the milestone request clearly spans multiple independent user-visible capabilities.",
|
|
106
|
+
);
|
|
107
|
+
} else {
|
|
108
|
+
lines.push(
|
|
109
|
+
"**Workflow sizing:** Existing untyped project. Use generic file-level workflow guidance and size slices by real capability boundaries, not by missing tooling markers.",
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
} else if (classification.kind === "greenfield") {
|
|
113
|
+
lines.push("**Workflow sizing:** No project content exists yet. Use normal greenfield sizing for the requested scope.");
|
|
114
|
+
} else if (classification.kind === "typed-existing") {
|
|
115
|
+
lines.push("**Workflow sizing:** Known project markers exist. Use normal ecosystem-aware planning guidance.");
|
|
116
|
+
} else {
|
|
117
|
+
lines.push("**Workflow sizing:** Invalid repository state. Planning should surface this as a blocker rather than inventing project structure.");
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
return lines.join("\n");
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function normalizeArtifactRef(value: string): string {
|
|
124
|
+
return value.trim().replace(/^[-\s]+/, "").replace(/^["'`]+|["'`]+$/g, "").replaceAll("\\", "/").replace(/^\.\//, "");
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function parseCoveredArtifacts(validationContent: string): Set<string> {
|
|
128
|
+
const covered = new Set<string>();
|
|
129
|
+
const lines = validationContent.split(/\r?\n/);
|
|
130
|
+
let inCoveredArtifacts = false;
|
|
131
|
+
for (const line of lines) {
|
|
132
|
+
if (/^\s*covered[-_]?artifacts\s*:/i.test(line)) {
|
|
133
|
+
inCoveredArtifacts = true;
|
|
134
|
+
const inline = line.split(/covered[-_]?artifacts\s*:/i)[1]?.trim();
|
|
135
|
+
if (inline && inline !== "[]") {
|
|
136
|
+
inline.replace(/^\[|\]$/g, "").split(",").map(normalizeArtifactRef).filter(Boolean).forEach((item) => covered.add(item));
|
|
137
|
+
}
|
|
138
|
+
continue;
|
|
139
|
+
}
|
|
140
|
+
if (!inCoveredArtifacts) continue;
|
|
141
|
+
if (/^\S/.test(line) && !/^\s*-/.test(line)) break;
|
|
142
|
+
const item = line.match(/^\s*-\s*(.+)$/)?.[1];
|
|
143
|
+
if (item) covered.add(normalizeArtifactRef(item));
|
|
144
|
+
}
|
|
145
|
+
return covered;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function isValidationFreshOrApplicable(validationContent: string | null, currentArtifacts: string[]): boolean {
|
|
149
|
+
if (!validationContent) return false;
|
|
150
|
+
if (!/validation_metadata:/i.test(validationContent)) return false;
|
|
151
|
+
const coveredArtifacts = parseCoveredArtifacts(validationContent);
|
|
152
|
+
if (coveredArtifacts.size === 0) return false;
|
|
153
|
+
return currentArtifacts
|
|
154
|
+
.map(normalizeArtifactRef)
|
|
155
|
+
.filter(Boolean)
|
|
156
|
+
.every((artifact) => coveredArtifacts.has(artifact));
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function formatCloseoutReviewInstructions(validationContent: string | null, validationRel: string, currentArtifacts: string[]): string {
|
|
160
|
+
const verdict = validationContent ? extractVerdict(validationContent) : null;
|
|
161
|
+
const validationFresh = isValidationFreshOrApplicable(validationContent, currentArtifacts);
|
|
162
|
+
if (verdict === "pass" && validationFresh) {
|
|
163
|
+
return [
|
|
164
|
+
"### Passing Validation Artifact",
|
|
165
|
+
"",
|
|
166
|
+
`A passing validation artifact is present at \`${validationRel}\`. Treat it as authoritative for success criteria, requirement coverage, verification classes, and cross-slice integration.`,
|
|
167
|
+
"",
|
|
168
|
+
"Do not delegate fresh reviewer/security/tester audits and do not redo the validation evidence review unless the artifact is internally inconsistent with the inlined summaries. Focus this unit on final milestone narrative, learnings, PROJECT/requirements updates, and `gsd_complete_milestone`.",
|
|
169
|
+
].join("\n");
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
if (verdict) {
|
|
173
|
+
return [
|
|
174
|
+
"### Validation Requires Attention",
|
|
175
|
+
"",
|
|
176
|
+
`A validation artifact is present at \`${validationRel}\` with verdict \`${verdict}\`, but it is missing freshness metadata or does not cover current milestone artifacts. Do not treat the milestone as complete unless the issues are resolved and evidence supports completion.`,
|
|
177
|
+
].join("\n");
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
return [
|
|
181
|
+
"### No Passing Validation Artifact",
|
|
182
|
+
"",
|
|
183
|
+
`No passing validation artifact was found at \`${validationRel}\`. Use the full closeout review path before completion.`,
|
|
184
|
+
].join("\n");
|
|
185
|
+
}
|
|
186
|
+
|
|
83
187
|
function capPreamble(preamble: string): string {
|
|
84
188
|
// Cap inlined context at min(historical 30K ceiling, scaled inline budget).
|
|
85
189
|
// The ceiling preserves pre-fix behavior for large-window users; the scaled
|
|
@@ -102,13 +206,28 @@ function renderContextModeForPrompt(
|
|
|
102
206
|
});
|
|
103
207
|
}
|
|
104
208
|
|
|
209
|
+
function renderContextModeBlockForPrompt(
|
|
210
|
+
unitType: string,
|
|
211
|
+
base: string,
|
|
212
|
+
renderMode: ContextModeRenderMode = "standalone",
|
|
213
|
+
): string {
|
|
214
|
+
const contextMode = renderContextModeForPrompt(unitType, base, renderMode);
|
|
215
|
+
if (!contextMode) return "";
|
|
216
|
+
if (renderMode === "nested") return contextMode;
|
|
217
|
+
|
|
218
|
+
const snapshot = readCompactionSnapshot(base);
|
|
219
|
+
if (!snapshot?.trim()) return contextMode;
|
|
220
|
+
|
|
221
|
+
return `${contextMode}\n\n## Context Snapshot\nSource: \`.gsd/last-snapshot.md\`\n\n${snapshot.trimEnd()}`;
|
|
222
|
+
}
|
|
223
|
+
|
|
105
224
|
function prependContextModeToBlock(
|
|
106
225
|
unitType: string,
|
|
107
226
|
base: string,
|
|
108
227
|
block: string,
|
|
109
228
|
renderMode: ContextModeRenderMode = "standalone",
|
|
110
229
|
): string {
|
|
111
|
-
const contextMode =
|
|
230
|
+
const contextMode = renderContextModeBlockForPrompt(unitType, base, renderMode);
|
|
112
231
|
if (!contextMode) return block;
|
|
113
232
|
if (!block.trim()) return contextMode;
|
|
114
233
|
return `${contextMode}\n\n${block}`;
|
|
@@ -1658,6 +1777,8 @@ export async function buildPlanMilestonePrompt(mid: string, midTitle: string, ba
|
|
|
1658
1777
|
const researchAnchor = readPhaseAnchor(base, mid, "research-milestone");
|
|
1659
1778
|
if (researchAnchor) inlined.push(formatAnchorForPrompt(researchAnchor));
|
|
1660
1779
|
|
|
1780
|
+
inlined.push(formatProjectClassificationForPlanning(classifyProject(base)));
|
|
1781
|
+
|
|
1661
1782
|
inlined.push(await inlineFile(contextPath, contextRel, "Milestone Context"));
|
|
1662
1783
|
const researchInline = await inlineFileOptional(researchPath, researchRel, "Milestone Research");
|
|
1663
1784
|
if (researchInline) inlined.push(researchInline);
|
|
@@ -2348,6 +2469,9 @@ export async function buildCompleteMilestonePrompt(
|
|
|
2348
2469
|
const inlineLevel = level ?? resolveInlineLevel();
|
|
2349
2470
|
const roadmapPath = resolveMilestoneFile(base, mid, "ROADMAP");
|
|
2350
2471
|
const roadmapRel = relMilestoneFile(base, mid, "ROADMAP");
|
|
2472
|
+
const validationPath = resolveMilestoneFile(base, mid, "VALIDATION");
|
|
2473
|
+
const validationRel = relMilestoneFile(base, mid, "VALIDATION");
|
|
2474
|
+
const validationContent = validationPath ? await loadFile(validationPath) : null;
|
|
2351
2475
|
|
|
2352
2476
|
const inlined: string[] = [];
|
|
2353
2477
|
inlined.push(await inlineFile(roadmapPath, roadmapRel, "Milestone Roadmap"));
|
|
@@ -2389,6 +2513,13 @@ export async function buildCompleteMilestonePrompt(
|
|
|
2389
2513
|
`### On-demand Slice Summaries\n\nExcerpted above. Read the full file for any slice when the excerpt's section heads don't carry enough narrative for the milestone summary you're drafting:\n\n${pathList}`,
|
|
2390
2514
|
);
|
|
2391
2515
|
}
|
|
2516
|
+
const validationContext = [
|
|
2517
|
+
formatCloseoutReviewInstructions(validationContent, validationRel, [validationRel, roadmapRel, ...summaryRelPaths]),
|
|
2518
|
+
];
|
|
2519
|
+
if (validationContent) {
|
|
2520
|
+
validationContext.push(`### Milestone Validation\nSource: \`${validationRel}\`\n\n${validationContent.trim()}`);
|
|
2521
|
+
}
|
|
2522
|
+
inlined.unshift(...validationContext);
|
|
2392
2523
|
|
|
2393
2524
|
// Inline root GSD files (skip for minimal — completion can read these if needed)
|
|
2394
2525
|
if (inlineLevel !== "minimal") {
|
|
@@ -14,7 +14,7 @@ import { appendEvent } from "./workflow-events.js";
|
|
|
14
14
|
import { atomicWriteSync } from "./atomic-write.js";
|
|
15
15
|
import { clearParseCache } from "./files.js";
|
|
16
16
|
import { parseRoadmap as parseLegacyRoadmap, parsePlan as parseLegacyPlan } from "./parsers-legacy.js";
|
|
17
|
-
import { isDbAvailable, getTask, getSlice, getSliceTasks, getPendingGates, updateTaskStatus, updateSliceStatus, insertSlice, getMilestone, refreshOpenDatabaseFromDisk } from "./gsd-db.js";
|
|
17
|
+
import { isDbAvailable, getTask, getSlice, getSliceTasks, getPendingGates, updateTaskStatus, updateSliceStatus, insertSlice, getMilestone, refreshOpenDatabaseFromDisk, getCompletedMilestoneTaskFileHints, getMilestoneCommitAttributionShas, recordMilestoneCommitAttribution } from "./gsd-db.js";
|
|
18
18
|
import { isValidationTerminal } from "./state.js";
|
|
19
19
|
import { getErrorMessage } from "./error-utils.js";
|
|
20
20
|
import { logWarning, logError } from "./workflow-logger.js";
|
|
@@ -67,6 +67,60 @@ export {
|
|
|
67
67
|
|
|
68
68
|
// ─── Artifact Resolution & Verification ───────────────────────────────────────
|
|
69
69
|
|
|
70
|
+
export type ArtifactRecoveryDbRefreshResult =
|
|
71
|
+
| { ok: true }
|
|
72
|
+
| { ok: false; fatal: boolean; message: string; reason: string };
|
|
73
|
+
|
|
74
|
+
export function refreshRecoveryDbForArtifact(
|
|
75
|
+
unitType: string,
|
|
76
|
+
unitId: string,
|
|
77
|
+
): ArtifactRecoveryDbRefreshResult {
|
|
78
|
+
if (unitType !== "plan-slice" && unitType !== "execute-task") return { ok: true };
|
|
79
|
+
if (!isDbAvailable()) return { ok: true };
|
|
80
|
+
|
|
81
|
+
if (!refreshOpenDatabaseFromDisk()) {
|
|
82
|
+
return {
|
|
83
|
+
ok: false,
|
|
84
|
+
fatal: unitType === "execute-task",
|
|
85
|
+
reason: `${unitType}-db-refresh-failed`,
|
|
86
|
+
message: `Stuck recovery found ${unitType} ${unitId} artifacts, but the DB refresh failed.`,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (unitType !== "execute-task") return { ok: true };
|
|
91
|
+
|
|
92
|
+
const { milestone: mid, slice: sid, task: tid } = parseUnitId(unitId);
|
|
93
|
+
if (!mid || !sid || !tid) {
|
|
94
|
+
return {
|
|
95
|
+
ok: false,
|
|
96
|
+
fatal: true,
|
|
97
|
+
reason: "execute-task-invalid-unit-id",
|
|
98
|
+
message: `Stuck recovery found execute-task ${unitId} artifacts, but the unit id could not be parsed for DB verification.`,
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const task = getTask(mid, sid, tid);
|
|
103
|
+
if (!task) {
|
|
104
|
+
return {
|
|
105
|
+
ok: false,
|
|
106
|
+
fatal: true,
|
|
107
|
+
reason: "execute-task-artifact-db-missing",
|
|
108
|
+
message: `Stuck recovery found execute-task ${unitId} artifacts, but no matching DB task row exists after refresh.`,
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if (!isClosedStatus(task.status)) {
|
|
113
|
+
return {
|
|
114
|
+
ok: false,
|
|
115
|
+
fatal: true,
|
|
116
|
+
reason: "execute-task-artifact-db-mismatch",
|
|
117
|
+
message: `Stuck recovery found execute-task ${unitId} artifacts, but the DB task status is still '${task.status}' after refresh.`,
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return { ok: true };
|
|
122
|
+
}
|
|
123
|
+
|
|
70
124
|
function hasCapturedWorkflowPrefs(base: string): boolean {
|
|
71
125
|
const prefsPath = resolveExpectedArtifactPath("workflow-preferences", "WORKFLOW-PREFS", base);
|
|
72
126
|
if (!prefsPath || !existsSync(prefsPath)) return false;
|
|
@@ -147,15 +201,29 @@ export function hasImplementationArtifacts(basePath: string, milestoneId?: strin
|
|
|
147
201
|
// milestone commits instead of treating the self-diff as proof of no work.
|
|
148
202
|
if (changedFiles.length === 0) {
|
|
149
203
|
if (milestoneId && currentBranch === integrationBranch) {
|
|
150
|
-
const
|
|
151
|
-
if (!
|
|
152
|
-
if (
|
|
204
|
+
const milestoneEvidence = getChangedFilesFromMilestoneEvidence(basePath, milestoneId);
|
|
205
|
+
if (!milestoneEvidence.ok) return "unknown";
|
|
206
|
+
if (milestoneEvidence.matched) return classifyImplementationFiles(milestoneEvidence.files);
|
|
153
207
|
}
|
|
154
208
|
if (currentBranch && currentBranch !== "HEAD") return "absent";
|
|
155
209
|
return "unknown";
|
|
156
210
|
}
|
|
157
211
|
|
|
158
|
-
|
|
212
|
+
const branchClassification = classifyImplementationFiles(changedFiles);
|
|
213
|
+
if (branchClassification === "present") return "present";
|
|
214
|
+
|
|
215
|
+
// A completing milestone branch can have a non-empty diff containing only
|
|
216
|
+
// .gsd/ closeout files after implementation commits already landed on the
|
|
217
|
+
// recorded integration branch. In that topology, the branch diff alone is
|
|
218
|
+
// insufficient; use the same milestone-tagged evidence fallback as the
|
|
219
|
+
// self-diff retry path before declaring the milestone implementation-free.
|
|
220
|
+
if (milestoneId) {
|
|
221
|
+
const milestoneEvidence = getChangedFilesFromMilestoneEvidence(basePath, milestoneId);
|
|
222
|
+
if (!milestoneEvidence.ok) return "unknown";
|
|
223
|
+
if (milestoneEvidence.matched) return classifyImplementationFiles(milestoneEvidence.files);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
return "absent";
|
|
159
227
|
} catch (e) {
|
|
160
228
|
// Non-fatal — if git operations fail, return unknown so callers can decide
|
|
161
229
|
logWarning("recovery", `implementation artifact check failed: ${(e as Error).message}`);
|
|
@@ -185,6 +253,10 @@ function isImplementationPath(file: string): boolean {
|
|
|
185
253
|
return !file.startsWith(".gsd/") && !file.startsWith(".gsd\\");
|
|
186
254
|
}
|
|
187
255
|
|
|
256
|
+
function normalizeRepoPath(file: string): string {
|
|
257
|
+
return file.trim().replace(/\\/g, "/").replace(/^\.\/+/, "");
|
|
258
|
+
}
|
|
259
|
+
|
|
188
260
|
/**
|
|
189
261
|
* Detect the main/master branch name.
|
|
190
262
|
*/
|
|
@@ -263,7 +335,7 @@ function getChangedFilesFromMilestoneTaggedCommits(
|
|
|
263
335
|
"log", "--format=%H%x1f%B%x1e", "HEAD", "--", `.gsd/milestones/${milestoneId}`,
|
|
264
336
|
]);
|
|
265
337
|
if (!scoped.ok) return scoped;
|
|
266
|
-
if (scoped.matched) return scoped;
|
|
338
|
+
if (scoped.matched && classifyImplementationFiles(scoped.files) === "present") return scoped;
|
|
267
339
|
|
|
268
340
|
// Fallback (#5033): when .gsd/ is gitignored / external / untracked, the
|
|
269
341
|
// path-scoped scan matches no commits even though GSD-tagged commits
|
|
@@ -274,9 +346,137 @@ function getChangedFilesFromMilestoneTaggedCommits(
|
|
|
274
346
|
// Intentionally unbounded — symmetric with the primary scan, and avoids
|
|
275
347
|
// reintroducing the rolling-depth failure class removed in #4699 where
|
|
276
348
|
// milestone evidence aged out behind unrelated activity.
|
|
277
|
-
|
|
349
|
+
const unscoped = scanGsdTaggedCommits(basePath, milestoneId, [
|
|
278
350
|
"log", "--format=%H%x1f%B%x1e", "HEAD",
|
|
279
351
|
]);
|
|
352
|
+
if (!unscoped.ok) return scoped.matched ? scoped : unscoped;
|
|
353
|
+
if (!unscoped.matched) return scoped;
|
|
354
|
+
|
|
355
|
+
return {
|
|
356
|
+
ok: true,
|
|
357
|
+
matched: true,
|
|
358
|
+
files: [...new Set([...scoped.files, ...unscoped.files])],
|
|
359
|
+
};
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
function getChangedFilesFromMilestoneEvidence(
|
|
363
|
+
basePath: string,
|
|
364
|
+
milestoneId: string,
|
|
365
|
+
): { ok: boolean; matched: boolean; files: string[] } {
|
|
366
|
+
const tagged = getChangedFilesFromMilestoneTaggedCommits(basePath, milestoneId);
|
|
367
|
+
if (!tagged.ok) return tagged;
|
|
368
|
+
if (tagged.matched && classifyImplementationFiles(tagged.files) === "present") return tagged;
|
|
369
|
+
|
|
370
|
+
const attributed = getChangedFilesFromAttributedMilestoneCommits(basePath, milestoneId);
|
|
371
|
+
if (!attributed.ok) return tagged.matched ? tagged : attributed;
|
|
372
|
+
if (attributed.matched && classifyImplementationFiles(attributed.files) === "present") return attributed;
|
|
373
|
+
|
|
374
|
+
const backfilled = backfillChangedFilesFromUntaggedMilestoneCommits(basePath, milestoneId);
|
|
375
|
+
if (!backfilled.ok) return tagged.matched ? tagged : attributed.matched ? attributed : backfilled;
|
|
376
|
+
if (!backfilled.matched) {
|
|
377
|
+
if (tagged.matched) return tagged;
|
|
378
|
+
return attributed.matched ? attributed : backfilled;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
return {
|
|
382
|
+
ok: true,
|
|
383
|
+
matched: true,
|
|
384
|
+
files: [...new Set([...tagged.files, ...attributed.files, ...backfilled.files])],
|
|
385
|
+
};
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
function getChangedFilesFromAttributedMilestoneCommits(
|
|
389
|
+
basePath: string,
|
|
390
|
+
milestoneId: string,
|
|
391
|
+
): { ok: boolean; matched: boolean; files: string[] } {
|
|
392
|
+
try {
|
|
393
|
+
const shas = getMilestoneCommitAttributionShas(milestoneId);
|
|
394
|
+
if (shas.length === 0) return { ok: true, matched: false, files: [] };
|
|
395
|
+
|
|
396
|
+
const files = new Set<string>();
|
|
397
|
+
let matched = false;
|
|
398
|
+
for (const sha of shas) {
|
|
399
|
+
if (!isFullCommitSha(sha)) continue;
|
|
400
|
+
const commitFiles = getChangedFilesForCommit(basePath, sha);
|
|
401
|
+
if (commitFiles.length === 0) continue;
|
|
402
|
+
matched = true;
|
|
403
|
+
for (const file of commitFiles) files.add(file);
|
|
404
|
+
}
|
|
405
|
+
return { ok: true, matched, files: [...files] };
|
|
406
|
+
} catch (e) {
|
|
407
|
+
logWarning("recovery", `milestone attribution scan failed: ${(e as Error).message}`);
|
|
408
|
+
return { ok: false, matched: false, files: [] };
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
function backfillChangedFilesFromUntaggedMilestoneCommits(
|
|
413
|
+
basePath: string,
|
|
414
|
+
milestoneId: string,
|
|
415
|
+
): { ok: boolean; matched: boolean; files: string[] } {
|
|
416
|
+
try {
|
|
417
|
+
const milestone = getMilestone(milestoneId);
|
|
418
|
+
const milestoneStartedAt = milestone?.created_at ? Math.floor(Date.parse(milestone.created_at) / 1000) * 1000 : NaN;
|
|
419
|
+
if (!Number.isFinite(milestoneStartedAt)) return { ok: true, matched: false, files: [] };
|
|
420
|
+
|
|
421
|
+
const taskFileHints = getCompletedMilestoneTaskFileHints(milestoneId);
|
|
422
|
+
if (taskFileHints.length === 0) return { ok: true, matched: false, files: [] };
|
|
423
|
+
|
|
424
|
+
const hintSet = new Set(taskFileHints.map(normalizeRepoPath).filter(Boolean));
|
|
425
|
+
if (hintSet.size === 0) return { ok: true, matched: false, files: [] };
|
|
426
|
+
|
|
427
|
+
const records = getCommitRecords(basePath);
|
|
428
|
+
const files = new Set<string>();
|
|
429
|
+
let matched = false;
|
|
430
|
+
for (const record of records) {
|
|
431
|
+
if (!isFullCommitSha(record.hash)) continue;
|
|
432
|
+
if (Date.parse(record.committedAt) < milestoneStartedAt) continue;
|
|
433
|
+
if (record.parents.trim().split(/\s+/).filter(Boolean).length > 1) continue;
|
|
434
|
+
if (commitMessageHasGsdTrailer(record.message)) continue;
|
|
435
|
+
|
|
436
|
+
const commitFiles = getChangedFilesForCommit(basePath, record.hash);
|
|
437
|
+
const implementationFiles = commitFiles.map(normalizeRepoPath).filter(isImplementationPath);
|
|
438
|
+
if (implementationFiles.length === 0) continue;
|
|
439
|
+
if (!implementationFiles.some((file) => hintSet.has(file))) continue;
|
|
440
|
+
|
|
441
|
+
matched = true;
|
|
442
|
+
for (const file of implementationFiles) files.add(file);
|
|
443
|
+
recordMilestoneCommitAttribution({
|
|
444
|
+
commitSha: record.hash,
|
|
445
|
+
milestoneId,
|
|
446
|
+
source: "backfill",
|
|
447
|
+
confidence: 0.8,
|
|
448
|
+
files: implementationFiles,
|
|
449
|
+
createdAt: new Date().toISOString(),
|
|
450
|
+
});
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
return { ok: true, matched, files: [...files] };
|
|
454
|
+
} catch (e) {
|
|
455
|
+
logWarning("recovery", `milestone attribution backfill failed: ${(e as Error).message}`);
|
|
456
|
+
return { ok: false, matched: false, files: [] };
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
function getCommitRecords(basePath: string): Array<{ hash: string; parents: string; committedAt: string; message: string }> {
|
|
461
|
+
const logOutput = execFileSync("git", ["log", "--format=%H%x1f%P%x1f%cI%x1f%B%x1e", "HEAD"], {
|
|
462
|
+
cwd: basePath,
|
|
463
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
464
|
+
encoding: "utf-8",
|
|
465
|
+
});
|
|
466
|
+
return logOutput
|
|
467
|
+
.split("\x1e")
|
|
468
|
+
.map((record) => record.trim())
|
|
469
|
+
.filter(Boolean)
|
|
470
|
+
.flatMap((record) => {
|
|
471
|
+
const parts = record.split("\x1f");
|
|
472
|
+
if (parts.length < 4) return [];
|
|
473
|
+
const [hash, parents, committedAt, ...messageParts] = parts;
|
|
474
|
+
return [{ hash: hash.trim(), parents: parents.trim(), committedAt: committedAt.trim(), message: messageParts.join("\x1f") }];
|
|
475
|
+
});
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
function isFullCommitSha(value: string): boolean {
|
|
479
|
+
return /^[0-9a-f]{40}$/i.test(value);
|
|
280
480
|
}
|
|
281
481
|
|
|
282
482
|
function scanGsdTaggedCommits(
|
|
@@ -664,12 +664,13 @@ export async function bootstrapAutoSession(
|
|
|
664
664
|
}
|
|
665
665
|
|
|
666
666
|
const effectivePrefs = loadEffectiveGSDPreferences(base)?.preferences;
|
|
667
|
-
const
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
667
|
+
const { shouldRunDeepProjectSetup } = await import("./auto-dispatch.js");
|
|
668
|
+
const deepProjectStagePending = shouldRunDeepProjectSetup(
|
|
669
|
+
state,
|
|
670
|
+
effectivePrefs,
|
|
671
|
+
base,
|
|
672
|
+
{ hasSurvivorBranch },
|
|
673
|
+
);
|
|
673
674
|
|
|
674
675
|
if (deepProjectStagePending) {
|
|
675
676
|
// Deep project-level setup runs before the first milestone exists. Let
|
|
@@ -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);
|
|
@@ -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,
|
|
@@ -200,6 +201,8 @@ import {
|
|
|
200
201
|
detectWorkingTreeActivity,
|
|
201
202
|
} from "./auto-supervisor.js";
|
|
202
203
|
import { isDbAvailable, getMilestone } from "./gsd-db.js";
|
|
204
|
+
import { markLatestActiveForWorkerCanceled } from "./db/unit-dispatches.js";
|
|
205
|
+
import { writeUnitRuntimeRecord } from "./unit-runtime.js";
|
|
203
206
|
import { countPendingCaptures } from "./captures.js";
|
|
204
207
|
import { CMUX_CHANNELS, type CmuxLogLevel } from "../shared/cmux-events.js";
|
|
205
208
|
import { ensureDbOpen } from "./bootstrap/dynamic-tools.js";
|
|
@@ -242,6 +245,20 @@ import {
|
|
|
242
245
|
type WorktreeResolverDeps,
|
|
243
246
|
} from "./worktree-resolver.js";
|
|
244
247
|
import { reorderForCaching } from "./prompt-ordering.js";
|
|
248
|
+
import { initTokenCounter } from "./token-counter.js";
|
|
249
|
+
|
|
250
|
+
// Warm the tiktoken encoder at extension startup so context-budget computations
|
|
251
|
+
// can use accurate token counts via countTokensSync without paying the load
|
|
252
|
+
// cost mid-prompt-build. Fire-and-forget — failure falls back to the
|
|
253
|
+
// provider-aware char-ratio estimator already used by getCharsPerToken().
|
|
254
|
+
// Catch rejections explicitly: an unhandled rejection at module-import time
|
|
255
|
+
// can destabilize startup before the engine logger is configured.
|
|
256
|
+
void initTokenCounter().catch((err) => {
|
|
257
|
+
logWarning(
|
|
258
|
+
"engine",
|
|
259
|
+
`token counter warm-up failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
260
|
+
);
|
|
261
|
+
});
|
|
245
262
|
|
|
246
263
|
// ─── Session State ─────────────────────────────────────────────────────────
|
|
247
264
|
|
|
@@ -293,11 +310,15 @@ const STATE_REBUILD_MIN_INTERVAL_MS = 30_000;
|
|
|
293
310
|
* the DB is unavailable (e.g. fresh project before init) we skip registration
|
|
294
311
|
* silently rather than blocking session start.
|
|
295
312
|
*/
|
|
296
|
-
function registerAutoWorkerForSession(
|
|
313
|
+
function registerAutoWorkerForSession(
|
|
314
|
+
session: AutoSession,
|
|
315
|
+
projectRootOverride?: string,
|
|
316
|
+
): void {
|
|
297
317
|
if (session.workerId) return; // already registered (e.g. resume re-runs)
|
|
298
318
|
try {
|
|
299
319
|
const projectRootRealpath = normalizeRealPath(
|
|
300
|
-
|
|
320
|
+
projectRootOverride
|
|
321
|
+
?? session.scope?.workspace.projectRoot
|
|
301
322
|
?? (session.originalBasePath || session.basePath),
|
|
302
323
|
);
|
|
303
324
|
session.workerId = registerAutoWorker({ projectRootRealpath });
|
|
@@ -420,6 +441,17 @@ export function _synthesizePausedSessionRecoveryForTest(
|
|
|
420
441
|
return synthesizePausedSessionRecovery(basePath, unitType, unitId, sessionFile);
|
|
421
442
|
}
|
|
422
443
|
|
|
444
|
+
const DETACHED_AUTO_KEEPALIVE_INTERVAL_MS = 30_000;
|
|
445
|
+
|
|
446
|
+
function withDetachedAutoKeepalive<T>(run: Promise<T>): Promise<T> {
|
|
447
|
+
const keepAlive = setInterval(() => {}, DETACHED_AUTO_KEEPALIVE_INTERVAL_MS);
|
|
448
|
+
return run.finally(() => {
|
|
449
|
+
clearInterval(keepAlive);
|
|
450
|
+
});
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
export const _withDetachedAutoKeepaliveForTest = withDetachedAutoKeepalive;
|
|
454
|
+
|
|
423
455
|
export function startAutoDetached(
|
|
424
456
|
ctx: ExtensionCommandContext,
|
|
425
457
|
pi: ExtensionAPI,
|
|
@@ -431,7 +463,7 @@ export function startAutoDetached(
|
|
|
431
463
|
milestoneLock?: string | null;
|
|
432
464
|
},
|
|
433
465
|
): void {
|
|
434
|
-
void startAuto(ctx, pi, base, verboseMode, options).catch((err) => {
|
|
466
|
+
void withDetachedAutoKeepalive(startAuto(ctx, pi, base, verboseMode, options)).catch((err) => {
|
|
435
467
|
const message = getErrorMessage(err);
|
|
436
468
|
ctx.ui.notify(`Auto-start failed: ${message}`, "error");
|
|
437
469
|
logWarning("engine", `auto start error: ${message}`, { file: "auto.ts" });
|
|
@@ -490,9 +522,54 @@ export {
|
|
|
490
522
|
getBudgetEnforcementAction,
|
|
491
523
|
} from "./auto-budget.js";
|
|
492
524
|
|
|
525
|
+
function closeOutSignalInterruptedUnit(currentBasePath: string): void {
|
|
526
|
+
const currentUnit = s.currentUnit;
|
|
527
|
+
if (!currentUnit) return;
|
|
528
|
+
|
|
529
|
+
const reason = "Auto-mode process received a termination signal";
|
|
530
|
+
const errorContext: ErrorContext = {
|
|
531
|
+
message: reason,
|
|
532
|
+
category: "aborted",
|
|
533
|
+
isTransient: false,
|
|
534
|
+
};
|
|
535
|
+
const basePath = s.basePath || currentBasePath;
|
|
536
|
+
|
|
537
|
+
try {
|
|
538
|
+
emitOpenUnitEndForUnit(basePath, currentUnit.type, currentUnit.id, "cancelled", errorContext);
|
|
539
|
+
} catch (err) {
|
|
540
|
+
logWarning("engine", `signal unit-end cleanup failed: ${getErrorMessage(err)}`, { file: "auto.ts" });
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
try {
|
|
544
|
+
writeUnitRuntimeRecord(basePath, currentUnit.type, currentUnit.id, currentUnit.startedAt, {
|
|
545
|
+
phase: "crashed",
|
|
546
|
+
lastProgressAt: Date.now(),
|
|
547
|
+
lastProgressKind: "signal",
|
|
548
|
+
});
|
|
549
|
+
} catch (err) {
|
|
550
|
+
logWarning("engine", `signal runtime cleanup failed: ${getErrorMessage(err)}`, { file: "auto.ts" });
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
try {
|
|
554
|
+
if (s.workerId) markLatestActiveForWorkerCanceled(s.workerId, "signal-exit");
|
|
555
|
+
} catch (err) {
|
|
556
|
+
logWarning("engine", `signal dispatch cleanup failed: ${getErrorMessage(err)}`, { file: "auto.ts" });
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
try {
|
|
560
|
+
resolveAgentEndCancelled(errorContext);
|
|
561
|
+
} catch (err) {
|
|
562
|
+
logWarning("engine", `signal resolve cleanup failed: ${getErrorMessage(err)}`, { file: "auto.ts" });
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
|
|
493
566
|
/** Wrapper: register SIGTERM handler and store reference. */
|
|
494
567
|
function registerSigtermHandler(currentBasePath: string): void {
|
|
495
|
-
s.sigtermHandler = _registerSigtermHandler(
|
|
568
|
+
s.sigtermHandler = _registerSigtermHandler(
|
|
569
|
+
currentBasePath,
|
|
570
|
+
s.sigtermHandler,
|
|
571
|
+
() => closeOutSignalInterruptedUnit(currentBasePath),
|
|
572
|
+
);
|
|
496
573
|
}
|
|
497
574
|
|
|
498
575
|
/** Wrapper: deregister SIGTERM handler and clear reference. */
|
|
@@ -1960,6 +2037,10 @@ export async function startAuto(
|
|
|
1960
2037
|
: new URL("../../../resource-loader.js", import.meta.url).href;
|
|
1961
2038
|
const { initResources } = await import(resourceLoaderPath);
|
|
1962
2039
|
initResources(agentDir);
|
|
2040
|
+
// initResources() uses synchronous fs APIs, so the prompt-template cache
|
|
2041
|
+
// can be primed immediately — no need for the legacy 1s setTimeout deferral.
|
|
2042
|
+
const { primeCache } = await import("./prompt-loader.js");
|
|
2043
|
+
primeCache();
|
|
1963
2044
|
// Open the project DB before rebuild/derive so resume uses DB-backed
|
|
1964
2045
|
// state instead of falling back to stale markdown parsing (#2940).
|
|
1965
2046
|
await openProjectDbIfPresent(s.basePath);
|
|
@@ -2046,6 +2127,11 @@ export async function startAuto(
|
|
|
2046
2127
|
buildResolver,
|
|
2047
2128
|
};
|
|
2048
2129
|
|
|
2130
|
+
// Register the worker before bootstrap enters a milestone worktree.
|
|
2131
|
+
// This ensures enterMilestone can claim a lease and seed dispatch claims
|
|
2132
|
+
// for crash-recovery fidelity (#5405).
|
|
2133
|
+
registerAutoWorkerForSession(s, base);
|
|
2134
|
+
|
|
2049
2135
|
const ready = await bootstrapAutoSession(
|
|
2050
2136
|
s,
|
|
2051
2137
|
ctx,
|