gsd-pi 2.73.1 → 2.74.0-dev.b741afb
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 +184 -206
- package/dist/headless-query.js +4 -1
- package/dist/help-text.js +23 -0
- 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/detect-stuck.js +11 -4
- package/dist/resources/extensions/gsd/auto/phases.js +60 -10
- package/dist/resources/extensions/gsd/auto-dispatch.js +11 -3
- package/dist/resources/extensions/gsd/auto-model-selection.js +54 -11
- package/dist/resources/extensions/gsd/auto-post-unit.js +93 -57
- package/dist/resources/extensions/gsd/auto-prompts.js +12 -0
- 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 +37 -10
- package/dist/resources/extensions/gsd/bootstrap/register-extension.js +21 -8
- package/dist/resources/extensions/gsd/commands/catalog.js +26 -1
- package/dist/resources/extensions/gsd/commands/handlers/ops.js +20 -0
- package/dist/resources/extensions/gsd/commands/handlers/workflow.js +68 -9
- package/dist/resources/extensions/gsd/commands-add-tests.js +111 -0
- package/dist/resources/extensions/gsd/commands-backlog.js +140 -0
- package/dist/resources/extensions/gsd/commands-do.js +79 -0
- package/dist/resources/extensions/gsd/commands-handlers.js +8 -2
- package/dist/resources/extensions/gsd/commands-maintenance.js +6 -6
- package/dist/resources/extensions/gsd/commands-pr-branch.js +180 -0
- package/dist/resources/extensions/gsd/commands-session-report.js +82 -0
- package/dist/resources/extensions/gsd/commands-ship.js +187 -0
- package/dist/resources/extensions/gsd/db-writer.js +3 -5
- package/dist/resources/extensions/gsd/docs/preferences-reference.md +1 -1
- package/dist/resources/extensions/gsd/graph-context.js +66 -0
- package/dist/resources/extensions/gsd/gsd-db.js +321 -0
- package/dist/resources/extensions/gsd/index.js +15 -2
- package/dist/resources/extensions/gsd/md-importer.js +3 -4
- package/dist/resources/extensions/gsd/memory-store.js +19 -51
- package/dist/resources/extensions/gsd/milestone-validation-gates.js +13 -12
- package/dist/resources/extensions/gsd/native-git-bridge.js +7 -4
- 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/prompts/add-tests.md +35 -0
- package/dist/resources/extensions/gsd/state.js +66 -15
- package/dist/resources/extensions/gsd/tools/complete-slice.js +15 -0
- package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +3 -14
- package/dist/resources/extensions/gsd/triage-resolution.js +2 -5
- package/dist/resources/extensions/gsd/workflow-manifest.js +8 -69
- package/dist/resources/extensions/gsd/workflow-migration.js +21 -22
- package/dist/resources/extensions/gsd/workflow-projections.js +4 -1
- package/dist/resources/extensions/gsd/workflow-reconcile.js +14 -11
- package/dist/tsconfig.extensions.tsbuildinfo +1 -0
- 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 +9 -9
- 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 +9 -9
- 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 +3 -3
- package/packages/daemon/package.json +2 -2
- package/packages/mcp-server/dist/index.d.ts +3 -0
- package/packages/mcp-server/dist/index.d.ts.map +1 -1
- package/packages/mcp-server/dist/index.js +3 -0
- package/packages/mcp-server/dist/index.js.map +1 -1
- package/packages/mcp-server/dist/readers/graph.d.ts +87 -0
- package/packages/mcp-server/dist/readers/graph.d.ts.map +1 -0
- package/packages/mcp-server/dist/readers/graph.js +548 -0
- package/packages/mcp-server/dist/readers/graph.js.map +1 -0
- package/packages/mcp-server/dist/readers/index.d.ts +2 -0
- package/packages/mcp-server/dist/readers/index.d.ts.map +1 -1
- package/packages/mcp-server/dist/readers/index.js +1 -0
- package/packages/mcp-server/dist/readers/index.js.map +1 -1
- package/packages/mcp-server/dist/server.d.ts.map +1 -1
- package/packages/mcp-server/dist/server.js +65 -0
- package/packages/mcp-server/dist/server.js.map +1 -1
- package/packages/mcp-server/package.json +2 -2
- package/packages/mcp-server/src/index.ts +15 -0
- package/packages/mcp-server/src/readers/graph.test.ts +426 -0
- package/packages/mcp-server/src/readers/graph.ts +708 -0
- package/packages/mcp-server/src/readers/index.ts +12 -0
- package/packages/mcp-server/src/server.ts +83 -0
- package/packages/mcp-server/tsconfig.json +1 -0
- package/packages/mcp-server/tsconfig.tsbuildinfo +1 -0
- package/packages/native/package.json +2 -2
- package/packages/native/tsconfig.tsbuildinfo +1 -0
- package/packages/pi-agent-core/package.json +1 -1
- package/packages/pi-agent-core/tsconfig.json +1 -0
- package/packages/pi-agent-core/tsconfig.tsbuildinfo +1 -0
- 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/package.json +1 -1
- 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-ai/tsconfig.json +1 -0
- package/packages/pi-ai/tsconfig.tsbuildinfo +1 -0
- 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/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.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +94 -16
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +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/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/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.ts +113 -21
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +11 -3
- package/packages/pi-coding-agent/tsconfig.json +1 -0
- package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -0
- 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/package.json +1 -1
- package/packages/pi-tui/src/__tests__/tui.test.ts +76 -1
- package/packages/pi-tui/src/tui.ts +31 -3
- package/packages/pi-tui/tsconfig.json +1 -0
- package/packages/pi-tui/tsconfig.tsbuildinfo +1 -0
- package/packages/rpc-client/package.json +1 -1
- package/packages/rpc-client/tsconfig.json +1 -0
- package/packages/rpc-client/tsconfig.tsbuildinfo +1 -0
- 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/detect-stuck.ts +12 -4
- package/src/resources/extensions/gsd/auto/loop-deps.ts +6 -0
- package/src/resources/extensions/gsd/auto/phases.ts +90 -10
- package/src/resources/extensions/gsd/auto-dispatch.ts +10 -4
- package/src/resources/extensions/gsd/auto-model-selection.ts +85 -11
- package/src/resources/extensions/gsd/auto-post-unit.ts +107 -58
- package/src/resources/extensions/gsd/auto-prompts.ts +13 -0
- 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 +38 -14
- package/src/resources/extensions/gsd/bootstrap/register-extension.ts +24 -8
- package/src/resources/extensions/gsd/commands/catalog.ts +26 -1
- package/src/resources/extensions/gsd/commands/handlers/ops.ts +20 -0
- package/src/resources/extensions/gsd/commands/handlers/workflow.ts +74 -9
- package/src/resources/extensions/gsd/commands-add-tests.ts +137 -0
- package/src/resources/extensions/gsd/commands-backlog.ts +182 -0
- package/src/resources/extensions/gsd/commands-do.ts +109 -0
- package/src/resources/extensions/gsd/commands-handlers.ts +8 -2
- package/src/resources/extensions/gsd/commands-maintenance.ts +6 -6
- package/src/resources/extensions/gsd/commands-pr-branch.ts +234 -0
- package/src/resources/extensions/gsd/commands-session-report.ts +101 -0
- package/src/resources/extensions/gsd/commands-ship.ts +219 -0
- package/src/resources/extensions/gsd/db-writer.ts +3 -5
- package/src/resources/extensions/gsd/docs/preferences-reference.md +1 -1
- package/src/resources/extensions/gsd/graph-context.ts +85 -0
- package/src/resources/extensions/gsd/gsd-db.ts +467 -0
- package/src/resources/extensions/gsd/index.ts +18 -2
- package/src/resources/extensions/gsd/md-importer.ts +3 -5
- package/src/resources/extensions/gsd/memory-store.ts +31 -62
- package/src/resources/extensions/gsd/milestone-validation-gates.ts +13 -14
- package/src/resources/extensions/gsd/native-git-bridge.ts +11 -12
- 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/prompts/add-tests.md +35 -0
- package/src/resources/extensions/gsd/state.ts +80 -17
- 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/commands-backlog.test.ts +158 -0
- package/src/resources/extensions/gsd/tests/commands-do.test.ts +127 -0
- package/src/resources/extensions/gsd/tests/commands-pr-branch.test.ts +68 -0
- package/src/resources/extensions/gsd/tests/commands-session-report.test.ts +82 -0
- package/src/resources/extensions/gsd/tests/commands-ship.test.ts +71 -0
- package/src/resources/extensions/gsd/tests/commands-workflow-custom.test.ts +14 -0
- 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/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/extension-bootstrap-isolation.test.ts +154 -0
- package/src/resources/extensions/gsd/tests/flat-rate-routing-guard.test.ts +137 -1
- package/src/resources/extensions/gsd/tests/graph-context.test.ts +337 -0
- package/src/resources/extensions/gsd/tests/integration/state-machine-edge-cases.test.ts +4 -2
- package/src/resources/extensions/gsd/tests/journal-integration.test.ts +68 -1
- package/src/resources/extensions/gsd/tests/model-isolation.test.ts +91 -2
- package/src/resources/extensions/gsd/tests/native-git-bridge-exec-fallback.test.ts +140 -0
- package/src/resources/extensions/gsd/tests/preferences.test.ts +47 -0
- package/src/resources/extensions/gsd/tests/single-writer-invariant.test.ts +180 -0
- package/src/resources/extensions/gsd/tests/state-machine-full-walkthrough.test.ts +5 -7
- 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/src/resources/extensions/gsd/tests/workflow-logger-wiring.test.ts +223 -0
- package/src/resources/extensions/gsd/tools/complete-slice.ts +19 -0
- package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +3 -11
- package/src/resources/extensions/gsd/triage-resolution.ts +2 -7
- package/src/resources/extensions/gsd/workflow-manifest.ts +9 -104
- package/src/resources/extensions/gsd/workflow-migration.ts +21 -29
- package/src/resources/extensions/gsd/workflow-projections.ts +8 -1
- package/src/resources/extensions/gsd/workflow-reconcile.ts +15 -15
- 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/{Qr27MOHx0lxRGnJvlhxxu → XnHY5eXUsTCFmNodWHetD}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{Qr27MOHx0lxRGnJvlhxxu → XnHY5eXUsTCFmNodWHetD}/_ssgManifest.js +0 -0
|
@@ -10,8 +10,10 @@ import {
|
|
|
10
10
|
mergePendingToolCalls,
|
|
11
11
|
resolveClaudePermissionMode,
|
|
12
12
|
buildPromptFromContext,
|
|
13
|
+
buildSdkQueryPrompt,
|
|
13
14
|
buildSdkOptions,
|
|
14
15
|
createClaudeCodeElicitationHandler,
|
|
16
|
+
extractImageBlocksFromContext,
|
|
15
17
|
extractToolResultsFromSdkUserMessage,
|
|
16
18
|
getClaudeLookupCommand,
|
|
17
19
|
parseAskUserQuestionsElicitation,
|
|
@@ -167,6 +169,92 @@ describe("stream-adapter — full context prompt (#2859)", () => {
|
|
|
167
169
|
});
|
|
168
170
|
});
|
|
169
171
|
|
|
172
|
+
describe("stream-adapter — image prompt forwarding (#4183)", () => {
|
|
173
|
+
test("extractImageBlocksFromContext maps user image parts to Anthropic base64 image blocks", () => {
|
|
174
|
+
const context: Context = {
|
|
175
|
+
messages: [
|
|
176
|
+
{
|
|
177
|
+
role: "user",
|
|
178
|
+
content: [
|
|
179
|
+
{ type: "text", text: "look" },
|
|
180
|
+
{
|
|
181
|
+
type: "image",
|
|
182
|
+
data: "data:image/png;base64,abc123",
|
|
183
|
+
mimeType: "image/png",
|
|
184
|
+
},
|
|
185
|
+
],
|
|
186
|
+
} as Message,
|
|
187
|
+
],
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
const imageBlocks = extractImageBlocksFromContext(context);
|
|
191
|
+
assert.deepEqual(imageBlocks, [
|
|
192
|
+
{
|
|
193
|
+
type: "image",
|
|
194
|
+
source: {
|
|
195
|
+
type: "base64",
|
|
196
|
+
media_type: "image/png",
|
|
197
|
+
data: "abc123",
|
|
198
|
+
},
|
|
199
|
+
},
|
|
200
|
+
]);
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
test("buildSdkQueryPrompt returns plain string when no images exist in context", () => {
|
|
204
|
+
const context: Context = {
|
|
205
|
+
messages: [{ role: "user", content: "hello" } as Message],
|
|
206
|
+
};
|
|
207
|
+
const textPrompt = buildPromptFromContext(context);
|
|
208
|
+
|
|
209
|
+
const prompt = buildSdkQueryPrompt(context, textPrompt);
|
|
210
|
+
assert.equal(typeof prompt, "string");
|
|
211
|
+
assert.equal(prompt, textPrompt);
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
test("buildSdkQueryPrompt wraps images and prompt text in an SDK user message iterable", async () => {
|
|
215
|
+
const context: Context = {
|
|
216
|
+
messages: [
|
|
217
|
+
{
|
|
218
|
+
role: "user",
|
|
219
|
+
content: [
|
|
220
|
+
{ type: "image", data: "ZmFrZQ==", mimeType: "image/jpeg" },
|
|
221
|
+
{ type: "text", text: "What is in this image?" },
|
|
222
|
+
],
|
|
223
|
+
} as Message,
|
|
224
|
+
],
|
|
225
|
+
};
|
|
226
|
+
const textPrompt = buildPromptFromContext(context);
|
|
227
|
+
|
|
228
|
+
const prompt = buildSdkQueryPrompt(context, textPrompt);
|
|
229
|
+
assert.notEqual(typeof prompt, "string");
|
|
230
|
+
assert.ok(prompt && typeof (prompt as any)[Symbol.asyncIterator] === "function");
|
|
231
|
+
|
|
232
|
+
const messages: any[] = [];
|
|
233
|
+
for await (const item of prompt as AsyncIterable<any>) {
|
|
234
|
+
messages.push(item);
|
|
235
|
+
}
|
|
236
|
+
assert.equal(messages.length, 1);
|
|
237
|
+
assert.deepEqual(messages[0], {
|
|
238
|
+
type: "user",
|
|
239
|
+
message: {
|
|
240
|
+
role: "user",
|
|
241
|
+
content: [
|
|
242
|
+
{
|
|
243
|
+
type: "image",
|
|
244
|
+
source: {
|
|
245
|
+
type: "base64",
|
|
246
|
+
media_type: "image/jpeg",
|
|
247
|
+
data: "ZmFrZQ==",
|
|
248
|
+
},
|
|
249
|
+
},
|
|
250
|
+
{ type: "text", text: textPrompt },
|
|
251
|
+
],
|
|
252
|
+
},
|
|
253
|
+
parent_tool_use_id: null,
|
|
254
|
+
});
|
|
255
|
+
});
|
|
256
|
+
});
|
|
257
|
+
|
|
170
258
|
// ---------------------------------------------------------------------------
|
|
171
259
|
// Bug #4102 — transcript fabrication regression tests
|
|
172
260
|
// ---------------------------------------------------------------------------
|
|
@@ -343,6 +431,26 @@ describe("stream-adapter — session persistence (#2859)", () => {
|
|
|
343
431
|
);
|
|
344
432
|
});
|
|
345
433
|
|
|
434
|
+
test("buildSdkOptions maps reasoning to effort for adaptive Claude Code models (#3917)", () => {
|
|
435
|
+
const options = buildSdkOptions("claude-sonnet-4-6", "test", undefined, { reasoning: "high" });
|
|
436
|
+
assert.equal(options.effort, "high");
|
|
437
|
+
});
|
|
438
|
+
|
|
439
|
+
test("buildSdkOptions upgrades xhigh reasoning to max for opus 4.6 (#3917)", () => {
|
|
440
|
+
const options = buildSdkOptions("claude-opus-4-6", "test", undefined, { reasoning: "xhigh" });
|
|
441
|
+
assert.equal(options.effort, "max");
|
|
442
|
+
});
|
|
443
|
+
|
|
444
|
+
test("buildSdkOptions omits effort when reasoning is undefined (#3917)", () => {
|
|
445
|
+
const options = buildSdkOptions("claude-sonnet-4-6", "test");
|
|
446
|
+
assert.equal("effort" in options, false);
|
|
447
|
+
});
|
|
448
|
+
|
|
449
|
+
test("buildSdkOptions omits effort for non-adaptive Claude models (#3917)", () => {
|
|
450
|
+
const options = buildSdkOptions("claude-sonnet-4-20250514", "test", undefined, { reasoning: "high" });
|
|
451
|
+
assert.equal("effort" in options, false);
|
|
452
|
+
});
|
|
453
|
+
|
|
346
454
|
test("buildSdkOptions includes workflow MCP server config when env is set", () => {
|
|
347
455
|
const prev = {
|
|
348
456
|
GSD_WORKFLOW_MCP_COMMAND: process.env.GSD_WORKFLOW_MCP_COMMAND,
|
|
@@ -774,11 +882,12 @@ describe("stream-adapter — MCP elicitation bridge", () => {
|
|
|
774
882
|
},
|
|
775
883
|
};
|
|
776
884
|
|
|
885
|
+
const secureValue = "ui-collected-value";
|
|
777
886
|
const inputCalls: Array<{ opts?: { secure?: boolean } }> = [];
|
|
778
887
|
const handler = createClaudeCodeElicitationHandler({
|
|
779
888
|
input: async (_title: string, _placeholder?: string, opts?: { secure?: boolean }) => {
|
|
780
889
|
inputCalls.push({ opts });
|
|
781
|
-
return
|
|
890
|
+
return secureValue;
|
|
782
891
|
},
|
|
783
892
|
} as any);
|
|
784
893
|
assert.ok(handler);
|
|
@@ -787,7 +896,7 @@ describe("stream-adapter — MCP elicitation bridge", () => {
|
|
|
787
896
|
assert.deepEqual(result, {
|
|
788
897
|
action: "accept",
|
|
789
898
|
content: {
|
|
790
|
-
TEST_SECURE_FIELD:
|
|
899
|
+
TEST_SECURE_FIELD: secureValue,
|
|
791
900
|
},
|
|
792
901
|
});
|
|
793
902
|
assert.equal(inputCalls.length, 1);
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import type { WindowEntry } from "./types.js";
|
|
8
|
+
import { summarizeLogs } from "../workflow-logger.js";
|
|
8
9
|
|
|
9
10
|
/**
|
|
10
11
|
* Pattern matching ENOENT errors with a file path.
|
|
@@ -28,6 +29,13 @@ export function detectStuck(
|
|
|
28
29
|
): { stuck: true; reason: string } | null {
|
|
29
30
|
if (window.length < 2) return null;
|
|
30
31
|
|
|
32
|
+
// Peek (not drain) the workflow-logger buffer so stuck reasons can surface
|
|
33
|
+
// the underlying diagnostic context (projection failures, DB degradations,
|
|
34
|
+
// reconcile warnings) that usually explains *why* the loop is stuck. The
|
|
35
|
+
// auto-loop's finalize step owns the buffer lifecycle — this is read-only.
|
|
36
|
+
const loggerSummary = summarizeLogs();
|
|
37
|
+
const suffix = loggerSummary ? ` — ${loggerSummary}` : "";
|
|
38
|
+
|
|
31
39
|
const last = window[window.length - 1];
|
|
32
40
|
const prev = window[window.length - 2];
|
|
33
41
|
|
|
@@ -35,7 +43,7 @@ export function detectStuck(
|
|
|
35
43
|
if (last.error && prev.error && last.error === prev.error) {
|
|
36
44
|
return {
|
|
37
45
|
stuck: true,
|
|
38
|
-
reason: `Same error repeated: ${last.error.slice(0, 200)}`,
|
|
46
|
+
reason: `Same error repeated: ${last.error.slice(0, 200)}${suffix}`,
|
|
39
47
|
};
|
|
40
48
|
}
|
|
41
49
|
|
|
@@ -45,7 +53,7 @@ export function detectStuck(
|
|
|
45
53
|
if (lastThree.every((u) => u.key === last.key)) {
|
|
46
54
|
return {
|
|
47
55
|
stuck: true,
|
|
48
|
-
reason: `${last.key} derived 3 consecutive times without progress`,
|
|
56
|
+
reason: `${last.key} derived 3 consecutive times without progress${suffix}`,
|
|
49
57
|
};
|
|
50
58
|
}
|
|
51
59
|
}
|
|
@@ -60,7 +68,7 @@ export function detectStuck(
|
|
|
60
68
|
) {
|
|
61
69
|
return {
|
|
62
70
|
stuck: true,
|
|
63
|
-
reason: `Oscillation detected: ${w[0].key} ↔ ${w[1].key}`,
|
|
71
|
+
reason: `Oscillation detected: ${w[0].key} ↔ ${w[1].key}${suffix}`,
|
|
64
72
|
};
|
|
65
73
|
}
|
|
66
74
|
}
|
|
@@ -77,7 +85,7 @@ export function detectStuck(
|
|
|
77
85
|
if (count >= 2) {
|
|
78
86
|
return {
|
|
79
87
|
stuck: true,
|
|
80
|
-
reason: `Missing file referenced twice: ${filePath} (ENOENT)`,
|
|
88
|
+
reason: `Missing file referenced twice: ${filePath} (ENOENT)${suffix}`,
|
|
81
89
|
};
|
|
82
90
|
}
|
|
83
91
|
enoentPaths.set(filePath, count);
|
|
@@ -180,6 +180,12 @@ export interface LoopDeps {
|
|
|
180
180
|
startedAt: number,
|
|
181
181
|
opts?: CloseoutOptions & Record<string, unknown>,
|
|
182
182
|
) => Promise<void>;
|
|
183
|
+
autoCommitUnit?: (
|
|
184
|
+
basePath: string,
|
|
185
|
+
unitType: string,
|
|
186
|
+
unitId: string,
|
|
187
|
+
ctx?: ExtensionContext,
|
|
188
|
+
) => Promise<string | null>;
|
|
183
189
|
recordOutcome: (unitType: string, tier: string, success: boolean) => void;
|
|
184
190
|
writeLock: (
|
|
185
191
|
lockBase: string,
|
|
@@ -30,7 +30,15 @@ import { MergeConflictError } from "../git-service.js";
|
|
|
30
30
|
import { setCurrentPhase, clearCurrentPhase } from "../../shared/gsd-phase-state.js";
|
|
31
31
|
import { join, basename, dirname, parse as parsePath } from "node:path";
|
|
32
32
|
import { existsSync, cpSync, readdirSync } from "node:fs";
|
|
33
|
-
import {
|
|
33
|
+
import {
|
|
34
|
+
logWarning,
|
|
35
|
+
logError,
|
|
36
|
+
_resetLogs,
|
|
37
|
+
drainLogs,
|
|
38
|
+
drainAndSummarize,
|
|
39
|
+
formatForNotification,
|
|
40
|
+
hasAnyIssues,
|
|
41
|
+
} from "../workflow-logger.js";
|
|
34
42
|
import { gsdRoot } from "../paths.js";
|
|
35
43
|
import { atomicWriteSync } from "../atomic-write.js";
|
|
36
44
|
import { verifyExpectedArtifact, diagnoseExpectedArtifact, buildLoopRemediationSteps } from "../auto-recovery.js";
|
|
@@ -159,6 +167,29 @@ async function closeoutAndStop(
|
|
|
159
167
|
await deps.stopAuto(ctx, pi, reason);
|
|
160
168
|
}
|
|
161
169
|
|
|
170
|
+
async function emitCancelledUnitEnd(
|
|
171
|
+
ic: IterationContext,
|
|
172
|
+
unitType: string,
|
|
173
|
+
unitId: string,
|
|
174
|
+
unitStartSeq: number,
|
|
175
|
+
errorContext?: { message: string; category: string; stopReason?: string; isTransient?: boolean; retryAfterMs?: number },
|
|
176
|
+
): Promise<void> {
|
|
177
|
+
ic.deps.emitJournalEvent({
|
|
178
|
+
ts: new Date().toISOString(),
|
|
179
|
+
flowId: ic.flowId,
|
|
180
|
+
seq: ic.nextSeq(),
|
|
181
|
+
eventType: "unit-end",
|
|
182
|
+
data: {
|
|
183
|
+
unitType,
|
|
184
|
+
unitId,
|
|
185
|
+
status: "cancelled",
|
|
186
|
+
artifactVerified: false,
|
|
187
|
+
...(errorContext ? { errorContext } : {}),
|
|
188
|
+
},
|
|
189
|
+
causedBy: { flowId: ic.flowId, seq: unitStartSeq },
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
|
|
162
193
|
// ─── runPreDispatch ───────────────────────────────────────────────────────────
|
|
163
194
|
|
|
164
195
|
/**
|
|
@@ -481,10 +512,13 @@ export async function runPreDispatch(
|
|
|
481
512
|
);
|
|
482
513
|
} else if (state.phase === "blocked") {
|
|
483
514
|
const blockerMsg = `Blocked: ${state.blockers.join(", ")}`;
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
deps.
|
|
515
|
+
// Pause instead of hard-stop so the session is resumable with `/gsd auto`.
|
|
516
|
+
// Hard-stop here was causing premature termination when slice dependencies
|
|
517
|
+
// were temporarily unresolvable (e.g. after reassessment added new slices).
|
|
518
|
+
await deps.pauseAuto(ctx, pi);
|
|
519
|
+
ctx.ui.notify(`${blockerMsg}. Fix and run /gsd auto to resume.`, "warning");
|
|
520
|
+
deps.sendDesktopNotification("GSD", blockerMsg, "warning", "attention", basename(s.originalBasePath || s.basePath));
|
|
521
|
+
deps.logCmuxEvent(prefs, blockerMsg, "warning");
|
|
488
522
|
} else {
|
|
489
523
|
const ids = incomplete.map((m: { id: string }) => m.id).join(", ");
|
|
490
524
|
const diag = `basePath=${s.basePath}, milestones=[${state.registry.map((m: { id: string; status: string }) => `${m.id}:${m.status}`).join(", ")}], phase=${state.phase}`;
|
|
@@ -583,13 +617,23 @@ export async function runPreDispatch(
|
|
|
583
617
|
return { action: "break", reason: "milestone-complete" };
|
|
584
618
|
}
|
|
585
619
|
|
|
586
|
-
// Terminal: blocked
|
|
620
|
+
// Terminal: blocked — pause instead of hard-stop so the session is resumable.
|
|
587
621
|
if (state.phase === "blocked") {
|
|
588
622
|
const blockerMsg = `Blocked: ${state.blockers.join(", ")}`;
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
623
|
+
if (s.currentUnit) {
|
|
624
|
+
await deps.closeoutUnit(
|
|
625
|
+
ctx,
|
|
626
|
+
s.basePath,
|
|
627
|
+
s.currentUnit.type,
|
|
628
|
+
s.currentUnit.id,
|
|
629
|
+
s.currentUnit.startedAt,
|
|
630
|
+
deps.buildSnapshotOpts(s.currentUnit.type, s.currentUnit.id),
|
|
631
|
+
);
|
|
632
|
+
}
|
|
633
|
+
await deps.pauseAuto(ctx, pi);
|
|
634
|
+
ctx.ui.notify(`${blockerMsg}. Fix and run /gsd auto to resume.`, "warning");
|
|
635
|
+
deps.sendDesktopNotification("GSD", blockerMsg, "warning", "attention", basename(s.originalBasePath || s.basePath));
|
|
636
|
+
deps.logCmuxEvent(prefs, blockerMsg, "warning");
|
|
593
637
|
debugLog("autoLoop", { phase: "exit", reason: "blocked" });
|
|
594
638
|
deps.emitJournalEvent({ ts: new Date().toISOString(), flowId: ic.flowId, seq: ic.nextSeq(), eventType: "terminal", data: { reason: "blocked", blockers: state.blockers } });
|
|
595
639
|
return { action: "break", reason: "blocked" };
|
|
@@ -1068,6 +1112,10 @@ export async function runUnitPhase(
|
|
|
1068
1112
|
);
|
|
1069
1113
|
const previousTier = s.currentUnitRouting?.tier;
|
|
1070
1114
|
|
|
1115
|
+
// Scope workflow-logger buffer to this unit so post-finalize drains are
|
|
1116
|
+
// per-unit. Without this, the module-level _buffer accumulates across every
|
|
1117
|
+
// unit in the same Node process (see workflow-logger.ts module header).
|
|
1118
|
+
_resetLogs();
|
|
1071
1119
|
s.currentUnit = { type: unitType, id: unitId, startedAt: Date.now() };
|
|
1072
1120
|
setCurrentPhase(unitType);
|
|
1073
1121
|
s.lastToolInvocationError = null; // #2883: clear stale error from previous unit
|
|
@@ -1334,6 +1382,7 @@ export async function runUnitPhase(
|
|
|
1334
1382
|
// Provider-error pause: pauseAuto already handled cleanup and scheduled
|
|
1335
1383
|
// recovery. Don't hard-stop — just break out of the loop (#2762).
|
|
1336
1384
|
if (unitResult.errorContext?.category === "provider") {
|
|
1385
|
+
await emitCancelledUnitEnd(ic, unitType, unitId, unitStartSeq, unitResult.errorContext);
|
|
1337
1386
|
debugLog("autoLoop", { phase: "exit", reason: "provider-pause", isTransient: unitResult.errorContext.isTransient });
|
|
1338
1387
|
return { action: "break", reason: "provider-pause" };
|
|
1339
1388
|
}
|
|
@@ -1352,9 +1401,23 @@ export async function runUnitPhase(
|
|
|
1352
1401
|
);
|
|
1353
1402
|
debugLog("autoLoop", { phase: "session-timeout-pause", unitType, unitId });
|
|
1354
1403
|
await deps.pauseAuto(ctx, pi);
|
|
1404
|
+
await deps.autoCommitUnit?.(s.basePath, unitType, unitId, ctx);
|
|
1405
|
+
await emitCancelledUnitEnd(ic, unitType, unitId, unitStartSeq, unitResult.errorContext);
|
|
1355
1406
|
return { action: "break", reason: "session-timeout" };
|
|
1356
1407
|
}
|
|
1357
1408
|
// All other cancelled states (structural errors, non-transient failures): hard stop
|
|
1409
|
+
if (s.currentUnit) {
|
|
1410
|
+
await deps.closeoutUnit(
|
|
1411
|
+
ctx,
|
|
1412
|
+
s.basePath,
|
|
1413
|
+
unitType,
|
|
1414
|
+
unitId,
|
|
1415
|
+
s.currentUnit.startedAt,
|
|
1416
|
+
deps.buildSnapshotOpts(unitType, unitId),
|
|
1417
|
+
);
|
|
1418
|
+
}
|
|
1419
|
+
await deps.autoCommitUnit?.(s.basePath, unitType, unitId, ctx);
|
|
1420
|
+
await emitCancelledUnitEnd(ic, unitType, unitId, unitStartSeq, unitResult.errorContext);
|
|
1358
1421
|
ctx.ui.notify(
|
|
1359
1422
|
`Session creation failed for ${unitType} ${unitId}: ${unitResult.errorContext?.message ?? "unknown"}. Stopping auto-mode.`,
|
|
1360
1423
|
"warning",
|
|
@@ -1532,6 +1595,9 @@ export async function runFinalize(
|
|
|
1532
1595
|
// cannot mutate state for the next unit (#3757).
|
|
1533
1596
|
s.currentUnit = null;
|
|
1534
1597
|
clearCurrentPhase();
|
|
1598
|
+
// Drop any logger entries from the timed-out unit so they don't bleed
|
|
1599
|
+
// into the next iteration's drain.
|
|
1600
|
+
drainLogs();
|
|
1535
1601
|
loopState.consecutiveFinalizeTimeouts++;
|
|
1536
1602
|
debugLog("autoLoop", {
|
|
1537
1603
|
phase: "pre-verification-timeout",
|
|
@@ -1630,6 +1696,9 @@ export async function runFinalize(
|
|
|
1630
1696
|
// cannot mutate state for the next unit (#3757).
|
|
1631
1697
|
s.currentUnit = null;
|
|
1632
1698
|
clearCurrentPhase();
|
|
1699
|
+
// Drop any logger entries from the timed-out unit so they don't bleed
|
|
1700
|
+
// into the next iteration's drain.
|
|
1701
|
+
drainLogs();
|
|
1633
1702
|
loopState.consecutiveFinalizeTimeouts++;
|
|
1634
1703
|
debugLog("autoLoop", {
|
|
1635
1704
|
phase: "post-verification-timeout",
|
|
@@ -1674,5 +1743,16 @@ export async function runFinalize(
|
|
|
1674
1743
|
// Both pre and post verification completed without timeout — reset counter
|
|
1675
1744
|
loopState.consecutiveFinalizeTimeouts = 0;
|
|
1676
1745
|
|
|
1746
|
+
// Surface accumulated workflow-logger issues for this unit to the user.
|
|
1747
|
+
// Warnings/errors logged during the unit are buffered in the logger and
|
|
1748
|
+
// drained here so the user sees a single consolidated post-unit alert.
|
|
1749
|
+
if (hasAnyIssues()) {
|
|
1750
|
+
const { logs } = drainAndSummarize();
|
|
1751
|
+
if (logs.length > 0) {
|
|
1752
|
+
const severity = logs.some((e) => e.severity === "error") ? "error" : "warning";
|
|
1753
|
+
ctx.ui.notify(formatForNotification(logs), severity);
|
|
1754
|
+
}
|
|
1755
|
+
}
|
|
1756
|
+
|
|
1677
1757
|
return { action: "next", data: undefined as void };
|
|
1678
1758
|
}
|
|
@@ -307,8 +307,11 @@ export const DISPATCH_RULES: DispatchRule[] = [
|
|
|
307
307
|
{
|
|
308
308
|
name: "reassess-roadmap (post-completion)",
|
|
309
309
|
match: async ({ state, mid, midTitle, basePath, prefs }) => {
|
|
310
|
-
if (prefs?.phases?.skip_reassess
|
|
311
|
-
|
|
310
|
+
if (prefs?.phases?.skip_reassess) return null;
|
|
311
|
+
// Default reassess_after_slice to true — reassessment after slice completion
|
|
312
|
+
// is essential for roadmap integrity. Opt-out via explicit `false`.
|
|
313
|
+
const reassessEnabled = prefs?.phases?.reassess_after_slice ?? true;
|
|
314
|
+
if (!reassessEnabled) return null;
|
|
312
315
|
const needsReassess = await checkNeedsReassessment(basePath, mid, state);
|
|
313
316
|
if (!needsReassess) return null;
|
|
314
317
|
return {
|
|
@@ -877,11 +880,14 @@ export async function resolveDispatch(
|
|
|
877
880
|
}
|
|
878
881
|
}
|
|
879
882
|
|
|
880
|
-
// No rule matched — unhandled phase
|
|
883
|
+
// No rule matched — unhandled phase.
|
|
884
|
+
// Use level "warning" so the loop pauses (resumable) instead of hard-stopping.
|
|
885
|
+
// Hard-stop here was causing premature termination for transient phase gaps
|
|
886
|
+
// (e.g. after reassessment modifies the roadmap and state needs re-derivation).
|
|
881
887
|
return {
|
|
882
888
|
action: "stop",
|
|
883
889
|
reason: `Unhandled phase "${ctx.state.phase}" — run /gsd doctor to diagnose.`,
|
|
884
|
-
level: "
|
|
890
|
+
level: "warning",
|
|
885
891
|
matchedRule: "<no-match>",
|
|
886
892
|
};
|
|
887
893
|
}
|
|
@@ -15,6 +15,7 @@ import { resolveModelForComplexity, escalateTier, getEligibleModels, loadCapabil
|
|
|
15
15
|
import { getLedger, getProjectTotals } from "./metrics.js";
|
|
16
16
|
import { unitPhaseLabel } from "./auto-dashboard.js";
|
|
17
17
|
import { getSessionModelOverride } from "./session-model-override.js";
|
|
18
|
+
import { logWarning } from "./workflow-logger.js";
|
|
18
19
|
|
|
19
20
|
export interface ModelSelectionResult {
|
|
20
21
|
/** Routing metadata for metrics recording */
|
|
@@ -25,9 +26,7 @@ export interface ModelSelectionResult {
|
|
|
25
26
|
|
|
26
27
|
export function resolvePreferredModelConfig(
|
|
27
28
|
unitType: string,
|
|
28
|
-
autoModeStartModel: { provider: string; id: string } | null,
|
|
29
|
-
/** When false, only return explicit per-phase model configs — do not
|
|
30
|
-
* synthesize a routing ceiling from dynamic_routing.tier_models (#3962). */
|
|
29
|
+
autoModeStartModel: { provider: string; id: string; flatRateCtx?: FlatRateContext } | null,
|
|
31
30
|
isAutoMode = true,
|
|
32
31
|
) {
|
|
33
32
|
const explicitConfig = resolveModelWithFallbacksForUnit(unitType);
|
|
@@ -41,7 +40,7 @@ export function resolvePreferredModelConfig(
|
|
|
41
40
|
if (!routingConfig.enabled || !routingConfig.tier_models) return undefined;
|
|
42
41
|
|
|
43
42
|
// Don't synthesize a routing config for flat-rate providers (#3453).
|
|
44
|
-
if (autoModeStartModel && isFlatRateProvider(autoModeStartModel.provider)) return undefined;
|
|
43
|
+
if (autoModeStartModel && isFlatRateProvider(autoModeStartModel.provider, autoModeStartModel.flatRateCtx)) return undefined;
|
|
45
44
|
|
|
46
45
|
const ceilingModel = routingConfig.tier_models.heavy
|
|
47
46
|
?? (autoModeStartModel ? `${autoModeStartModel.provider}/${autoModeStartModel.id}` : undefined);
|
|
@@ -68,7 +67,7 @@ export async function selectAndApplyModel(
|
|
|
68
67
|
basePath: string,
|
|
69
68
|
prefs: GSDPreferences | undefined,
|
|
70
69
|
verbose: boolean,
|
|
71
|
-
autoModeStartModel: { provider: string; id: string } | null,
|
|
70
|
+
autoModeStartModel: { provider: string; id: string; flatRateCtx?: FlatRateContext } | null,
|
|
72
71
|
retryContext?: { isRetry: boolean; previousTier?: string },
|
|
73
72
|
/** When false (interactive/guided-flow), skip dynamic routing and use the session model.
|
|
74
73
|
* Dynamic routing only applies in auto-mode where cost optimization is expected. (#3962) */
|
|
@@ -79,6 +78,17 @@ export async function selectAndApplyModel(
|
|
|
79
78
|
const effectiveSessionModelOverride = sessionModelOverride === undefined
|
|
80
79
|
? getSessionModelOverride(ctx.sessionManager.getSessionId())
|
|
81
80
|
: (sessionModelOverride ?? undefined);
|
|
81
|
+
// Enrich the start model with a flat-rate context up front so routing
|
|
82
|
+
// synthesis and the dispatch-time guard see the same signals (built-in
|
|
83
|
+
// list + user `flat_rate_providers` preference + externalCli auto-
|
|
84
|
+
// detection). The dispatch-time primary-model check below builds its
|
|
85
|
+
// own per-provider context when it has a resolved primary model.
|
|
86
|
+
if (autoModeStartModel) {
|
|
87
|
+
autoModeStartModel = {
|
|
88
|
+
...autoModeStartModel,
|
|
89
|
+
flatRateCtx: buildFlatRateContext(autoModeStartModel.provider, ctx, prefs),
|
|
90
|
+
};
|
|
91
|
+
}
|
|
82
92
|
const modelConfig = effectiveSessionModelOverride
|
|
83
93
|
? undefined
|
|
84
94
|
: resolvePreferredModelConfig(unitType, autoModeStartModel, isAutoMode);
|
|
@@ -107,12 +117,16 @@ export async function selectAndApplyModel(
|
|
|
107
117
|
if (routingConfig.enabled) {
|
|
108
118
|
const primaryModel = resolveModelId(modelConfig.primary, availableModels, ctx.model?.provider);
|
|
109
119
|
if (primaryModel) {
|
|
110
|
-
|
|
120
|
+
const primaryFlatRateCtx = buildFlatRateContext(primaryModel.provider, ctx, prefs);
|
|
121
|
+
if (isFlatRateProvider(primaryModel.provider, primaryFlatRateCtx)) {
|
|
111
122
|
routingConfig.enabled = false;
|
|
112
123
|
}
|
|
113
124
|
} else if (
|
|
114
|
-
(autoModeStartModel && isFlatRateProvider(autoModeStartModel.provider))
|
|
115
|
-
|| (ctx.model?.provider && isFlatRateProvider(
|
|
125
|
+
(autoModeStartModel && isFlatRateProvider(autoModeStartModel.provider, autoModeStartModel.flatRateCtx))
|
|
126
|
+
|| (ctx.model?.provider && isFlatRateProvider(
|
|
127
|
+
ctx.model.provider,
|
|
128
|
+
buildFlatRateContext(ctx.model.provider, ctx, prefs),
|
|
129
|
+
))
|
|
116
130
|
) {
|
|
117
131
|
// Primary model unresolvable but provider signals indicate flat-rate —
|
|
118
132
|
// disable routing to prevent quality degradation.
|
|
@@ -416,8 +430,68 @@ export function resolveModelId<T extends { id: string; provider: string }>(
|
|
|
416
430
|
* Uses case-insensitive matching with alias support to prevent fail-open on
|
|
417
431
|
* provider naming variations (e.g. "copilot" vs "github-copilot").
|
|
418
432
|
*/
|
|
419
|
-
const
|
|
433
|
+
const BUILTIN_FLAT_RATE = new Set(["github-copilot", "copilot", "claude-code"]);
|
|
434
|
+
|
|
435
|
+
/**
|
|
436
|
+
* Optional context that lets callers extend flat-rate detection beyond the
|
|
437
|
+
* hard-coded built-in list. Either signal on its own is enough to classify
|
|
438
|
+
* a provider as flat-rate.
|
|
439
|
+
*/
|
|
440
|
+
export interface FlatRateContext {
|
|
441
|
+
/**
|
|
442
|
+
* Auth mode for the specific provider being checked, as returned by
|
|
443
|
+
* `ctx.modelRegistry.getProviderAuthMode(provider)`. Any provider that
|
|
444
|
+
* wraps a local CLI (externalCli) is, by definition, a flat-rate
|
|
445
|
+
* subscription wrapper — every request costs the same regardless of
|
|
446
|
+
* model, so dynamic routing only degrades quality.
|
|
447
|
+
*/
|
|
448
|
+
authMode?: "apiKey" | "oauth" | "externalCli" | "none";
|
|
449
|
+
/**
|
|
450
|
+
* Case-insensitive list of extra provider IDs the user has declared as
|
|
451
|
+
* flat-rate via `preferences.flat_rate_providers`. Used for private
|
|
452
|
+
* subscription-backed proxies and enterprise-gated deployments that the
|
|
453
|
+
* built-in list doesn't know about.
|
|
454
|
+
*/
|
|
455
|
+
userFlatRate?: readonly string[];
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
export function isFlatRateProvider(provider: string, opts?: FlatRateContext): boolean {
|
|
459
|
+
const p = provider.toLowerCase();
|
|
460
|
+
if (BUILTIN_FLAT_RATE.has(p)) return true;
|
|
461
|
+
if (opts?.userFlatRate?.some(id => id.toLowerCase() === p)) return true;
|
|
462
|
+
if (opts?.authMode === "externalCli") return true;
|
|
463
|
+
return false;
|
|
464
|
+
}
|
|
420
465
|
|
|
421
|
-
|
|
422
|
-
|
|
466
|
+
/**
|
|
467
|
+
* Build a FlatRateContext for a given provider from live runtime state.
|
|
468
|
+
* Safe to call when ctx or prefs are undefined — missing pieces are
|
|
469
|
+
* treated as "no signal".
|
|
470
|
+
*/
|
|
471
|
+
export function buildFlatRateContext(
|
|
472
|
+
provider: string,
|
|
473
|
+
ctx?: { modelRegistry?: { getProviderAuthMode?: (p: string) => string } },
|
|
474
|
+
prefs?: { flat_rate_providers?: readonly string[] },
|
|
475
|
+
): FlatRateContext {
|
|
476
|
+
let authMode: FlatRateContext["authMode"];
|
|
477
|
+
const getAuthMode = ctx?.modelRegistry?.getProviderAuthMode;
|
|
478
|
+
if (typeof getAuthMode === "function") {
|
|
479
|
+
try {
|
|
480
|
+
const mode = getAuthMode(provider);
|
|
481
|
+
if (mode === "apiKey" || mode === "oauth" || mode === "externalCli" || mode === "none") {
|
|
482
|
+
authMode = mode;
|
|
483
|
+
}
|
|
484
|
+
} catch (err) {
|
|
485
|
+
// Registry lookup failure must never break flat-rate detection —
|
|
486
|
+
// fall through with authMode undefined and surface the cause.
|
|
487
|
+
logWarning(
|
|
488
|
+
"dispatch",
|
|
489
|
+
`flat-rate auth-mode lookup failed for ${provider}: ${err instanceof Error ? err.message : String(err)}`,
|
|
490
|
+
);
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
return {
|
|
494
|
+
authMode,
|
|
495
|
+
userFlatRate: prefs?.flat_rate_providers,
|
|
496
|
+
};
|
|
423
497
|
}
|