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
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,
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Leaf node in the import DAG.
|
|
5
5
|
*/
|
|
6
|
+
import { summarizeLogs } from "../workflow-logger.js";
|
|
6
7
|
/**
|
|
7
8
|
* Pattern matching ENOENT errors with a file path.
|
|
8
9
|
* Matches: "ENOENT: no such file or directory, access '/path/to/file'"
|
|
@@ -22,13 +23,19 @@ const ENOENT_PATH_RE = /ENOENT[^']*'([^']+)'/;
|
|
|
22
23
|
export function detectStuck(window) {
|
|
23
24
|
if (window.length < 2)
|
|
24
25
|
return null;
|
|
26
|
+
// Peek (not drain) the workflow-logger buffer so stuck reasons can surface
|
|
27
|
+
// the underlying diagnostic context (projection failures, DB degradations,
|
|
28
|
+
// reconcile warnings) that usually explains *why* the loop is stuck. The
|
|
29
|
+
// auto-loop's finalize step owns the buffer lifecycle — this is read-only.
|
|
30
|
+
const loggerSummary = summarizeLogs();
|
|
31
|
+
const suffix = loggerSummary ? ` — ${loggerSummary}` : "";
|
|
25
32
|
const last = window[window.length - 1];
|
|
26
33
|
const prev = window[window.length - 2];
|
|
27
34
|
// Rule 1: Same error repeated consecutively
|
|
28
35
|
if (last.error && prev.error && last.error === prev.error) {
|
|
29
36
|
return {
|
|
30
37
|
stuck: true,
|
|
31
|
-
reason: `Same error repeated: ${last.error.slice(0, 200)}`,
|
|
38
|
+
reason: `Same error repeated: ${last.error.slice(0, 200)}${suffix}`,
|
|
32
39
|
};
|
|
33
40
|
}
|
|
34
41
|
// Rule 2: Same unit 3+ consecutive times
|
|
@@ -37,7 +44,7 @@ export function detectStuck(window) {
|
|
|
37
44
|
if (lastThree.every((u) => u.key === last.key)) {
|
|
38
45
|
return {
|
|
39
46
|
stuck: true,
|
|
40
|
-
reason: `${last.key} derived 3 consecutive times without progress`,
|
|
47
|
+
reason: `${last.key} derived 3 consecutive times without progress${suffix}`,
|
|
41
48
|
};
|
|
42
49
|
}
|
|
43
50
|
}
|
|
@@ -49,7 +56,7 @@ export function detectStuck(window) {
|
|
|
49
56
|
w[0].key !== w[1].key) {
|
|
50
57
|
return {
|
|
51
58
|
stuck: true,
|
|
52
|
-
reason: `Oscillation detected: ${w[0].key} ↔ ${w[1].key}`,
|
|
59
|
+
reason: `Oscillation detected: ${w[0].key} ↔ ${w[1].key}${suffix}`,
|
|
53
60
|
};
|
|
54
61
|
}
|
|
55
62
|
}
|
|
@@ -67,7 +74,7 @@ export function detectStuck(window) {
|
|
|
67
74
|
if (count >= 2) {
|
|
68
75
|
return {
|
|
69
76
|
stuck: true,
|
|
70
|
-
reason: `Missing file referenced twice: ${filePath} (ENOENT)`,
|
|
77
|
+
reason: `Missing file referenced twice: ${filePath} (ENOENT)${suffix}`,
|
|
71
78
|
};
|
|
72
79
|
}
|
|
73
80
|
enoentPaths.set(filePath, count);
|
|
@@ -16,7 +16,7 @@ import { MergeConflictError } from "../git-service.js";
|
|
|
16
16
|
import { setCurrentPhase, clearCurrentPhase } from "../../shared/gsd-phase-state.js";
|
|
17
17
|
import { join, basename, dirname, parse as parsePath } from "node:path";
|
|
18
18
|
import { existsSync, cpSync, readdirSync } from "node:fs";
|
|
19
|
-
import { logWarning, logError } from "../workflow-logger.js";
|
|
19
|
+
import { logWarning, logError, _resetLogs, drainLogs, drainAndSummarize, formatForNotification, hasAnyIssues, } from "../workflow-logger.js";
|
|
20
20
|
import { gsdRoot } from "../paths.js";
|
|
21
21
|
import { atomicWriteSync } from "../atomic-write.js";
|
|
22
22
|
import { verifyExpectedArtifact, diagnoseExpectedArtifact, buildLoopRemediationSteps } from "../auto-recovery.js";
|
|
@@ -100,6 +100,22 @@ async function closeoutAndStop(ctx, pi, s, deps, reason) {
|
|
|
100
100
|
}
|
|
101
101
|
await deps.stopAuto(ctx, pi, reason);
|
|
102
102
|
}
|
|
103
|
+
async function emitCancelledUnitEnd(ic, unitType, unitId, unitStartSeq, errorContext) {
|
|
104
|
+
ic.deps.emitJournalEvent({
|
|
105
|
+
ts: new Date().toISOString(),
|
|
106
|
+
flowId: ic.flowId,
|
|
107
|
+
seq: ic.nextSeq(),
|
|
108
|
+
eventType: "unit-end",
|
|
109
|
+
data: {
|
|
110
|
+
unitType,
|
|
111
|
+
unitId,
|
|
112
|
+
status: "cancelled",
|
|
113
|
+
artifactVerified: false,
|
|
114
|
+
...(errorContext ? { errorContext } : {}),
|
|
115
|
+
},
|
|
116
|
+
causedBy: { flowId: ic.flowId, seq: unitStartSeq },
|
|
117
|
+
});
|
|
118
|
+
}
|
|
103
119
|
// ─── runPreDispatch ───────────────────────────────────────────────────────────
|
|
104
120
|
/**
|
|
105
121
|
* Phase 1: Pre-dispatch — resource guard, health gate, state derivation,
|
|
@@ -320,10 +336,13 @@ export async function runPreDispatch(ic, loopState) {
|
|
|
320
336
|
}
|
|
321
337
|
else if (state.phase === "blocked") {
|
|
322
338
|
const blockerMsg = `Blocked: ${state.blockers.join(", ")}`;
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
deps.
|
|
339
|
+
// Pause instead of hard-stop so the session is resumable with `/gsd auto`.
|
|
340
|
+
// Hard-stop here was causing premature termination when slice dependencies
|
|
341
|
+
// were temporarily unresolvable (e.g. after reassessment added new slices).
|
|
342
|
+
await deps.pauseAuto(ctx, pi);
|
|
343
|
+
ctx.ui.notify(`${blockerMsg}. Fix and run /gsd auto to resume.`, "warning");
|
|
344
|
+
deps.sendDesktopNotification("GSD", blockerMsg, "warning", "attention", basename(s.originalBasePath || s.basePath));
|
|
345
|
+
deps.logCmuxEvent(prefs, blockerMsg, "warning");
|
|
327
346
|
}
|
|
328
347
|
else {
|
|
329
348
|
const ids = incomplete.map((m) => m.id).join(", ");
|
|
@@ -392,13 +411,16 @@ export async function runPreDispatch(ic, loopState) {
|
|
|
392
411
|
deps.emitJournalEvent({ ts: new Date().toISOString(), flowId: ic.flowId, seq: ic.nextSeq(), eventType: "terminal", data: { reason: "milestone-complete", milestoneId: mid } });
|
|
393
412
|
return { action: "break", reason: "milestone-complete" };
|
|
394
413
|
}
|
|
395
|
-
// Terminal: blocked
|
|
414
|
+
// Terminal: blocked — pause instead of hard-stop so the session is resumable.
|
|
396
415
|
if (state.phase === "blocked") {
|
|
397
416
|
const blockerMsg = `Blocked: ${state.blockers.join(", ")}`;
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
deps.
|
|
417
|
+
if (s.currentUnit) {
|
|
418
|
+
await deps.closeoutUnit(ctx, s.basePath, s.currentUnit.type, s.currentUnit.id, s.currentUnit.startedAt, deps.buildSnapshotOpts(s.currentUnit.type, s.currentUnit.id));
|
|
419
|
+
}
|
|
420
|
+
await deps.pauseAuto(ctx, pi);
|
|
421
|
+
ctx.ui.notify(`${blockerMsg}. Fix and run /gsd auto to resume.`, "warning");
|
|
422
|
+
deps.sendDesktopNotification("GSD", blockerMsg, "warning", "attention", basename(s.originalBasePath || s.basePath));
|
|
423
|
+
deps.logCmuxEvent(prefs, blockerMsg, "warning");
|
|
402
424
|
debugLog("autoLoop", { phase: "exit", reason: "blocked" });
|
|
403
425
|
deps.emitJournalEvent({ ts: new Date().toISOString(), flowId: ic.flowId, seq: ic.nextSeq(), eventType: "terminal", data: { reason: "blocked", blockers: state.blockers } });
|
|
404
426
|
return { action: "break", reason: "blocked" };
|
|
@@ -770,6 +792,10 @@ export async function runUnitPhase(ic, iterData, loopState, sidecarItem) {
|
|
|
770
792
|
s.currentUnit.type === unitType &&
|
|
771
793
|
s.currentUnit.id === unitId);
|
|
772
794
|
const previousTier = s.currentUnitRouting?.tier;
|
|
795
|
+
// Scope workflow-logger buffer to this unit so post-finalize drains are
|
|
796
|
+
// per-unit. Without this, the module-level _buffer accumulates across every
|
|
797
|
+
// unit in the same Node process (see workflow-logger.ts module header).
|
|
798
|
+
_resetLogs();
|
|
773
799
|
s.currentUnit = { type: unitType, id: unitId, startedAt: Date.now() };
|
|
774
800
|
setCurrentPhase(unitType);
|
|
775
801
|
s.lastToolInvocationError = null; // #2883: clear stale error from previous unit
|
|
@@ -969,6 +995,7 @@ export async function runUnitPhase(ic, iterData, loopState, sidecarItem) {
|
|
|
969
995
|
// Provider-error pause: pauseAuto already handled cleanup and scheduled
|
|
970
996
|
// recovery. Don't hard-stop — just break out of the loop (#2762).
|
|
971
997
|
if (unitResult.errorContext?.category === "provider") {
|
|
998
|
+
await emitCancelledUnitEnd(ic, unitType, unitId, unitStartSeq, unitResult.errorContext);
|
|
972
999
|
debugLog("autoLoop", { phase: "exit", reason: "provider-pause", isTransient: unitResult.errorContext.isTransient });
|
|
973
1000
|
return { action: "break", reason: "provider-pause" };
|
|
974
1001
|
}
|
|
@@ -982,9 +1009,16 @@ export async function runUnitPhase(ic, iterData, loopState, sidecarItem) {
|
|
|
982
1009
|
ctx.ui.notify(`Session creation timed out for ${unitType} ${unitId}. Pausing auto-mode (recoverable).`, "warning");
|
|
983
1010
|
debugLog("autoLoop", { phase: "session-timeout-pause", unitType, unitId });
|
|
984
1011
|
await deps.pauseAuto(ctx, pi);
|
|
1012
|
+
await deps.autoCommitUnit?.(s.basePath, unitType, unitId, ctx);
|
|
1013
|
+
await emitCancelledUnitEnd(ic, unitType, unitId, unitStartSeq, unitResult.errorContext);
|
|
985
1014
|
return { action: "break", reason: "session-timeout" };
|
|
986
1015
|
}
|
|
987
1016
|
// All other cancelled states (structural errors, non-transient failures): hard stop
|
|
1017
|
+
if (s.currentUnit) {
|
|
1018
|
+
await deps.closeoutUnit(ctx, s.basePath, unitType, unitId, s.currentUnit.startedAt, deps.buildSnapshotOpts(unitType, unitId));
|
|
1019
|
+
}
|
|
1020
|
+
await deps.autoCommitUnit?.(s.basePath, unitType, unitId, ctx);
|
|
1021
|
+
await emitCancelledUnitEnd(ic, unitType, unitId, unitStartSeq, unitResult.errorContext);
|
|
988
1022
|
ctx.ui.notify(`Session creation failed for ${unitType} ${unitId}: ${unitResult.errorContext?.message ?? "unknown"}. Stopping auto-mode.`, "warning");
|
|
989
1023
|
await deps.stopAuto(ctx, pi, `Session creation failed: ${unitResult.errorContext?.message ?? "unknown"}`);
|
|
990
1024
|
debugLog("autoLoop", { phase: "exit", reason: "session-failed" });
|
|
@@ -1118,6 +1152,9 @@ export async function runFinalize(ic, iterData, loopState, sidecarItem) {
|
|
|
1118
1152
|
// cannot mutate state for the next unit (#3757).
|
|
1119
1153
|
s.currentUnit = null;
|
|
1120
1154
|
clearCurrentPhase();
|
|
1155
|
+
// Drop any logger entries from the timed-out unit so they don't bleed
|
|
1156
|
+
// into the next iteration's drain.
|
|
1157
|
+
drainLogs();
|
|
1121
1158
|
loopState.consecutiveFinalizeTimeouts++;
|
|
1122
1159
|
debugLog("autoLoop", {
|
|
1123
1160
|
phase: "pre-verification-timeout",
|
|
@@ -1193,6 +1230,9 @@ export async function runFinalize(ic, iterData, loopState, sidecarItem) {
|
|
|
1193
1230
|
// cannot mutate state for the next unit (#3757).
|
|
1194
1231
|
s.currentUnit = null;
|
|
1195
1232
|
clearCurrentPhase();
|
|
1233
|
+
// Drop any logger entries from the timed-out unit so they don't bleed
|
|
1234
|
+
// into the next iteration's drain.
|
|
1235
|
+
drainLogs();
|
|
1196
1236
|
loopState.consecutiveFinalizeTimeouts++;
|
|
1197
1237
|
debugLog("autoLoop", {
|
|
1198
1238
|
phase: "post-verification-timeout",
|
|
@@ -1224,5 +1264,15 @@ export async function runFinalize(ic, iterData, loopState, sidecarItem) {
|
|
|
1224
1264
|
}
|
|
1225
1265
|
// Both pre and post verification completed without timeout — reset counter
|
|
1226
1266
|
loopState.consecutiveFinalizeTimeouts = 0;
|
|
1267
|
+
// Surface accumulated workflow-logger issues for this unit to the user.
|
|
1268
|
+
// Warnings/errors logged during the unit are buffered in the logger and
|
|
1269
|
+
// drained here so the user sees a single consolidated post-unit alert.
|
|
1270
|
+
if (hasAnyIssues()) {
|
|
1271
|
+
const { logs } = drainAndSummarize();
|
|
1272
|
+
if (logs.length > 0) {
|
|
1273
|
+
const severity = logs.some((e) => e.severity === "error") ? "error" : "warning";
|
|
1274
|
+
ctx.ui.notify(formatForNotification(logs), severity);
|
|
1275
|
+
}
|
|
1276
|
+
}
|
|
1227
1277
|
return { action: "next", data: undefined };
|
|
1228
1278
|
}
|
|
@@ -216,7 +216,12 @@ export const DISPATCH_RULES = [
|
|
|
216
216
|
{
|
|
217
217
|
name: "reassess-roadmap (post-completion)",
|
|
218
218
|
match: async ({ state, mid, midTitle, basePath, prefs }) => {
|
|
219
|
-
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)
|
|
220
225
|
return null;
|
|
221
226
|
const needsReassess = await checkNeedsReassessment(basePath, mid, state);
|
|
222
227
|
if (!needsReassess)
|
|
@@ -710,11 +715,14 @@ export async function resolveDispatch(ctx) {
|
|
|
710
715
|
return result;
|
|
711
716
|
}
|
|
712
717
|
}
|
|
713
|
-
// 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).
|
|
714
722
|
return {
|
|
715
723
|
action: "stop",
|
|
716
724
|
reason: `Unhandled phase "${ctx.state.phase}" — run /gsd doctor to diagnose.`,
|
|
717
|
-
level: "
|
|
725
|
+
level: "warning",
|
|
718
726
|
matchedRule: "<no-match>",
|
|
719
727
|
};
|
|
720
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
|
}
|