gsd-pi 2.65.0 → 2.66.0-dev.e159299
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/mcp-server.js +6 -2
- package/dist/resources/extensions/browser-tools/capture.js +20 -1
- package/dist/resources/extensions/browser-tools/tests/capture-sharp-optional.test.cjs +93 -0
- package/dist/resources/extensions/gsd/auto/finalize-timeout.js +2 -0
- package/dist/resources/extensions/gsd/auto/loop.js +2 -2
- package/dist/resources/extensions/gsd/auto/phases.js +48 -5
- package/dist/resources/extensions/gsd/auto/run-unit.js +13 -2
- package/dist/resources/extensions/gsd/auto/session.js +4 -0
- package/dist/resources/extensions/gsd/auto/types.js +2 -0
- package/dist/resources/extensions/gsd/auto-dashboard.js +2 -1
- package/dist/resources/extensions/gsd/auto-dispatch.js +99 -9
- package/dist/resources/extensions/gsd/auto-model-selection.js +7 -5
- package/dist/resources/extensions/gsd/auto-post-unit.js +17 -6
- package/dist/resources/extensions/gsd/auto-prompts.js +24 -0
- package/dist/resources/extensions/gsd/auto-recovery.js +40 -22
- package/dist/resources/extensions/gsd/auto-start.js +175 -12
- package/dist/resources/extensions/gsd/auto-tool-tracking.js +10 -0
- package/dist/resources/extensions/gsd/auto-worktree.js +29 -7
- package/dist/resources/extensions/gsd/auto.js +21 -15
- package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +17 -4
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +10 -0
- package/dist/resources/extensions/gsd/bootstrap/query-tools.js +6 -4
- package/dist/resources/extensions/gsd/bootstrap/register-extension.js +5 -1
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +11 -3
- package/dist/resources/extensions/gsd/bootstrap/system-context.js +3 -1
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +31 -1
- package/dist/resources/extensions/gsd/commands/context.js +8 -1
- package/dist/resources/extensions/gsd/commands/handlers/core.js +23 -2
- package/dist/resources/extensions/gsd/commands-extensions.js +1 -1
- package/dist/resources/extensions/gsd/config-overlay.js +312 -0
- package/dist/resources/extensions/gsd/db-writer.js +13 -3
- package/dist/resources/extensions/gsd/detection.js +1 -1
- package/dist/resources/extensions/gsd/dispatch-guard.js +2 -1
- package/dist/resources/extensions/gsd/docs/preferences-reference.md +1 -0
- package/dist/resources/extensions/gsd/doctor.js +2 -1
- package/dist/resources/extensions/gsd/files.js +17 -0
- package/dist/resources/extensions/gsd/gitignore.js +1 -0
- package/dist/resources/extensions/gsd/gsd-db.js +47 -4
- package/dist/resources/extensions/gsd/guided-flow.js +220 -29
- package/dist/resources/extensions/gsd/index.js +1 -1
- package/dist/resources/extensions/gsd/json-persistence.js +5 -2
- package/dist/resources/extensions/gsd/md-importer.js +14 -7
- package/dist/resources/extensions/gsd/notification-overlay.js +1 -1
- package/dist/resources/extensions/gsd/notification-widget.js +2 -1
- package/dist/resources/extensions/gsd/parallel-monitor-overlay.js +1 -1
- package/dist/resources/extensions/gsd/parallel-orchestrator.js +17 -11
- package/dist/resources/extensions/gsd/pre-execution-checks.js +26 -5
- package/dist/resources/extensions/gsd/preferences-types.js +3 -0
- package/dist/resources/extensions/gsd/preferences-validation.js +45 -1
- package/dist/resources/extensions/gsd/preferences.js +9 -2
- package/dist/resources/extensions/gsd/preparation.js +1092 -0
- package/dist/resources/extensions/gsd/prompt-validation.js +67 -0
- package/dist/resources/extensions/gsd/prompts/complete-milestone.md +3 -3
- package/dist/resources/extensions/gsd/prompts/complete-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/discuss-prepared.md +424 -0
- package/dist/resources/extensions/gsd/prompts/discuss.md +2 -0
- package/dist/resources/extensions/gsd/prompts/guided-discuss-milestone.md +6 -1
- package/dist/resources/extensions/gsd/prompts/guided-discuss-slice.md +5 -4
- package/dist/resources/extensions/gsd/prompts/parallel-research-slices.md +23 -0
- package/dist/resources/extensions/gsd/prompts/queue.md +2 -0
- package/dist/resources/extensions/gsd/prompts/rethink.md +2 -1
- package/dist/resources/extensions/gsd/prompts/system.md +2 -2
- package/dist/resources/extensions/gsd/prompts/validate-milestone.md +56 -23
- package/dist/resources/extensions/gsd/quick.js +19 -15
- package/dist/resources/extensions/gsd/reactive-graph.js +12 -0
- package/dist/resources/extensions/gsd/roadmap-slices.js +24 -5
- package/dist/resources/extensions/gsd/safety/content-validator.js +3 -3
- package/dist/resources/extensions/gsd/session-lock.js +23 -1
- package/dist/resources/extensions/gsd/state.js +115 -28
- package/dist/resources/extensions/gsd/templates/context-enhanced.md +138 -0
- package/dist/resources/extensions/gsd/tools/complete-milestone.js +15 -3
- package/dist/resources/extensions/gsd/tools/complete-slice.js +27 -6
- package/dist/resources/extensions/gsd/tools/complete-task.js +31 -7
- package/dist/resources/extensions/gsd/tools/plan-milestone.js +7 -5
- package/dist/resources/extensions/gsd/tools/reassess-roadmap.js +5 -2
- package/dist/resources/extensions/gsd/tools/reopen-milestone.js +119 -0
- package/dist/resources/extensions/gsd/tools/reopen-slice.js +30 -0
- package/dist/resources/extensions/gsd/tools/reopen-task.js +18 -0
- package/dist/resources/extensions/gsd/triage-resolution.js +33 -16
- package/dist/resources/extensions/gsd/undo.js +3 -2
- package/dist/resources/extensions/gsd/workflow-events.js +1 -0
- package/dist/resources/extensions/gsd/workflow-logger.js +1 -1
- package/dist/resources/extensions/gsd/workflow-projections.js +7 -9
- package/dist/resources/extensions/gsd/workflow-reconcile.js +100 -9
- package/dist/resources/extensions/gsd/workflow-templates.js +11 -2
- package/dist/resources/extensions/gsd/worktree-manager.js +5 -2
- package/dist/resources/extensions/gsd/worktree.js +9 -0
- package/dist/resources/extensions/shared/interview-ui.js +1 -1
- package/dist/resources/extensions/subagent/agents.js +19 -5
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +17 -17
- package/dist/web/standalone/.next/build-manifest.json +4 -4
- 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/required-server-files.json +3 -3
- package/dist/web/standalone/.next/server/app/_global-error/page.js +3 -3
- package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.html +2 -2
- package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found/page.js +2 -2
- package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.rsc +3 -3
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +3 -3
- 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 +3 -3
- 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/boot/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/boot/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/browse-directories/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/browse-directories/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/captures/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/captures/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/cleanup/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/cleanup/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/dev-mode/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/dev-mode/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/doctor/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/doctor/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/experimental/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/experimental/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/export-data/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/export-data/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/files/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/files/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/forensics/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/forensics/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/git/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/history/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/history/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/hooks/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/hooks/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/inspect/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/inspect/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/knowledge/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/knowledge/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/live-state/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/live-state/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/notifications/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/notifications/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/onboarding/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/preferences/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/preferences/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/projects/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/projects/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/recovery/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/recovery/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/remote-questions/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/remote-questions/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/browser/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/browser/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/command/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/command/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/events/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/session/events/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/manage/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/manage/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/settings-data/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/settings-data/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/shutdown/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/shutdown/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/skill-health/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/skill-health/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/steer/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/steer/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/switch-root/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/switch-root/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/input/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/terminal/input/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/resize/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/terminal/resize/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/terminal/sessions/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js +4 -4
- package/dist/web/standalone/.next/server/app/api/terminal/stream/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/upload/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/upload/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/undo/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/undo/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/update/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/visualizer/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/visualizer/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +4 -4
- package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
- package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +4 -4
- 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 +3 -3
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/page.js +2 -2
- package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +17 -17
- package/dist/web/standalone/.next/server/chunks/6897.js +1 -1
- package/dist/web/standalone/.next/server/chunks/7471.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/middleware.js +2 -2
- package/dist/web/standalone/.next/server/next-font-manifest.js +1 -1
- package/dist/web/standalone/.next/server/next-font-manifest.json +1 -1
- package/dist/web/standalone/.next/server/pages/404.html +1 -1
- package/dist/web/standalone/.next/server/pages/500.html +2 -2
- package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
- package/dist/web/standalone/.next/static/chunks/6502.8874bcae249c02e1.js +9 -0
- package/dist/web/standalone/.next/static/chunks/app/_not-found/{page-2f24283c162b6ab3.js → page-f2a7482d42a5614b.js} +1 -1
- package/dist/web/standalone/.next/static/chunks/app/{layout-9ecfd95f343793f0.js → layout-a16c7a7ecdf0c2cf.js} +1 -1
- package/dist/web/standalone/.next/static/chunks/app/page-0c485498795110d6.js +1 -0
- package/dist/web/standalone/.next/static/chunks/main-app-fdab67f7802d7832.js +1 -0
- package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-459824ffb8c323dd.js +1 -0
- package/dist/web/standalone/.next/static/chunks/{webpack-a1c1e452c6b32d04.js → webpack-9fed74684e1c5bb1.js} +1 -1
- package/dist/web/standalone/node_modules/node-pty/build/Makefile +2 -2
- package/dist/web/standalone/node_modules/node-pty/build/Release/pty.node +0 -0
- package/dist/web/standalone/node_modules/node-pty/build/pty.target.mk +14 -14
- package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api.target.mk +14 -14
- package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_except.target.mk +14 -14
- package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_maybe.target.mk +14 -14
- package/dist/web/standalone/server.js +1 -1
- package/package.json +1 -1
- package/packages/pi-coding-agent/dist/core/retry-handler.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/retry-handler.js +30 -19
- package/packages/pi-coding-agent/dist/core/retry-handler.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/retry-handler.test.js +51 -0
- package/packages/pi-coding-agent/dist/core/retry-handler.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/sdk.js +9 -9
- package/packages/pi-coding-agent/dist/core/sdk.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.d.ts +2 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.js +10 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.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 +20 -5
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js +15 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.js +18 -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.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +4 -0
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/packages/pi-coding-agent/package.json +1 -1
- package/packages/pi-coding-agent/src/core/retry-handler.test.ts +80 -0
- package/packages/pi-coding-agent/src/core/retry-handler.ts +37 -25
- package/packages/pi-coding-agent/src/core/sdk.ts +9 -9
- package/packages/pi-coding-agent/src/modes/interactive/components/provider-manager.ts +10 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +20 -4
- package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.test.ts +27 -0
- package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.ts +16 -1
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +5 -0
- package/packages/pi-tui/dist/components/image.d.ts +2 -0
- package/packages/pi-tui/dist/components/image.d.ts.map +1 -1
- package/packages/pi-tui/dist/components/image.js +4 -0
- package/packages/pi-tui/dist/components/image.js.map +1 -1
- package/packages/pi-tui/dist/components/image.test.d.ts +6 -0
- package/packages/pi-tui/dist/components/image.test.d.ts.map +1 -0
- package/packages/pi-tui/dist/components/image.test.js +32 -0
- package/packages/pi-tui/dist/components/image.test.js.map +1 -0
- package/packages/pi-tui/dist/tui.d.ts.map +1 -1
- package/packages/pi-tui/dist/tui.js +3 -1
- package/packages/pi-tui/dist/tui.js.map +1 -1
- package/packages/pi-tui/src/components/image.test.ts +36 -0
- package/packages/pi-tui/src/components/image.ts +5 -0
- package/packages/pi-tui/src/tui.ts +3 -1
- package/pkg/package.json +1 -1
- package/src/resources/extensions/browser-tools/capture.ts +19 -1
- package/src/resources/extensions/browser-tools/tests/capture-sharp-optional.test.cjs +93 -0
- package/src/resources/extensions/gsd/auto/finalize-timeout.ts +3 -0
- package/src/resources/extensions/gsd/auto/loop.ts +2 -2
- package/src/resources/extensions/gsd/auto/phases.ts +68 -3
- package/src/resources/extensions/gsd/auto/run-unit.ts +12 -2
- package/src/resources/extensions/gsd/auto/session.ts +4 -0
- package/src/resources/extensions/gsd/auto/types.ts +5 -0
- package/src/resources/extensions/gsd/auto-dashboard.ts +2 -1
- package/src/resources/extensions/gsd/auto-dispatch.ts +110 -9
- package/src/resources/extensions/gsd/auto-model-selection.ts +7 -5
- package/src/resources/extensions/gsd/auto-post-unit.ts +16 -6
- package/src/resources/extensions/gsd/auto-prompts.ts +31 -0
- package/src/resources/extensions/gsd/auto-recovery.ts +29 -23
- package/src/resources/extensions/gsd/auto-start.ts +188 -10
- package/src/resources/extensions/gsd/auto-tool-tracking.ts +10 -0
- package/src/resources/extensions/gsd/auto-worktree.ts +28 -7
- package/src/resources/extensions/gsd/auto.ts +19 -8
- package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +16 -4
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +10 -0
- package/src/resources/extensions/gsd/bootstrap/query-tools.ts +5 -4
- package/src/resources/extensions/gsd/bootstrap/register-extension.ts +4 -1
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +11 -3
- package/src/resources/extensions/gsd/bootstrap/system-context.ts +3 -1
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +36 -1
- package/src/resources/extensions/gsd/commands/context.ts +7 -1
- package/src/resources/extensions/gsd/commands/handlers/core.ts +26 -2
- package/src/resources/extensions/gsd/commands-extensions.ts +1 -1
- package/src/resources/extensions/gsd/config-overlay.ts +331 -0
- package/src/resources/extensions/gsd/db-writer.ts +11 -3
- package/src/resources/extensions/gsd/detection.ts +1 -1
- package/src/resources/extensions/gsd/dispatch-guard.ts +2 -1
- package/src/resources/extensions/gsd/docs/preferences-reference.md +1 -0
- package/src/resources/extensions/gsd/doctor.ts +2 -1
- package/src/resources/extensions/gsd/files.ts +19 -0
- package/src/resources/extensions/gsd/gitignore.ts +1 -0
- package/src/resources/extensions/gsd/gsd-db.ts +46 -4
- package/src/resources/extensions/gsd/guided-flow.ts +254 -30
- package/src/resources/extensions/gsd/index.ts +1 -0
- package/src/resources/extensions/gsd/json-persistence.ts +6 -3
- package/src/resources/extensions/gsd/md-importer.ts +13 -6
- package/src/resources/extensions/gsd/notification-overlay.ts +1 -1
- package/src/resources/extensions/gsd/notification-widget.ts +2 -1
- package/src/resources/extensions/gsd/parallel-monitor-overlay.ts +1 -1
- package/src/resources/extensions/gsd/parallel-orchestrator.ts +19 -11
- package/src/resources/extensions/gsd/pre-execution-checks.ts +32 -7
- package/src/resources/extensions/gsd/preferences-types.ts +25 -0
- package/src/resources/extensions/gsd/preferences-validation.ts +45 -1
- package/src/resources/extensions/gsd/preferences.ts +9 -2
- package/src/resources/extensions/gsd/preparation.ts +1419 -0
- package/src/resources/extensions/gsd/prompt-validation.ts +88 -0
- package/src/resources/extensions/gsd/prompts/complete-milestone.md +3 -3
- package/src/resources/extensions/gsd/prompts/complete-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/discuss-prepared.md +424 -0
- package/src/resources/extensions/gsd/prompts/discuss.md +2 -0
- package/src/resources/extensions/gsd/prompts/guided-discuss-milestone.md +6 -1
- package/src/resources/extensions/gsd/prompts/guided-discuss-slice.md +5 -4
- package/src/resources/extensions/gsd/prompts/parallel-research-slices.md +23 -0
- package/src/resources/extensions/gsd/prompts/queue.md +2 -0
- package/src/resources/extensions/gsd/prompts/rethink.md +2 -1
- package/src/resources/extensions/gsd/prompts/system.md +2 -2
- package/src/resources/extensions/gsd/prompts/validate-milestone.md +56 -23
- package/src/resources/extensions/gsd/quick.ts +20 -15
- package/src/resources/extensions/gsd/reactive-graph.ts +18 -0
- package/src/resources/extensions/gsd/roadmap-slices.ts +21 -5
- package/src/resources/extensions/gsd/safety/content-validator.ts +3 -3
- package/src/resources/extensions/gsd/session-lock.ts +17 -1
- package/src/resources/extensions/gsd/state.ts +115 -26
- package/src/resources/extensions/gsd/templates/context-enhanced.md +138 -0
- package/src/resources/extensions/gsd/tests/adversarial-review-fixes.test.ts +223 -0
- package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +33 -2
- package/src/resources/extensions/gsd/tests/auto-remediate-slice-status.test.ts +56 -0
- package/src/resources/extensions/gsd/tests/clear-stale-autostart.test.ts +41 -0
- package/src/resources/extensions/gsd/tests/complete-slice-verification-gate.test.ts +72 -0
- package/src/resources/extensions/gsd/tests/complete-task-normalize-lists.test.ts +54 -0
- package/src/resources/extensions/gsd/tests/defer-milestone-stamp.test.ts +30 -0
- package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +4 -3
- package/src/resources/extensions/gsd/tests/discuss-incremental-persistence.test.ts +36 -0
- package/src/resources/extensions/gsd/tests/discuss-slice-structured-questions.test.ts +46 -0
- package/src/resources/extensions/gsd/tests/dispatch-guard-closed-status.test.ts +33 -0
- package/src/resources/extensions/gsd/tests/dispatcher-stuck-planning.test.ts +37 -0
- package/src/resources/extensions/gsd/tests/error-success-mask.test.ts +37 -0
- package/src/resources/extensions/gsd/tests/finalize-timeout-guard.test.ts +125 -0
- package/src/resources/extensions/gsd/tests/find-missing-summaries-closed.test.ts +48 -0
- package/src/resources/extensions/gsd/tests/format-shortcut.test.ts +69 -0
- package/src/resources/extensions/gsd/tests/frontmatter-parse-noise.test.ts +42 -0
- package/src/resources/extensions/gsd/tests/gitignore-bg-shell.test.ts +38 -0
- package/src/resources/extensions/gsd/tests/guided-flow-state-rebuild.test.ts +103 -0
- package/src/resources/extensions/gsd/tests/import-done-milestones.test.ts +42 -0
- package/src/resources/extensions/gsd/tests/integration/auto-recovery.test.ts +11 -9
- package/src/resources/extensions/gsd/tests/integration/state-machine-edge-cases.test.ts +4 -2
- package/src/resources/extensions/gsd/tests/integration/state-machine-live-validation.test.ts +28 -30
- package/src/resources/extensions/gsd/tests/integration/test-isolation.ts +53 -0
- package/src/resources/extensions/gsd/tests/integration-prepared-discussion.test.ts +525 -0
- package/src/resources/extensions/gsd/tests/isolation-none-branch-guard.test.ts +62 -0
- package/src/resources/extensions/gsd/tests/journal-integration.test.ts +11 -10
- package/src/resources/extensions/gsd/tests/needs-remediation-revalidation.test.ts +48 -0
- package/src/resources/extensions/gsd/tests/note-captures-executed.test.ts +46 -0
- package/src/resources/extensions/gsd/tests/orphaned-worktree-audit.test.ts +189 -0
- package/src/resources/extensions/gsd/tests/parallel-research-dispatch.test.ts +77 -0
- package/src/resources/extensions/gsd/tests/phantom-ghost-detection.test.ts +55 -0
- package/src/resources/extensions/gsd/tests/phantom-milestone-default-queued.test.ts +39 -0
- package/src/resources/extensions/gsd/tests/pre-exec-backtick-strip.test.ts +68 -0
- package/src/resources/extensions/gsd/tests/pre-execution-checks.test.ts +284 -20
- package/src/resources/extensions/gsd/tests/pre-execution-fail-closed.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/pre-execution-pause-wiring.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/preparation.test.ts +1211 -0
- package/src/resources/extensions/gsd/tests/project-root-cwd-crash.test.ts +53 -0
- package/src/resources/extensions/gsd/tests/projection-no-plan-overwrite.test.ts +83 -0
- package/src/resources/extensions/gsd/tests/prompt-builder.test.ts +669 -0
- package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +7 -4
- package/src/resources/extensions/gsd/tests/prompt-step-ordering.test.ts +85 -0
- package/src/resources/extensions/gsd/tests/provider-errors.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/query-tools-db-open.test.ts +47 -0
- package/src/resources/extensions/gsd/tests/queued-discuss-fast-path.test.ts +107 -0
- package/src/resources/extensions/gsd/tests/reactive-graph.test.ts +45 -0
- package/src/resources/extensions/gsd/tests/restore-tools-after-discuss.test.ts +63 -0
- package/src/resources/extensions/gsd/tests/rogue-file-detection.test.ts +4 -5
- package/src/resources/extensions/gsd/tests/run-uat-replay-cap.test.ts +51 -0
- package/src/resources/extensions/gsd/tests/show-config-command.test.ts +56 -0
- package/src/resources/extensions/gsd/tests/skip-slice-state-rebuild.test.ts +31 -0
- package/src/resources/extensions/gsd/tests/skipped-validation-completion.test.ts +39 -0
- package/src/resources/extensions/gsd/tests/slice-sequence-insert.test.ts +51 -0
- package/src/resources/extensions/gsd/tests/smart-entry-complete.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/stale-lockfile-recovery.test.ts +36 -0
- package/src/resources/extensions/gsd/tests/stale-queued-milestone.test.ts +147 -0
- package/src/resources/extensions/gsd/tests/stale-worktree-cwd.test.ts +13 -0
- package/src/resources/extensions/gsd/tests/stash-pop-gsd-conflict.test.ts +21 -0
- package/src/resources/extensions/gsd/tests/stash-queued-context-files.test.ts +21 -0
- package/src/resources/extensions/gsd/tests/state-machine-full-walkthrough.test.ts +6 -7
- package/src/resources/extensions/gsd/tests/status-db-open.test.ts +47 -0
- package/src/resources/extensions/gsd/tests/stuck-detection-coverage.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/subagent-agent-discovery.test.ts +47 -0
- package/src/resources/extensions/gsd/tests/symlink-extension-discovery.test.ts +125 -0
- package/src/resources/extensions/gsd/tests/sync-worktree-skip-current.test.ts +65 -0
- package/src/resources/extensions/gsd/tests/tool-invocation-error-loop-break.test.ts +29 -1
- package/src/resources/extensions/gsd/tests/triage-resolution.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/validate-milestone.test.ts +3 -4
- package/src/resources/extensions/gsd/tests/verification-operational-gate.test.ts +15 -0
- package/src/resources/extensions/gsd/tests/verify-artifact-tightened.test.ts +89 -0
- package/src/resources/extensions/gsd/tests/wave1-critical-regressions.test.ts +49 -0
- package/src/resources/extensions/gsd/tests/wave2-events-regressions.test.ts +48 -0
- package/src/resources/extensions/gsd/tests/wave3-session-regressions.test.ts +47 -0
- package/src/resources/extensions/gsd/tests/wave4-write-safety-regressions.test.ts +70 -0
- package/src/resources/extensions/gsd/tests/wave5-consistency-regressions.test.ts +165 -0
- package/src/resources/extensions/gsd/tests/worker-model-override.test.ts +48 -0
- package/src/resources/extensions/gsd/tests/workflow-logger-audit.test.ts +6 -3
- package/src/resources/extensions/gsd/tests/worktree-expected-warnings.test.ts +38 -0
- package/src/resources/extensions/gsd/tests/worktree-integration.test.ts +16 -0
- package/src/resources/extensions/gsd/tests/worktree-main-branch.test.ts +20 -0
- package/src/resources/extensions/gsd/tests/worktree-sync-milestones.test.ts +16 -17
- package/src/resources/extensions/gsd/tests/worktree-sync-tasks.test.ts +13 -9
- package/src/resources/extensions/gsd/tests/worktree.test.ts +26 -9
- package/src/resources/extensions/gsd/tests/write-gate.test.ts +127 -2
- package/src/resources/extensions/gsd/tests/zero-slice-roadmap-guided.test.ts +19 -0
- package/src/resources/extensions/gsd/tools/complete-milestone.ts +13 -3
- package/src/resources/extensions/gsd/tools/complete-slice.ts +26 -6
- package/src/resources/extensions/gsd/tools/complete-task.ts +29 -7
- package/src/resources/extensions/gsd/tools/plan-milestone.ts +11 -9
- package/src/resources/extensions/gsd/tools/reassess-roadmap.ts +5 -2
- package/src/resources/extensions/gsd/tools/reopen-milestone.ts +152 -0
- package/src/resources/extensions/gsd/tools/reopen-slice.ts +27 -0
- package/src/resources/extensions/gsd/tools/reopen-task.ts +17 -0
- package/src/resources/extensions/gsd/triage-resolution.ts +37 -17
- package/src/resources/extensions/gsd/types.ts +4 -0
- package/src/resources/extensions/gsd/undo.ts +3 -2
- package/src/resources/extensions/gsd/workflow-events.ts +5 -3
- package/src/resources/extensions/gsd/workflow-logger.ts +1 -1
- package/src/resources/extensions/gsd/workflow-projections.ts +7 -8
- package/src/resources/extensions/gsd/workflow-reconcile.ts +109 -8
- package/src/resources/extensions/gsd/workflow-templates.ts +11 -2
- package/src/resources/extensions/gsd/worktree-manager.ts +4 -2
- package/src/resources/extensions/gsd/worktree.ts +10 -0
- package/src/resources/extensions/shared/interview-ui.ts +1 -1
- package/src/resources/extensions/shared/tests/interview-notes-loop.test.ts +8 -10
- package/src/resources/extensions/subagent/agents.ts +30 -6
- package/dist/web/standalone/.next/static/chunks/6502.7593d7797a4b3999.js +0 -9
- package/dist/web/standalone/.next/static/chunks/app/page-62be3b5fa91e4c8f.js +0 -1
- package/dist/web/standalone/.next/static/chunks/main-app-d3d4c336195465f9.js +0 -1
- package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-ab5a8926e07ec673.js +0 -1
- /package/dist/web/standalone/.next/static/{MRM3OSYIAa4HMDqVGQ9nt → h8aBiLMFjb__ogynY08cm}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{MRM3OSYIAa4HMDqVGQ9nt → h8aBiLMFjb__ogynY08cm}/_ssgManifest.js +0 -0
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
* globals or AutoContext dependency.
|
|
8
8
|
*/
|
|
9
9
|
import { parseUnitId } from "./unit-id.js";
|
|
10
|
+
import { appendEvent } from "./workflow-events.js";
|
|
10
11
|
import { clearParseCache } from "./files.js";
|
|
11
12
|
import { parseRoadmap as parseLegacyRoadmap, parsePlan as parseLegacyPlan } from "./parsers-legacy.js";
|
|
12
13
|
import { isDbAvailable, getTask, getSlice, getSliceTasks, updateTaskStatus, updateSliceStatus } from "./gsd-db.js";
|
|
@@ -27,13 +28,12 @@ export { resolveExpectedArtifactPath, diagnoseExpectedArtifact };
|
|
|
27
28
|
* in the git history. Uses `git log --name-only` to inspect all commits on the
|
|
28
29
|
* current branch that touch files outside `.gsd/`.
|
|
29
30
|
*
|
|
30
|
-
* Returns
|
|
31
|
-
*
|
|
32
|
-
* running outside a git repo (e.g., tests).
|
|
31
|
+
* Returns "present" if implementation files found, "absent" if only .gsd/ files,
|
|
32
|
+
* "unknown" if git is unavailable or check failed (callers decide how to handle).
|
|
33
33
|
*/
|
|
34
34
|
export function hasImplementationArtifacts(basePath) {
|
|
35
35
|
try {
|
|
36
|
-
// Verify we're in a git repo
|
|
36
|
+
// Verify we're in a git repo
|
|
37
37
|
try {
|
|
38
38
|
execFileSync("git", ["rev-parse", "--is-inside-work-tree"], {
|
|
39
39
|
cwd: basePath,
|
|
@@ -43,7 +43,7 @@ export function hasImplementationArtifacts(basePath) {
|
|
|
43
43
|
}
|
|
44
44
|
catch (e) {
|
|
45
45
|
logWarning("recovery", `git rev-parse check failed: ${e.message}`);
|
|
46
|
-
return
|
|
46
|
+
return "unknown";
|
|
47
47
|
}
|
|
48
48
|
// Strategy: check `git diff --name-only` against the merge-base with the
|
|
49
49
|
// main branch. This captures ALL files changed during the milestone's
|
|
@@ -51,20 +51,20 @@ export function hasImplementationArtifacts(basePath) {
|
|
|
51
51
|
// back to checking the last N commits.
|
|
52
52
|
const mainBranch = detectMainBranch(basePath);
|
|
53
53
|
const changedFiles = getChangedFilesSinceBranch(basePath, mainBranch);
|
|
54
|
-
// No files changed at all —
|
|
54
|
+
// No files changed at all — unknown (could be detached HEAD, single-
|
|
55
55
|
// commit repo, or other edge case where git diff returns nothing).
|
|
56
56
|
if (changedFiles.length === 0)
|
|
57
|
-
return
|
|
57
|
+
return "unknown";
|
|
58
58
|
// Filter out .gsd/ files — only implementation files count.
|
|
59
59
|
// If every changed file is under .gsd/, the milestone produced no
|
|
60
60
|
// implementation code (#1703).
|
|
61
61
|
const implFiles = changedFiles.filter(f => !f.startsWith(".gsd/") && !f.startsWith(".gsd\\"));
|
|
62
|
-
return implFiles.length > 0;
|
|
62
|
+
return implFiles.length > 0 ? "present" : "absent";
|
|
63
63
|
}
|
|
64
64
|
catch (e) {
|
|
65
|
-
// Non-fatal — if git operations fail,
|
|
65
|
+
// Non-fatal — if git operations fail, return unknown so callers can decide
|
|
66
66
|
logWarning("recovery", `implementation artifact check failed: ${e.message}`);
|
|
67
|
-
return
|
|
67
|
+
return "unknown";
|
|
68
68
|
}
|
|
69
69
|
}
|
|
70
70
|
/**
|
|
@@ -238,7 +238,7 @@ export function verifyExpectedArtifact(unitType, unitId, base) {
|
|
|
238
238
|
if (!hasCheckboxTask && !hasHeadingTask)
|
|
239
239
|
return false;
|
|
240
240
|
}
|
|
241
|
-
// execute-task: DB status is authoritative. Fall back to
|
|
241
|
+
// execute-task: DB status is authoritative. Fall back to checked-checkbox
|
|
242
242
|
// detection when the DB is unavailable (unmigrated projects).
|
|
243
243
|
if (unitType === "execute-task") {
|
|
244
244
|
const { milestone: mid, slice: sid, task: tid } = parseUnitId(unitId);
|
|
@@ -251,21 +251,25 @@ export function verifyExpectedArtifact(unitType, unitId, base) {
|
|
|
251
251
|
}
|
|
252
252
|
else if (!isDbAvailable()) {
|
|
253
253
|
// LEGACY: Pre-migration fallback for projects without DB.
|
|
254
|
-
//
|
|
255
|
-
//
|
|
256
|
-
//
|
|
254
|
+
// Require a CHECKED checkbox — a bare heading or unchecked checkbox
|
|
255
|
+
// does not prove gsd_complete_task ran. Summary file on disk alone
|
|
256
|
+
// is not sufficient evidence (could be a rogue write) (#3607).
|
|
257
257
|
const planAbs = resolveSliceFile(base, mid, sid, "PLAN");
|
|
258
258
|
if (planAbs && existsSync(planAbs)) {
|
|
259
259
|
const planContent = readFileSync(planAbs, "utf-8");
|
|
260
260
|
const escapedTid = tid.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
261
|
-
const hdRe = new RegExp(`^#{2,4}\\s+${escapedTid}\\s*(?:--|—|:)`, "m");
|
|
262
261
|
const cbRe = new RegExp(`^- \\[[xX]\\] \\*\\*${escapedTid}:`, "m");
|
|
263
|
-
if (!
|
|
262
|
+
if (!cbRe.test(planContent))
|
|
264
263
|
return false;
|
|
265
264
|
}
|
|
265
|
+
else {
|
|
266
|
+
return false; // no plan file → cannot verify
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
else {
|
|
270
|
+
// DB available but task row not found — completion tool never ran (#3607)
|
|
271
|
+
return false;
|
|
266
272
|
}
|
|
267
|
-
// else: DB available but task not found — summary file exists (checked above),
|
|
268
|
-
// so treat as verified (task may not be imported yet)
|
|
269
273
|
}
|
|
270
274
|
}
|
|
271
275
|
// plan-slice must also produce individual task plan files for every task listed
|
|
@@ -350,7 +354,7 @@ export function verifyExpectedArtifact(unitType, unitId, base) {
|
|
|
350
354
|
// A milestone with only .gsd/ plan files and zero implementation code is
|
|
351
355
|
// not genuinely complete — the LLM wrote plan files but skipped actual work.
|
|
352
356
|
if (unitType === "complete-milestone") {
|
|
353
|
-
if (
|
|
357
|
+
if (hasImplementationArtifacts(base) === "absent")
|
|
354
358
|
return false;
|
|
355
359
|
}
|
|
356
360
|
return true;
|
|
@@ -382,21 +386,35 @@ export function writeBlockerPlaceholder(unitType, unitId, base, reason) {
|
|
|
382
386
|
// re-derives the same unit indefinitely (#2531, #2653).
|
|
383
387
|
if (isDbAvailable()) {
|
|
384
388
|
const { milestone: mid, slice: sid, task: tid } = parseUnitId(unitId);
|
|
389
|
+
const ts = new Date().toISOString();
|
|
385
390
|
if (unitType === "execute-task" && mid && sid && tid) {
|
|
386
391
|
try {
|
|
387
|
-
updateTaskStatus(mid, sid, tid, "complete",
|
|
392
|
+
updateTaskStatus(mid, sid, tid, "complete", ts);
|
|
388
393
|
}
|
|
389
394
|
catch (e) {
|
|
390
395
|
logWarning("recovery", `updateTaskStatus failed during context exhaustion: ${e instanceof Error ? e.message : String(e)}`);
|
|
391
396
|
}
|
|
397
|
+
// Append event so worktree reconciliation can replay this recovery completion
|
|
398
|
+
try {
|
|
399
|
+
appendEvent(base, { cmd: "complete-task", params: { milestoneId: mid, sliceId: sid, taskId: tid }, ts, actor: "system", trigger_reason: "blocker-placeholder-recovery" });
|
|
400
|
+
}
|
|
401
|
+
catch (e) {
|
|
402
|
+
logWarning("recovery", `appendEvent failed for task recovery: ${e instanceof Error ? e.message : String(e)}`);
|
|
403
|
+
}
|
|
392
404
|
}
|
|
393
405
|
if (unitType === "complete-slice" && mid && sid) {
|
|
394
406
|
try {
|
|
395
|
-
updateSliceStatus(mid, sid, "complete",
|
|
407
|
+
updateSliceStatus(mid, sid, "complete", ts);
|
|
396
408
|
}
|
|
397
409
|
catch (e) {
|
|
398
410
|
logWarning("recovery", `updateSliceStatus failed during context exhaustion: ${e instanceof Error ? e.message : String(e)}`);
|
|
399
411
|
}
|
|
412
|
+
try {
|
|
413
|
+
appendEvent(base, { cmd: "complete-slice", params: { milestoneId: mid, sliceId: sid }, ts, actor: "system", trigger_reason: "blocker-placeholder-recovery" });
|
|
414
|
+
}
|
|
415
|
+
catch (e) {
|
|
416
|
+
logWarning("recovery", `appendEvent failed for slice recovery: ${e instanceof Error ? e.message : String(e)}`);
|
|
417
|
+
}
|
|
400
418
|
}
|
|
401
419
|
}
|
|
402
420
|
return diagnoseExpectedArtifact(unitType, unitId, base);
|
|
@@ -451,7 +469,7 @@ export function reconcileMergeState(basePath, ctx) {
|
|
|
451
469
|
if (conflictedFiles.length === 0) {
|
|
452
470
|
// All conflicts resolved — finalize the merge/squash commit
|
|
453
471
|
try {
|
|
454
|
-
const commitSha = nativeCommit(basePath, "
|
|
472
|
+
const commitSha = nativeCommit(basePath, "chore(gsd): reconcile merge state");
|
|
455
473
|
if (commitSha) {
|
|
456
474
|
const mode = hasMergeHead ? "merge" : "squash commit";
|
|
457
475
|
ctx.ui.notify(`Finalized leftover ${mode} from prior session.`, "info");
|
|
@@ -20,11 +20,12 @@ import { synthesizeCrashRecovery } from "./session-forensics.js";
|
|
|
20
20
|
import { writeLock, clearLock, readCrashLock, formatCrashInfo, isLockProcessAlive, } from "./crash-recovery.js";
|
|
21
21
|
import { acquireSessionLock, releaseSessionLock, updateSessionLock, } from "./session-lock.js";
|
|
22
22
|
import { ensureGitignore, untrackRuntimeFiles } from "./gitignore.js";
|
|
23
|
-
import { nativeInit, nativeAddAll, nativeCommit, } from "./native-git-bridge.js";
|
|
23
|
+
import { nativeIsRepo, nativeInit, nativeAddAll, nativeCommit, nativeGetCurrentBranch, nativeDetectMainBranch, nativeCheckoutBranch, nativeBranchList, nativeBranchListMerged, nativeBranchDelete, nativeWorktreeRemove, } from "./native-git-bridge.js";
|
|
24
24
|
import { GitServiceImpl } from "./git-service.js";
|
|
25
25
|
import { captureIntegrationBranch, detectWorktreeName, setActiveMilestoneId, } from "./worktree.js";
|
|
26
26
|
import { getAutoWorktreePath } from "./auto-worktree.js";
|
|
27
27
|
import { readResourceVersion, cleanStaleRuntimeUnits } from "./auto-worktree.js";
|
|
28
|
+
import { worktreePath as getWorktreeDir, isInsideWorktreesDir } from "./worktree-manager.js";
|
|
28
29
|
import { initMetrics } from "./metrics.js";
|
|
29
30
|
import { initRoutingHistory } from "./routing-history.js";
|
|
30
31
|
import { restoreHookState, resetHookState } from "./post-unit-hooks.js";
|
|
@@ -35,7 +36,7 @@ import { hideFooter } from "./auto-dashboard.js";
|
|
|
35
36
|
import { debugLog, enableDebug, isDebugEnabled, getDebugLogPath, } from "./debug-logger.js";
|
|
36
37
|
import { logWarning, logError } from "./workflow-logger.js";
|
|
37
38
|
import { parseUnitId } from "./unit-id.js";
|
|
38
|
-
import { existsSync, mkdirSync, readdirSync, statSync, unlinkSync, } from "node:fs";
|
|
39
|
+
import { existsSync, mkdirSync, readdirSync, rmSync, statSync, unlinkSync, } from "node:fs";
|
|
39
40
|
import { join } from "node:path";
|
|
40
41
|
import { sep as pathSep } from "node:path";
|
|
41
42
|
import { resolveProjectRootDbPath } from "./bootstrap/dynamic-tools.js";
|
|
@@ -48,11 +49,8 @@ import { resolveDefaultSessionModel } from "./preferences-models.js";
|
|
|
48
49
|
* Returns false if the bootstrap aborted (e.g., guided flow returned,
|
|
49
50
|
* concurrent session detected). Returns true when ready to dispatch.
|
|
50
51
|
*/
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
* bootstrapAutoSession → showSmartEntry → checkAutoStartAfterDiscuss → startAuto
|
|
54
|
-
* cycles indefinitely when the discuss workflow doesn't produce a milestone. */
|
|
55
|
-
let _consecutiveCompleteBootstraps = 0;
|
|
52
|
+
// Guard constant for consecutive bootstrap attempts that found phase === "complete".
|
|
53
|
+
// Counter moved to AutoSession.consecutiveCompleteBootstraps so s.reset() clears it.
|
|
56
54
|
const MAX_CONSECUTIVE_COMPLETE_BOOTSTRAPS = 2;
|
|
57
55
|
export async function openProjectDbIfPresent(basePath) {
|
|
58
56
|
const gsdDbPath = resolveProjectRootDbPath(basePath);
|
|
@@ -65,6 +63,117 @@ export async function openProjectDbIfPresent(basePath) {
|
|
|
65
63
|
logWarning("engine", `gsd-db: failed to open existing database: ${err instanceof Error ? err.message : String(err)}`);
|
|
66
64
|
}
|
|
67
65
|
}
|
|
66
|
+
/**
|
|
67
|
+
* Audit for orphaned milestone branches at bootstrap.
|
|
68
|
+
*
|
|
69
|
+
* After a milestone completes, the teardown step (merge branch → main,
|
|
70
|
+
* delete branch, remove worktree) runs as a post-completion engine step.
|
|
71
|
+
* If the session ends between completion and teardown, the branch and
|
|
72
|
+
* worktree are orphaned — the DB says "complete" so auto-mode won't
|
|
73
|
+
* re-enter the milestone, and the teardown is never retried.
|
|
74
|
+
*
|
|
75
|
+
* This audit runs on every fresh bootstrap to catch that gap:
|
|
76
|
+
* 1. Lists all local `milestone/*` branches.
|
|
77
|
+
* 2. For each, checks if the milestone's DB status is "complete".
|
|
78
|
+
* 3. If the branch is already merged into main → deletes the branch
|
|
79
|
+
* and cleans up any orphaned worktree directory (safe, no data loss).
|
|
80
|
+
* 4. If the branch is NOT merged → preserves it and warns the user
|
|
81
|
+
* so they can merge manually (data safety first).
|
|
82
|
+
*
|
|
83
|
+
* Returns a summary of actions taken for the caller to surface via notify.
|
|
84
|
+
*/
|
|
85
|
+
export function auditOrphanedMilestoneBranches(basePath, isolationMode) {
|
|
86
|
+
const recovered = [];
|
|
87
|
+
const warnings = [];
|
|
88
|
+
// Skip in none mode — no milestone branches are created
|
|
89
|
+
if (isolationMode === "none")
|
|
90
|
+
return { recovered, warnings };
|
|
91
|
+
// Skip if DB not available — can't determine completion status
|
|
92
|
+
if (!isDbAvailable())
|
|
93
|
+
return { recovered, warnings };
|
|
94
|
+
let milestoneBranches;
|
|
95
|
+
try {
|
|
96
|
+
milestoneBranches = nativeBranchList(basePath, "milestone/*");
|
|
97
|
+
}
|
|
98
|
+
catch {
|
|
99
|
+
// git branch list failed — skip audit
|
|
100
|
+
return { recovered, warnings };
|
|
101
|
+
}
|
|
102
|
+
if (milestoneBranches.length === 0)
|
|
103
|
+
return { recovered, warnings };
|
|
104
|
+
// Detect main branch for merge-check
|
|
105
|
+
let mainBranch;
|
|
106
|
+
try {
|
|
107
|
+
mainBranch = nativeDetectMainBranch(basePath);
|
|
108
|
+
}
|
|
109
|
+
catch {
|
|
110
|
+
mainBranch = "main";
|
|
111
|
+
}
|
|
112
|
+
// Get branches already merged into main
|
|
113
|
+
let mergedBranches;
|
|
114
|
+
try {
|
|
115
|
+
mergedBranches = new Set(nativeBranchListMerged(basePath, mainBranch, "milestone/*"));
|
|
116
|
+
}
|
|
117
|
+
catch {
|
|
118
|
+
mergedBranches = new Set();
|
|
119
|
+
}
|
|
120
|
+
for (const branch of milestoneBranches) {
|
|
121
|
+
const milestoneId = branch.replace(/^milestone\//, "");
|
|
122
|
+
const milestone = getMilestone(milestoneId);
|
|
123
|
+
// Only audit completed milestones
|
|
124
|
+
if (!milestone || milestone.status !== "complete")
|
|
125
|
+
continue;
|
|
126
|
+
const isMerged = mergedBranches.has(branch);
|
|
127
|
+
if (isMerged) {
|
|
128
|
+
// Branch is merged — safe to delete branch and clean up worktree dir
|
|
129
|
+
try {
|
|
130
|
+
nativeBranchDelete(basePath, branch, true);
|
|
131
|
+
recovered.push(`Deleted merged branch ${branch} for completed milestone ${milestoneId}.`);
|
|
132
|
+
}
|
|
133
|
+
catch (err) {
|
|
134
|
+
warnings.push(`Failed to delete merged branch ${branch}: ${err instanceof Error ? err.message : String(err)}`);
|
|
135
|
+
}
|
|
136
|
+
// Clean up orphaned worktree directory if it exists
|
|
137
|
+
const wtDir = getWorktreeDir(basePath, milestoneId);
|
|
138
|
+
if (existsSync(wtDir)) {
|
|
139
|
+
// Try git worktree remove first (handles registered worktrees)
|
|
140
|
+
try {
|
|
141
|
+
nativeWorktreeRemove(basePath, wtDir, true);
|
|
142
|
+
}
|
|
143
|
+
catch (e) {
|
|
144
|
+
// Not a registered worktree — expected for orphaned dirs
|
|
145
|
+
logWarning("engine", `worktree remove failed (expected for orphaned dirs): ${e instanceof Error ? e.message : String(e)}`);
|
|
146
|
+
}
|
|
147
|
+
// If the directory still exists after git worktree remove (either it
|
|
148
|
+
// wasn't registered or the remove was a noop), fall back to direct
|
|
149
|
+
// filesystem removal — but only inside .gsd/worktrees/ for safety (#2365).
|
|
150
|
+
if (existsSync(wtDir)) {
|
|
151
|
+
if (isInsideWorktreesDir(basePath, wtDir)) {
|
|
152
|
+
try {
|
|
153
|
+
rmSync(wtDir, { recursive: true, force: true });
|
|
154
|
+
recovered.push(`Removed orphaned worktree directory for ${milestoneId}.`);
|
|
155
|
+
}
|
|
156
|
+
catch (err2) {
|
|
157
|
+
warnings.push(`Failed to remove worktree directory for ${milestoneId}: ${err2 instanceof Error ? err2.message : String(err2)}`);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
else {
|
|
161
|
+
warnings.push(`Orphaned worktree directory for ${milestoneId} is outside .gsd/worktrees/ — skipping removal for safety.`);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
else {
|
|
165
|
+
recovered.push(`Removed orphaned worktree directory for ${milestoneId}.`);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
else {
|
|
170
|
+
// Branch is NOT merged — preserve for safety, warn the user
|
|
171
|
+
warnings.push(`Branch ${branch} exists for completed milestone ${milestoneId} but is NOT merged into ${mainBranch}. ` +
|
|
172
|
+
`This may contain unmerged work. Merge manually or run \`/gsd health --fix\` to resolve.`);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
return { recovered, warnings };
|
|
176
|
+
}
|
|
68
177
|
export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, requestedStepMode, deps) {
|
|
69
178
|
const { shouldUseWorktreeIsolation, registerSigtermHandler, lockBase, buildResolver, } = deps;
|
|
70
179
|
const lockResult = acquireSessionLock(base);
|
|
@@ -194,6 +303,26 @@ export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, reques
|
|
|
194
303
|
// Open the project-root DB before deriveState so DB-backed state
|
|
195
304
|
// derivation (queue-order, task status) works on a cold start (#2841).
|
|
196
305
|
await openProjectDbIfPresent(base);
|
|
306
|
+
// ── Orphaned milestone branch audit ──
|
|
307
|
+
// Catches completed milestones whose teardown (merge + branch delete)
|
|
308
|
+
// was lost due to session ending between completion and teardown.
|
|
309
|
+
// Must run after DB open and before worktree entry.
|
|
310
|
+
try {
|
|
311
|
+
const auditResult = auditOrphanedMilestoneBranches(base, getIsolationMode());
|
|
312
|
+
for (const msg of auditResult.recovered) {
|
|
313
|
+
ctx.ui.notify(`Orphan audit: ${msg}`, "info");
|
|
314
|
+
}
|
|
315
|
+
for (const msg of auditResult.warnings) {
|
|
316
|
+
ctx.ui.notify(`Orphan audit: ${msg}`, "warning");
|
|
317
|
+
}
|
|
318
|
+
if (auditResult.recovered.length > 0) {
|
|
319
|
+
debugLog("orphan-audit", { recovered: auditResult.recovered, warnings: auditResult.warnings });
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
catch (err) {
|
|
323
|
+
// Non-fatal — the audit is defensive, never block bootstrap
|
|
324
|
+
logWarning("bootstrap", `orphaned milestone branch audit failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
325
|
+
}
|
|
197
326
|
let state = await deriveState(base);
|
|
198
327
|
// Stale worktree state recovery (#654)
|
|
199
328
|
if (state.activeMilestone &&
|
|
@@ -263,9 +392,9 @@ export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, reques
|
|
|
263
392
|
// Guard against recursive dialog loop (#1348):
|
|
264
393
|
// If we've entered this branch multiple times in quick succession,
|
|
265
394
|
// the discuss workflow isn't producing a milestone. Break the cycle.
|
|
266
|
-
|
|
267
|
-
if (
|
|
268
|
-
|
|
395
|
+
s.consecutiveCompleteBootstraps++;
|
|
396
|
+
if (s.consecutiveCompleteBootstraps > MAX_CONSECUTIVE_COMPLETE_BOOTSTRAPS) {
|
|
397
|
+
s.consecutiveCompleteBootstraps = 0;
|
|
269
398
|
ctx.ui.notify("All milestones are complete and the discussion didn't produce a new one. " +
|
|
270
399
|
"Run /gsd to start a new milestone manually.", "warning");
|
|
271
400
|
return releaseLockAndReturn();
|
|
@@ -277,7 +406,7 @@ export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, reques
|
|
|
277
406
|
if (postState.activeMilestone &&
|
|
278
407
|
postState.phase !== "complete" &&
|
|
279
408
|
postState.phase !== "pre-planning") {
|
|
280
|
-
|
|
409
|
+
s.consecutiveCompleteBootstraps = 0; // Successfully advanced past "complete"
|
|
281
410
|
state = postState;
|
|
282
411
|
}
|
|
283
412
|
else if (postState.activeMilestone &&
|
|
@@ -338,7 +467,7 @@ export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, reques
|
|
|
338
467
|
return releaseLockAndReturn();
|
|
339
468
|
}
|
|
340
469
|
// Successfully resolved an active milestone — reset the re-entry guard
|
|
341
|
-
|
|
470
|
+
s.consecutiveCompleteBootstraps = 0;
|
|
342
471
|
// ── Initialize session state ──
|
|
343
472
|
s.active = true;
|
|
344
473
|
s.stepMode = requestedStepMode;
|
|
@@ -373,6 +502,22 @@ export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, reques
|
|
|
373
502
|
}
|
|
374
503
|
setActiveMilestoneId(base, s.currentMilestoneId);
|
|
375
504
|
}
|
|
505
|
+
// Guard against stale milestone branch when isolation:none (#3613).
|
|
506
|
+
// A prior session with isolation:branch/worktree may have left HEAD on
|
|
507
|
+
// milestone/<MID>. Auto-checkout back to the integration branch.
|
|
508
|
+
if (getIsolationMode() === "none" && nativeIsRepo(base)) {
|
|
509
|
+
try {
|
|
510
|
+
const currentBranch = nativeGetCurrentBranch(base);
|
|
511
|
+
if (currentBranch.startsWith("milestone/")) {
|
|
512
|
+
const integrationBranch = nativeDetectMainBranch(base);
|
|
513
|
+
nativeCheckoutBranch(base, integrationBranch);
|
|
514
|
+
logWarning("bootstrap", `Returned to "${integrationBranch}" — HEAD was on stale milestone branch "${currentBranch}" (isolation: none does not use milestone branches).`);
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
catch (err) {
|
|
518
|
+
logWarning("bootstrap", `Could not auto-checkout from stale milestone branch: ${err instanceof Error ? err.message : String(err)}`);
|
|
519
|
+
}
|
|
520
|
+
}
|
|
376
521
|
// ── Auto-worktree setup ──
|
|
377
522
|
s.originalBasePath = base;
|
|
378
523
|
const isUnderGsdWorktrees = (p) => {
|
|
@@ -448,6 +593,24 @@ export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, reques
|
|
|
448
593
|
id: startModelSnapshot.id,
|
|
449
594
|
};
|
|
450
595
|
}
|
|
596
|
+
// Apply worker model override from parallel orchestrator (#worker-model).
|
|
597
|
+
// GSD_WORKER_MODEL is injected by the coordinator when parallel.worker_model
|
|
598
|
+
// is configured, so parallel milestone workers use a cheaper model than the
|
|
599
|
+
// coordinator session (e.g. Haiku for execution, Sonnet for planning).
|
|
600
|
+
const workerModelOverride = process.env.GSD_WORKER_MODEL;
|
|
601
|
+
if (workerModelOverride && process.env.GSD_PARALLEL_WORKER === "1") {
|
|
602
|
+
const availableModels = ctx.modelRegistry.getAvailable();
|
|
603
|
+
const { resolveModelId } = await import("./auto-model-selection.js");
|
|
604
|
+
const overrideModel = resolveModelId(workerModelOverride, availableModels, ctx.model?.provider);
|
|
605
|
+
if (overrideModel) {
|
|
606
|
+
const ok = await pi.setModel(overrideModel, { persist: false });
|
|
607
|
+
if (ok) {
|
|
608
|
+
// Update start model so all subsequent units use this as the baseline
|
|
609
|
+
s.autoModeStartModel = { provider: overrideModel.provider, id: overrideModel.id };
|
|
610
|
+
ctx.ui.notify(`Worker model override: ${overrideModel.provider}/${overrideModel.id}`, "info");
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
}
|
|
451
614
|
// Snapshot installed skills
|
|
452
615
|
if (resolveSkillDiscoveryMode() !== "off") {
|
|
453
616
|
snapshotSkills();
|
|
@@ -92,3 +92,13 @@ export function isToolInvocationError(errorMsg) {
|
|
|
92
92
|
return false;
|
|
93
93
|
return TOOL_INVOCATION_ERROR_RE.test(errorMsg);
|
|
94
94
|
}
|
|
95
|
+
/**
|
|
96
|
+
* Returns true if the error message indicates the tool was skipped because
|
|
97
|
+
* a queued user message interrupted the turn (#3595). Retrying will produce
|
|
98
|
+
* the same skip, so the unit should be paused rather than retried.
|
|
99
|
+
*/
|
|
100
|
+
export function isQueuedUserMessageSkip(errorMsg) {
|
|
101
|
+
if (!errorMsg)
|
|
102
|
+
return false;
|
|
103
|
+
return /^Skipped due to queued user message\.?$/i.test(errorMsg.trim());
|
|
104
|
+
}
|
|
@@ -135,8 +135,10 @@ function clearProjectRootStateFiles(basePath, milestoneId) {
|
|
|
135
135
|
unlinkSync(file);
|
|
136
136
|
}
|
|
137
137
|
catch (err) {
|
|
138
|
-
|
|
139
|
-
|
|
138
|
+
// ENOENT is expected — file may not exist (#3597)
|
|
139
|
+
if (err.code !== "ENOENT") {
|
|
140
|
+
logWarning("worktree", `file unlink failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
141
|
+
}
|
|
140
142
|
}
|
|
141
143
|
}
|
|
142
144
|
// Clean up entire synced milestone directory and runtime/units.
|
|
@@ -160,8 +162,11 @@ function clearProjectRootStateFiles(basePath, milestoneId) {
|
|
|
160
162
|
unlinkSync(join(basePath, f));
|
|
161
163
|
}
|
|
162
164
|
catch (err) {
|
|
163
|
-
|
|
164
|
-
|
|
165
|
+
// ENOENT/EISDIR are expected for already-removed or directory entries (#3597)
|
|
166
|
+
const code = err.code;
|
|
167
|
+
if (code !== "ENOENT" && code !== "EISDIR") {
|
|
168
|
+
logWarning("worktree", `untracked file unlink failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
169
|
+
}
|
|
165
170
|
}
|
|
166
171
|
}
|
|
167
172
|
}
|
|
@@ -656,6 +661,10 @@ export function syncWorktreeStateBack(mainBasePath, worktreePath, milestoneId) {
|
|
|
656
661
|
.filter((d) => d.isDirectory())
|
|
657
662
|
.map((d) => d.name);
|
|
658
663
|
for (const mid of wtMilestones) {
|
|
664
|
+
// Skip the current milestone being merged — its files are already in the
|
|
665
|
+
// milestone branch and would conflict with the squash merge (#3641).
|
|
666
|
+
if (mid === milestoneId)
|
|
667
|
+
continue;
|
|
659
668
|
syncMilestoneDir(wtGsd, mainGsd, mid, synced);
|
|
660
669
|
}
|
|
661
670
|
}
|
|
@@ -901,11 +910,19 @@ export function createAutoWorktree(basePath, milestoneId) {
|
|
|
901
910
|
});
|
|
902
911
|
}
|
|
903
912
|
else {
|
|
904
|
-
// Fresh start — create branch from integration branch
|
|
913
|
+
// Fresh start — create branch from integration branch.
|
|
914
|
+
// Use the same 3-tier fallback as mergeMilestoneToMain (#3461):
|
|
915
|
+
// 1. META.json integration branch (explicit per-milestone override)
|
|
916
|
+
// 2. git.main_branch preference (user's configured working branch)
|
|
917
|
+
// 3. nativeDetectMainBranch (origin/HEAD auto-detection)
|
|
918
|
+
// Without tier 2, projects with main_branch=dev but origin/HEAD→master
|
|
919
|
+
// would fork worktrees from the wrong (stale) branch.
|
|
905
920
|
const integrationBranch = readIntegrationBranch(basePath, milestoneId) ?? undefined;
|
|
921
|
+
const gitPrefs = loadEffectiveGSDPreferences()?.preferences?.git;
|
|
922
|
+
const startPoint = integrationBranch ?? gitPrefs?.main_branch ?? undefined;
|
|
906
923
|
info = createWorktree(basePath, milestoneId, {
|
|
907
924
|
branch,
|
|
908
|
-
startPoint
|
|
925
|
+
startPoint,
|
|
909
926
|
});
|
|
910
927
|
}
|
|
911
928
|
// Copy .gsd/ planning artifacts from the source repo into the new worktree.
|
|
@@ -1235,7 +1252,12 @@ export function mergeMilestoneToMain(originalBasePath_, milestoneId, roadmapCont
|
|
|
1235
1252
|
// checkout and leave the user with a broken merge state (#1668).
|
|
1236
1253
|
const prefs = loadEffectiveGSDPreferences()?.preferences?.git ?? {};
|
|
1237
1254
|
const integrationBranch = readIntegrationBranch(originalBasePath_, milestoneId);
|
|
1238
|
-
|
|
1255
|
+
// Validate prefs.main_branch exists before using it — a stale preference
|
|
1256
|
+
// (e.g. "master" when repo uses "main") causes merge failure (#3589).
|
|
1257
|
+
const validatedPrefBranch = prefs.main_branch && nativeBranchExists(originalBasePath_, prefs.main_branch)
|
|
1258
|
+
? prefs.main_branch
|
|
1259
|
+
: undefined;
|
|
1260
|
+
const mainBranch = integrationBranch ?? validatedPrefBranch ?? nativeDetectMainBranch(originalBasePath_);
|
|
1239
1261
|
// Remove transient project-root state files before any branch or merge
|
|
1240
1262
|
// operation. Untracked milestone metadata can otherwise block squash merges.
|
|
1241
1263
|
clearProjectRootStateFiles(originalBasePath_, milestoneId);
|
|
@@ -23,7 +23,7 @@ import { acquireSessionLock, getSessionLockStatus, releaseSessionLock, updateSes
|
|
|
23
23
|
import { resolveAutoSupervisorConfig, loadEffectiveGSDPreferences, getIsolationMode, } from "./preferences.js";
|
|
24
24
|
import { sendDesktopNotification } from "./notifications.js";
|
|
25
25
|
import { getBudgetAlertLevel, getNewBudgetAlertLevel, getBudgetEnforcementAction, } from "./auto-budget.js";
|
|
26
|
-
import { markToolStart as _markToolStart, markToolEnd as _markToolEnd, getOldestInFlightToolAgeMs as _getOldestInFlightToolAgeMs, clearInFlightTools, isToolInvocationError, } from "./auto-tool-tracking.js";
|
|
26
|
+
import { markToolStart as _markToolStart, markToolEnd as _markToolEnd, getOldestInFlightToolAgeMs as _getOldestInFlightToolAgeMs, clearInFlightTools, isToolInvocationError, isQueuedUserMessageSkip, } from "./auto-tool-tracking.js";
|
|
27
27
|
import { closeoutUnit } from "./auto-unit-closeout.js";
|
|
28
28
|
import { selectAndApplyModel, resolveModelId } from "./auto-model-selection.js";
|
|
29
29
|
import { resetRoutingHistory, recordOutcome } from "./routing-history.js";
|
|
@@ -201,7 +201,7 @@ export function markToolEnd(toolCallId) {
|
|
|
201
201
|
export function recordToolInvocationError(toolName, errorMsg) {
|
|
202
202
|
if (!s.active)
|
|
203
203
|
return;
|
|
204
|
-
if (isToolInvocationError(errorMsg)) {
|
|
204
|
+
if (isToolInvocationError(errorMsg) || isQueuedUserMessageSkip(errorMsg)) {
|
|
205
205
|
s.lastToolInvocationError = `${toolName}: ${errorMsg}`;
|
|
206
206
|
}
|
|
207
207
|
}
|
|
@@ -845,12 +845,9 @@ export async function startAuto(ctx, pi, base, verboseMode, options) {
|
|
|
845
845
|
s.stepMode = meta.stepMode ?? requestedStepMode;
|
|
846
846
|
s.autoStartTime = meta.autoStartTime || Date.now();
|
|
847
847
|
s.paused = true;
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
catch (err) { /* non-fatal */
|
|
852
|
-
logWarning("session", `pause file cleanup failed: ${err instanceof Error ? err.message : String(err)}`, { file: "auto.ts" });
|
|
853
|
-
}
|
|
848
|
+
// Don't delete pause file yet — defer until lock is acquired.
|
|
849
|
+
// If lock fails, the file must survive for retry.
|
|
850
|
+
s.pausedSessionFile = pausedPath;
|
|
854
851
|
ctx.ui.notify(`Resuming paused custom workflow${meta.activeRunDir ? ` (${meta.activeRunDir})` : ""}.`, "info");
|
|
855
852
|
}
|
|
856
853
|
else if (meta.milestoneId) {
|
|
@@ -873,13 +870,9 @@ export async function startAuto(ctx, pi, base, verboseMode, options) {
|
|
|
873
870
|
s.stepMode = meta.stepMode ?? requestedStepMode;
|
|
874
871
|
s.autoStartTime = meta.autoStartTime || Date.now();
|
|
875
872
|
s.paused = true;
|
|
876
|
-
//
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
}
|
|
880
|
-
catch (err) { /* non-fatal */
|
|
881
|
-
logWarning("session", `pause file cleanup failed: ${err instanceof Error ? err.message : String(err)}`, { file: "auto.ts" });
|
|
882
|
-
}
|
|
873
|
+
// Don't delete pause file yet — defer until lock is acquired.
|
|
874
|
+
// If lock fails, the file must survive for retry.
|
|
875
|
+
s.pausedSessionFile = pausedPath;
|
|
883
876
|
ctx.ui.notify(`Resuming paused session for ${meta.milestoneId}${meta.worktreePath ? ` (worktree)` : ""}.`, "info");
|
|
884
877
|
}
|
|
885
878
|
}
|
|
@@ -893,9 +886,22 @@ export async function startAuto(ctx, pi, base, verboseMode, options) {
|
|
|
893
886
|
if (s.paused) {
|
|
894
887
|
const resumeLock = acquireSessionLock(base);
|
|
895
888
|
if (!resumeLock.acquired) {
|
|
889
|
+
// Reset paused state so isAutoPaused() doesn't stick true after lock failure.
|
|
890
|
+
// Pause file is preserved on disk for retry — not deleted.
|
|
891
|
+
s.paused = false;
|
|
896
892
|
ctx.ui.notify(`Cannot resume: ${resumeLock.reason}`, "error");
|
|
897
893
|
return;
|
|
898
894
|
}
|
|
895
|
+
// Lock acquired — now safe to delete the pause file
|
|
896
|
+
if (s.pausedSessionFile) {
|
|
897
|
+
try {
|
|
898
|
+
unlinkSync(s.pausedSessionFile);
|
|
899
|
+
}
|
|
900
|
+
catch (err) {
|
|
901
|
+
logWarning("session", `pause file cleanup failed: ${err instanceof Error ? err.message : String(err)}`, { file: "auto.ts" });
|
|
902
|
+
}
|
|
903
|
+
s.pausedSessionFile = null;
|
|
904
|
+
}
|
|
899
905
|
s.paused = false;
|
|
900
906
|
s.active = true;
|
|
901
907
|
s.verbose = verboseMode;
|
|
@@ -79,11 +79,24 @@ export async function handleAgentEnd(pi, event, ctx) {
|
|
|
79
79
|
return;
|
|
80
80
|
}
|
|
81
81
|
if (lastMsg && "stopReason" in lastMsg && lastMsg.stopReason === "error") {
|
|
82
|
-
|
|
83
|
-
|
|
82
|
+
// #3588: errorMessage can be useless (e.g. "success") while the real error
|
|
83
|
+
// is in the assistant message text content. Fall back to content when
|
|
84
|
+
// errorMessage looks uninformative.
|
|
85
|
+
const rawErrorMsg = ("errorMessage" in lastMsg && lastMsg.errorMessage) ? String(lastMsg.errorMessage) : "";
|
|
86
|
+
const isUseless = !rawErrorMsg || /^(success|ok|true|error|unknown)$/i.test(rawErrorMsg.trim());
|
|
87
|
+
// #3588: When errorMessage is uninformative, extract the real error from
|
|
88
|
+
// the assistant message text content for display purposes only.
|
|
89
|
+
// Classification still uses rawErrorMsg to avoid false positives from prose.
|
|
90
|
+
let displayMsg = rawErrorMsg;
|
|
91
|
+
if (isUseless && "content" in lastMsg && Array.isArray(lastMsg.content)) {
|
|
92
|
+
const textBlock = lastMsg.content.find((b) => b.type === "text" && b.text);
|
|
93
|
+
if (textBlock)
|
|
94
|
+
displayMsg = textBlock.text.slice(0, 300);
|
|
95
|
+
}
|
|
96
|
+
const errorDetail = displayMsg ? `: ${displayMsg}` : "";
|
|
84
97
|
const explicitRetryAfterMs = ("retryAfterMs" in lastMsg && typeof lastMsg.retryAfterMs === "number") ? lastMsg.retryAfterMs : undefined;
|
|
85
|
-
// ── 1. Classify
|
|
86
|
-
const cls = classifyError(
|
|
98
|
+
// ── 1. Classify using rawErrorMsg to avoid prose false-positives ────
|
|
99
|
+
const cls = classifyError(rawErrorMsg, explicitRetryAfterMs);
|
|
87
100
|
// Cap rate-limit backoff for CLI-style providers (openai-codex, google-gemini-cli)
|
|
88
101
|
// which use per-user quotas with shorter windows (#2922).
|
|
89
102
|
if (cls.kind === "rate-limit") {
|
|
@@ -943,6 +943,16 @@ export function registerDbTools(pi) {
|
|
|
943
943
|
}
|
|
944
944
|
updateSliceStatus(params.milestoneId, params.sliceId, "skipped");
|
|
945
945
|
invalidateStateCache();
|
|
946
|
+
// Rebuild STATE.md so it reflects the skip immediately (#3477).
|
|
947
|
+
// Without this, /gsd auto reads stale STATE.md and resumes the skipped slice.
|
|
948
|
+
try {
|
|
949
|
+
const basePath = process.cwd();
|
|
950
|
+
const { rebuildState } = await import("../doctor.js");
|
|
951
|
+
await rebuildState(basePath);
|
|
952
|
+
}
|
|
953
|
+
catch (err) {
|
|
954
|
+
logError("tool", `skip_slice rebuildState failed: ${err.message}`, { tool: "gsd_skip_slice" });
|
|
955
|
+
}
|
|
946
956
|
return {
|
|
947
957
|
content: [{ type: "text", text: `Skipped slice ${params.sliceId} (${params.milestoneId}). Reason: ${params.reason ?? "User-directed skip"}. Auto-mode will advance past this slice.` }],
|
|
948
958
|
details: {
|
|
@@ -17,10 +17,12 @@ export function registerQueryTools(pi) {
|
|
|
17
17
|
}),
|
|
18
18
|
async execute(_toolCallId, params, _signal, _onUpdate, _ctx) {
|
|
19
19
|
try {
|
|
20
|
-
//
|
|
21
|
-
//
|
|
22
|
-
const {
|
|
23
|
-
|
|
20
|
+
// Open the DB if not already open — safe for read-only use since
|
|
21
|
+
// ensureDbOpen() only creates/migrates when .gsd/ has content (#3644).
|
|
22
|
+
const { ensureDbOpen } = await import("./dynamic-tools.js");
|
|
23
|
+
const dbAvailable = await ensureDbOpen();
|
|
24
|
+
const { getMilestone, getSliceStatusSummary, getSliceTaskCounts, _getAdapter, } = await import("../gsd-db.js");
|
|
25
|
+
if (!dbAvailable) {
|
|
24
26
|
return {
|
|
25
27
|
content: [{ type: "text", text: "Error: GSD database is not available." }],
|
|
26
28
|
details: { operation: "milestone_status", error: "db_unavailable" },
|