gsd-pi 2.73.0 → 2.73.1-dev.06e4302
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/cli-web-branch.d.ts +4 -3
- package/dist/cli-web-branch.js +10 -7
- package/dist/cli.js +99 -253
- package/dist/help-text.js +1 -1
- package/dist/logo.d.ts +1 -1
- package/dist/logo.js +1 -1
- package/dist/onboarding.js +59 -53
- package/dist/resource-loader.js +2 -2
- package/dist/resources/extensions/claude-code-cli/stream-adapter.js +68 -4
- package/dist/resources/extensions/gsd/auto/phases.js +15 -9
- package/dist/resources/extensions/gsd/auto-dispatch.js +16 -6
- package/dist/resources/extensions/gsd/auto-model-selection.js +54 -11
- package/dist/resources/extensions/gsd/auto-post-unit.js +41 -1
- package/dist/resources/extensions/gsd/auto-prompts.js +9 -6
- package/dist/resources/extensions/gsd/auto-start.js +23 -6
- package/dist/resources/extensions/gsd/auto-timeout-recovery.js +13 -0
- package/dist/resources/extensions/gsd/auto-verification.js +88 -3
- package/dist/resources/extensions/gsd/auto.js +34 -9
- package/dist/resources/extensions/gsd/bootstrap/crash-log.js +31 -0
- package/dist/resources/extensions/gsd/bootstrap/register-extension.js +18 -7
- package/dist/resources/extensions/gsd/bootstrap/system-context.js +6 -1
- package/dist/resources/extensions/gsd/commands-handlers.js +8 -2
- package/dist/resources/extensions/gsd/crash-recovery.js +51 -0
- package/dist/resources/extensions/gsd/docs/preferences-reference.md +1 -1
- package/dist/resources/extensions/gsd/gsd-db.js +36 -2
- package/dist/resources/extensions/gsd/milestone-actions.js +19 -1
- package/dist/resources/extensions/gsd/notification-widget.js +2 -2
- package/dist/resources/extensions/gsd/preferences-models.js +43 -0
- package/dist/resources/extensions/gsd/preferences-types.js +1 -0
- package/dist/resources/extensions/gsd/preferences-validation.js +22 -0
- package/dist/resources/extensions/gsd/state.js +61 -14
- package/dist/startup-model-validation.js +8 -5
- package/dist/update-check.d.ts +1 -0
- package/dist/update-check.js +13 -5
- package/dist/update-cmd.js +4 -3
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +12 -12
- package/dist/web/standalone/.next/build-manifest.json +3 -3
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- package/dist/web/standalone/.next/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 +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found/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 +12 -12
- package/dist/web/standalone/.next/server/chunks/63.js +3 -3
- package/dist/web/standalone/.next/server/chunks/6897.js +1 -1
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/middleware-manifest.json +5 -5
- 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 +1 -1
- package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
- 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-f1e30ab6bb269149.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/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 -2
- package/packages/pi-ai/dist/index.d.ts +1 -0
- package/packages/pi-ai/dist/index.d.ts.map +1 -1
- package/packages/pi-ai/dist/index.js +1 -0
- package/packages/pi-ai/dist/index.js.map +1 -1
- package/packages/pi-ai/dist/utils/overflow.d.ts.map +1 -1
- package/packages/pi-ai/dist/utils/overflow.js +12 -0
- package/packages/pi-ai/dist/utils/overflow.js.map +1 -1
- package/packages/pi-ai/dist/utils/tests/overflow.test.d.ts +2 -0
- package/packages/pi-ai/dist/utils/tests/overflow.test.d.ts.map +1 -0
- package/packages/pi-ai/dist/utils/tests/overflow.test.js +50 -0
- package/packages/pi-ai/dist/utils/tests/overflow.test.js.map +1 -0
- package/packages/pi-ai/src/index.ts +4 -0
- package/packages/pi-ai/src/utils/overflow.ts +14 -1
- package/packages/pi-ai/src/utils/tests/overflow.test.ts +58 -0
- package/packages/pi-coding-agent/dist/core/auth-storage.js +1 -1
- package/packages/pi-coding-agent/dist/core/auth-storage.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/auth-storage.test.js +27 -0
- package/packages/pi-coding-agent/dist/core/auth-storage.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js +313 -8
- package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/compaction/utils.js +5 -5
- package/packages/pi-coding-agent/dist/core/compaction/utils.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/compaction-utils.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/compaction-utils.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/compaction-utils.test.js +45 -0
- package/packages/pi-coding-agent/dist/core/compaction-utils.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/model-resolver.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-resolver.js +25 -68
- package/packages/pi-coding-agent/dist/core/model-resolver.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts +12 -2
- package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js +61 -28
- package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.d.ts +2 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.js +9 -3
- package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.test.js +52 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +116 -25
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.test.js +63 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +11 -3
- 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/auth-storage.test.ts +38 -0
- package/packages/pi-coding-agent/src/core/auth-storage.ts +1 -1
- package/packages/pi-coding-agent/src/core/chat-controller-ordering.test.ts +355 -8
- package/packages/pi-coding-agent/src/core/compaction/utils.ts +5 -5
- package/packages/pi-coding-agent/src/core/compaction-utils.test.ts +50 -0
- package/packages/pi-coding-agent/src/core/model-resolver.ts +26 -70
- package/packages/pi-coding-agent/src/modes/interactive/components/assistant-message.ts +74 -32
- package/packages/pi-coding-agent/src/modes/interactive/components/dynamic-border.test.ts +73 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/dynamic-border.ts +9 -3
- package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.test.ts +71 -0
- package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +136 -30
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +11 -3
- package/packages/pi-tui/dist/__tests__/tui.test.js +60 -1
- package/packages/pi-tui/dist/__tests__/tui.test.js.map +1 -1
- package/packages/pi-tui/dist/tui.d.ts +8 -0
- package/packages/pi-tui/dist/tui.d.ts.map +1 -1
- package/packages/pi-tui/dist/tui.js +32 -3
- package/packages/pi-tui/dist/tui.js.map +1 -1
- package/packages/pi-tui/src/__tests__/tui.test.ts +76 -1
- package/packages/pi-tui/src/tui.ts +31 -3
- package/pkg/package.json +1 -1
- package/src/resources/extensions/claude-code-cli/stream-adapter.ts +107 -5
- package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +111 -2
- package/src/resources/extensions/gsd/auto/phases.ts +22 -9
- package/src/resources/extensions/gsd/auto-dispatch.ts +15 -4
- package/src/resources/extensions/gsd/auto-model-selection.ts +85 -11
- package/src/resources/extensions/gsd/auto-post-unit.ts +47 -1
- package/src/resources/extensions/gsd/auto-prompts.ts +9 -3
- package/src/resources/extensions/gsd/auto-start.ts +30 -6
- package/src/resources/extensions/gsd/auto-timeout-recovery.ts +17 -0
- package/src/resources/extensions/gsd/auto-verification.ts +98 -3
- package/src/resources/extensions/gsd/auto.ts +36 -14
- package/src/resources/extensions/gsd/bootstrap/crash-log.ts +32 -0
- package/src/resources/extensions/gsd/bootstrap/register-extension.ts +19 -7
- package/src/resources/extensions/gsd/bootstrap/system-context.ts +8 -1
- package/src/resources/extensions/gsd/commands-handlers.ts +8 -2
- package/src/resources/extensions/gsd/crash-recovery.ts +59 -0
- package/src/resources/extensions/gsd/docs/preferences-reference.md +1 -1
- package/src/resources/extensions/gsd/gsd-db.ts +52 -2
- package/src/resources/extensions/gsd/milestone-actions.ts +19 -1
- package/src/resources/extensions/gsd/notification-widget.ts +2 -2
- package/src/resources/extensions/gsd/preferences-models.ts +41 -0
- package/src/resources/extensions/gsd/preferences-types.ts +12 -0
- package/src/resources/extensions/gsd/preferences-validation.ts +23 -0
- package/src/resources/extensions/gsd/state.ts +71 -15
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/auto-post-unit-step-message.test.ts +53 -0
- package/src/resources/extensions/gsd/tests/auto-start-model-capture.test.ts +51 -2
- package/src/resources/extensions/gsd/tests/complete-milestone-false-merge.test.ts +142 -0
- package/src/resources/extensions/gsd/tests/completed-at-reconcile.test.ts +42 -0
- package/src/resources/extensions/gsd/tests/crash-handler-secondary.test.ts +235 -0
- package/src/resources/extensions/gsd/tests/derive-state-crossval.test.ts +3 -2
- package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +3 -2
- package/src/resources/extensions/gsd/tests/derive-state-helpers.test.ts +68 -8
- package/src/resources/extensions/gsd/tests/derive-state.test.ts +3 -3
- package/src/resources/extensions/gsd/tests/flat-rate-routing-guard.test.ts +137 -1
- package/src/resources/extensions/gsd/tests/gsd-db.test.ts +59 -1
- package/src/resources/extensions/gsd/tests/integration/state-machine-edge-cases.test.ts +4 -2
- package/src/resources/extensions/gsd/tests/model-isolation.test.ts +91 -2
- package/src/resources/extensions/gsd/tests/park-milestone.test.ts +64 -0
- package/src/resources/extensions/gsd/tests/preferences.test.ts +47 -0
- package/src/resources/extensions/gsd/tests/state-machine-full-walkthrough.test.ts +5 -7
- package/src/resources/extensions/gsd/tests/subagent-model-dispatch.test.ts +267 -0
- package/src/resources/extensions/gsd/tests/token-profile.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/validate-milestone-stuck-guard.test.ts +179 -0
- package/dist/web/standalone/.next/static/chunks/app/page-7115e62689b5fd84.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/{KSZ2dcC3p4z6lOmUpPpzr → RXD20AQgB9BHSQJ07MDdd}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{KSZ2dcC3p4z6lOmUpPpzr → RXD20AQgB9BHSQJ07MDdd}/_ssgManifest.js +0 -0
package/dist/onboarding.js
CHANGED
|
@@ -71,8 +71,8 @@ const OTHER_PROVIDERS = [
|
|
|
71
71
|
];
|
|
72
72
|
// ─── Dynamic imports ──────────────────────────────────────────────────────────
|
|
73
73
|
/**
|
|
74
|
-
* Dynamically import @clack/prompts
|
|
75
|
-
* Dynamic import with fallback so the module doesn't crash if
|
|
74
|
+
* Dynamically import @clack/prompts.
|
|
75
|
+
* Dynamic import with fallback so the module doesn't crash if it's missing.
|
|
76
76
|
*/
|
|
77
77
|
async function loadClack() {
|
|
78
78
|
try {
|
|
@@ -82,10 +82,23 @@ async function loadClack() {
|
|
|
82
82
|
throw new Error('[gsd] @clack/prompts not found — onboarding wizard requires this dependency');
|
|
83
83
|
}
|
|
84
84
|
}
|
|
85
|
+
/**
|
|
86
|
+
* Build the PicoModule color surface from chalk. Chalk is already a
|
|
87
|
+
* dependency of the CLI; this adapter keeps the onboarding call sites stable
|
|
88
|
+
* while removing the redundant picocolors dep.
|
|
89
|
+
*/
|
|
85
90
|
async function loadPico() {
|
|
86
91
|
try {
|
|
87
|
-
const
|
|
88
|
-
return
|
|
92
|
+
const { default: chalk } = await import('chalk');
|
|
93
|
+
return {
|
|
94
|
+
cyan: (s) => chalk.cyan(s),
|
|
95
|
+
green: (s) => chalk.green(s),
|
|
96
|
+
yellow: (s) => chalk.yellow(s),
|
|
97
|
+
dim: (s) => chalk.dim(s),
|
|
98
|
+
bold: (s) => chalk.bold(s),
|
|
99
|
+
red: (s) => chalk.red(s),
|
|
100
|
+
reset: (s) => chalk.reset(s),
|
|
101
|
+
};
|
|
89
102
|
}
|
|
90
103
|
catch {
|
|
91
104
|
// Fallback: return identity functions
|
|
@@ -105,9 +118,29 @@ function openBrowser(url) {
|
|
|
105
118
|
execFile(cmd, [url], () => { });
|
|
106
119
|
}
|
|
107
120
|
}
|
|
108
|
-
/**
|
|
109
|
-
|
|
110
|
-
|
|
121
|
+
/** Sentinel returned by runStep when the user cancels — tells the caller
|
|
122
|
+
* to abort the entire wizard. */
|
|
123
|
+
const STEP_CANCELLED = Symbol('step-cancelled');
|
|
124
|
+
/**
|
|
125
|
+
* Run a single onboarding step with shared error handling:
|
|
126
|
+
* - user cancel (Ctrl+C) → p.cancel(cancelMessage), returns STEP_CANCELLED
|
|
127
|
+
* - other error → p.log.warn + optional info follow-up, returns null
|
|
128
|
+
* - success → the step's return value
|
|
129
|
+
*/
|
|
130
|
+
async function runStep(p, warnLabel, fn, opts = {}) {
|
|
131
|
+
try {
|
|
132
|
+
return await fn();
|
|
133
|
+
}
|
|
134
|
+
catch (err) {
|
|
135
|
+
if (p.isCancel(err)) {
|
|
136
|
+
p.cancel(opts.cancelMessage ?? 'Setup cancelled.');
|
|
137
|
+
return STEP_CANCELLED;
|
|
138
|
+
}
|
|
139
|
+
p.log.warn(`${warnLabel}: ${err instanceof Error ? err.message : String(err)}`);
|
|
140
|
+
if (opts.errorInfo)
|
|
141
|
+
p.log.info(opts.errorInfo);
|
|
142
|
+
return null;
|
|
143
|
+
}
|
|
111
144
|
}
|
|
112
145
|
// ─── Public API ───────────────────────────────────────────────────────────────
|
|
113
146
|
/**
|
|
@@ -160,55 +193,28 @@ export async function runOnboarding(authStorage) {
|
|
|
160
193
|
process.stderr.write(renderLogo(pc.cyan));
|
|
161
194
|
p.intro(pc.bold('Welcome to GSD — let\'s get you set up'));
|
|
162
195
|
// ── LLM Provider Selection ────────────────────────────────────────────────
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
p.cancel('Setup cancelled — you can run /login inside GSD later.');
|
|
171
|
-
return;
|
|
172
|
-
}
|
|
173
|
-
p.log.warn(`LLM setup failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
174
|
-
p.log.info('You can configure your LLM provider later with /login inside GSD.');
|
|
175
|
-
}
|
|
196
|
+
const llmResult = await runStep(p, 'LLM setup failed', () => runLlmStep(p, pc, authStorage), {
|
|
197
|
+
cancelMessage: 'Setup cancelled — you can run /login inside GSD later.',
|
|
198
|
+
errorInfo: 'You can configure your LLM provider later with /login inside GSD.',
|
|
199
|
+
});
|
|
200
|
+
if (llmResult === STEP_CANCELLED)
|
|
201
|
+
return;
|
|
202
|
+
const llmConfigured = llmResult ?? false;
|
|
176
203
|
// ── Web Search Provider ──────────────────────────────────────────────────
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
catch (err) {
|
|
182
|
-
if (isCancelError(p, err)) {
|
|
183
|
-
p.cancel('Setup cancelled.');
|
|
184
|
-
return;
|
|
185
|
-
}
|
|
186
|
-
p.log.warn(`Web search setup failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
187
|
-
}
|
|
204
|
+
const searchResult = await runStep(p, 'Web search setup failed', () => runWebSearchStep(p, pc, authStorage, llmConfigured));
|
|
205
|
+
if (searchResult === STEP_CANCELLED)
|
|
206
|
+
return;
|
|
207
|
+
const searchConfigured = searchResult;
|
|
188
208
|
// ── Remote Questions ─────────────────────────────────────────────────────
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
catch (err) {
|
|
194
|
-
if (isCancelError(p, err)) {
|
|
195
|
-
p.cancel('Setup cancelled.');
|
|
196
|
-
return;
|
|
197
|
-
}
|
|
198
|
-
p.log.warn(`Remote questions setup failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
199
|
-
}
|
|
209
|
+
const remoteResult = await runStep(p, 'Remote questions setup failed', () => runRemoteQuestionsStep(p, pc, authStorage));
|
|
210
|
+
if (remoteResult === STEP_CANCELLED)
|
|
211
|
+
return;
|
|
212
|
+
const remoteConfigured = remoteResult;
|
|
200
213
|
// ── Tool API Keys ─────────────────────────────────────────────────────────
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
catch (err) {
|
|
206
|
-
if (isCancelError(p, err)) {
|
|
207
|
-
p.cancel('Setup cancelled.');
|
|
208
|
-
return;
|
|
209
|
-
}
|
|
210
|
-
p.log.warn(`Tool key setup failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
211
|
-
}
|
|
214
|
+
const toolResult = await runStep(p, 'Tool key setup failed', () => runToolKeysStep(p, pc, authStorage));
|
|
215
|
+
if (toolResult === STEP_CANCELLED)
|
|
216
|
+
return;
|
|
217
|
+
const toolKeyCount = toolResult ?? 0;
|
|
212
218
|
// ── Summary ───────────────────────────────────────────────────────────────
|
|
213
219
|
const summaryLines = [];
|
|
214
220
|
if (llmConfigured) {
|
package/dist/resource-loader.js
CHANGED
|
@@ -358,7 +358,7 @@ function reconcileMergedNodeModules(agentNodeModules, hoisted, internal) {
|
|
|
358
358
|
if (entry.name.startsWith('.'))
|
|
359
359
|
continue;
|
|
360
360
|
try {
|
|
361
|
-
symlinkSync(join(hoisted, entry.name), join(agentNodeModules, entry.name));
|
|
361
|
+
symlinkSync(join(hoisted, entry.name), join(agentNodeModules, entry.name), 'junction');
|
|
362
362
|
linkedCount++;
|
|
363
363
|
}
|
|
364
364
|
catch { /* skip individual */ }
|
|
@@ -382,7 +382,7 @@ function reconcileMergedNodeModules(agentNodeModules, hoisted, internal) {
|
|
|
382
382
|
}
|
|
383
383
|
catch { /* didn't exist — will create below */ }
|
|
384
384
|
try {
|
|
385
|
-
symlinkSync(join(internal, entry.name), link);
|
|
385
|
+
symlinkSync(join(internal, entry.name), link, 'junction');
|
|
386
386
|
linkedCount++;
|
|
387
387
|
}
|
|
388
388
|
catch { /* skip individual */ }
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* AssistantMessageEvents for TUI rendering, then strips tool-call blocks from
|
|
7
7
|
* the final AssistantMessage so GSD's agent loop doesn't try to dispatch them.
|
|
8
8
|
*/
|
|
9
|
-
import { EventStream } from "@gsd/pi-ai";
|
|
9
|
+
import { EventStream, mapThinkingLevelToEffort, supportsAdaptiveThinking } from "@gsd/pi-ai";
|
|
10
10
|
import { execSync } from "node:child_process";
|
|
11
11
|
import { PartialMessageBuilder, ZERO_USAGE, mapUsage } from "./partial-builder.js";
|
|
12
12
|
import { buildWorkflowMcpServers } from "../gsd/workflow-mcp.js";
|
|
@@ -123,6 +123,63 @@ export function buildPromptFromContext(context) {
|
|
|
123
123
|
}
|
|
124
124
|
return parts.join("\n\n");
|
|
125
125
|
}
|
|
126
|
+
function stripDataUriPrefix(value) {
|
|
127
|
+
const commaIndex = value.indexOf(",");
|
|
128
|
+
if (value.startsWith("data:") && commaIndex !== -1) {
|
|
129
|
+
return value.slice(commaIndex + 1);
|
|
130
|
+
}
|
|
131
|
+
return value;
|
|
132
|
+
}
|
|
133
|
+
function inferMimeTypeFromDataUri(value) {
|
|
134
|
+
const match = /^data:([^;,]+);base64,/.exec(value);
|
|
135
|
+
return match?.[1] ?? null;
|
|
136
|
+
}
|
|
137
|
+
export function extractImageBlocksFromContext(context) {
|
|
138
|
+
const imageBlocks = [];
|
|
139
|
+
for (const msg of context.messages) {
|
|
140
|
+
if (msg.role !== "user" || !Array.isArray(msg.content))
|
|
141
|
+
continue;
|
|
142
|
+
for (const part of msg.content) {
|
|
143
|
+
if (!part || typeof part !== "object")
|
|
144
|
+
continue;
|
|
145
|
+
const block = part;
|
|
146
|
+
if (block.type !== "image" || typeof block.data !== "string")
|
|
147
|
+
continue;
|
|
148
|
+
const mimeType = typeof block.mimeType === "string" && block.mimeType.length > 0
|
|
149
|
+
? block.mimeType
|
|
150
|
+
: inferMimeTypeFromDataUri(block.data);
|
|
151
|
+
if (!mimeType)
|
|
152
|
+
continue;
|
|
153
|
+
imageBlocks.push({
|
|
154
|
+
type: "image",
|
|
155
|
+
source: {
|
|
156
|
+
type: "base64",
|
|
157
|
+
media_type: mimeType,
|
|
158
|
+
data: stripDataUriPrefix(block.data),
|
|
159
|
+
},
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
return imageBlocks;
|
|
164
|
+
}
|
|
165
|
+
export function buildSdkQueryPrompt(context, textPrompt = buildPromptFromContext(context)) {
|
|
166
|
+
const imageBlocks = extractImageBlocksFromContext(context);
|
|
167
|
+
if (imageBlocks.length === 0) {
|
|
168
|
+
return textPrompt;
|
|
169
|
+
}
|
|
170
|
+
const content = [...imageBlocks];
|
|
171
|
+
if (textPrompt) {
|
|
172
|
+
content.push({ type: "text", text: textPrompt });
|
|
173
|
+
}
|
|
174
|
+
const sdkMessage = {
|
|
175
|
+
type: "user",
|
|
176
|
+
message: { role: "user", content },
|
|
177
|
+
parent_tool_use_id: null,
|
|
178
|
+
};
|
|
179
|
+
return (async function* () {
|
|
180
|
+
yield sdkMessage;
|
|
181
|
+
})();
|
|
182
|
+
}
|
|
126
183
|
// ---------------------------------------------------------------------------
|
|
127
184
|
// Error helper
|
|
128
185
|
// ---------------------------------------------------------------------------
|
|
@@ -437,6 +494,7 @@ export async function resolveClaudePermissionMode(env = process.env) {
|
|
|
437
494
|
* behaviour pass `permissionMode: "bypassPermissions"` explicitly.
|
|
438
495
|
*/
|
|
439
496
|
export function buildSdkOptions(modelId, prompt, overrides, extraOptions = {}) {
|
|
497
|
+
const { reasoning, ...sdkExtraOptions } = extraOptions;
|
|
440
498
|
const mcpServers = buildWorkflowMcpServers();
|
|
441
499
|
const permissionMode = overrides?.permissionMode ?? "bypassPermissions";
|
|
442
500
|
const disallowedTools = ["AskUserQuestion"];
|
|
@@ -455,6 +513,9 @@ export function buildSdkOptions(modelId, prompt, overrides, extraOptions = {}) {
|
|
|
455
513
|
"Bash(pwd)",
|
|
456
514
|
...(mcpServers ? Object.keys(mcpServers).map((serverName) => `mcp__${serverName}__*`) : []),
|
|
457
515
|
];
|
|
516
|
+
const effort = reasoning && supportsAdaptiveThinking(modelId)
|
|
517
|
+
? mapThinkingLevelToEffort(reasoning, modelId)
|
|
518
|
+
: undefined;
|
|
458
519
|
return {
|
|
459
520
|
pathToClaudeCodeExecutable: getClaudePath(),
|
|
460
521
|
model: modelId,
|
|
@@ -469,7 +530,8 @@ export function buildSdkOptions(modelId, prompt, overrides, extraOptions = {}) {
|
|
|
469
530
|
...(allowedTools.length > 0 ? { allowedTools } : {}),
|
|
470
531
|
...(mcpServers ? { mcpServers } : {}),
|
|
471
532
|
betas: modelId.includes("sonnet") ? ["context-1m-2025-08-07"] : [],
|
|
472
|
-
...
|
|
533
|
+
...(effort ? { effort } : {}),
|
|
534
|
+
...sdkExtraOptions,
|
|
473
535
|
};
|
|
474
536
|
}
|
|
475
537
|
function normalizeToolResultContent(content) {
|
|
@@ -617,14 +679,16 @@ async function pumpSdkMessages(model, context, options, stream) {
|
|
|
617
679
|
options.signal.addEventListener("abort", () => controller.abort(), { once: true });
|
|
618
680
|
}
|
|
619
681
|
const prompt = buildPromptFromContext(context);
|
|
682
|
+
const queryPrompt = buildSdkQueryPrompt(context, prompt);
|
|
620
683
|
const permissionMode = await resolveClaudePermissionMode();
|
|
621
684
|
const sdkOpts = buildSdkOptions(modelId, prompt, { permissionMode }, typeof options?.extensionUIContext === "object"
|
|
622
685
|
? {
|
|
686
|
+
reasoning: options?.reasoning,
|
|
623
687
|
onElicitation: createClaudeCodeElicitationHandler(options?.extensionUIContext),
|
|
624
688
|
}
|
|
625
|
-
: {});
|
|
689
|
+
: { reasoning: options?.reasoning });
|
|
626
690
|
const queryResult = sdk.query({
|
|
627
|
-
prompt,
|
|
691
|
+
prompt: queryPrompt,
|
|
628
692
|
options: {
|
|
629
693
|
...sdkOpts,
|
|
630
694
|
abortController: controller,
|
|
@@ -320,10 +320,13 @@ export async function runPreDispatch(ic, loopState) {
|
|
|
320
320
|
}
|
|
321
321
|
else if (state.phase === "blocked") {
|
|
322
322
|
const blockerMsg = `Blocked: ${state.blockers.join(", ")}`;
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
deps.
|
|
323
|
+
// Pause instead of hard-stop so the session is resumable with `/gsd auto`.
|
|
324
|
+
// Hard-stop here was causing premature termination when slice dependencies
|
|
325
|
+
// were temporarily unresolvable (e.g. after reassessment added new slices).
|
|
326
|
+
await deps.pauseAuto(ctx, pi);
|
|
327
|
+
ctx.ui.notify(`${blockerMsg}. Fix and run /gsd auto to resume.`, "warning");
|
|
328
|
+
deps.sendDesktopNotification("GSD", blockerMsg, "warning", "attention", basename(s.originalBasePath || s.basePath));
|
|
329
|
+
deps.logCmuxEvent(prefs, blockerMsg, "warning");
|
|
327
330
|
}
|
|
328
331
|
else {
|
|
329
332
|
const ids = incomplete.map((m) => m.id).join(", ");
|
|
@@ -392,13 +395,16 @@ export async function runPreDispatch(ic, loopState) {
|
|
|
392
395
|
deps.emitJournalEvent({ ts: new Date().toISOString(), flowId: ic.flowId, seq: ic.nextSeq(), eventType: "terminal", data: { reason: "milestone-complete", milestoneId: mid } });
|
|
393
396
|
return { action: "break", reason: "milestone-complete" };
|
|
394
397
|
}
|
|
395
|
-
// Terminal: blocked
|
|
398
|
+
// Terminal: blocked — pause instead of hard-stop so the session is resumable.
|
|
396
399
|
if (state.phase === "blocked") {
|
|
397
400
|
const blockerMsg = `Blocked: ${state.blockers.join(", ")}`;
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
deps.
|
|
401
|
+
if (s.currentUnit) {
|
|
402
|
+
await deps.closeoutUnit(ctx, s.basePath, s.currentUnit.type, s.currentUnit.id, s.currentUnit.startedAt, deps.buildSnapshotOpts(s.currentUnit.type, s.currentUnit.id));
|
|
403
|
+
}
|
|
404
|
+
await deps.pauseAuto(ctx, pi);
|
|
405
|
+
ctx.ui.notify(`${blockerMsg}. Fix and run /gsd auto to resume.`, "warning");
|
|
406
|
+
deps.sendDesktopNotification("GSD", blockerMsg, "warning", "attention", basename(s.originalBasePath || s.basePath));
|
|
407
|
+
deps.logCmuxEvent(prefs, blockerMsg, "warning");
|
|
402
408
|
debugLog("autoLoop", { phase: "exit", reason: "blocked" });
|
|
403
409
|
deps.emitJournalEvent({ ts: new Date().toISOString(), flowId: ic.flowId, seq: ic.nextSeq(), eventType: "terminal", data: { reason: "blocked", blockers: state.blockers } });
|
|
404
410
|
return { action: "break", reason: "blocked" };
|
|
@@ -18,6 +18,7 @@ import { logWarning, logError } from "./workflow-logger.js";
|
|
|
18
18
|
import { join } from "node:path";
|
|
19
19
|
import { hasImplementationArtifacts } from "./auto-recovery.js";
|
|
20
20
|
import { buildDiscussMilestonePrompt, buildResearchMilestonePrompt, buildPlanMilestonePrompt, buildResearchSlicePrompt, buildPlanSlicePrompt, buildExecuteTaskPrompt, buildCompleteSlicePrompt, buildCompleteMilestonePrompt, buildValidateMilestonePrompt, buildReplanSlicePrompt, buildRunUatPrompt, buildReassessRoadmapPrompt, buildRewriteDocsPrompt, buildReactiveExecutePrompt, buildGateEvaluatePrompt, buildParallelResearchSlicesPrompt, checkNeedsReassessment, checkNeedsRunUat, } from "./auto-prompts.js";
|
|
21
|
+
import { resolveModelWithFallbacksForUnit } from "./preferences-models.js";
|
|
21
22
|
function missingSliceStop(mid, phase) {
|
|
22
23
|
return {
|
|
23
24
|
action: "stop",
|
|
@@ -215,7 +216,12 @@ export const DISPATCH_RULES = [
|
|
|
215
216
|
{
|
|
216
217
|
name: "reassess-roadmap (post-completion)",
|
|
217
218
|
match: async ({ state, mid, midTitle, basePath, prefs }) => {
|
|
218
|
-
if (prefs?.phases?.skip_reassess
|
|
219
|
+
if (prefs?.phases?.skip_reassess)
|
|
220
|
+
return null;
|
|
221
|
+
// Default reassess_after_slice to true — reassessment after slice completion
|
|
222
|
+
// is essential for roadmap integrity. Opt-out via explicit `false`.
|
|
223
|
+
const reassessEnabled = prefs?.phases?.reassess_after_slice ?? true;
|
|
224
|
+
if (!reassessEnabled)
|
|
219
225
|
return null;
|
|
220
226
|
const needsReassess = await checkNeedsReassessment(basePath, mid, state);
|
|
221
227
|
if (!needsReassess)
|
|
@@ -330,7 +336,7 @@ export const DISPATCH_RULES = [
|
|
|
330
336
|
action: "dispatch",
|
|
331
337
|
unitType: "research-slice",
|
|
332
338
|
unitId: `${mid}/parallel-research`,
|
|
333
|
-
prompt: await buildParallelResearchSlicesPrompt(mid, midTitle, researchReadySlices, basePath),
|
|
339
|
+
prompt: await buildParallelResearchSlicesPrompt(mid, midTitle, researchReadySlices, basePath, resolveModelWithFallbacksForUnit("subagent")?.primary),
|
|
334
340
|
};
|
|
335
341
|
},
|
|
336
342
|
},
|
|
@@ -401,7 +407,7 @@ export const DISPATCH_RULES = [
|
|
|
401
407
|
action: "dispatch",
|
|
402
408
|
unitType: "gate-evaluate",
|
|
403
409
|
unitId: `${mid}/${sid}/gates+${pending.map(g => g.gate_id).join(",")}`,
|
|
404
|
-
prompt: await buildGateEvaluatePrompt(mid, midTitle, sid, sTitle, basePath),
|
|
410
|
+
prompt: await buildGateEvaluatePrompt(mid, midTitle, sid, sTitle, basePath, resolveModelWithFallbacksForUnit("subagent")?.primary),
|
|
405
411
|
};
|
|
406
412
|
},
|
|
407
413
|
},
|
|
@@ -436,6 +442,7 @@ export const DISPATCH_RULES = [
|
|
|
436
442
|
const sid = state.activeSlice.id;
|
|
437
443
|
const sTitle = state.activeSlice.title;
|
|
438
444
|
const maxParallel = reactiveConfig.max_parallel ?? 2;
|
|
445
|
+
const subagentModel = reactiveConfig.subagent_model ?? resolveModelWithFallbacksForUnit("subagent")?.primary;
|
|
439
446
|
// Dry-run mode: max_parallel=1 means graph is derived and logged but
|
|
440
447
|
// execution remains sequential
|
|
441
448
|
if (maxParallel <= 1)
|
|
@@ -478,7 +485,7 @@ export const DISPATCH_RULES = [
|
|
|
478
485
|
action: "dispatch",
|
|
479
486
|
unitType: "reactive-execute",
|
|
480
487
|
unitId: `${mid}/${sid}/reactive+${batchSuffix}`,
|
|
481
|
-
prompt: await buildReactiveExecutePrompt(mid, midTitle, sid, sTitle, selected, basePath),
|
|
488
|
+
prompt: await buildReactiveExecutePrompt(mid, midTitle, sid, sTitle, selected, basePath, subagentModel),
|
|
482
489
|
};
|
|
483
490
|
}
|
|
484
491
|
catch (err) {
|
|
@@ -708,11 +715,14 @@ export async function resolveDispatch(ctx) {
|
|
|
708
715
|
return result;
|
|
709
716
|
}
|
|
710
717
|
}
|
|
711
|
-
// No rule matched — unhandled phase
|
|
718
|
+
// No rule matched — unhandled phase.
|
|
719
|
+
// Use level "warning" so the loop pauses (resumable) instead of hard-stopping.
|
|
720
|
+
// Hard-stop here was causing premature termination for transient phase gaps
|
|
721
|
+
// (e.g. after reassessment modifies the roadmap and state needs re-derivation).
|
|
712
722
|
return {
|
|
713
723
|
action: "stop",
|
|
714
724
|
reason: `Unhandled phase "${ctx.state.phase}" — run /gsd doctor to diagnose.`,
|
|
715
|
-
level: "
|
|
725
|
+
level: "warning",
|
|
716
726
|
matchedRule: "<no-match>",
|
|
717
727
|
};
|
|
718
728
|
}
|
|
@@ -9,10 +9,8 @@ import { resolveModelForComplexity, escalateTier, getEligibleModels, loadCapabil
|
|
|
9
9
|
import { getLedger, getProjectTotals } from "./metrics.js";
|
|
10
10
|
import { unitPhaseLabel } from "./auto-dashboard.js";
|
|
11
11
|
import { getSessionModelOverride } from "./session-model-override.js";
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
* synthesize a routing ceiling from dynamic_routing.tier_models (#3962). */
|
|
15
|
-
isAutoMode = true) {
|
|
12
|
+
import { logWarning } from "./workflow-logger.js";
|
|
13
|
+
export function resolvePreferredModelConfig(unitType, autoModeStartModel, isAutoMode = true) {
|
|
16
14
|
const explicitConfig = resolveModelWithFallbacksForUnit(unitType);
|
|
17
15
|
if (explicitConfig)
|
|
18
16
|
return explicitConfig;
|
|
@@ -24,7 +22,7 @@ isAutoMode = true) {
|
|
|
24
22
|
if (!routingConfig.enabled || !routingConfig.tier_models)
|
|
25
23
|
return undefined;
|
|
26
24
|
// Don't synthesize a routing config for flat-rate providers (#3453).
|
|
27
|
-
if (autoModeStartModel && isFlatRateProvider(autoModeStartModel.provider))
|
|
25
|
+
if (autoModeStartModel && isFlatRateProvider(autoModeStartModel.provider, autoModeStartModel.flatRateCtx))
|
|
28
26
|
return undefined;
|
|
29
27
|
const ceilingModel = routingConfig.tier_models.heavy
|
|
30
28
|
?? (autoModeStartModel ? `${autoModeStartModel.provider}/${autoModeStartModel.id}` : undefined);
|
|
@@ -51,6 +49,17 @@ sessionModelOverride) {
|
|
|
51
49
|
const effectiveSessionModelOverride = sessionModelOverride === undefined
|
|
52
50
|
? getSessionModelOverride(ctx.sessionManager.getSessionId())
|
|
53
51
|
: (sessionModelOverride ?? undefined);
|
|
52
|
+
// Enrich the start model with a flat-rate context up front so routing
|
|
53
|
+
// synthesis and the dispatch-time guard see the same signals (built-in
|
|
54
|
+
// list + user `flat_rate_providers` preference + externalCli auto-
|
|
55
|
+
// detection). The dispatch-time primary-model check below builds its
|
|
56
|
+
// own per-provider context when it has a resolved primary model.
|
|
57
|
+
if (autoModeStartModel) {
|
|
58
|
+
autoModeStartModel = {
|
|
59
|
+
...autoModeStartModel,
|
|
60
|
+
flatRateCtx: buildFlatRateContext(autoModeStartModel.provider, ctx, prefs),
|
|
61
|
+
};
|
|
62
|
+
}
|
|
54
63
|
const modelConfig = effectiveSessionModelOverride
|
|
55
64
|
? undefined
|
|
56
65
|
: resolvePreferredModelConfig(unitType, autoModeStartModel, isAutoMode);
|
|
@@ -76,12 +85,13 @@ sessionModelOverride) {
|
|
|
76
85
|
if (routingConfig.enabled) {
|
|
77
86
|
const primaryModel = resolveModelId(modelConfig.primary, availableModels, ctx.model?.provider);
|
|
78
87
|
if (primaryModel) {
|
|
79
|
-
|
|
88
|
+
const primaryFlatRateCtx = buildFlatRateContext(primaryModel.provider, ctx, prefs);
|
|
89
|
+
if (isFlatRateProvider(primaryModel.provider, primaryFlatRateCtx)) {
|
|
80
90
|
routingConfig.enabled = false;
|
|
81
91
|
}
|
|
82
92
|
}
|
|
83
|
-
else if ((autoModeStartModel && isFlatRateProvider(autoModeStartModel.provider))
|
|
84
|
-
|| (ctx.model?.provider && isFlatRateProvider(ctx.model.provider))) {
|
|
93
|
+
else if ((autoModeStartModel && isFlatRateProvider(autoModeStartModel.provider, autoModeStartModel.flatRateCtx))
|
|
94
|
+
|| (ctx.model?.provider && isFlatRateProvider(ctx.model.provider, buildFlatRateContext(ctx.model.provider, ctx, prefs)))) {
|
|
85
95
|
// Primary model unresolvable but provider signals indicate flat-rate —
|
|
86
96
|
// disable routing to prevent quality degradation.
|
|
87
97
|
routingConfig.enabled = false;
|
|
@@ -331,7 +341,40 @@ export function resolveModelId(modelId, availableModels, currentProvider) {
|
|
|
331
341
|
* Uses case-insensitive matching with alias support to prevent fail-open on
|
|
332
342
|
* provider naming variations (e.g. "copilot" vs "github-copilot").
|
|
333
343
|
*/
|
|
334
|
-
const
|
|
335
|
-
export function isFlatRateProvider(provider) {
|
|
336
|
-
|
|
344
|
+
const BUILTIN_FLAT_RATE = new Set(["github-copilot", "copilot", "claude-code"]);
|
|
345
|
+
export function isFlatRateProvider(provider, opts) {
|
|
346
|
+
const p = provider.toLowerCase();
|
|
347
|
+
if (BUILTIN_FLAT_RATE.has(p))
|
|
348
|
+
return true;
|
|
349
|
+
if (opts?.userFlatRate?.some(id => id.toLowerCase() === p))
|
|
350
|
+
return true;
|
|
351
|
+
if (opts?.authMode === "externalCli")
|
|
352
|
+
return true;
|
|
353
|
+
return false;
|
|
354
|
+
}
|
|
355
|
+
/**
|
|
356
|
+
* Build a FlatRateContext for a given provider from live runtime state.
|
|
357
|
+
* Safe to call when ctx or prefs are undefined — missing pieces are
|
|
358
|
+
* treated as "no signal".
|
|
359
|
+
*/
|
|
360
|
+
export function buildFlatRateContext(provider, ctx, prefs) {
|
|
361
|
+
let authMode;
|
|
362
|
+
const getAuthMode = ctx?.modelRegistry?.getProviderAuthMode;
|
|
363
|
+
if (typeof getAuthMode === "function") {
|
|
364
|
+
try {
|
|
365
|
+
const mode = getAuthMode(provider);
|
|
366
|
+
if (mode === "apiKey" || mode === "oauth" || mode === "externalCli" || mode === "none") {
|
|
367
|
+
authMode = mode;
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
catch (err) {
|
|
371
|
+
// Registry lookup failure must never break flat-rate detection —
|
|
372
|
+
// fall through with authMode undefined and surface the cause.
|
|
373
|
+
logWarning("dispatch", `flat-rate auth-mode lookup failed for ${provider}: ${err instanceof Error ? err.message : String(err)}`);
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
return {
|
|
377
|
+
authMode,
|
|
378
|
+
userFlatRate: prefs?.flat_rate_providers,
|
|
379
|
+
};
|
|
337
380
|
}
|
|
@@ -67,6 +67,7 @@ const LIFECYCLE_ONLY_UNITS = new Set([
|
|
|
67
67
|
"replan-slice", "complete-slice", "run-uat",
|
|
68
68
|
"reassess-roadmap", "rewrite-docs",
|
|
69
69
|
]);
|
|
70
|
+
import { describeNextUnit, } from "./auto-dashboard.js";
|
|
70
71
|
import { existsSync, unlinkSync } from "node:fs";
|
|
71
72
|
import { join } from "node:path";
|
|
72
73
|
import { _resetHasChangesCache } from "./native-git-bridge.js";
|
|
@@ -179,6 +180,15 @@ export function detectRogueFileWrites(unitType, unitId, basePath) {
|
|
|
179
180
|
}
|
|
180
181
|
return rogues;
|
|
181
182
|
}
|
|
183
|
+
export const STEP_COMPLETE_FALLBACK_MESSAGE = "Step complete. Run /clear, then /gsd to continue (or /gsd auto to run continuously).";
|
|
184
|
+
export function buildStepCompleteMessage(nextState) {
|
|
185
|
+
if (nextState.phase === "complete") {
|
|
186
|
+
return "Step complete — milestone finished. Run /gsd status to review, or start the next milestone.";
|
|
187
|
+
}
|
|
188
|
+
const next = describeNextUnit(nextState);
|
|
189
|
+
return `Step complete. Next: ${next.label}\n`
|
|
190
|
+
+ `Run /clear, then /gsd to continue (or /gsd auto to run continuously).`;
|
|
191
|
+
}
|
|
182
192
|
/**
|
|
183
193
|
* Pre-verification processing: parallel worker signal check, cache invalidation,
|
|
184
194
|
* auto-commit, doctor run, state rebuild, worktree sync, artifact verification.
|
|
@@ -509,6 +519,26 @@ export async function postUnitPreVerification(pctx, opts) {
|
|
|
509
519
|
const attempt = (s.verificationRetryCount.get(retryKey) ?? 0) + 1;
|
|
510
520
|
s.verificationRetryCount.set(retryKey, attempt);
|
|
511
521
|
if (attempt > MAX_VERIFICATION_RETRIES) {
|
|
522
|
+
// #4175: For complete-milestone, a blocker placeholder is harmful —
|
|
523
|
+
// the stub SUMMARY has no recovery value (milestone is terminal),
|
|
524
|
+
// it does not update DB status (so deriveState never advances),
|
|
525
|
+
// and it fools stopAuto's presence check into merging a milestone
|
|
526
|
+
// that was never legitimately completed. Pause auto-mode with a
|
|
527
|
+
// clear single failure signal and preserve the worktree branch.
|
|
528
|
+
if (s.currentUnit.type === "complete-milestone") {
|
|
529
|
+
debugLog("postUnit", {
|
|
530
|
+
phase: "artifact-verify-pause-complete-milestone",
|
|
531
|
+
unitType: s.currentUnit.type,
|
|
532
|
+
unitId: s.currentUnit.id,
|
|
533
|
+
attempt,
|
|
534
|
+
maxRetries: MAX_VERIFICATION_RETRIES,
|
|
535
|
+
});
|
|
536
|
+
s.verificationRetryCount.delete(retryKey);
|
|
537
|
+
s.pendingVerificationRetry = null;
|
|
538
|
+
ctx.ui.notify(`Milestone ${s.currentUnit.id} verification failed after ${MAX_VERIFICATION_RETRIES} retries — worktree branch preserved. Re-run /gsd auto once blockers are resolved.`, "error");
|
|
539
|
+
await pauseAuto(ctx, pi);
|
|
540
|
+
return "dispatched";
|
|
541
|
+
}
|
|
512
542
|
// Retries exhausted — write a blocker placeholder so the pipeline
|
|
513
543
|
// can advance past this stuck unit (#2653).
|
|
514
544
|
debugLog("postUnit", {
|
|
@@ -836,8 +866,18 @@ export async function postUnitPostVerification(pctx) {
|
|
|
836
866
|
debugLog("postUnit", { phase: "quick-task-dispatch", error: String(e) });
|
|
837
867
|
}
|
|
838
868
|
}
|
|
839
|
-
// Step mode → show wizard instead of dispatch
|
|
869
|
+
// Step mode → show wizard instead of dispatch.
|
|
870
|
+
// Without this notify(), /gsd in step mode finishes a unit and silently
|
|
871
|
+
// exits the loop, leaving the user with no hint to /clear and /gsd again.
|
|
840
872
|
if (s.stepMode) {
|
|
873
|
+
try {
|
|
874
|
+
const nextState = await deriveState(s.basePath);
|
|
875
|
+
ctx.ui.notify(buildStepCompleteMessage(nextState), "info");
|
|
876
|
+
}
|
|
877
|
+
catch (e) {
|
|
878
|
+
debugLog("postUnit", { phase: "step-wizard-notify", error: String(e) });
|
|
879
|
+
ctx.ui.notify(STEP_COMPLETE_FALLBACK_MESSAGE, "info");
|
|
880
|
+
}
|
|
841
881
|
return "step-wizard";
|
|
842
882
|
}
|
|
843
883
|
return "continue";
|
|
@@ -1712,7 +1712,7 @@ export async function buildReassessRoadmapPrompt(mid, midTitle, completedSliceId
|
|
|
1712
1712
|
});
|
|
1713
1713
|
}
|
|
1714
1714
|
// ─── Reactive Execute Prompt ──────────────────────────────────────────────
|
|
1715
|
-
export async function buildReactiveExecutePrompt(mid, midTitle, sid, sTitle, readyTaskIds, base) {
|
|
1715
|
+
export async function buildReactiveExecutePrompt(mid, midTitle, sid, sTitle, readyTaskIds, base, subagentModel) {
|
|
1716
1716
|
const { loadSliceTaskIO, deriveTaskGraph, graphMetrics } = await import("./reactive-graph.js");
|
|
1717
1717
|
// Build graph for context
|
|
1718
1718
|
const taskIO = await loadSliceTaskIO(base, mid, sid);
|
|
@@ -1744,10 +1744,11 @@ export async function buildReactiveExecutePrompt(mid, midTitle, sid, sTitle, rea
|
|
|
1744
1744
|
const depPaths = await getDependencyTaskSummaryPaths(mid, sid, tid, node?.dependsOn ?? [], base);
|
|
1745
1745
|
// Build a full execute-task prompt with dependency-based carry-forward
|
|
1746
1746
|
const taskPrompt = await buildExecuteTaskPrompt(mid, sid, sTitle, tid, tTitle, base, { carryForwardPaths: depPaths });
|
|
1747
|
+
const modelSuffix = subagentModel ? ` with model: "${subagentModel}"` : "";
|
|
1747
1748
|
subagentSections.push([
|
|
1748
1749
|
`### ${tid}: ${tTitle}`,
|
|
1749
1750
|
"",
|
|
1750
|
-
|
|
1751
|
+
`Use this as the prompt for a \`subagent\` call${modelSuffix}:`,
|
|
1751
1752
|
"",
|
|
1752
1753
|
"```",
|
|
1753
1754
|
taskPrompt,
|
|
@@ -1806,15 +1807,16 @@ function renderGatesToCloseBlock(gates, opts) {
|
|
|
1806
1807
|
}
|
|
1807
1808
|
return lines.join("\n").trimEnd();
|
|
1808
1809
|
}
|
|
1809
|
-
export async function buildParallelResearchSlicesPrompt(mid, midTitle, slices, basePath) {
|
|
1810
|
+
export async function buildParallelResearchSlicesPrompt(mid, midTitle, slices, basePath, subagentModel) {
|
|
1810
1811
|
// Build individual research-slice prompts for each slice
|
|
1811
1812
|
const subagentSections = [];
|
|
1813
|
+
const modelSuffix = subagentModel ? ` with model: "${subagentModel}"` : "";
|
|
1812
1814
|
for (const slice of slices) {
|
|
1813
1815
|
const slicePrompt = await buildResearchSlicePrompt(mid, midTitle, slice.id, slice.title, basePath);
|
|
1814
1816
|
subagentSections.push([
|
|
1815
1817
|
`### ${slice.id}: ${slice.title}`,
|
|
1816
1818
|
"",
|
|
1817
|
-
|
|
1819
|
+
`Use this as the prompt for a \`subagent\` call${modelSuffix} (agent: \`gsd-executor\` or the default agent):`,
|
|
1818
1820
|
"",
|
|
1819
1821
|
"```",
|
|
1820
1822
|
slicePrompt,
|
|
@@ -1829,7 +1831,7 @@ export async function buildParallelResearchSlicesPrompt(mid, midTitle, slices, b
|
|
|
1829
1831
|
subagentPrompts: subagentSections.join("\n\n---\n\n"),
|
|
1830
1832
|
});
|
|
1831
1833
|
}
|
|
1832
|
-
export async function buildGateEvaluatePrompt(mid, midTitle, sid, sTitle, base) {
|
|
1834
|
+
export async function buildGateEvaluatePrompt(mid, midTitle, sid, sTitle, base, subagentModel) {
|
|
1833
1835
|
// Pull only the gates this turn actually owns (Q3/Q4). Filter via the
|
|
1834
1836
|
// registry so that scope:"slice" gates owned by other turns (Q8) can't
|
|
1835
1837
|
// leak into this prompt and can't block dispatch via silent skip.
|
|
@@ -1873,10 +1875,11 @@ export async function buildGateEvaluatePrompt(mid, midTitle, sid, sTitle, base)
|
|
|
1873
1875
|
"- `rationale`: one-sentence justification",
|
|
1874
1876
|
"- `findings`: detailed markdown findings (or empty if omitted)",
|
|
1875
1877
|
].join("\n");
|
|
1878
|
+
const modelSuffix = subagentModel ? ` with model: "${subagentModel}"` : "";
|
|
1876
1879
|
subagentSections.push([
|
|
1877
1880
|
`### ${def.id}: ${def.question}`,
|
|
1878
1881
|
"",
|
|
1879
|
-
|
|
1882
|
+
`Use this as the prompt for a \`subagent\` call${modelSuffix}:`,
|
|
1880
1883
|
"",
|
|
1881
1884
|
"```",
|
|
1882
1885
|
subPrompt,
|