gsd-pi 2.65.0 → 2.66.0-dev.1b4e601
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 +19 -19
- 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 +19 -19
- 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 +1 -0
- package/packages/pi-tui/dist/tui.d.ts.map +1 -1
- package/packages/pi-tui/dist/tui.js +8 -2
- 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 +8 -2
- 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 → fcV2z87tmOazTEreFWNdG}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{MRM3OSYIAa4HMDqVGQ9nt → fcV2z87tmOazTEreFWNdG}/_ssgManifest.js +0 -0
|
@@ -15,6 +15,7 @@ import type { PostUnitContext, PreVerificationOpts } from "../auto-post-unit.js"
|
|
|
15
15
|
import {
|
|
16
16
|
MAX_RECOVERY_CHARS,
|
|
17
17
|
BUDGET_THRESHOLDS,
|
|
18
|
+
MAX_FINALIZE_TIMEOUTS,
|
|
18
19
|
type PhaseResult,
|
|
19
20
|
type IterationContext,
|
|
20
21
|
type LoopState,
|
|
@@ -33,7 +34,7 @@ import { gsdRoot } from "../paths.js";
|
|
|
33
34
|
import { atomicWriteSync } from "../atomic-write.js";
|
|
34
35
|
import { verifyExpectedArtifact, diagnoseExpectedArtifact, buildLoopRemediationSteps } from "../auto-recovery.js";
|
|
35
36
|
import { writeUnitRuntimeRecord } from "../unit-runtime.js";
|
|
36
|
-
import { withTimeout, FINALIZE_POST_TIMEOUT_MS } from "./finalize-timeout.js";
|
|
37
|
+
import { withTimeout, FINALIZE_PRE_TIMEOUT_MS, FINALIZE_POST_TIMEOUT_MS } from "./finalize-timeout.js";
|
|
37
38
|
import { getEligibleSlices } from "../slice-parallel-eligibility.js";
|
|
38
39
|
import { startSliceParallel } from "../slice-parallel-orchestrator.js";
|
|
39
40
|
import { isDbAvailable, getMilestoneSlices } from "../gsd-db.js";
|
|
@@ -1427,6 +1428,7 @@ export async function runUnitPhase(
|
|
|
1427
1428
|
export async function runFinalize(
|
|
1428
1429
|
ic: IterationContext,
|
|
1429
1430
|
iterData: IterationData,
|
|
1431
|
+
loopState: LoopState,
|
|
1430
1432
|
sidecarItem?: SidecarItem,
|
|
1431
1433
|
): Promise<PhaseResult> {
|
|
1432
1434
|
const { ctx, pi, s, deps } = ic;
|
|
@@ -1450,13 +1452,58 @@ export async function runFinalize(
|
|
|
1450
1452
|
};
|
|
1451
1453
|
|
|
1452
1454
|
// Pre-verification processing (commit, doctor, state rebuild, etc.)
|
|
1455
|
+
// Timeout guard: if postUnitPreVerification hangs (e.g., safety harness
|
|
1456
|
+
// deadlock, browser teardown hang, worktree sync stall), force-continue
|
|
1457
|
+
// after timeout so the auto-loop is not permanently frozen (#3757).
|
|
1458
|
+
//
|
|
1459
|
+
// On timeout, null out s.currentUnit so the timed-out task's late async
|
|
1460
|
+
// mutations are harmless — postUnitPreVerification guards all side effects
|
|
1461
|
+
// behind `if (s.currentUnit)`. The next iteration sets a fresh currentUnit.
|
|
1453
1462
|
// Sidecar items use lightweight pre-verification opts
|
|
1454
1463
|
const preVerificationOpts: PreVerificationOpts | undefined = sidecarItem
|
|
1455
1464
|
? sidecarItem.kind === "hook"
|
|
1456
1465
|
? { skipSettleDelay: true, skipWorktreeSync: true }
|
|
1457
1466
|
: { skipSettleDelay: true }
|
|
1458
1467
|
: undefined;
|
|
1459
|
-
const
|
|
1468
|
+
const preUnitSnapshot = s.currentUnit
|
|
1469
|
+
? { type: s.currentUnit.type, id: s.currentUnit.id, startedAt: s.currentUnit.startedAt }
|
|
1470
|
+
: null;
|
|
1471
|
+
const preResultGuard = await withTimeout(
|
|
1472
|
+
deps.postUnitPreVerification(postUnitCtx, preVerificationOpts),
|
|
1473
|
+
FINALIZE_PRE_TIMEOUT_MS,
|
|
1474
|
+
"postUnitPreVerification",
|
|
1475
|
+
);
|
|
1476
|
+
|
|
1477
|
+
if (preResultGuard.timedOut) {
|
|
1478
|
+
// Detach session from the timed-out unit so late async completions
|
|
1479
|
+
// cannot mutate state for the next unit (#3757).
|
|
1480
|
+
s.currentUnit = null;
|
|
1481
|
+
loopState.consecutiveFinalizeTimeouts++;
|
|
1482
|
+
debugLog("autoLoop", {
|
|
1483
|
+
phase: "pre-verification-timeout",
|
|
1484
|
+
iteration: ic.iteration,
|
|
1485
|
+
unitType: iterData.unitType,
|
|
1486
|
+
unitId: iterData.unitId,
|
|
1487
|
+
consecutiveTimeouts: loopState.consecutiveFinalizeTimeouts,
|
|
1488
|
+
});
|
|
1489
|
+
|
|
1490
|
+
if (loopState.consecutiveFinalizeTimeouts >= MAX_FINALIZE_TIMEOUTS) {
|
|
1491
|
+
ctx.ui.notify(
|
|
1492
|
+
`postUnitPreVerification timed out ${loopState.consecutiveFinalizeTimeouts} consecutive times — stopping auto-mode to prevent budget waste`,
|
|
1493
|
+
"error",
|
|
1494
|
+
);
|
|
1495
|
+
await deps.stopAuto(ctx, pi, `${loopState.consecutiveFinalizeTimeouts} consecutive finalize timeouts`);
|
|
1496
|
+
return { action: "break", reason: "finalize-timeout-escalation" };
|
|
1497
|
+
}
|
|
1498
|
+
|
|
1499
|
+
ctx.ui.notify(
|
|
1500
|
+
`postUnitPreVerification timed out after ${FINALIZE_PRE_TIMEOUT_MS / 1000}s for ${iterData.unitType} ${iterData.unitId} (${loopState.consecutiveFinalizeTimeouts}/${MAX_FINALIZE_TIMEOUTS}) — continuing to next iteration`,
|
|
1501
|
+
"warning",
|
|
1502
|
+
);
|
|
1503
|
+
return { action: "next", data: undefined as void };
|
|
1504
|
+
}
|
|
1505
|
+
|
|
1506
|
+
const preResult = preResultGuard.value;
|
|
1460
1507
|
if (preResult === "dispatched") {
|
|
1461
1508
|
debugLog("autoLoop", {
|
|
1462
1509
|
phase: "exit",
|
|
@@ -1525,14 +1572,29 @@ export async function runFinalize(
|
|
|
1525
1572
|
);
|
|
1526
1573
|
|
|
1527
1574
|
if (postResultGuard.timedOut) {
|
|
1575
|
+
// Detach session from the timed-out unit so late async completions
|
|
1576
|
+
// cannot mutate state for the next unit (#3757).
|
|
1577
|
+
s.currentUnit = null;
|
|
1578
|
+
loopState.consecutiveFinalizeTimeouts++;
|
|
1528
1579
|
debugLog("autoLoop", {
|
|
1529
1580
|
phase: "post-verification-timeout",
|
|
1530
1581
|
iteration: ic.iteration,
|
|
1531
1582
|
unitType: iterData.unitType,
|
|
1532
1583
|
unitId: iterData.unitId,
|
|
1584
|
+
consecutiveTimeouts: loopState.consecutiveFinalizeTimeouts,
|
|
1533
1585
|
});
|
|
1586
|
+
|
|
1587
|
+
if (loopState.consecutiveFinalizeTimeouts >= MAX_FINALIZE_TIMEOUTS) {
|
|
1588
|
+
ctx.ui.notify(
|
|
1589
|
+
`postUnitPostVerification timed out ${loopState.consecutiveFinalizeTimeouts} consecutive times — stopping auto-mode to prevent budget waste`,
|
|
1590
|
+
"error",
|
|
1591
|
+
);
|
|
1592
|
+
await deps.stopAuto(ctx, pi, `${loopState.consecutiveFinalizeTimeouts} consecutive finalize timeouts`);
|
|
1593
|
+
return { action: "break", reason: "finalize-timeout-escalation" };
|
|
1594
|
+
}
|
|
1595
|
+
|
|
1534
1596
|
ctx.ui.notify(
|
|
1535
|
-
`postUnitPostVerification timed out after ${FINALIZE_POST_TIMEOUT_MS / 1000}s for ${iterData.unitType} ${iterData.unitId} — continuing to next iteration`,
|
|
1597
|
+
`postUnitPostVerification timed out after ${FINALIZE_POST_TIMEOUT_MS / 1000}s for ${iterData.unitType} ${iterData.unitId} (${loopState.consecutiveFinalizeTimeouts}/${MAX_FINALIZE_TIMEOUTS}) — continuing to next iteration`,
|
|
1536
1598
|
"warning",
|
|
1537
1599
|
);
|
|
1538
1600
|
return { action: "next", data: undefined as void };
|
|
@@ -1554,6 +1616,9 @@ export async function runFinalize(
|
|
|
1554
1616
|
return { action: "break", reason: "step-wizard" };
|
|
1555
1617
|
}
|
|
1556
1618
|
|
|
1619
|
+
// Both pre and post verification completed without timeout — reset counter
|
|
1620
|
+
loopState.consecutiveFinalizeTimeouts = 0;
|
|
1621
|
+
|
|
1557
1622
|
return { action: "next", data: undefined as void };
|
|
1558
1623
|
}
|
|
1559
1624
|
|
|
@@ -108,9 +108,19 @@ export async function runUnit(
|
|
|
108
108
|
{ triggerTurn: true },
|
|
109
109
|
);
|
|
110
110
|
|
|
111
|
-
// ── Await agent_end ──
|
|
111
|
+
// ── Await agent_end with absolute timeout (H4 fix) ──
|
|
112
|
+
// If supervision fails to resolve unitPromise within 30s, treat as cancelled.
|
|
113
|
+
// Without this, a crashed agent that never emits agent_end hangs the loop (#3161).
|
|
112
114
|
debugLog("runUnit", { phase: "awaiting-agent-end", unitType, unitId });
|
|
113
|
-
const
|
|
115
|
+
const UNIT_HARD_TIMEOUT_MS = 30_000;
|
|
116
|
+
let unitTimeoutHandle: ReturnType<typeof setTimeout> | undefined;
|
|
117
|
+
const timeoutResult = new Promise<UnitResult>((resolve) => {
|
|
118
|
+
unitTimeoutHandle = setTimeout(() => {
|
|
119
|
+
resolve({ status: "cancelled", errorContext: { message: "Unit hard timeout — supervision may have failed", category: "timeout", isTransient: true } });
|
|
120
|
+
}, UNIT_HARD_TIMEOUT_MS);
|
|
121
|
+
});
|
|
122
|
+
const result = await Promise.race([unitPromise, timeoutResult]);
|
|
123
|
+
if (unitTimeoutHandle) clearTimeout(unitTimeoutHandle);
|
|
114
124
|
debugLog("runUnit", {
|
|
115
125
|
phase: "agent-end-received",
|
|
116
126
|
unitType,
|
|
@@ -138,6 +138,9 @@ export class AutoSession {
|
|
|
138
138
|
|
|
139
139
|
// ── Dispatch circuit breakers ──────────────────────────────────────
|
|
140
140
|
rewriteAttemptCount = 0;
|
|
141
|
+
/** Tracks consecutive bootstrap attempts that found phase === "complete".
|
|
142
|
+
* Moved from module-level to per-session so s.reset() clears it (#1348). */
|
|
143
|
+
consecutiveCompleteBootstraps = 0;
|
|
141
144
|
|
|
142
145
|
// ── Metrics ──────────────────────────────────────────────────────────────
|
|
143
146
|
autoStartTime = 0;
|
|
@@ -224,6 +227,7 @@ export class AutoSession {
|
|
|
224
227
|
this.pendingQuickTasks = [];
|
|
225
228
|
this.sidecarQueue = [];
|
|
226
229
|
this.rewriteAttemptCount = 0;
|
|
230
|
+
this.consecutiveCompleteBootstraps = 0;
|
|
227
231
|
this.lastToolInvocationError = null;
|
|
228
232
|
this.isolationDegraded = false;
|
|
229
233
|
this.milestoneMergedInPhases = false;
|
|
@@ -91,8 +91,13 @@ export interface IterationContext {
|
|
|
91
91
|
export interface LoopState {
|
|
92
92
|
recentUnits: Array<{ key: string; error?: string }>;
|
|
93
93
|
stuckRecoveryAttempts: number;
|
|
94
|
+
/** Consecutive finalize timeout count — stops auto-mode after threshold. */
|
|
95
|
+
consecutiveFinalizeTimeouts: number;
|
|
94
96
|
}
|
|
95
97
|
|
|
98
|
+
/** Max consecutive finalize timeouts before hard-stopping auto-mode. */
|
|
99
|
+
export const MAX_FINALIZE_TIMEOUTS = 3;
|
|
100
|
+
|
|
96
101
|
export interface PreDispatchData {
|
|
97
102
|
state: GSDState;
|
|
98
103
|
mid: string;
|
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
resolveSliceFile,
|
|
17
17
|
} from "./paths.js";
|
|
18
18
|
import { isDbAvailable, getMilestoneSlices, getSliceTasks } from "./gsd-db.js";
|
|
19
|
+
import { formatShortcut } from "./files.js";
|
|
19
20
|
import { readFileSync, writeFileSync, existsSync } from "node:fs";
|
|
20
21
|
import { execFileSync } from "node:child_process";
|
|
21
22
|
import { truncateToWidth, visibleWidth } from "@gsd/pi-tui";
|
|
@@ -855,7 +856,7 @@ export function updateProgressWidget(
|
|
|
855
856
|
// Hints line
|
|
856
857
|
const hintParts: string[] = [];
|
|
857
858
|
hintParts.push("esc pause");
|
|
858
|
-
hintParts.push(
|
|
859
|
+
hintParts.push(`${formatShortcut("Ctrl+Alt+G")} dashboard`);
|
|
859
860
|
const hintStr = theme.fg("dim", hintParts.join(" | "));
|
|
860
861
|
const commitStr = lastCommit
|
|
861
862
|
? theme.fg("dim", `${lastCommit.timeAgo} ago: ${commitMsg}`)
|
|
@@ -27,6 +27,7 @@ import {
|
|
|
27
27
|
buildMilestoneFileName,
|
|
28
28
|
buildSliceFileName,
|
|
29
29
|
} from "./paths.js";
|
|
30
|
+
import { parseRoadmap } from "./parsers-legacy.js";
|
|
30
31
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
31
32
|
import { logWarning, logError } from "./workflow-logger.js";
|
|
32
33
|
import { join } from "node:path";
|
|
@@ -47,6 +48,7 @@ import {
|
|
|
47
48
|
buildRewriteDocsPrompt,
|
|
48
49
|
buildReactiveExecutePrompt,
|
|
49
50
|
buildGateEvaluatePrompt,
|
|
51
|
+
buildParallelResearchSlicesPrompt,
|
|
50
52
|
checkNeedsReassessment,
|
|
51
53
|
checkNeedsRunUat,
|
|
52
54
|
} from "./auto-prompts.js";
|
|
@@ -93,14 +95,22 @@ function missingSliceStop(mid: string, phase: string): DispatchAction {
|
|
|
93
95
|
/**
|
|
94
96
|
* Check for milestone slices missing SUMMARY files.
|
|
95
97
|
* Returns array of missing slice IDs, or empty array if all present or DB unavailable.
|
|
98
|
+
*
|
|
99
|
+
* Excludes skipped slices (intentionally summary-less) and legacy-complete
|
|
100
|
+
* slices whose DB status is authoritative even without on-disk SUMMARY (#3620).
|
|
96
101
|
*/
|
|
97
102
|
function findMissingSummaries(basePath: string, mid: string): string[] {
|
|
98
103
|
if (!isDbAvailable()) return [];
|
|
99
|
-
const
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
+
const slices = getMilestoneSlices(mid);
|
|
105
|
+
// Skipped slices never produce SUMMARYs; legacy-complete slices may lack them
|
|
106
|
+
const CLOSED_STATUSES = new Set(["skipped", "complete", "done"]);
|
|
107
|
+
return slices
|
|
108
|
+
.filter(s => !CLOSED_STATUSES.has(s.status))
|
|
109
|
+
.filter(s => {
|
|
110
|
+
const summaryPath = resolveSliceFile(basePath, mid, s.id, "SUMMARY");
|
|
111
|
+
return !summaryPath || !existsSync(summaryPath);
|
|
112
|
+
})
|
|
113
|
+
.map(s => s.id);
|
|
104
114
|
}
|
|
105
115
|
|
|
106
116
|
// ─── Rewrite Circuit Breaker ──────────────────────────────────────────────
|
|
@@ -130,6 +140,32 @@ export function setRewriteCount(basePath: string, count: number): void {
|
|
|
130
140
|
writeFileSync(filePath, JSON.stringify({ count, updatedAt: new Date().toISOString() }) + "\n");
|
|
131
141
|
}
|
|
132
142
|
|
|
143
|
+
// ─── Run-UAT dispatch counter (per-slice) ────────────────────────────────
|
|
144
|
+
// Caps run-uat dispatches to prevent infinite replay when verification
|
|
145
|
+
// commands fail before writing a verdict (#3624).
|
|
146
|
+
const MAX_UAT_ATTEMPTS = 3;
|
|
147
|
+
|
|
148
|
+
function uatCountPath(basePath: string, mid: string, sid: string): string {
|
|
149
|
+
return join(gsdRoot(basePath), "runtime", `uat-count-${mid}-${sid}.json`);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
export function getUatCount(basePath: string, mid: string, sid: string): number {
|
|
153
|
+
try {
|
|
154
|
+
const data = JSON.parse(readFileSync(uatCountPath(basePath, mid, sid), "utf-8"));
|
|
155
|
+
return typeof data.count === "number" ? data.count : 0;
|
|
156
|
+
} catch {
|
|
157
|
+
return 0;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
export function incrementUatCount(basePath: string, mid: string, sid: string): number {
|
|
162
|
+
const count = getUatCount(basePath, mid, sid) + 1;
|
|
163
|
+
const filePath = uatCountPath(basePath, mid, sid);
|
|
164
|
+
mkdirSync(join(gsdRoot(basePath), "runtime"), { recursive: true });
|
|
165
|
+
writeFileSync(filePath, JSON.stringify({ count, updatedAt: new Date().toISOString() }) + "\n");
|
|
166
|
+
return count;
|
|
167
|
+
}
|
|
168
|
+
|
|
133
169
|
// ─── Helpers ─────────────────────────────────────────────────────────────
|
|
134
170
|
|
|
135
171
|
/**
|
|
@@ -140,9 +176,9 @@ export function setRewriteCount(basePath: string, count: number): void {
|
|
|
140
176
|
* @see https://github.com/gsd-build/gsd-2/issues/2931
|
|
141
177
|
*/
|
|
142
178
|
export function isVerificationNotApplicable(value: string): boolean {
|
|
143
|
-
const v = (value ?? "").toLowerCase().trim();
|
|
179
|
+
const v = (value ?? "").toLowerCase().trim().replace(/[.\s]+$/, "");
|
|
144
180
|
if (!v || v === "none") return true;
|
|
145
|
-
return /^(?:none[\s._-]*(?:required|needed|planned)?|n\/?a|not[\s._-]+(?:applicable|required|needed)|no[\s._-]+operational[\s\S]*)$/i.test(v);
|
|
181
|
+
return /^(?:none[\s._-]*(?:required|needed|planned)?|n\/?a|not[\s._-]+(?:applicable|required|needed|provided)|no[\s._-]+operational[\s\S]*)$/i.test(v);
|
|
146
182
|
}
|
|
147
183
|
|
|
148
184
|
// ─── Rules ────────────────────────────────────────────────────────────────
|
|
@@ -203,6 +239,16 @@ export const DISPATCH_RULES: DispatchRule[] = [
|
|
|
203
239
|
const needsRunUat = await checkNeedsRunUat(basePath, mid, state, prefs);
|
|
204
240
|
if (!needsRunUat) return null;
|
|
205
241
|
const { sliceId, uatType } = needsRunUat;
|
|
242
|
+
|
|
243
|
+
// Cap run-uat dispatch attempts to prevent infinite replay (#3624)
|
|
244
|
+
const attempts = incrementUatCount(basePath, mid, sliceId);
|
|
245
|
+
if (attempts > MAX_UAT_ATTEMPTS) {
|
|
246
|
+
return {
|
|
247
|
+
action: "stop" as const,
|
|
248
|
+
reason: `run-uat for ${mid}/${sliceId} has been dispatched ${attempts - 1} times without producing a verdict. Verification commands may be broken — fix the UAT spec or manually write an ASSESSMENT verdict.`,
|
|
249
|
+
level: "warning" as const,
|
|
250
|
+
};
|
|
251
|
+
}
|
|
206
252
|
const uatFile = resolveSliceFile(basePath, mid, sliceId, "UAT")!;
|
|
207
253
|
const uatContent = await loadFile(uatFile);
|
|
208
254
|
return {
|
|
@@ -366,6 +412,53 @@ export const DISPATCH_RULES: DispatchRule[] = [
|
|
|
366
412
|
};
|
|
367
413
|
},
|
|
368
414
|
},
|
|
415
|
+
{
|
|
416
|
+
name: "planning (multiple slices need research) → parallel-research-slices",
|
|
417
|
+
match: async ({ state, mid, midTitle, basePath, prefs }) => {
|
|
418
|
+
if (state.phase !== "planning") return null;
|
|
419
|
+
if (prefs?.phases?.skip_research || prefs?.phases?.skip_slice_research) return null;
|
|
420
|
+
|
|
421
|
+
// Load roadmap to find all slices
|
|
422
|
+
const roadmapFile = resolveMilestoneFile(basePath, mid, "ROADMAP");
|
|
423
|
+
const roadmapContent = roadmapFile ? await loadFile(roadmapFile) : null;
|
|
424
|
+
if (!roadmapContent) return null;
|
|
425
|
+
const roadmap = parseRoadmap(roadmapContent);
|
|
426
|
+
|
|
427
|
+
// Find slices that need research (no RESEARCH file, dependencies done)
|
|
428
|
+
const milestoneResearchFile = resolveMilestoneFile(basePath, mid, "RESEARCH");
|
|
429
|
+
const researchReadySlices: Array<{ id: string; title: string }> = [];
|
|
430
|
+
|
|
431
|
+
for (const slice of roadmap.slices) {
|
|
432
|
+
if (slice.done) continue;
|
|
433
|
+
// Skip S01 when milestone research exists
|
|
434
|
+
if (milestoneResearchFile && slice.id === "S01") continue;
|
|
435
|
+
// Skip if already has research
|
|
436
|
+
if (resolveSliceFile(basePath, mid, slice.id, "RESEARCH")) continue;
|
|
437
|
+
// Skip if dependencies aren't done (check for SUMMARY files)
|
|
438
|
+
const depsComplete = (slice.depends ?? []).every((depId) =>
|
|
439
|
+
!!resolveSliceFile(basePath, mid, depId, "SUMMARY"),
|
|
440
|
+
);
|
|
441
|
+
if (!depsComplete) continue;
|
|
442
|
+
|
|
443
|
+
researchReadySlices.push({ id: slice.id, title: slice.title });
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
// Only dispatch parallel if 2+ slices are ready
|
|
447
|
+
if (researchReadySlices.length < 2) return null;
|
|
448
|
+
|
|
449
|
+
return {
|
|
450
|
+
action: "dispatch",
|
|
451
|
+
unitType: "research-slice",
|
|
452
|
+
unitId: `${mid}/parallel-research`,
|
|
453
|
+
prompt: await buildParallelResearchSlicesPrompt(
|
|
454
|
+
mid,
|
|
455
|
+
midTitle,
|
|
456
|
+
researchReadySlices,
|
|
457
|
+
basePath,
|
|
458
|
+
),
|
|
459
|
+
};
|
|
460
|
+
},
|
|
461
|
+
},
|
|
369
462
|
{
|
|
370
463
|
name: "planning → plan-slice",
|
|
371
464
|
match: async ({ state, mid, midTitle, basePath }) => {
|
|
@@ -674,13 +767,17 @@ export const DISPATCH_RULES: DispatchRule[] = [
|
|
|
674
767
|
// Safety guard (#1703): verify the milestone produced implementation
|
|
675
768
|
// artifacts (non-.gsd/ files). A milestone with only plan files and
|
|
676
769
|
// zero implementation code should not be marked complete.
|
|
677
|
-
|
|
770
|
+
const artifactCheck = hasImplementationArtifacts(basePath);
|
|
771
|
+
if (artifactCheck === "absent") {
|
|
678
772
|
return {
|
|
679
773
|
action: "stop",
|
|
680
774
|
reason: `Cannot complete milestone ${mid}: no implementation files found outside .gsd/. The milestone has only plan files — actual code changes are required.`,
|
|
681
775
|
level: "error",
|
|
682
776
|
};
|
|
683
777
|
}
|
|
778
|
+
if (artifactCheck === "unknown") {
|
|
779
|
+
logWarning("dispatch", `Implementation artifact check inconclusive for ${mid} — proceeding (git context unavailable)`);
|
|
780
|
+
}
|
|
684
781
|
|
|
685
782
|
// Verification class compliance: if operational verification was planned,
|
|
686
783
|
// ensure the validation output documents it before allowing completion.
|
|
@@ -693,6 +790,10 @@ export const DISPATCH_RULES: DispatchRule[] = [
|
|
|
693
790
|
if (validationPath) {
|
|
694
791
|
const validationContent = await loadFile(validationPath);
|
|
695
792
|
if (validationContent) {
|
|
793
|
+
// Allow completion when validation was intentionally skipped by
|
|
794
|
+
// preference/budget profile (#3399, #3344).
|
|
795
|
+
const skippedByPreference = /skip(?:ped)?[\s\-]+(?:by|per|due to)\s+(?:preference|budget|profile)/i.test(validationContent);
|
|
796
|
+
|
|
696
797
|
// Accept either the structured template format (table with MET/N/A/SATISFIED)
|
|
697
798
|
// or prose evidence patterns the validation agent may emit.
|
|
698
799
|
const structuredMatch =
|
|
@@ -700,7 +801,7 @@ export const DISPATCH_RULES: DispatchRule[] = [
|
|
|
700
801
|
(validationContent.includes("MET") || validationContent.includes("N/A") || validationContent.includes("SATISFIED"));
|
|
701
802
|
const proseMatch =
|
|
702
803
|
/[Oo]perational[\s\S]{0,500}?(?:✅|pass|verified|confirmed|met|complete|true|yes|addressed|covered|satisfied|partially|n\/a|not[\s-]+applicable)/i.test(validationContent);
|
|
703
|
-
const hasOperationalCheck = structuredMatch || proseMatch;
|
|
804
|
+
const hasOperationalCheck = skippedByPreference || structuredMatch || proseMatch;
|
|
704
805
|
if (!hasOperationalCheck) {
|
|
705
806
|
return {
|
|
706
807
|
action: "stop" as const,
|
|
@@ -246,11 +246,13 @@ export async function selectAndApplyModel(
|
|
|
246
246
|
const ok = await pi.setModel(model, { persist: false });
|
|
247
247
|
if (ok) {
|
|
248
248
|
appliedModel = model;
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
249
|
+
if (verbose) {
|
|
250
|
+
const fallbackNote = modelId === effectiveModelConfig.primary
|
|
251
|
+
? ""
|
|
252
|
+
: ` (fallback from ${effectiveModelConfig.primary})`;
|
|
253
|
+
const phase = unitPhaseLabel(unitType);
|
|
254
|
+
ctx.ui.notify(`Model [${phase}]${routingTierLabel}: ${model.provider}/${model.id}${fallbackNote}`, "info");
|
|
255
|
+
}
|
|
254
256
|
break;
|
|
255
257
|
} else {
|
|
256
258
|
const nextModel = modelsToTry[modelsToTry.indexOf(modelId) + 1];
|
|
@@ -39,7 +39,7 @@ import {
|
|
|
39
39
|
} from "./auto-recovery.js";
|
|
40
40
|
import { regenerateIfMissing } from "./workflow-projections.js";
|
|
41
41
|
import { syncStateToProjectRoot } from "./auto-worktree.js";
|
|
42
|
-
import { isDbAvailable, getTask, getSlice, getMilestone, updateTaskStatus, _getAdapter } from "./gsd-db.js";
|
|
42
|
+
import { isDbAvailable, getTask, getSlice, getMilestone, updateTaskStatus, updateSliceStatus, _getAdapter } from "./gsd-db.js";
|
|
43
43
|
import { renderPlanCheckboxes } from "./markdown-renderer.js";
|
|
44
44
|
import { consumeSignal } from "./session-status-io.js";
|
|
45
45
|
import {
|
|
@@ -161,7 +161,14 @@ export function detectRogueFileWrites(
|
|
|
161
161
|
|
|
162
162
|
const dbRow = getSlice(mid, sid);
|
|
163
163
|
if (!dbRow || dbRow.status !== "complete") {
|
|
164
|
-
|
|
164
|
+
// Auto-remediate: SUMMARY exists on disk but DB is stale — sync DB to
|
|
165
|
+
// match filesystem instead of reporting as rogue (#3633).
|
|
166
|
+
try {
|
|
167
|
+
updateSliceStatus(mid, sid, "complete", new Date().toISOString());
|
|
168
|
+
} catch {
|
|
169
|
+
// If DB update fails, fall back to rogue detection so the issue is visible
|
|
170
|
+
rogues.push({ path: summaryPath, unitType, unitId });
|
|
171
|
+
}
|
|
165
172
|
}
|
|
166
173
|
} else if (unitType === "plan-milestone") {
|
|
167
174
|
if (!mid) return [];
|
|
@@ -582,11 +589,14 @@ export async function postUnitPreVerification(pctx: PostUnitContext, opts?: PreV
|
|
|
582
589
|
"error",
|
|
583
590
|
);
|
|
584
591
|
} else if (!triggerArtifactVerified) {
|
|
585
|
-
// #2883: If the artifact is missing because the tool invocation
|
|
586
|
-
// failed (malformed
|
|
587
|
-
// same failure. Pause auto-mode instead of
|
|
592
|
+
// #2883/#3595: If the artifact is missing because the tool invocation
|
|
593
|
+
// failed (malformed JSON) or was skipped (queued user message), retrying
|
|
594
|
+
// will produce the same failure. Pause auto-mode instead of looping.
|
|
588
595
|
if (s.lastToolInvocationError) {
|
|
589
|
-
const
|
|
596
|
+
const isUserSkip = /queued user message/i.test(s.lastToolInvocationError);
|
|
597
|
+
const errMsg = isUserSkip
|
|
598
|
+
? `Tool skipped for ${s.currentUnit.type}: ${s.lastToolInvocationError}. Queued user message interrupted the turn — pausing auto-mode.`
|
|
599
|
+
: `Tool invocation failed for ${s.currentUnit.type}: ${s.lastToolInvocationError}. Structured argument generation failed — pausing auto-mode.`;
|
|
590
600
|
debugLog("postUnit", { phase: "tool-invocation-error-pause", unitType: s.currentUnit.type, unitId: s.currentUnit.id, error: s.lastToolInvocationError });
|
|
591
601
|
ctx.ui.notify(errMsg, "error");
|
|
592
602
|
s.lastToolInvocationError = null;
|
|
@@ -858,6 +858,7 @@ export async function buildDiscussMilestonePrompt(mid: string, midTitle: string,
|
|
|
858
858
|
inlinedTemplates: discussTemplates,
|
|
859
859
|
structuredQuestionsAvailable: "true",
|
|
860
860
|
commitInstruction: "Do not commit planning artifacts — .gsd/ is managed externally.",
|
|
861
|
+
fastPathInstruction: "",
|
|
861
862
|
});
|
|
862
863
|
|
|
863
864
|
// If a CONTEXT-DRAFT.md exists, append it as seed material
|
|
@@ -1801,6 +1802,36 @@ const GATE_QUESTIONS: Record<string, { question: string; guidance: string }> = {
|
|
|
1801
1802
|
},
|
|
1802
1803
|
};
|
|
1803
1804
|
|
|
1805
|
+
export async function buildParallelResearchSlicesPrompt(
|
|
1806
|
+
mid: string,
|
|
1807
|
+
midTitle: string,
|
|
1808
|
+
slices: Array<{ id: string; title: string }>,
|
|
1809
|
+
basePath: string,
|
|
1810
|
+
): Promise<string> {
|
|
1811
|
+
// Build individual research-slice prompts for each slice
|
|
1812
|
+
const subagentSections: string[] = [];
|
|
1813
|
+
for (const slice of slices) {
|
|
1814
|
+
const slicePrompt = await buildResearchSlicePrompt(mid, midTitle, slice.id, slice.title, basePath);
|
|
1815
|
+
subagentSections.push([
|
|
1816
|
+
`### ${slice.id}: ${slice.title}`,
|
|
1817
|
+
"",
|
|
1818
|
+
"Use this as the prompt for a `subagent` call (agent: `gsd-executor` or the default agent):",
|
|
1819
|
+
"",
|
|
1820
|
+
"```",
|
|
1821
|
+
slicePrompt,
|
|
1822
|
+
"```",
|
|
1823
|
+
].join("\n"));
|
|
1824
|
+
}
|
|
1825
|
+
|
|
1826
|
+
return loadPrompt("parallel-research-slices", {
|
|
1827
|
+
mid,
|
|
1828
|
+
midTitle,
|
|
1829
|
+
sliceCount: String(slices.length),
|
|
1830
|
+
sliceList: slices.map((s) => `- **${s.id}**: ${s.title}`).join("\n"),
|
|
1831
|
+
subagentPrompts: subagentSections.join("\n\n---\n\n"),
|
|
1832
|
+
});
|
|
1833
|
+
}
|
|
1834
|
+
|
|
1804
1835
|
export async function buildGateEvaluatePrompt(
|
|
1805
1836
|
mid: string, midTitle: string, sid: string, sTitle: string,
|
|
1806
1837
|
base: string,
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
|
|
10
10
|
import type { ExtensionContext } from "@gsd/pi-coding-agent";
|
|
11
11
|
import { parseUnitId } from "./unit-id.js";
|
|
12
|
+
import { appendEvent } from "./workflow-events.js";
|
|
12
13
|
import { atomicWriteSync } from "./atomic-write.js";
|
|
13
14
|
import { clearParseCache } from "./files.js";
|
|
14
15
|
import { parseRoadmap as parseLegacyRoadmap, parsePlan as parseLegacyPlan } from "./parsers-legacy.js";
|
|
@@ -60,13 +61,12 @@ export { resolveExpectedArtifactPath, diagnoseExpectedArtifact };
|
|
|
60
61
|
* in the git history. Uses `git log --name-only` to inspect all commits on the
|
|
61
62
|
* current branch that touch files outside `.gsd/`.
|
|
62
63
|
*
|
|
63
|
-
* Returns
|
|
64
|
-
*
|
|
65
|
-
* running outside a git repo (e.g., tests).
|
|
64
|
+
* Returns "present" if implementation files found, "absent" if only .gsd/ files,
|
|
65
|
+
* "unknown" if git is unavailable or check failed (callers decide how to handle).
|
|
66
66
|
*/
|
|
67
|
-
export function hasImplementationArtifacts(basePath: string):
|
|
67
|
+
export function hasImplementationArtifacts(basePath: string): "present" | "absent" | "unknown" {
|
|
68
68
|
try {
|
|
69
|
-
// Verify we're in a git repo
|
|
69
|
+
// Verify we're in a git repo
|
|
70
70
|
try {
|
|
71
71
|
execFileSync("git", ["rev-parse", "--is-inside-work-tree"], {
|
|
72
72
|
cwd: basePath,
|
|
@@ -75,7 +75,7 @@ export function hasImplementationArtifacts(basePath: string): boolean {
|
|
|
75
75
|
});
|
|
76
76
|
} catch (e) {
|
|
77
77
|
logWarning("recovery", `git rev-parse check failed: ${(e as Error).message}`);
|
|
78
|
-
return
|
|
78
|
+
return "unknown";
|
|
79
79
|
}
|
|
80
80
|
|
|
81
81
|
// Strategy: check `git diff --name-only` against the merge-base with the
|
|
@@ -85,19 +85,19 @@ export function hasImplementationArtifacts(basePath: string): boolean {
|
|
|
85
85
|
const mainBranch = detectMainBranch(basePath);
|
|
86
86
|
const changedFiles = getChangedFilesSinceBranch(basePath, mainBranch);
|
|
87
87
|
|
|
88
|
-
// No files changed at all —
|
|
88
|
+
// No files changed at all — unknown (could be detached HEAD, single-
|
|
89
89
|
// commit repo, or other edge case where git diff returns nothing).
|
|
90
|
-
if (changedFiles.length === 0) return
|
|
90
|
+
if (changedFiles.length === 0) return "unknown";
|
|
91
91
|
|
|
92
92
|
// Filter out .gsd/ files — only implementation files count.
|
|
93
93
|
// If every changed file is under .gsd/, the milestone produced no
|
|
94
94
|
// implementation code (#1703).
|
|
95
95
|
const implFiles = changedFiles.filter(f => !f.startsWith(".gsd/") && !f.startsWith(".gsd\\"));
|
|
96
|
-
return implFiles.length > 0;
|
|
96
|
+
return implFiles.length > 0 ? "present" : "absent";
|
|
97
97
|
} catch (e) {
|
|
98
|
-
// Non-fatal — if git operations fail,
|
|
98
|
+
// Non-fatal — if git operations fail, return unknown so callers can decide
|
|
99
99
|
logWarning("recovery", `implementation artifact check failed: ${(e as Error).message}`);
|
|
100
|
-
return
|
|
100
|
+
return "unknown";
|
|
101
101
|
}
|
|
102
102
|
}
|
|
103
103
|
|
|
@@ -286,7 +286,7 @@ export function verifyExpectedArtifact(
|
|
|
286
286
|
if (!hasCheckboxTask && !hasHeadingTask) return false;
|
|
287
287
|
}
|
|
288
288
|
|
|
289
|
-
// execute-task: DB status is authoritative. Fall back to
|
|
289
|
+
// execute-task: DB status is authoritative. Fall back to checked-checkbox
|
|
290
290
|
// detection when the DB is unavailable (unmigrated projects).
|
|
291
291
|
if (unitType === "execute-task") {
|
|
292
292
|
const { milestone: mid, slice: sid, task: tid } = parseUnitId(unitId);
|
|
@@ -297,20 +297,22 @@ export function verifyExpectedArtifact(
|
|
|
297
297
|
if (dbTask.status !== "complete" && dbTask.status !== "done") return false;
|
|
298
298
|
} else if (!isDbAvailable()) {
|
|
299
299
|
// LEGACY: Pre-migration fallback for projects without DB.
|
|
300
|
-
//
|
|
301
|
-
//
|
|
302
|
-
//
|
|
300
|
+
// Require a CHECKED checkbox — a bare heading or unchecked checkbox
|
|
301
|
+
// does not prove gsd_complete_task ran. Summary file on disk alone
|
|
302
|
+
// is not sufficient evidence (could be a rogue write) (#3607).
|
|
303
303
|
const planAbs = resolveSliceFile(base, mid, sid, "PLAN");
|
|
304
304
|
if (planAbs && existsSync(planAbs)) {
|
|
305
305
|
const planContent = readFileSync(planAbs, "utf-8");
|
|
306
306
|
const escapedTid = tid.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
307
|
-
const hdRe = new RegExp(`^#{2,4}\\s+${escapedTid}\\s*(?:--|—|:)`, "m");
|
|
308
307
|
const cbRe = new RegExp(`^- \\[[xX]\\] \\*\\*${escapedTid}:`, "m");
|
|
309
|
-
if (!
|
|
308
|
+
if (!cbRe.test(planContent)) return false;
|
|
309
|
+
} else {
|
|
310
|
+
return false; // no plan file → cannot verify
|
|
310
311
|
}
|
|
312
|
+
} else {
|
|
313
|
+
// DB available but task row not found — completion tool never ran (#3607)
|
|
314
|
+
return false;
|
|
311
315
|
}
|
|
312
|
-
// else: DB available but task not found — summary file exists (checked above),
|
|
313
|
-
// so treat as verified (task may not be imported yet)
|
|
314
316
|
}
|
|
315
317
|
}
|
|
316
318
|
|
|
@@ -392,7 +394,7 @@ export function verifyExpectedArtifact(
|
|
|
392
394
|
// A milestone with only .gsd/ plan files and zero implementation code is
|
|
393
395
|
// not genuinely complete — the LLM wrote plan files but skipped actual work.
|
|
394
396
|
if (unitType === "complete-milestone") {
|
|
395
|
-
if (
|
|
397
|
+
if (hasImplementationArtifacts(base) === "absent") return false;
|
|
396
398
|
}
|
|
397
399
|
|
|
398
400
|
return true;
|
|
@@ -429,11 +431,15 @@ export function writeBlockerPlaceholder(
|
|
|
429
431
|
// re-derives the same unit indefinitely (#2531, #2653).
|
|
430
432
|
if (isDbAvailable()) {
|
|
431
433
|
const { milestone: mid, slice: sid, task: tid } = parseUnitId(unitId);
|
|
434
|
+
const ts = new Date().toISOString();
|
|
432
435
|
if (unitType === "execute-task" && mid && sid && tid) {
|
|
433
|
-
try { updateTaskStatus(mid, sid, tid, "complete",
|
|
436
|
+
try { updateTaskStatus(mid, sid, tid, "complete", ts); } catch (e) { logWarning("recovery", `updateTaskStatus failed during context exhaustion: ${e instanceof Error ? e.message : String(e)}`); }
|
|
437
|
+
// Append event so worktree reconciliation can replay this recovery completion
|
|
438
|
+
try { appendEvent(base, { cmd: "complete-task", params: { milestoneId: mid, sliceId: sid, taskId: tid }, ts, actor: "system", trigger_reason: "blocker-placeholder-recovery" }); } catch (e) { logWarning("recovery", `appendEvent failed for task recovery: ${e instanceof Error ? e.message : String(e)}`); }
|
|
434
439
|
}
|
|
435
440
|
if (unitType === "complete-slice" && mid && sid) {
|
|
436
|
-
try { updateSliceStatus(mid, sid, "complete",
|
|
441
|
+
try { updateSliceStatus(mid, sid, "complete", ts); } catch (e) { logWarning("recovery", `updateSliceStatus failed during context exhaustion: ${e instanceof Error ? e.message : String(e)}`); }
|
|
442
|
+
try { appendEvent(base, { cmd: "complete-slice", params: { milestoneId: mid, sliceId: sid }, ts, actor: "system", trigger_reason: "blocker-placeholder-recovery" }); } catch (e) { logWarning("recovery", `appendEvent failed for slice recovery: ${e instanceof Error ? e.message : String(e)}`); }
|
|
437
443
|
}
|
|
438
444
|
}
|
|
439
445
|
|
|
@@ -495,7 +501,7 @@ export function reconcileMergeState(
|
|
|
495
501
|
if (conflictedFiles.length === 0) {
|
|
496
502
|
// All conflicts resolved — finalize the merge/squash commit
|
|
497
503
|
try {
|
|
498
|
-
const commitSha = nativeCommit(basePath, "
|
|
504
|
+
const commitSha = nativeCommit(basePath, "chore(gsd): reconcile merge state");
|
|
499
505
|
if (commitSha) {
|
|
500
506
|
const mode = hasMergeHead ? "merge" : "squash commit";
|
|
501
507
|
ctx.ui.notify(`Finalized leftover ${mode} from prior session.`, "info");
|