gsd-pi 2.66.1 → 2.67.0-dev.43b0159
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/claude-cli-check.d.ts +8 -0
- package/dist/claude-cli-check.js +36 -0
- package/dist/cli.js +40 -0
- package/dist/onboarding.js +19 -2
- package/dist/resources/extensions/ask-user-questions.js +79 -11
- package/dist/resources/extensions/claude-code-cli/partial-builder.js +4 -3
- package/dist/resources/extensions/claude-code-cli/readiness.js +63 -12
- package/dist/resources/extensions/claude-code-cli/stream-adapter.js +10 -3
- package/dist/resources/extensions/gsd/auto/loop.js +13 -1
- package/dist/resources/extensions/gsd/auto/phases.js +22 -3
- package/dist/resources/extensions/gsd/auto/run-unit.js +10 -2
- package/dist/resources/extensions/gsd/auto/session.js +1 -1
- package/dist/resources/extensions/gsd/auto-dashboard.js +65 -15
- package/dist/resources/extensions/gsd/auto-dispatch.js +30 -28
- package/dist/resources/extensions/gsd/auto-model-selection.js +12 -3
- package/dist/resources/extensions/gsd/auto-prompts.js +173 -25
- package/dist/resources/extensions/gsd/auto-recovery.js +11 -12
- package/dist/resources/extensions/gsd/auto.js +13 -1
- package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +32 -1
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +18 -6
- package/dist/resources/extensions/gsd/bootstrap/provider-error-resume.js +5 -0
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +59 -5
- package/dist/resources/extensions/gsd/bootstrap/register-shortcuts.js +8 -5
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +186 -14
- package/dist/resources/extensions/gsd/codebase-generator.js +4 -0
- package/dist/resources/extensions/gsd/commands/catalog.js +2 -1
- package/dist/resources/extensions/gsd/commands/dispatcher.js +1 -1
- package/dist/resources/extensions/gsd/commands/handlers/core.js +94 -4
- package/dist/resources/extensions/gsd/commands-prefs-wizard.js +49 -9
- package/dist/resources/extensions/gsd/context-store.js +134 -2
- package/dist/resources/extensions/gsd/custom-workflow-engine.js +3 -1
- package/dist/resources/extensions/gsd/detection.js +6 -0
- package/dist/resources/extensions/gsd/files.js +19 -2
- package/dist/resources/extensions/gsd/guided-flow.js +12 -8
- package/dist/resources/extensions/gsd/index.js +1 -1
- package/dist/resources/extensions/gsd/parallel-monitor-overlay.js +2 -0
- package/dist/resources/extensions/gsd/parsers-legacy.js +3 -1
- package/dist/resources/extensions/gsd/preferences.js +6 -1
- package/dist/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
- package/dist/resources/extensions/gsd/prompts/complete-slice.md +3 -3
- package/dist/resources/extensions/gsd/prompts/discuss-prepared.md +7 -7
- package/dist/resources/extensions/gsd/prompts/discuss.md +3 -3
- package/dist/resources/extensions/gsd/prompts/execute-task.md +3 -3
- package/dist/resources/extensions/gsd/prompts/guided-discuss-milestone.md +3 -3
- package/dist/resources/extensions/gsd/prompts/guided-discuss-slice.md +3 -1
- package/dist/resources/extensions/gsd/prompts/rethink.md +6 -2
- package/dist/resources/extensions/gsd/prompts/system.md +1 -1
- package/dist/resources/extensions/gsd/prompts/triage-captures.md +1 -1
- package/dist/resources/extensions/gsd/prompts/validate-milestone.md +11 -9
- package/dist/resources/extensions/gsd/prompts/worktree-merge.md +3 -1
- package/dist/resources/extensions/gsd/safety/file-change-validator.js +2 -1
- package/dist/resources/extensions/gsd/state.js +2 -1
- package/dist/resources/extensions/gsd/visualizer-overlay.js +27 -26
- package/dist/resources/extensions/gsd/workflow-reconcile.js +46 -7
- package/dist/resources/extensions/remote-questions/manager.js +8 -0
- package/dist/resources/extensions/shared/interview-ui.js +10 -0
- 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 → 6502.b804e48b7919f55e.js} +3 -3
- 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-9fed74684e1c5bb1.js → webpack-65f0501b197d1c49.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-ai/dist/providers/anthropic-shared.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/anthropic-shared.js +4 -3
- package/packages/pi-ai/dist/providers/anthropic-shared.js.map +1 -1
- package/packages/pi-ai/dist/utils/json-parse.d.ts.map +1 -1
- package/packages/pi-ai/dist/utils/json-parse.js +11 -1
- package/packages/pi-ai/dist/utils/json-parse.js.map +1 -1
- package/packages/pi-ai/dist/utils/repair-tool-json.d.ts.map +1 -1
- package/packages/pi-ai/dist/utils/repair-tool-json.js +60 -1
- package/packages/pi-ai/dist/utils/repair-tool-json.js.map +1 -1
- package/packages/pi-ai/dist/utils/tests/json-parse.test.d.ts +2 -0
- package/packages/pi-ai/dist/utils/tests/json-parse.test.d.ts.map +1 -0
- package/packages/pi-ai/dist/utils/tests/json-parse.test.js +14 -0
- package/packages/pi-ai/dist/utils/tests/json-parse.test.js.map +1 -0
- package/packages/pi-ai/dist/utils/tests/repair-tool-json.test.js +10 -0
- package/packages/pi-ai/dist/utils/tests/repair-tool-json.test.js.map +1 -1
- package/packages/pi-ai/src/providers/anthropic-shared.ts +4 -3
- package/packages/pi-ai/src/utils/json-parse.ts +11 -1
- package/packages/pi-ai/src/utils/repair-tool-json.ts +69 -1
- package/packages/pi-ai/src/utils/tests/json-parse.test.ts +17 -0
- package/packages/pi-ai/src/utils/tests/repair-tool-json.test.ts +13 -0
- package/packages/pi-coding-agent/dist/core/agent-session.d.ts +3 -0
- package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session.js +1 -0
- package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/retry-handler.d.ts +16 -0
- package/packages/pi-coding-agent/dist/core/retry-handler.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/retry-handler.js +58 -1
- package/packages/pi-coding-agent/dist/core/retry-handler.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/retry-handler.test.js +58 -0
- package/packages/pi-coding-agent/dist/core/retry-handler.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/sdk.d.ts +3 -0
- package/packages/pi-coding-agent/dist/core/sdk.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/sdk.js +1 -0
- package/packages/pi-coding-agent/dist/core/sdk.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/provider-display-name.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/provider-display-name.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/provider-display-name.test.js +17 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/provider-display-name.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js +2 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/model-selector.d.ts +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/model-selector.js +9 -2
- package/packages/pi-coding-agent/dist/modes/interactive/components/model-selector.js.map +1 -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 +2 -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/scoped-models-selector.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/scoped-models-selector.js +2 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/scoped-models-selector.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +2 -2
- 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/agent-session.ts +4 -0
- package/packages/pi-coding-agent/src/core/retry-handler.test.ts +69 -0
- package/packages/pi-coding-agent/src/core/retry-handler.ts +66 -1
- package/packages/pi-coding-agent/src/core/sdk.ts +5 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/provider-display-name.test.ts +18 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/footer.ts +2 -1
- package/packages/pi-coding-agent/src/modes/interactive/components/model-selector.ts +11 -2
- package/packages/pi-coding-agent/src/modes/interactive/components/provider-manager.ts +2 -1
- package/packages/pi-coding-agent/src/modes/interactive/components/scoped-models-selector.ts +2 -1
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +2 -2
- package/packages/pi-tui/dist/__tests__/autocomplete.test.js +13 -0
- package/packages/pi-tui/dist/__tests__/autocomplete.test.js.map +1 -1
- package/packages/pi-tui/dist/__tests__/stdin-buffer.test.d.ts +2 -0
- package/packages/pi-tui/dist/__tests__/stdin-buffer.test.d.ts.map +1 -0
- package/packages/pi-tui/dist/__tests__/stdin-buffer.test.js +35 -0
- package/packages/pi-tui/dist/__tests__/stdin-buffer.test.js.map +1 -0
- package/packages/pi-tui/dist/__tests__/tui.test.d.ts +2 -0
- package/packages/pi-tui/dist/__tests__/tui.test.d.ts.map +1 -0
- package/packages/pi-tui/dist/__tests__/tui.test.js +43 -0
- package/packages/pi-tui/dist/__tests__/tui.test.js.map +1 -0
- package/packages/pi-tui/dist/autocomplete.d.ts.map +1 -1
- package/packages/pi-tui/dist/autocomplete.js +9 -7
- package/packages/pi-tui/dist/autocomplete.js.map +1 -1
- package/packages/pi-tui/dist/components/__tests__/editor.test.d.ts +2 -0
- package/packages/pi-tui/dist/components/__tests__/editor.test.d.ts.map +1 -0
- package/packages/pi-tui/dist/components/__tests__/editor.test.js +54 -0
- package/packages/pi-tui/dist/components/__tests__/editor.test.js.map +1 -0
- package/packages/pi-tui/dist/components/editor.d.ts +3 -1
- package/packages/pi-tui/dist/components/editor.d.ts.map +1 -1
- package/packages/pi-tui/dist/components/editor.js +14 -3
- package/packages/pi-tui/dist/components/editor.js.map +1 -1
- package/packages/pi-tui/dist/stdin-buffer.d.ts.map +1 -1
- package/packages/pi-tui/dist/stdin-buffer.js +6 -0
- package/packages/pi-tui/dist/stdin-buffer.js.map +1 -1
- package/packages/pi-tui/dist/tui.d.ts.map +1 -1
- package/packages/pi-tui/dist/tui.js +8 -0
- package/packages/pi-tui/dist/tui.js.map +1 -1
- package/packages/pi-tui/src/__tests__/autocomplete.test.ts +15 -0
- package/packages/pi-tui/src/__tests__/stdin-buffer.test.ts +43 -0
- package/packages/pi-tui/src/__tests__/tui.test.ts +50 -0
- package/packages/pi-tui/src/autocomplete.ts +9 -7
- package/packages/pi-tui/src/components/__tests__/editor.test.ts +64 -0
- package/packages/pi-tui/src/components/editor.ts +14 -3
- package/packages/pi-tui/src/stdin-buffer.ts +7 -0
- package/packages/pi-tui/src/tui.ts +9 -0
- package/pkg/package.json +1 -1
- package/src/resources/extensions/ask-user-questions.ts +103 -11
- package/src/resources/extensions/claude-code-cli/partial-builder.ts +4 -3
- package/src/resources/extensions/claude-code-cli/readiness.ts +67 -12
- package/src/resources/extensions/claude-code-cli/stream-adapter.ts +12 -3
- package/src/resources/extensions/claude-code-cli/tests/partial-builder.test.ts +17 -0
- package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +18 -0
- package/src/resources/extensions/gsd/auto/loop-deps.ts +2 -1
- package/src/resources/extensions/gsd/auto/loop.ts +14 -1
- package/src/resources/extensions/gsd/auto/phases.ts +27 -4
- package/src/resources/extensions/gsd/auto/run-unit.ts +14 -2
- package/src/resources/extensions/gsd/auto/session.ts +1 -1
- package/src/resources/extensions/gsd/auto-dashboard.ts +76 -16
- package/src/resources/extensions/gsd/auto-dispatch.ts +36 -35
- package/src/resources/extensions/gsd/auto-model-selection.ts +12 -3
- package/src/resources/extensions/gsd/auto-prompts.ts +195 -25
- package/src/resources/extensions/gsd/auto-recovery.ts +15 -15
- package/src/resources/extensions/gsd/auto.ts +12 -1
- package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +34 -1
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +27 -6
- package/src/resources/extensions/gsd/bootstrap/provider-error-resume.ts +6 -0
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +67 -6
- package/src/resources/extensions/gsd/bootstrap/register-shortcuts.ts +11 -8
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +209 -16
- package/src/resources/extensions/gsd/codebase-generator.ts +4 -0
- package/src/resources/extensions/gsd/commands/catalog.ts +2 -1
- package/src/resources/extensions/gsd/commands/dispatcher.ts +1 -2
- package/src/resources/extensions/gsd/commands/handlers/core.ts +113 -8
- package/src/resources/extensions/gsd/commands-prefs-wizard.ts +49 -11
- package/src/resources/extensions/gsd/context-store.ts +167 -2
- package/src/resources/extensions/gsd/custom-workflow-engine.ts +3 -1
- package/src/resources/extensions/gsd/detection.ts +6 -0
- package/src/resources/extensions/gsd/files.ts +21 -2
- package/src/resources/extensions/gsd/guided-flow.ts +15 -8
- package/src/resources/extensions/gsd/index.ts +6 -0
- package/src/resources/extensions/gsd/parallel-monitor-overlay.ts +2 -0
- package/src/resources/extensions/gsd/parsers-legacy.ts +3 -1
- package/src/resources/extensions/gsd/preferences.ts +6 -1
- package/src/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
- package/src/resources/extensions/gsd/prompts/complete-slice.md +3 -3
- package/src/resources/extensions/gsd/prompts/discuss-prepared.md +7 -7
- package/src/resources/extensions/gsd/prompts/discuss.md +3 -3
- package/src/resources/extensions/gsd/prompts/execute-task.md +3 -3
- package/src/resources/extensions/gsd/prompts/guided-discuss-milestone.md +3 -3
- package/src/resources/extensions/gsd/prompts/guided-discuss-slice.md +3 -1
- package/src/resources/extensions/gsd/prompts/rethink.md +6 -2
- package/src/resources/extensions/gsd/prompts/system.md +1 -1
- package/src/resources/extensions/gsd/prompts/triage-captures.md +1 -1
- package/src/resources/extensions/gsd/prompts/validate-milestone.md +11 -9
- package/src/resources/extensions/gsd/prompts/worktree-merge.md +3 -1
- package/src/resources/extensions/gsd/safety/file-change-validator.ts +4 -1
- package/src/resources/extensions/gsd/state.ts +2 -1
- package/src/resources/extensions/gsd/tests/auto-dashboard.test.ts +52 -1
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +50 -2
- package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +21 -7
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +48 -0
- package/src/resources/extensions/gsd/tests/codebase-generator.test.ts +22 -0
- package/src/resources/extensions/gsd/tests/commands-workflow-custom.test.ts +12 -0
- package/src/resources/extensions/gsd/tests/context-store.test.ts +176 -0
- package/src/resources/extensions/gsd/tests/core-overlay-fallback.test.ts +76 -0
- package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +7 -1
- package/src/resources/extensions/gsd/tests/custom-workflow-engine.test.ts +31 -0
- package/src/resources/extensions/gsd/tests/decision-scope-cascade.test.ts +370 -0
- package/src/resources/extensions/gsd/tests/detection.test.ts +37 -0
- package/src/resources/extensions/gsd/tests/file-change-validator.test.ts +50 -0
- package/src/resources/extensions/gsd/tests/gsd-tools.test.ts +35 -0
- package/src/resources/extensions/gsd/tests/guided-flow-session-isolation.test.ts +34 -0
- package/src/resources/extensions/gsd/tests/health-widget.test.ts +45 -0
- package/src/resources/extensions/gsd/tests/integration/auto-recovery.test.ts +53 -13
- package/src/resources/extensions/gsd/tests/integration/state-machine-runtime-failures.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/journal-integration.test.ts +3 -3
- package/src/resources/extensions/gsd/tests/measurement.test.ts +531 -0
- package/src/resources/extensions/gsd/tests/migrate-writer-integration.test.ts +3 -4
- package/src/resources/extensions/gsd/tests/parallel-monitor-overlay.test.ts +21 -0
- package/src/resources/extensions/gsd/tests/parallel-research-dispatch.test.ts +71 -2
- package/src/resources/extensions/gsd/tests/parsers.test.ts +25 -0
- package/src/resources/extensions/gsd/tests/preferences.test.ts +37 -0
- package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +26 -4
- package/src/resources/extensions/gsd/tests/provider-errors.test.ts +60 -0
- package/src/resources/extensions/gsd/tests/queue-execution-guard.test.ts +9 -0
- package/src/resources/extensions/gsd/tests/reactive-graph.test.ts +19 -0
- package/src/resources/extensions/gsd/tests/register-shortcuts.test.ts +73 -0
- package/src/resources/extensions/gsd/tests/remote-questions.test.ts +98 -0
- package/src/resources/extensions/gsd/tests/smart-entry-complete.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/validate-milestone.test.ts +26 -0
- package/src/resources/extensions/gsd/tests/visualizer-overlay.test.ts +59 -0
- package/src/resources/extensions/gsd/tests/workflow-reconcile.test.ts +91 -0
- package/src/resources/extensions/gsd/tests/write-gate.test.ts +210 -35
- package/src/resources/extensions/gsd/visualizer-overlay.ts +31 -27
- package/src/resources/extensions/gsd/workflow-reconcile.ts +59 -8
- package/src/resources/extensions/remote-questions/manager.ts +9 -0
- package/src/resources/extensions/shared/interview-ui.ts +13 -0
- 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/{y5P0reMrCMs-4-gswdawm → CrKrzIIxk55witDF1eS0L}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{y5P0reMrCMs-4-gswdawm → CrKrzIIxk55witDF1eS0L}/_ssgManifest.js +0 -0
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
import { getCurrentBranch } from "./worktree.js";
|
|
9
9
|
import { getActiveHook } from "./post-unit-hooks.js";
|
|
10
10
|
import { getLedger, getProjectTotals } from "./metrics.js";
|
|
11
|
+
import { getErrorMessage } from "./error-utils.js";
|
|
11
12
|
import { isDbAvailable, getMilestoneSlices, getSliceTasks } from "./gsd-db.js";
|
|
12
13
|
import { formatShortcut } from "./files.js";
|
|
13
14
|
import { readFileSync, writeFileSync, existsSync } from "node:fs";
|
|
@@ -17,7 +18,7 @@ import { makeUI } from "../shared/tui.js";
|
|
|
17
18
|
import { GLYPH, INDENT } from "../shared/mod.js";
|
|
18
19
|
import { computeProgressScore } from "./progress-score.js";
|
|
19
20
|
import { getActiveWorktreeName } from "./worktree-command.js";
|
|
20
|
-
import {
|
|
21
|
+
import { getGlobalGSDPreferencesPath, getProjectGSDPreferencesPath, parsePreferencesMarkdown, } from "./preferences.js";
|
|
21
22
|
import { resolveServiceTierIcon, getEffectiveServiceTier } from "./service-tier.js";
|
|
22
23
|
import { parseUnitId } from "./unit-id.js";
|
|
23
24
|
import { formatRtkSavingsLabel, getRtkSessionSavings, } from "../shared/rtk-session-stats.js";
|
|
@@ -293,26 +294,68 @@ export const hideFooter = () => ({
|
|
|
293
294
|
const WIDGET_MODES = ["full", "small", "min", "off"];
|
|
294
295
|
let widgetMode = "full";
|
|
295
296
|
let widgetModeInitialized = false;
|
|
297
|
+
let widgetModePreferencePath = null;
|
|
298
|
+
function safeReadTextFile(path) {
|
|
299
|
+
try {
|
|
300
|
+
if (!existsSync(path))
|
|
301
|
+
return null;
|
|
302
|
+
return readFileSync(path, "utf-8");
|
|
303
|
+
}
|
|
304
|
+
catch {
|
|
305
|
+
return null;
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
function readWidgetModeFromFile(path) {
|
|
309
|
+
const raw = safeReadTextFile(path);
|
|
310
|
+
if (!raw)
|
|
311
|
+
return undefined;
|
|
312
|
+
const prefs = parsePreferencesMarkdown(raw);
|
|
313
|
+
const saved = prefs?.widget_mode;
|
|
314
|
+
if (saved && WIDGET_MODES.includes(saved)) {
|
|
315
|
+
return saved;
|
|
316
|
+
}
|
|
317
|
+
return undefined;
|
|
318
|
+
}
|
|
319
|
+
function resolveWidgetModePreferencePath(projectPath = getProjectGSDPreferencesPath(), globalPath = getGlobalGSDPreferencesPath()) {
|
|
320
|
+
if (readWidgetModeFromFile(projectPath)) {
|
|
321
|
+
return projectPath;
|
|
322
|
+
}
|
|
323
|
+
if (readWidgetModeFromFile(globalPath)) {
|
|
324
|
+
return globalPath;
|
|
325
|
+
}
|
|
326
|
+
if (safeReadTextFile(projectPath) !== null)
|
|
327
|
+
return projectPath;
|
|
328
|
+
if (safeReadTextFile(globalPath) !== null)
|
|
329
|
+
return globalPath;
|
|
330
|
+
return getGlobalGSDPreferencesPath();
|
|
331
|
+
}
|
|
296
332
|
/** Load widget mode from preferences (once). */
|
|
297
|
-
function ensureWidgetModeLoaded() {
|
|
333
|
+
function ensureWidgetModeLoaded(projectPath, globalPath) {
|
|
298
334
|
if (widgetModeInitialized)
|
|
299
335
|
return;
|
|
300
336
|
widgetModeInitialized = true;
|
|
301
337
|
try {
|
|
302
|
-
const
|
|
303
|
-
const
|
|
338
|
+
const resolvedProjectPath = projectPath ?? getProjectGSDPreferencesPath();
|
|
339
|
+
const resolvedGlobalPath = globalPath ?? getGlobalGSDPreferencesPath();
|
|
340
|
+
const saved = readWidgetModeFromFile(resolvedProjectPath) ?? readWidgetModeFromFile(resolvedGlobalPath);
|
|
304
341
|
if (saved && WIDGET_MODES.includes(saved)) {
|
|
305
342
|
widgetMode = saved;
|
|
306
343
|
}
|
|
344
|
+
widgetModePreferencePath = resolveWidgetModePreferencePath(resolvedProjectPath, resolvedGlobalPath);
|
|
307
345
|
}
|
|
308
346
|
catch (err) { /* non-fatal — use default */
|
|
309
|
-
logWarning("dashboard", `operation failed: ${
|
|
347
|
+
logWarning("dashboard", `operation failed: ${getErrorMessage(err)}`);
|
|
348
|
+
widgetModePreferencePath = getGlobalGSDPreferencesPath();
|
|
310
349
|
}
|
|
311
350
|
}
|
|
312
|
-
/**
|
|
313
|
-
|
|
351
|
+
/**
|
|
352
|
+
* Persist widget mode to the preference file that owns the effective value.
|
|
353
|
+
* Project-scoped widget_mode wins over global; if neither scope defines it,
|
|
354
|
+
* we prefer an existing project preferences file and otherwise fall back to
|
|
355
|
+
* the global preferences file.
|
|
356
|
+
*/
|
|
357
|
+
function persistWidgetMode(mode, prefsPath = widgetModePreferencePath ?? resolveWidgetModePreferencePath()) {
|
|
314
358
|
try {
|
|
315
|
-
const prefsPath = getGlobalGSDPreferencesPath();
|
|
316
359
|
let content = "";
|
|
317
360
|
if (existsSync(prefsPath)) {
|
|
318
361
|
content = readFileSync(prefsPath, "utf-8");
|
|
@@ -332,23 +375,30 @@ function persistWidgetMode(mode) {
|
|
|
332
375
|
}
|
|
333
376
|
}
|
|
334
377
|
/** Cycle to the next widget mode. Returns the new mode. */
|
|
335
|
-
export function cycleWidgetMode() {
|
|
336
|
-
ensureWidgetModeLoaded();
|
|
378
|
+
export function cycleWidgetMode(projectPath, globalPath) {
|
|
379
|
+
ensureWidgetModeLoaded(projectPath, globalPath);
|
|
337
380
|
const idx = WIDGET_MODES.indexOf(widgetMode);
|
|
338
381
|
widgetMode = WIDGET_MODES[(idx + 1) % WIDGET_MODES.length];
|
|
339
|
-
persistWidgetMode(widgetMode);
|
|
382
|
+
persistWidgetMode(widgetMode, widgetModePreferencePath ?? resolveWidgetModePreferencePath(projectPath, globalPath));
|
|
340
383
|
return widgetMode;
|
|
341
384
|
}
|
|
342
385
|
/** Set widget mode directly. */
|
|
343
|
-
export function setWidgetMode(mode) {
|
|
386
|
+
export function setWidgetMode(mode, projectPath, globalPath) {
|
|
387
|
+
ensureWidgetModeLoaded(projectPath, globalPath);
|
|
344
388
|
widgetMode = mode;
|
|
345
|
-
persistWidgetMode(widgetMode);
|
|
389
|
+
persistWidgetMode(widgetMode, widgetModePreferencePath ?? resolveWidgetModePreferencePath(projectPath, globalPath));
|
|
346
390
|
}
|
|
347
391
|
/** Get current widget mode. */
|
|
348
|
-
export function getWidgetMode() {
|
|
349
|
-
ensureWidgetModeLoaded();
|
|
392
|
+
export function getWidgetMode(projectPath, globalPath) {
|
|
393
|
+
ensureWidgetModeLoaded(projectPath, globalPath);
|
|
350
394
|
return widgetMode;
|
|
351
395
|
}
|
|
396
|
+
/** Test-only reset for widget mode caching. */
|
|
397
|
+
export function _resetWidgetModeForTests() {
|
|
398
|
+
widgetMode = "full";
|
|
399
|
+
widgetModeInitialized = false;
|
|
400
|
+
widgetModePreferencePath = null;
|
|
401
|
+
}
|
|
352
402
|
export function updateProgressWidget(ctx, unitType, unitId, state, accessors, tierBadge) {
|
|
353
403
|
if (!ctx.hasUI)
|
|
354
404
|
return;
|
|
@@ -291,34 +291,8 @@ export const DISPATCH_RULES = [
|
|
|
291
291
|
},
|
|
292
292
|
},
|
|
293
293
|
{
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
if (state.phase !== "planning")
|
|
297
|
-
return null;
|
|
298
|
-
// Phase skip: skip research when preference or profile says so
|
|
299
|
-
if (prefs?.phases?.skip_research || prefs?.phases?.skip_slice_research)
|
|
300
|
-
return null;
|
|
301
|
-
if (!state.activeSlice)
|
|
302
|
-
return missingSliceStop(mid, state.phase);
|
|
303
|
-
const sid = state.activeSlice.id;
|
|
304
|
-
const sTitle = state.activeSlice.title;
|
|
305
|
-
const researchFile = resolveSliceFile(basePath, mid, sid, "RESEARCH");
|
|
306
|
-
if (researchFile)
|
|
307
|
-
return null; // has research, fall through
|
|
308
|
-
// Skip slice research for S01 when milestone research already exists —
|
|
309
|
-
// the milestone research already covers the same ground for the first slice.
|
|
310
|
-
const milestoneResearchFile = resolveMilestoneFile(basePath, mid, "RESEARCH");
|
|
311
|
-
if (milestoneResearchFile && sid === "S01")
|
|
312
|
-
return null; // fall through to plan-slice
|
|
313
|
-
return {
|
|
314
|
-
action: "dispatch",
|
|
315
|
-
unitType: "research-slice",
|
|
316
|
-
unitId: `${mid}/${sid}`,
|
|
317
|
-
prompt: await buildResearchSlicePrompt(mid, midTitle, sid, sTitle, basePath),
|
|
318
|
-
};
|
|
319
|
-
},
|
|
320
|
-
},
|
|
321
|
-
{
|
|
294
|
+
// Keep this rule before the single-slice research rule so the multi-slice
|
|
295
|
+
// path wins whenever 2+ slices are ready.
|
|
322
296
|
name: "planning (multiple slices need research) → parallel-research-slices",
|
|
323
297
|
match: async ({ state, mid, midTitle, basePath, prefs }) => {
|
|
324
298
|
if (state.phase !== "planning")
|
|
@@ -360,6 +334,34 @@ export const DISPATCH_RULES = [
|
|
|
360
334
|
};
|
|
361
335
|
},
|
|
362
336
|
},
|
|
337
|
+
{
|
|
338
|
+
name: "planning (no research, not S01) → research-slice",
|
|
339
|
+
match: async ({ state, mid, midTitle, basePath, prefs }) => {
|
|
340
|
+
if (state.phase !== "planning")
|
|
341
|
+
return null;
|
|
342
|
+
// Phase skip: skip research when preference or profile says so
|
|
343
|
+
if (prefs?.phases?.skip_research || prefs?.phases?.skip_slice_research)
|
|
344
|
+
return null;
|
|
345
|
+
if (!state.activeSlice)
|
|
346
|
+
return missingSliceStop(mid, state.phase);
|
|
347
|
+
const sid = state.activeSlice.id;
|
|
348
|
+
const sTitle = state.activeSlice.title;
|
|
349
|
+
const researchFile = resolveSliceFile(basePath, mid, sid, "RESEARCH");
|
|
350
|
+
if (researchFile)
|
|
351
|
+
return null; // has research, fall through
|
|
352
|
+
// Skip slice research for S01 when milestone research already exists —
|
|
353
|
+
// the milestone research already covers the same ground for the first slice.
|
|
354
|
+
const milestoneResearchFile = resolveMilestoneFile(basePath, mid, "RESEARCH");
|
|
355
|
+
if (milestoneResearchFile && sid === "S01")
|
|
356
|
+
return null; // fall through to plan-slice
|
|
357
|
+
return {
|
|
358
|
+
action: "dispatch",
|
|
359
|
+
unitType: "research-slice",
|
|
360
|
+
unitId: `${mid}/${sid}`,
|
|
361
|
+
prompt: await buildResearchSlicePrompt(mid, midTitle, sid, sTitle, basePath),
|
|
362
|
+
};
|
|
363
|
+
},
|
|
364
|
+
},
|
|
363
365
|
{
|
|
364
366
|
name: "planning → plan-slice",
|
|
365
367
|
match: async ({ state, mid, midTitle, basePath }) => {
|
|
@@ -252,8 +252,17 @@ export function resolveModelId(modelId, availableModels, currentProvider) {
|
|
|
252
252
|
return undefined;
|
|
253
253
|
if (candidates.length === 1)
|
|
254
254
|
return candidates[0];
|
|
255
|
-
//
|
|
256
|
-
//
|
|
255
|
+
// When the user's current provider is claude-code (set by startup migration
|
|
256
|
+
// or explicit selection), honour it for bare IDs. Routing back to anthropic
|
|
257
|
+
// would undo the migration and hit the third-party subscription block (#3772).
|
|
258
|
+
if (currentProvider === "claude-code") {
|
|
259
|
+
const ccMatch = candidates.find(m => m.provider === "claude-code");
|
|
260
|
+
if (ccMatch)
|
|
261
|
+
return ccMatch;
|
|
262
|
+
}
|
|
263
|
+
// Extension / CLI-wrapper providers that should not win bare-ID resolution
|
|
264
|
+
// when a first-class API provider also offers the same model AND the user
|
|
265
|
+
// has not explicitly chosen the extension provider.
|
|
257
266
|
const EXTENSION_PROVIDERS = new Set(["claude-code"]);
|
|
258
267
|
// Prefer currentProvider only when it is a first-class API provider
|
|
259
268
|
if (currentProvider && !EXTENSION_PROVIDERS.has(currentProvider)) {
|
|
@@ -274,7 +283,7 @@ export function resolveModelId(modelId, availableModels, currentProvider) {
|
|
|
274
283
|
* Uses case-insensitive matching with alias support to prevent fail-open on
|
|
275
284
|
* provider naming variations (e.g. "copilot" vs "github-copilot").
|
|
276
285
|
*/
|
|
277
|
-
const FLAT_RATE_PROVIDERS = new Set(["github-copilot", "copilot"]);
|
|
286
|
+
const FLAT_RATE_PROVIDERS = new Set(["github-copilot", "copilot", "claude-code"]);
|
|
278
287
|
export function isFlatRateProvider(provider) {
|
|
279
288
|
return FLAT_RATE_PROVIDERS.has(provider.toLowerCase());
|
|
280
289
|
}
|
|
@@ -219,7 +219,12 @@ export async function inlineGsdRootFile(base, filename, label) {
|
|
|
219
219
|
// ─── DB-Aware Inline Helpers ──────────────────────────────────────────────
|
|
220
220
|
/**
|
|
221
221
|
* Inline decisions with optional milestone scoping from the DB.
|
|
222
|
-
* Falls back to filesystem via inlineGsdRootFile when DB unavailable
|
|
222
|
+
* Falls back to filesystem via inlineGsdRootFile only when DB is unavailable.
|
|
223
|
+
*
|
|
224
|
+
* Cascade logic (R005):
|
|
225
|
+
* 1. Query with { milestoneId, scope } if scope provided
|
|
226
|
+
* 2. If empty AND scope was provided, retry with { milestoneId } only (drop scope)
|
|
227
|
+
* 3. If still empty, return null (intentional per D020)
|
|
223
228
|
*/
|
|
224
229
|
export async function inlineDecisionsFromDb(base, milestoneId, scope, level) {
|
|
225
230
|
const inlineLevel = level ?? resolveInlineLevel();
|
|
@@ -227,7 +232,12 @@ export async function inlineDecisionsFromDb(base, milestoneId, scope, level) {
|
|
|
227
232
|
const { isDbAvailable } = await import("./gsd-db.js");
|
|
228
233
|
if (isDbAvailable()) {
|
|
229
234
|
const { queryDecisions, formatDecisionsForPrompt } = await import("./context-store.js");
|
|
230
|
-
|
|
235
|
+
// First query: try with both milestoneId and scope (if scope provided)
|
|
236
|
+
let decisions = queryDecisions({ milestoneId, scope });
|
|
237
|
+
// Cascade: if empty AND scope was provided, retry without scope
|
|
238
|
+
if (decisions.length === 0 && scope) {
|
|
239
|
+
decisions = queryDecisions({ milestoneId });
|
|
240
|
+
}
|
|
231
241
|
if (decisions.length > 0) {
|
|
232
242
|
// Use compact format for non-full levels to save ~35% tokens
|
|
233
243
|
const formatted = inlineLevel !== "full"
|
|
@@ -235,24 +245,27 @@ export async function inlineDecisionsFromDb(base, milestoneId, scope, level) {
|
|
|
235
245
|
: formatDecisionsForPrompt(decisions);
|
|
236
246
|
return `### Decisions\nSource: \`.gsd/DECISIONS.md\`\n\n${formatted}`;
|
|
237
247
|
}
|
|
248
|
+
// DB available but cascade returned empty — intentional per D020, don't fall back to file
|
|
249
|
+
return null;
|
|
238
250
|
}
|
|
239
251
|
}
|
|
240
252
|
catch (err) {
|
|
241
253
|
logWarning("prompt", `inlineDecisionsFromDb failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
242
254
|
}
|
|
255
|
+
// DB unavailable — fall back to filesystem
|
|
243
256
|
return inlineGsdRootFile(base, "decisions.md", "Decisions");
|
|
244
257
|
}
|
|
245
258
|
/**
|
|
246
|
-
* Inline requirements with optional slice scoping from the DB.
|
|
259
|
+
* Inline requirements with optional milestone and slice scoping from the DB.
|
|
247
260
|
* Falls back to filesystem via inlineGsdRootFile when DB unavailable or empty.
|
|
248
261
|
*/
|
|
249
|
-
export async function inlineRequirementsFromDb(base, sliceId, level) {
|
|
262
|
+
export async function inlineRequirementsFromDb(base, milestoneId, sliceId, level) {
|
|
250
263
|
const inlineLevel = level ?? resolveInlineLevel();
|
|
251
264
|
try {
|
|
252
265
|
const { isDbAvailable } = await import("./gsd-db.js");
|
|
253
266
|
if (isDbAvailable()) {
|
|
254
267
|
const { queryRequirements, formatRequirementsForPrompt } = await import("./context-store.js");
|
|
255
|
-
const requirements = queryRequirements({ sliceId });
|
|
268
|
+
const requirements = queryRequirements({ milestoneId, sliceId });
|
|
256
269
|
if (requirements.length > 0) {
|
|
257
270
|
// Use compact format for non-full levels to save ~40% tokens
|
|
258
271
|
const formatted = inlineLevel !== "full"
|
|
@@ -287,6 +300,117 @@ export async function inlineProjectFromDb(base) {
|
|
|
287
300
|
}
|
|
288
301
|
return inlineGsdRootFile(base, "project.md", "Project");
|
|
289
302
|
}
|
|
303
|
+
// ─── Stopwords for keyword extraction ─────────────────────────────────────
|
|
304
|
+
const STOPWORDS = new Set(['of', 'the', 'and', 'a', 'for', '+', '-', 'to', 'in', 'on', 'with', 'is', 'as', 'by']);
|
|
305
|
+
// Generic words that don't provide meaningful scope differentiation
|
|
306
|
+
const GENERIC_WORDS = new Set([
|
|
307
|
+
'setup', 'integration', 'implementation', 'testing', 'test', 'tests',
|
|
308
|
+
'config', 'configuration', 'init', 'initial', 'basic', 'core',
|
|
309
|
+
'main', 'primary', 'final', 'complete', 'finish', 'end',
|
|
310
|
+
'start', 'begin', 'first', 'last', 'update', 'updates',
|
|
311
|
+
'fix', 'fixes', 'add', 'adds', 'remove', 'removes',
|
|
312
|
+
'create', 'creates', 'build', 'builds', 'deploy', 'deployment',
|
|
313
|
+
'refactor', 'refactoring', 'cleanup', 'polish', 'review',
|
|
314
|
+
// Process/activity words that describe what you're doing, not what domain
|
|
315
|
+
'hardening', 'validation', 'verification', 'optimization',
|
|
316
|
+
'improvement', 'enhancement', 'infrastructure',
|
|
317
|
+
]);
|
|
318
|
+
// Pattern to match slice/milestone/task IDs (e.g., S01, M001, T03)
|
|
319
|
+
const UNIT_ID_PATTERN = /^[smt]\d+$/i;
|
|
320
|
+
/**
|
|
321
|
+
* Derive a scope keyword from slice title and optional description.
|
|
322
|
+
* Returns the most specific noun (first non-generic keyword) for decision scoping.
|
|
323
|
+
*
|
|
324
|
+
* Examples:
|
|
325
|
+
* - "Auth Middleware & Protected Route" → "auth"
|
|
326
|
+
* - "Database & User Model Setup" → "database"
|
|
327
|
+
* - "Integration Testing" → undefined (too generic)
|
|
328
|
+
* - "API Rate Limiting" → "api"
|
|
329
|
+
*
|
|
330
|
+
* @param sliceTitle - The slice title
|
|
331
|
+
* @param sliceDescription - Optional roadmap description (demo text)
|
|
332
|
+
* @returns A single lowercase keyword or undefined if no meaningful scope
|
|
333
|
+
*/
|
|
334
|
+
export function deriveSliceScope(sliceTitle, sliceDescription) {
|
|
335
|
+
// Combine title and description for keyword extraction
|
|
336
|
+
const combinedText = sliceDescription
|
|
337
|
+
? `${sliceTitle} ${sliceDescription}`
|
|
338
|
+
: sliceTitle;
|
|
339
|
+
// Extract all words, lowercase, remove punctuation
|
|
340
|
+
const words = combinedText
|
|
341
|
+
.split(/[\s&+,;:|/\\()-]+/)
|
|
342
|
+
.map(w => w.toLowerCase().replace(/[^a-z0-9]/g, ''))
|
|
343
|
+
.filter(w => w.length >= 2);
|
|
344
|
+
// Find the first word that is:
|
|
345
|
+
// 1. Not a stopword
|
|
346
|
+
// 2. Not a generic word
|
|
347
|
+
// 3. Not a unit ID (S01, M001, T03)
|
|
348
|
+
// 4. At least 3 characters (meaningful scope)
|
|
349
|
+
for (const word of words) {
|
|
350
|
+
if (STOPWORDS.has(word))
|
|
351
|
+
continue;
|
|
352
|
+
if (GENERIC_WORDS.has(word))
|
|
353
|
+
continue;
|
|
354
|
+
if (UNIT_ID_PATTERN.test(word))
|
|
355
|
+
continue;
|
|
356
|
+
if (word.length < 3)
|
|
357
|
+
continue;
|
|
358
|
+
return word;
|
|
359
|
+
}
|
|
360
|
+
return undefined;
|
|
361
|
+
}
|
|
362
|
+
/**
|
|
363
|
+
* Extract keywords from a slice title for scoped knowledge queries.
|
|
364
|
+
* Splits on whitespace, filters stopwords, lowercases.
|
|
365
|
+
* Example: 'KNOWLEDGE scoping + roadmap excerpt' → ['knowledge', 'scoping', 'roadmap', 'excerpt']
|
|
366
|
+
*/
|
|
367
|
+
function extractKeywords(title) {
|
|
368
|
+
return title
|
|
369
|
+
.split(/\s+/)
|
|
370
|
+
.map(w => w.toLowerCase().replace(/[^a-z0-9]/g, ''))
|
|
371
|
+
.filter(w => w.length > 0 && !STOPWORDS.has(w));
|
|
372
|
+
}
|
|
373
|
+
/**
|
|
374
|
+
* Inline scoped KNOWLEDGE.md content based on keywords from slice title.
|
|
375
|
+
* Reads KNOWLEDGE.md, filters to sections matching keywords, formats with header.
|
|
376
|
+
* Returns null if no KNOWLEDGE.md exists or no sections match.
|
|
377
|
+
*/
|
|
378
|
+
export async function inlineKnowledgeScoped(base, keywords) {
|
|
379
|
+
const knowledgePath = resolveGsdRootFile(base, "KNOWLEDGE");
|
|
380
|
+
if (!existsSync(knowledgePath))
|
|
381
|
+
return null;
|
|
382
|
+
const content = await loadFile(knowledgePath);
|
|
383
|
+
if (!content)
|
|
384
|
+
return null;
|
|
385
|
+
// Import queryKnowledge from context-store
|
|
386
|
+
const { queryKnowledge } = await import("./context-store.js");
|
|
387
|
+
const scoped = await queryKnowledge(content, keywords);
|
|
388
|
+
// Return null if no sections matched (empty string from queryKnowledge)
|
|
389
|
+
if (!scoped)
|
|
390
|
+
return null;
|
|
391
|
+
return `### Project Knowledge (scoped)\nSource: \`${relGsdRootFile("KNOWLEDGE")}\`\n\n${scoped.trim()}`;
|
|
392
|
+
}
|
|
393
|
+
/**
|
|
394
|
+
* Inline a roadmap excerpt for a specific slice.
|
|
395
|
+
* Reads full roadmap, extracts minimal excerpt with header + predecessor + target row.
|
|
396
|
+
* Returns null if roadmap doesn't exist or slice not found.
|
|
397
|
+
*/
|
|
398
|
+
export async function inlineRoadmapExcerpt(base, mid, sid) {
|
|
399
|
+
const roadmapPath = resolveMilestoneFile(base, mid, "ROADMAP");
|
|
400
|
+
if (!roadmapPath || !existsSync(roadmapPath))
|
|
401
|
+
return null;
|
|
402
|
+
const roadmapRel = relMilestoneFile(base, mid, "ROADMAP");
|
|
403
|
+
const content = await loadFile(roadmapPath);
|
|
404
|
+
if (!content)
|
|
405
|
+
return null;
|
|
406
|
+
// Import formatRoadmapExcerpt from context-store
|
|
407
|
+
const { formatRoadmapExcerpt } = await import("./context-store.js");
|
|
408
|
+
const excerpt = formatRoadmapExcerpt(content, sid, roadmapRel);
|
|
409
|
+
// Return null if slice not found in roadmap
|
|
410
|
+
if (!excerpt)
|
|
411
|
+
return null;
|
|
412
|
+
return `### Milestone Roadmap (excerpt)\nSource: \`${roadmapRel}\`\n\n${excerpt}`;
|
|
413
|
+
}
|
|
290
414
|
// ─── Skill Activation & Discovery ─────────────────────────────────────────
|
|
291
415
|
function normalizeSkillReference(ref) {
|
|
292
416
|
const normalized = ref.replace(/\\/g, "/").trim();
|
|
@@ -772,7 +896,7 @@ export async function buildResearchMilestonePrompt(mid, midTitle, base) {
|
|
|
772
896
|
const projectInline = await inlineProjectFromDb(base);
|
|
773
897
|
if (projectInline)
|
|
774
898
|
inlined.push(projectInline);
|
|
775
|
-
const requirementsInline = await inlineRequirementsFromDb(base);
|
|
899
|
+
const requirementsInline = await inlineRequirementsFromDb(base, mid);
|
|
776
900
|
if (requirementsInline)
|
|
777
901
|
inlined.push(requirementsInline);
|
|
778
902
|
const decisionsInline = await inlineDecisionsFromDb(base, mid);
|
|
@@ -823,7 +947,7 @@ export async function buildPlanMilestonePrompt(mid, midTitle, base, level) {
|
|
|
823
947
|
const projectInline = await inlineProjectFromDb(base);
|
|
824
948
|
if (projectInline)
|
|
825
949
|
inlined.push(projectInline);
|
|
826
|
-
const requirementsInline = await inlineRequirementsFromDb(base, undefined, inlineLevel);
|
|
950
|
+
const requirementsInline = await inlineRequirementsFromDb(base, mid, undefined, inlineLevel);
|
|
827
951
|
if (requirementsInline)
|
|
828
952
|
inlined.push(requirementsInline);
|
|
829
953
|
const decisionsInline = await inlineDecisionsFromDb(base, mid, undefined, inlineLevel);
|
|
@@ -884,7 +1008,15 @@ export async function buildResearchSlicePrompt(mid, _midTitle, sid, sTitle, base
|
|
|
884
1008
|
const sliceContextPath = resolveSliceFile(base, mid, sid, "CONTEXT");
|
|
885
1009
|
const sliceContextRel = relSliceFile(base, mid, sid, "CONTEXT");
|
|
886
1010
|
const inlined = [];
|
|
887
|
-
|
|
1011
|
+
// Use roadmap excerpt instead of full roadmap for context reduction
|
|
1012
|
+
const roadmapExcerptRS = await inlineRoadmapExcerpt(base, mid, sid);
|
|
1013
|
+
if (roadmapExcerptRS) {
|
|
1014
|
+
inlined.push(roadmapExcerptRS);
|
|
1015
|
+
}
|
|
1016
|
+
else {
|
|
1017
|
+
// Fall back to full roadmap if excerpt fails
|
|
1018
|
+
inlined.push(await inlineFile(roadmapPath, roadmapRel, "Milestone Roadmap"));
|
|
1019
|
+
}
|
|
888
1020
|
const contextInline = await inlineFileOptional(contextPath, contextRel, "Milestone Context");
|
|
889
1021
|
if (contextInline)
|
|
890
1022
|
inlined.push(contextInline);
|
|
@@ -894,13 +1026,17 @@ export async function buildResearchSlicePrompt(mid, _midTitle, sid, sTitle, base
|
|
|
894
1026
|
const researchInline = await inlineFileOptional(milestoneResearchPath, milestoneResearchRel, "Milestone Research");
|
|
895
1027
|
if (researchInline)
|
|
896
1028
|
inlined.push(researchInline);
|
|
897
|
-
|
|
1029
|
+
// Derive scope from slice title for decision filtering (R005)
|
|
1030
|
+
const derivedScope = deriveSliceScope(sTitle);
|
|
1031
|
+
const decisionsInline = await inlineDecisionsFromDb(base, mid, derivedScope);
|
|
898
1032
|
if (decisionsInline)
|
|
899
1033
|
inlined.push(decisionsInline);
|
|
900
|
-
const requirementsInline = await inlineRequirementsFromDb(base, sid);
|
|
1034
|
+
const requirementsInline = await inlineRequirementsFromDb(base, mid, sid);
|
|
901
1035
|
if (requirementsInline)
|
|
902
1036
|
inlined.push(requirementsInline);
|
|
903
|
-
|
|
1037
|
+
// Use scoped knowledge based on slice title keywords
|
|
1038
|
+
const keywords = extractKeywords(sTitle);
|
|
1039
|
+
const knowledgeInlineRS = await inlineKnowledgeScoped(base, keywords);
|
|
904
1040
|
if (knowledgeInlineRS)
|
|
905
1041
|
inlined.push(knowledgeInlineRS);
|
|
906
1042
|
inlined.push(inlineTemplate("research", "Research"));
|
|
@@ -944,7 +1080,15 @@ export async function buildPlanSlicePrompt(mid, _midTitle, sid, sTitle, base, le
|
|
|
944
1080
|
const researchSliceAnchor = readPhaseAnchor(base, mid, "research-slice");
|
|
945
1081
|
if (researchSliceAnchor)
|
|
946
1082
|
inlined.push(formatAnchorForPrompt(researchSliceAnchor));
|
|
947
|
-
|
|
1083
|
+
// Use roadmap excerpt instead of full roadmap for context reduction
|
|
1084
|
+
const roadmapExcerptPS = await inlineRoadmapExcerpt(base, mid, sid);
|
|
1085
|
+
if (roadmapExcerptPS) {
|
|
1086
|
+
inlined.push(roadmapExcerptPS);
|
|
1087
|
+
}
|
|
1088
|
+
else {
|
|
1089
|
+
// Fall back to full roadmap if excerpt fails
|
|
1090
|
+
inlined.push(await inlineFile(roadmapPath, roadmapRel, "Milestone Roadmap"));
|
|
1091
|
+
}
|
|
948
1092
|
const sliceCtxInline = await inlineFileOptional(sliceContextPath, sliceContextRel, "Slice Context (from discussion)");
|
|
949
1093
|
if (sliceCtxInline)
|
|
950
1094
|
inlined.push(sliceCtxInline);
|
|
@@ -952,14 +1096,18 @@ export async function buildPlanSlicePrompt(mid, _midTitle, sid, sTitle, base, le
|
|
|
952
1096
|
if (researchInline)
|
|
953
1097
|
inlined.push(researchInline);
|
|
954
1098
|
if (inlineLevel !== "minimal") {
|
|
955
|
-
|
|
1099
|
+
// Derive scope from slice title for decision filtering (R005)
|
|
1100
|
+
const derivedScopePS = deriveSliceScope(sTitle);
|
|
1101
|
+
const decisionsInline = await inlineDecisionsFromDb(base, mid, derivedScopePS, inlineLevel);
|
|
956
1102
|
if (decisionsInline)
|
|
957
1103
|
inlined.push(decisionsInline);
|
|
958
|
-
const requirementsInline = await inlineRequirementsFromDb(base, sid, inlineLevel);
|
|
1104
|
+
const requirementsInline = await inlineRequirementsFromDb(base, mid, sid, inlineLevel);
|
|
959
1105
|
if (requirementsInline)
|
|
960
1106
|
inlined.push(requirementsInline);
|
|
961
1107
|
}
|
|
962
|
-
|
|
1108
|
+
// Use scoped knowledge based on slice title keywords
|
|
1109
|
+
const keywordsPS = extractKeywords(sTitle);
|
|
1110
|
+
const knowledgeInlinePS = await inlineKnowledgeScoped(base, keywordsPS);
|
|
963
1111
|
if (knowledgeInlinePS)
|
|
964
1112
|
inlined.push(knowledgeInlinePS);
|
|
965
1113
|
inlined.push(inlineTemplate("plan", "Slice Plan"));
|
|
@@ -1117,7 +1265,7 @@ export async function buildCompleteSlicePrompt(mid, _midTitle, sid, sTitle, base
|
|
|
1117
1265
|
inlined.push(sliceCtxInline);
|
|
1118
1266
|
inlined.push(await inlineFile(slicePlanPath, slicePlanRel, "Slice Plan"));
|
|
1119
1267
|
if (inlineLevel !== "minimal") {
|
|
1120
|
-
const requirementsInline = await inlineRequirementsFromDb(base, sid, inlineLevel);
|
|
1268
|
+
const requirementsInline = await inlineRequirementsFromDb(base, mid, sid, inlineLevel);
|
|
1121
1269
|
if (requirementsInline)
|
|
1122
1270
|
inlined.push(requirementsInline);
|
|
1123
1271
|
}
|
|
@@ -1195,7 +1343,7 @@ export async function buildCompleteMilestonePrompt(mid, midTitle, base, level) {
|
|
|
1195
1343
|
}
|
|
1196
1344
|
// Inline root GSD files (skip for minimal — completion can read these if needed)
|
|
1197
1345
|
if (inlineLevel !== "minimal") {
|
|
1198
|
-
const requirementsInline = await inlineRequirementsFromDb(base, undefined, inlineLevel);
|
|
1346
|
+
const requirementsInline = await inlineRequirementsFromDb(base, mid, undefined, inlineLevel);
|
|
1199
1347
|
if (requirementsInline)
|
|
1200
1348
|
inlined.push(requirementsInline);
|
|
1201
1349
|
const decisionsInline = await inlineDecisionsFromDb(base, mid, undefined, inlineLevel);
|
|
@@ -1262,7 +1410,7 @@ export async function buildValidateMilestonePrompt(mid, midTitle, base, level) {
|
|
|
1262
1410
|
catch (err) {
|
|
1263
1411
|
logWarning("prompt", `buildValidateMilestonePrompt verification classes lookup failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
1264
1412
|
}
|
|
1265
|
-
// Inline all slice summaries and
|
|
1413
|
+
// Inline all slice summaries and assessment results
|
|
1266
1414
|
let valSliceIds = [];
|
|
1267
1415
|
try {
|
|
1268
1416
|
const { isDbAvailable, getMilestoneSlices } = await import("./gsd-db.js");
|
|
@@ -1288,11 +1436,11 @@ export async function buildValidateMilestonePrompt(mid, midTitle, base, level) {
|
|
|
1288
1436
|
const summaryPath = resolveSliceFile(base, mid, sid, "SUMMARY");
|
|
1289
1437
|
const summaryRel = relSliceFile(base, mid, sid, "SUMMARY");
|
|
1290
1438
|
inlined.push(await inlineFile(summaryPath, summaryRel, `${sid} Summary`));
|
|
1291
|
-
const
|
|
1292
|
-
const
|
|
1293
|
-
const
|
|
1294
|
-
if (
|
|
1295
|
-
inlined.push(
|
|
1439
|
+
const assessmentPath = resolveSliceFile(base, mid, sid, "ASSESSMENT");
|
|
1440
|
+
const assessmentRel = relSliceFile(base, mid, sid, "ASSESSMENT");
|
|
1441
|
+
const assessmentInline = await inlineFileOptional(assessmentPath, assessmentRel, `${sid} Assessment`);
|
|
1442
|
+
if (assessmentInline)
|
|
1443
|
+
inlined.push(assessmentInline);
|
|
1296
1444
|
}
|
|
1297
1445
|
// Aggregate unresolved follow-ups and known limitations across slices
|
|
1298
1446
|
const outstandingItems = [];
|
|
@@ -1324,7 +1472,7 @@ export async function buildValidateMilestonePrompt(mid, midTitle, base, level) {
|
|
|
1324
1472
|
}
|
|
1325
1473
|
// Inline root GSD files
|
|
1326
1474
|
if (inlineLevel !== "minimal") {
|
|
1327
|
-
const requirementsInline = await inlineRequirementsFromDb(base, undefined, inlineLevel);
|
|
1475
|
+
const requirementsInline = await inlineRequirementsFromDb(base, mid, undefined, inlineLevel);
|
|
1328
1476
|
if (requirementsInline)
|
|
1329
1477
|
inlined.push(requirementsInline);
|
|
1330
1478
|
const decisionsInline = await inlineDecisionsFromDb(base, mid, undefined, inlineLevel);
|
|
@@ -1487,7 +1635,7 @@ export async function buildReassessRoadmapPrompt(mid, midTitle, completedSliceId
|
|
|
1487
1635
|
const projectInline = await inlineProjectFromDb(base);
|
|
1488
1636
|
if (projectInline)
|
|
1489
1637
|
inlined.push(projectInline);
|
|
1490
|
-
const requirementsInline = await inlineRequirementsFromDb(base, undefined, inlineLevel);
|
|
1638
|
+
const requirementsInline = await inlineRequirementsFromDb(base, mid, undefined, inlineLevel);
|
|
1491
1639
|
if (requirementsInline)
|
|
1492
1640
|
inlined.push(requirementsInline);
|
|
1493
1641
|
const decisionsInline = await inlineDecisionsFromDb(base, mid, undefined, inlineLevel);
|
|
@@ -10,7 +10,7 @@ import { parseUnitId } from "./unit-id.js";
|
|
|
10
10
|
import { appendEvent } from "./workflow-events.js";
|
|
11
11
|
import { clearParseCache } from "./files.js";
|
|
12
12
|
import { parseRoadmap as parseLegacyRoadmap, parsePlan as parseLegacyPlan } from "./parsers-legacy.js";
|
|
13
|
-
import { isDbAvailable, getTask, getSlice, getSliceTasks, updateTaskStatus, updateSliceStatus } from "./gsd-db.js";
|
|
13
|
+
import { isDbAvailable, getTask, getSlice, getSliceTasks, getPendingGates, updateTaskStatus, updateSliceStatus } from "./gsd-db.js";
|
|
14
14
|
import { isValidationTerminal } from "./state.js";
|
|
15
15
|
import { getErrorMessage } from "./error-utils.js";
|
|
16
16
|
import { logWarning, logError } from "./workflow-logger.js";
|
|
@@ -198,8 +198,7 @@ export function verifyExpectedArtifact(unitType, unitId, base) {
|
|
|
198
198
|
if (gateIds.length === 0)
|
|
199
199
|
return true;
|
|
200
200
|
try {
|
|
201
|
-
const
|
|
202
|
-
const pending = getPending(mid, sid, "slice");
|
|
201
|
+
const pending = getPendingGates(mid, sid, "slice");
|
|
203
202
|
const pendingIds = new Set(pending.map((g) => g.gate_id));
|
|
204
203
|
// All dispatched gates must no longer be pending
|
|
205
204
|
for (const gid of gateIds) {
|
|
@@ -454,9 +453,8 @@ function abortAndResetMerge(basePath, hasMergeHead, squashMsgPath) {
|
|
|
454
453
|
/**
|
|
455
454
|
* Detect leftover merge state from a prior session and reconcile it.
|
|
456
455
|
* If MERGE_HEAD or SQUASH_MSG exists, check whether conflicts are resolved.
|
|
457
|
-
* If resolved: finalize the commit. If
|
|
458
|
-
*
|
|
459
|
-
* Returns true if state was dirty and re-derivation is needed.
|
|
456
|
+
* If resolved: finalize the commit. If only .gsd conflicts remain: auto-resolve.
|
|
457
|
+
* If code conflicts remain: fail safe without modifying the worktree.
|
|
460
458
|
*/
|
|
461
459
|
export function reconcileMergeState(basePath, ctx) {
|
|
462
460
|
const mergeHeadPath = join(basePath, ".git", "MERGE_HEAD");
|
|
@@ -464,7 +462,7 @@ export function reconcileMergeState(basePath, ctx) {
|
|
|
464
462
|
const hasMergeHead = existsSync(mergeHeadPath);
|
|
465
463
|
const hasSquashMsg = existsSync(squashMsgPath);
|
|
466
464
|
if (!hasMergeHead && !hasSquashMsg)
|
|
467
|
-
return
|
|
465
|
+
return "clean";
|
|
468
466
|
const conflictedFiles = nativeConflictFiles(basePath);
|
|
469
467
|
if (conflictedFiles.length === 0) {
|
|
470
468
|
// All conflicts resolved — finalize the merge/squash commit
|
|
@@ -481,7 +479,7 @@ export function reconcileMergeState(basePath, ctx) {
|
|
|
481
479
|
catch (err) {
|
|
482
480
|
const errorMessage = getErrorMessage(err);
|
|
483
481
|
ctx.ui.notify(`Failed to finalize leftover merge/squash commit: ${errorMessage}`, "error");
|
|
484
|
-
return
|
|
482
|
+
return "blocked";
|
|
485
483
|
}
|
|
486
484
|
}
|
|
487
485
|
else {
|
|
@@ -515,12 +513,13 @@ export function reconcileMergeState(basePath, ctx) {
|
|
|
515
513
|
}
|
|
516
514
|
}
|
|
517
515
|
else {
|
|
518
|
-
// Code conflicts present —
|
|
519
|
-
|
|
520
|
-
ctx.ui.notify("Detected leftover merge state with unresolved conflicts
|
|
516
|
+
// Code conflicts present — fail safe and preserve any manual resolution
|
|
517
|
+
// work instead of discarding it with merge --abort/reset --hard.
|
|
518
|
+
ctx.ui.notify("Detected leftover merge state with unresolved code conflicts. Auto-mode will pause without modifying the worktree so manual conflict resolution is preserved.", "error");
|
|
519
|
+
return "blocked";
|
|
521
520
|
}
|
|
522
521
|
}
|
|
523
|
-
return
|
|
522
|
+
return "reconciled";
|
|
524
523
|
}
|
|
525
524
|
// ─── Loop Remediation ─────────────────────────────────────────────────────────
|
|
526
525
|
/**
|
|
@@ -906,7 +906,19 @@ export async function startAuto(ctx, pi, base, verboseMode, options) {
|
|
|
906
906
|
s.active = true;
|
|
907
907
|
s.verbose = verboseMode;
|
|
908
908
|
s.stepMode = requestedStepMode;
|
|
909
|
-
|
|
909
|
+
// Preserve the original cmdCtx (ExtensionCommandContext with newSession)
|
|
910
|
+
// when resuming from a provider-error pause. The resume callback receives
|
|
911
|
+
// an ExtensionContext (from the agent_end hook) which lacks newSession —
|
|
912
|
+
// using it would crash runUnit with "newSession is not a function".
|
|
913
|
+
// Only override if the new ctx actually has newSession (user-initiated resume).
|
|
914
|
+
if ("newSession" in ctx && typeof ctx.newSession === "function") {
|
|
915
|
+
s.cmdCtx = ctx;
|
|
916
|
+
}
|
|
917
|
+
else if (!s.cmdCtx) {
|
|
918
|
+
// No saved cmdCtx — this shouldn't happen, but handle gracefully
|
|
919
|
+
s.cmdCtx = ctx;
|
|
920
|
+
}
|
|
921
|
+
// else: keep existing s.cmdCtx which has the real newSession
|
|
910
922
|
s.basePath = base;
|
|
911
923
|
setLogBasePath(base);
|
|
912
924
|
if (!s.autoStartTime || s.autoStartTime <= 0)
|