gsd-pi 2.54.0-dev.e1efc1a → 2.55.0-dev.9ec7cdf

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.
Files changed (201) hide show
  1. package/dist/cli.js +19 -19
  2. package/dist/headless-ui.d.ts +27 -1
  3. package/dist/headless-ui.js +203 -13
  4. package/dist/headless.js +60 -3
  5. package/dist/resources/extensions/bg-shell/bg-shell-lifecycle.js +2 -2
  6. package/dist/resources/extensions/bg-shell/utilities.js +34 -5
  7. package/dist/resources/extensions/gsd/auto/phases.js +19 -3
  8. package/dist/resources/extensions/gsd/auto-dispatch.js +1 -1
  9. package/dist/resources/extensions/gsd/auto-model-selection.js +17 -1
  10. package/dist/resources/extensions/gsd/auto-prompts.js +9 -0
  11. package/dist/resources/extensions/gsd/auto-start.js +12 -5
  12. package/dist/resources/extensions/gsd/auto-worktree.js +39 -14
  13. package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +5 -1
  14. package/dist/resources/extensions/gsd/bootstrap/provider-error-resume.js +18 -0
  15. package/dist/resources/extensions/gsd/bootstrap/register-extension.js +18 -5
  16. package/dist/resources/extensions/gsd/bootstrap/register-shortcuts.js +20 -0
  17. package/dist/resources/extensions/gsd/commands/catalog.js +2 -1
  18. package/dist/resources/extensions/gsd/commands/handlers/parallel.js +15 -1
  19. package/dist/resources/extensions/gsd/crash-recovery.js +2 -2
  20. package/dist/resources/extensions/gsd/parallel-monitor-overlay.js +413 -0
  21. package/dist/resources/extensions/gsd/parallel-orchestrator.js +5 -1
  22. package/dist/resources/extensions/gsd/session-lock.js +46 -12
  23. package/dist/resources/extensions/gsd/skill-health.js +2 -2
  24. package/dist/resources/extensions/gsd/visualizer-overlay.js +3 -3
  25. package/dist/resources/extensions/shared/format-utils.js +1 -1
  26. package/dist/resources/extensions/subagent/worker-registry.js +2 -1
  27. package/dist/web/standalone/.next/BUILD_ID +1 -1
  28. package/dist/web/standalone/.next/app-path-routes-manifest.json +18 -18
  29. package/dist/web/standalone/.next/build-manifest.json +3 -3
  30. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  31. package/dist/web/standalone/.next/react-loadable-manifest.json +2 -2
  32. package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  33. package/dist/web/standalone/.next/server/app/_global-error.html +2 -2
  34. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  35. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  36. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  37. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  38. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  39. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  40. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  41. package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  42. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  43. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  44. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  45. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  46. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  47. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  48. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  49. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  50. package/dist/web/standalone/.next/server/app/api/boot/route_client-reference-manifest.js +1 -1
  51. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route_client-reference-manifest.js +1 -1
  52. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route_client-reference-manifest.js +1 -1
  53. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route_client-reference-manifest.js +1 -1
  54. package/dist/web/standalone/.next/server/app/api/browse-directories/route_client-reference-manifest.js +1 -1
  55. package/dist/web/standalone/.next/server/app/api/captures/route_client-reference-manifest.js +1 -1
  56. package/dist/web/standalone/.next/server/app/api/cleanup/route_client-reference-manifest.js +1 -1
  57. package/dist/web/standalone/.next/server/app/api/dev-mode/route_client-reference-manifest.js +1 -1
  58. package/dist/web/standalone/.next/server/app/api/doctor/route_client-reference-manifest.js +1 -1
  59. package/dist/web/standalone/.next/server/app/api/experimental/route_client-reference-manifest.js +1 -1
  60. package/dist/web/standalone/.next/server/app/api/export-data/route_client-reference-manifest.js +1 -1
  61. package/dist/web/standalone/.next/server/app/api/files/route_client-reference-manifest.js +1 -1
  62. package/dist/web/standalone/.next/server/app/api/forensics/route_client-reference-manifest.js +1 -1
  63. package/dist/web/standalone/.next/server/app/api/git/route_client-reference-manifest.js +1 -1
  64. package/dist/web/standalone/.next/server/app/api/history/route_client-reference-manifest.js +1 -1
  65. package/dist/web/standalone/.next/server/app/api/hooks/route_client-reference-manifest.js +1 -1
  66. package/dist/web/standalone/.next/server/app/api/inspect/route_client-reference-manifest.js +1 -1
  67. package/dist/web/standalone/.next/server/app/api/knowledge/route_client-reference-manifest.js +1 -1
  68. package/dist/web/standalone/.next/server/app/api/live-state/route_client-reference-manifest.js +1 -1
  69. package/dist/web/standalone/.next/server/app/api/onboarding/route_client-reference-manifest.js +1 -1
  70. package/dist/web/standalone/.next/server/app/api/preferences/route_client-reference-manifest.js +1 -1
  71. package/dist/web/standalone/.next/server/app/api/projects/route.js +1 -1
  72. package/dist/web/standalone/.next/server/app/api/projects/route_client-reference-manifest.js +1 -1
  73. package/dist/web/standalone/.next/server/app/api/recovery/route_client-reference-manifest.js +1 -1
  74. package/dist/web/standalone/.next/server/app/api/remote-questions/route_client-reference-manifest.js +1 -1
  75. package/dist/web/standalone/.next/server/app/api/session/browser/route_client-reference-manifest.js +1 -1
  76. package/dist/web/standalone/.next/server/app/api/session/command/route_client-reference-manifest.js +1 -1
  77. package/dist/web/standalone/.next/server/app/api/session/events/route_client-reference-manifest.js +1 -1
  78. package/dist/web/standalone/.next/server/app/api/session/manage/route_client-reference-manifest.js +1 -1
  79. package/dist/web/standalone/.next/server/app/api/settings-data/route_client-reference-manifest.js +1 -1
  80. package/dist/web/standalone/.next/server/app/api/shutdown/route_client-reference-manifest.js +1 -1
  81. package/dist/web/standalone/.next/server/app/api/skill-health/route_client-reference-manifest.js +1 -1
  82. package/dist/web/standalone/.next/server/app/api/steer/route_client-reference-manifest.js +1 -1
  83. package/dist/web/standalone/.next/server/app/api/switch-root/route.js +1 -1
  84. package/dist/web/standalone/.next/server/app/api/switch-root/route_client-reference-manifest.js +1 -1
  85. package/dist/web/standalone/.next/server/app/api/terminal/input/route_client-reference-manifest.js +1 -1
  86. package/dist/web/standalone/.next/server/app/api/terminal/resize/route_client-reference-manifest.js +1 -1
  87. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route_client-reference-manifest.js +1 -1
  88. package/dist/web/standalone/.next/server/app/api/terminal/stream/route_client-reference-manifest.js +1 -1
  89. package/dist/web/standalone/.next/server/app/api/terminal/upload/route_client-reference-manifest.js +1 -1
  90. package/dist/web/standalone/.next/server/app/api/undo/route_client-reference-manifest.js +1 -1
  91. package/dist/web/standalone/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
  92. package/dist/web/standalone/.next/server/app/api/visualizer/route_client-reference-manifest.js +1 -1
  93. package/dist/web/standalone/.next/server/app/index.html +1 -1
  94. package/dist/web/standalone/.next/server/app/index.rsc +2 -2
  95. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  96. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +2 -2
  97. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  98. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  99. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  100. package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  101. package/dist/web/standalone/.next/server/app-paths-manifest.json +18 -18
  102. package/dist/web/standalone/.next/server/chunks/2229.js +1 -1
  103. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  104. package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
  105. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  106. package/dist/web/standalone/.next/server/pages/500.html +2 -2
  107. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  108. package/dist/web/standalone/.next/static/chunks/6502.2305d0afd2385711.js +9 -0
  109. package/dist/web/standalone/.next/static/chunks/app/{page-b950e4e384cc62b3.js → page-0c485498795110d6.js} +1 -1
  110. package/dist/web/standalone/.next/static/chunks/{webpack-bca0e732db0dcec3.js → webpack-4332cbd5dd1be584.js} +1 -1
  111. package/package.json +6 -4
  112. package/packages/pi-coding-agent/dist/core/model-registry.d.ts +1 -1
  113. package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
  114. package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
  115. package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.d.ts +2 -0
  116. package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.d.ts.map +1 -1
  117. package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.js +14 -2
  118. package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.js.map +1 -1
  119. package/packages/pi-coding-agent/package.json +1 -1
  120. package/packages/pi-coding-agent/src/core/model-registry.ts +1 -1
  121. package/packages/pi-coding-agent/src/modes/interactive/components/provider-manager.ts +16 -2
  122. package/pkg/package.json +1 -1
  123. package/scripts/ensure-workspace-builds.cjs +45 -41
  124. package/src/resources/extensions/bg-shell/bg-shell-lifecycle.ts +2 -2
  125. package/src/resources/extensions/bg-shell/utilities.ts +39 -4
  126. package/src/resources/extensions/gsd/auto/phases.ts +25 -4
  127. package/src/resources/extensions/gsd/auto-dispatch.ts +1 -1
  128. package/src/resources/extensions/gsd/auto-model-selection.ts +21 -1
  129. package/src/resources/extensions/gsd/auto-prompts.ts +15 -0
  130. package/src/resources/extensions/gsd/auto-start.ts +13 -5
  131. package/src/resources/extensions/gsd/auto-worktree.ts +46 -13
  132. package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +5 -4
  133. package/src/resources/extensions/gsd/bootstrap/provider-error-resume.ts +53 -0
  134. package/src/resources/extensions/gsd/bootstrap/register-extension.ts +19 -6
  135. package/src/resources/extensions/gsd/bootstrap/register-shortcuts.ts +24 -0
  136. package/src/resources/extensions/gsd/commands/catalog.ts +2 -1
  137. package/src/resources/extensions/gsd/commands/handlers/parallel.ts +19 -1
  138. package/src/resources/extensions/gsd/crash-recovery.ts +2 -3
  139. package/src/resources/extensions/gsd/parallel-monitor-overlay.ts +497 -0
  140. package/src/resources/extensions/gsd/parallel-orchestrator.ts +6 -1
  141. package/src/resources/extensions/gsd/session-lock.ts +46 -12
  142. package/src/resources/extensions/gsd/skill-health.ts +2 -2
  143. package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +139 -0
  144. package/src/resources/extensions/gsd/tests/auto-start-model-capture.test.ts +28 -0
  145. package/src/resources/extensions/gsd/tests/{all-milestones-complete-merge.test.ts → integration/all-milestones-complete-merge.test.ts} +3 -3
  146. package/src/resources/extensions/gsd/tests/{atomic-task-closeout.test.ts → integration/atomic-task-closeout.test.ts} +1 -1
  147. package/src/resources/extensions/gsd/tests/{auto-preflight.test.ts → integration/auto-preflight.test.ts} +1 -1
  148. package/src/resources/extensions/gsd/tests/{auto-recovery.test.ts → integration/auto-recovery.test.ts} +7 -7
  149. package/src/resources/extensions/gsd/tests/{auto-secrets-gate.test.ts → integration/auto-secrets-gate.test.ts} +2 -2
  150. package/src/resources/extensions/gsd/tests/{auto-stash-merge.test.ts → integration/auto-stash-merge.test.ts} +3 -3
  151. package/src/resources/extensions/gsd/tests/{auto-worktree-milestone-merge.test.ts → integration/auto-worktree-milestone-merge.test.ts} +4 -4
  152. package/src/resources/extensions/gsd/tests/{auto-worktree.test.ts → integration/auto-worktree.test.ts} +5 -5
  153. package/src/resources/extensions/gsd/tests/{continue-here.test.ts → integration/continue-here.test.ts} +3 -3
  154. package/src/resources/extensions/gsd/tests/{doctor-completion-deferral.test.ts → integration/doctor-completion-deferral.test.ts} +1 -1
  155. package/src/resources/extensions/gsd/tests/{doctor-delimiter-fix.test.ts → integration/doctor-delimiter-fix.test.ts} +1 -1
  156. package/src/resources/extensions/gsd/tests/{doctor-enhancements.test.ts → integration/doctor-enhancements.test.ts} +3 -3
  157. package/src/resources/extensions/gsd/tests/{doctor-environment-worktree.test.ts → integration/doctor-environment-worktree.test.ts} +1 -1
  158. package/src/resources/extensions/gsd/tests/{doctor-environment.test.ts → integration/doctor-environment.test.ts} +1 -1
  159. package/src/resources/extensions/gsd/tests/{doctor-fixlevel.test.ts → integration/doctor-fixlevel.test.ts} +2 -2
  160. package/src/resources/extensions/gsd/tests/{doctor-git.test.ts → integration/doctor-git.test.ts} +1 -1
  161. package/src/resources/extensions/gsd/tests/{doctor-proactive.test.ts → integration/doctor-proactive.test.ts} +1 -1
  162. package/src/resources/extensions/gsd/tests/{doctor-roadmap-summary-atomicity.test.ts → integration/doctor-roadmap-summary-atomicity.test.ts} +1 -1
  163. package/src/resources/extensions/gsd/tests/{doctor-runtime.test.ts → integration/doctor-runtime.test.ts} +1 -1
  164. package/src/resources/extensions/gsd/tests/{doctor.test.ts → integration/doctor.test.ts} +1 -1
  165. package/src/resources/extensions/gsd/tests/{e2e-workflow-pipeline-integration.test.ts → integration/e2e-workflow-pipeline-integration.test.ts} +5 -5
  166. package/src/resources/extensions/gsd/tests/{feature-branch-lifecycle-integration.test.ts → integration/feature-branch-lifecycle-integration.test.ts} +4 -4
  167. package/src/resources/extensions/gsd/tests/{git-locale.test.ts → integration/git-locale.test.ts} +4 -4
  168. package/src/resources/extensions/gsd/tests/{git-self-heal.test.ts → integration/git-self-heal.test.ts} +1 -1
  169. package/src/resources/extensions/gsd/tests/{git-service.test.ts → integration/git-service.test.ts} +4 -4
  170. package/src/resources/extensions/gsd/tests/{gitignore-tracked-gsd.test.ts → integration/gitignore-tracked-gsd.test.ts} +2 -2
  171. package/src/resources/extensions/gsd/tests/{idle-recovery.test.ts → integration/idle-recovery.test.ts} +3 -3
  172. package/src/resources/extensions/gsd/tests/{inherited-repo-home-dir.test.ts → integration/inherited-repo-home-dir.test.ts} +1 -1
  173. package/src/resources/extensions/gsd/tests/{integration-lifecycle.test.ts → integration/integration-lifecycle.test.ts} +4 -4
  174. package/src/resources/extensions/gsd/tests/{integration-mixed-milestones.test.ts → integration/integration-mixed-milestones.test.ts} +6 -6
  175. package/src/resources/extensions/gsd/tests/{integration-proof.test.ts → integration/integration-proof.test.ts} +12 -12
  176. package/src/resources/extensions/gsd/tests/{migrate-command.test.ts → integration/migrate-command.test.ts} +2 -2
  177. package/src/resources/extensions/gsd/tests/{milestone-transition-worktree.test.ts → integration/milestone-transition-worktree.test.ts} +3 -3
  178. package/src/resources/extensions/gsd/tests/{parallel-merge.test.ts → integration/parallel-merge.test.ts} +3 -3
  179. package/src/resources/extensions/gsd/tests/{parallel-workers-multi-milestone-e2e.test.ts → integration/parallel-workers-multi-milestone-e2e.test.ts} +3 -3
  180. package/src/resources/extensions/gsd/tests/{paths.test.ts → integration/paths.test.ts} +1 -1
  181. package/src/resources/extensions/gsd/tests/{plugin-importer-live.test.ts → integration/plugin-importer-live.test.ts} +2 -2
  182. package/src/resources/extensions/gsd/tests/{queue-completed-milestone-perf.test.ts → integration/queue-completed-milestone-perf.test.ts} +3 -3
  183. package/src/resources/extensions/gsd/tests/{queue-reorder-e2e.test.ts → integration/queue-reorder-e2e.test.ts} +5 -5
  184. package/src/resources/extensions/gsd/tests/{quick-branch-lifecycle.test.ts → integration/quick-branch-lifecycle.test.ts} +5 -5
  185. package/src/resources/extensions/gsd/tests/{run-uat.test.ts → integration/run-uat.test.ts} +4 -4
  186. package/src/resources/extensions/gsd/tests/{token-savings.test.ts → integration/token-savings.test.ts} +3 -3
  187. package/src/resources/extensions/gsd/tests/{worktree-e2e.test.ts → integration/worktree-e2e.test.ts} +4 -4
  188. package/src/resources/extensions/gsd/tests/journal-integration.test.ts +55 -0
  189. package/src/resources/extensions/gsd/tests/parallel-monitor-overlay.test.ts +60 -0
  190. package/src/resources/extensions/gsd/tests/parallel-worker-lock-contention.test.ts +226 -0
  191. package/src/resources/extensions/gsd/tests/plan-milestone-queue-context.test.ts +48 -0
  192. package/src/resources/extensions/gsd/tests/preferences-worktree-sync.test.ts +61 -19
  193. package/src/resources/extensions/gsd/tests/provider-errors.test.ts +98 -0
  194. package/src/resources/extensions/gsd/tests/register-extension-guard.test.ts +59 -0
  195. package/src/resources/extensions/gsd/tests/worktree-preferences-sync.test.ts +49 -24
  196. package/src/resources/extensions/gsd/visualizer-overlay.ts +3 -3
  197. package/src/resources/extensions/shared/format-utils.ts +1 -1
  198. package/src/resources/extensions/subagent/worker-registry.ts +2 -1
  199. package/dist/web/standalone/.next/static/chunks/4024.87fd909ae0110f50.js +0 -9
  200. /package/dist/web/standalone/.next/static/{nISuDzAIpGYC-DVTvs4Po → k92jvAf8IfV4dZE3nnrAr}/_buildManifest.js +0 -0
  201. /package/dist/web/standalone/.next/static/{nISuDzAIpGYC-DVTvs4Po → k92jvAf8IfV4dZE3nnrAr}/_ssgManifest.js +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"provider-manager.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/provider-manager.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * TUI component for managing provider configurations.\n * Shows providers with auth status, discovery support, and model counts.\n */\n\nimport {\n\tContainer,\n\ttype Focusable,\n\tgetEditorKeybindings,\n\tSpacer,\n\tText,\n\ttype TUI,\n} from \"@gsd/pi-tui\";\nimport type { AuthStorage } from \"../../../core/auth-storage.js\";\nimport { getDiscoverableProviders } from \"../../../core/model-discovery.js\";\nimport type { ModelRegistry } from \"../../../core/model-registry.js\";\nimport { theme } from \"../theme/theme.js\";\nimport { rawKeyHint } from \"./keybinding-hints.js\";\n\ninterface ProviderInfo {\n\tname: string;\n\thasAuth: boolean;\n\tsupportsDiscovery: boolean;\n\tmodelCount: number;\n}\n\nexport class ProviderManagerComponent extends Container implements Focusable {\n\tprivate _focused = false;\n\tget focused(): boolean {\n\t\treturn this._focused;\n\t}\n\tset focused(value: boolean) {\n\t\tthis._focused = value;\n\t}\n\n\tprivate providers: ProviderInfo[] = [];\n\tprivate selectedIndex = 0;\n\tprivate listContainer: Container;\n\tprivate tui: TUI;\n\tprivate authStorage: AuthStorage;\n\tprivate modelRegistry: ModelRegistry;\n\tprivate onDone: () => void;\n\tprivate onDiscover: (provider: string) => void;\n\n\tconstructor(\n\t\ttui: TUI,\n\t\tauthStorage: AuthStorage,\n\t\tmodelRegistry: ModelRegistry,\n\t\tonDone: () => void,\n\t\tonDiscover: (provider: string) => void,\n\t) {\n\t\tsuper();\n\n\t\tthis.tui = tui;\n\t\tthis.authStorage = authStorage;\n\t\tthis.modelRegistry = modelRegistry;\n\t\tthis.onDone = onDone;\n\t\tthis.onDiscover = onDiscover;\n\n\t\t// Header\n\t\tthis.addChild(new Text(theme.fg(\"accent\", \"Provider Manager\"), 0, 0));\n\t\tthis.addChild(new Spacer(1));\n\n\t\t// Hints\n\t\tconst hints = [\n\t\t\trawKeyHint(\"d\", \"discover\"),\n\t\t\trawKeyHint(\"r\", \"remove auth\"),\n\t\t\trawKeyHint(\"esc\", \"close\"),\n\t\t].join(\" \");\n\t\tthis.addChild(new Text(hints, 0, 0));\n\t\tthis.addChild(new Spacer(1));\n\n\t\t// List\n\t\tthis.listContainer = new Container();\n\t\tthis.addChild(this.listContainer);\n\n\t\tthis.loadProviders();\n\t\tthis.updateList();\n\t}\n\n\tprivate loadProviders(): void {\n\t\tconst discoverableSet = new Set(getDiscoverableProviders());\n\t\tconst allModels = this.modelRegistry.getAll();\n\n\t\t// Group models by provider\n\t\tconst providerModelCounts = new Map<string, number>();\n\t\tfor (const model of allModels) {\n\t\t\tproviderModelCounts.set(model.provider, (providerModelCounts.get(model.provider) ?? 0) + 1);\n\t\t}\n\n\t\t// Build provider list from all known providers\n\t\tconst providerNames = new Set([\n\t\t\t...providerModelCounts.keys(),\n\t\t\t...discoverableSet,\n\t\t]);\n\n\t\tthis.providers = Array.from(providerNames)\n\t\t\t.sort()\n\t\t\t.map((name) => ({\n\t\t\t\tname,\n\t\t\t\thasAuth: this.authStorage.hasAuth(name),\n\t\t\t\tsupportsDiscovery: discoverableSet.has(name),\n\t\t\t\tmodelCount: providerModelCounts.get(name) ?? 0,\n\t\t\t}));\n\t}\n\n\tprivate updateList(): void {\n\t\tthis.listContainer.clear();\n\n\t\tfor (let i = 0; i < this.providers.length; i++) {\n\t\t\tconst p = this.providers[i];\n\t\t\tconst isSelected = i === this.selectedIndex;\n\n\t\t\tconst authBadge = p.hasAuth ? theme.fg(\"success\", \"[auth]\") : theme.fg(\"muted\", \"[no auth]\");\n\t\t\tconst discoveryBadge = p.supportsDiscovery ? theme.fg(\"accent\", \"[discovery]\") : \"\";\n\t\t\tconst countBadge = theme.fg(\"muted\", `(${p.modelCount} models)`);\n\n\t\t\tconst prefix = isSelected ? theme.fg(\"accent\", \"> \") : \" \";\n\t\t\tconst nameText = isSelected ? theme.fg(\"accent\", p.name) : p.name;\n\n\t\t\tconst parts = [prefix, nameText, \" \", authBadge];\n\t\t\tif (discoveryBadge) parts.push(\" \", discoveryBadge);\n\t\t\tparts.push(\" \", countBadge);\n\n\t\t\tthis.listContainer.addChild(new Text(parts.join(\"\"), 0, 0));\n\t\t}\n\n\t\tif (this.providers.length === 0) {\n\t\t\tthis.listContainer.addChild(new Text(theme.fg(\"muted\", \" No providers configured\"), 0, 0));\n\t\t}\n\t}\n\n\thandleInput(keyData: string): void {\n\t\tconst kb = getEditorKeybindings();\n\n\t\tif (kb.matches(keyData, \"selectUp\")) {\n\t\t\tif (this.providers.length === 0) return;\n\t\t\tthis.selectedIndex = this.selectedIndex === 0 ? this.providers.length - 1 : this.selectedIndex - 1;\n\t\t\tthis.updateList();\n\t\t\tthis.tui.requestRender();\n\t\t} else if (kb.matches(keyData, \"selectDown\")) {\n\t\t\tif (this.providers.length === 0) return;\n\t\t\tthis.selectedIndex = this.selectedIndex === this.providers.length - 1 ? 0 : this.selectedIndex + 1;\n\t\t\tthis.updateList();\n\t\t\tthis.tui.requestRender();\n\t\t} else if (kb.matches(keyData, \"selectCancel\")) {\n\t\t\tthis.onDone();\n\t\t} else if (keyData === \"d\" || keyData === \"D\") {\n\t\t\tconst provider = this.providers[this.selectedIndex];\n\t\t\tif (provider?.supportsDiscovery) {\n\t\t\t\tthis.onDiscover(provider.name);\n\t\t\t}\n\t\t} else if (keyData === \"r\" || keyData === \"R\") {\n\t\t\tconst provider = this.providers[this.selectedIndex];\n\t\t\tif (provider?.hasAuth) {\n\t\t\t\tthis.authStorage.remove(provider.name);\n\t\t\t\tthis.loadProviders();\n\t\t\t\tthis.updateList();\n\t\t\t\tthis.tui.requestRender();\n\t\t\t}\n\t\t}\n\t}\n}\n"]}
1
+ {"version":3,"file":"provider-manager.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/provider-manager.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * TUI component for managing provider configurations.\n * Shows providers with auth status, discovery support, and model counts.\n */\n\nimport {\n\tContainer,\n\ttype Focusable,\n\tgetEditorKeybindings,\n\tSpacer,\n\tText,\n\ttype TUI,\n} from \"@gsd/pi-tui\";\nimport type { AuthStorage } from \"../../../core/auth-storage.js\";\nimport { getDiscoverableProviders } from \"../../../core/model-discovery.js\";\nimport type { ModelRegistry } from \"../../../core/model-registry.js\";\nimport { ModelsJsonWriter } from \"../../../core/models-json-writer.js\";\nimport { theme } from \"../theme/theme.js\";\nimport { rawKeyHint } from \"./keybinding-hints.js\";\n\ninterface ProviderInfo {\n\tname: string;\n\thasAuth: boolean;\n\tsupportsDiscovery: boolean;\n\tmodelCount: number;\n}\n\nexport class ProviderManagerComponent extends Container implements Focusable {\n\tprivate _focused = false;\n\tget focused(): boolean {\n\t\treturn this._focused;\n\t}\n\tset focused(value: boolean) {\n\t\tthis._focused = value;\n\t}\n\n\tprivate providers: ProviderInfo[] = [];\n\tprivate selectedIndex = 0;\n\tprivate listContainer: Container;\n\tprivate tui: TUI;\n\tprivate authStorage: AuthStorage;\n\tprivate modelRegistry: ModelRegistry;\n\tprivate modelsJsonWriter: ModelsJsonWriter;\n\tprivate onDone: () => void;\n\tprivate onDiscover: (provider: string) => void;\n\n\tconstructor(\n\t\ttui: TUI,\n\t\tauthStorage: AuthStorage,\n\t\tmodelRegistry: ModelRegistry,\n\t\tonDone: () => void,\n\t\tonDiscover: (provider: string) => void,\n\t) {\n\t\tsuper();\n\n\t\tthis.tui = tui;\n\t\tthis.authStorage = authStorage;\n\t\tthis.modelRegistry = modelRegistry;\n\t\tthis.modelsJsonWriter = new ModelsJsonWriter(this.modelRegistry.modelsJsonPath);\n\t\tthis.onDone = onDone;\n\t\tthis.onDiscover = onDiscover;\n\n\t\t// Header\n\t\tthis.addChild(new Text(theme.fg(\"accent\", \"Provider Manager\"), 0, 0));\n\t\tthis.addChild(new Spacer(1));\n\n\t\t// Hints\n\t\tconst hints = [\n\t\t\trawKeyHint(\"d\", \"discover\"),\n\t\t\trawKeyHint(\"r\", \"remove\"),\n\t\t\trawKeyHint(\"esc\", \"close\"),\n\t\t].join(\" \");\n\t\tthis.addChild(new Text(hints, 0, 0));\n\t\tthis.addChild(new Spacer(1));\n\n\t\t// List\n\t\tthis.listContainer = new Container();\n\t\tthis.addChild(this.listContainer);\n\n\t\tthis.loadProviders();\n\t\tthis.updateList();\n\t}\n\n\tprivate loadProviders(): void {\n\t\tconst discoverableSet = new Set(getDiscoverableProviders());\n\t\tconst allModels = this.modelRegistry.getAll();\n\n\t\t// Group models by provider\n\t\tconst providerModelCounts = new Map<string, number>();\n\t\tfor (const model of allModels) {\n\t\t\tproviderModelCounts.set(model.provider, (providerModelCounts.get(model.provider) ?? 0) + 1);\n\t\t}\n\n\t\t// Build provider list from all known providers\n\t\tconst providerNames = new Set([\n\t\t\t...providerModelCounts.keys(),\n\t\t\t...discoverableSet,\n\t\t]);\n\n\t\tthis.providers = Array.from(providerNames)\n\t\t\t.sort()\n\t\t\t.map((name) => ({\n\t\t\t\tname,\n\t\t\t\thasAuth: this.authStorage.hasAuth(name),\n\t\t\t\tsupportsDiscovery: discoverableSet.has(name),\n\t\t\t\tmodelCount: providerModelCounts.get(name) ?? 0,\n\t\t\t}));\n\t\tthis.clampSelectedIndex();\n\t}\n\n\tprivate clampSelectedIndex(): void {\n\t\tif (this.providers.length === 0) {\n\t\t\tthis.selectedIndex = 0;\n\t\t\treturn;\n\t\t}\n\t\tthis.selectedIndex = Math.min(this.selectedIndex, this.providers.length - 1);\n\t}\n\n\tprivate updateList(): void {\n\t\tthis.listContainer.clear();\n\n\t\tfor (let i = 0; i < this.providers.length; i++) {\n\t\t\tconst p = this.providers[i];\n\t\t\tconst isSelected = i === this.selectedIndex;\n\n\t\t\tconst authBadge = p.hasAuth ? theme.fg(\"success\", \"[auth]\") : theme.fg(\"muted\", \"[no auth]\");\n\t\t\tconst discoveryBadge = p.supportsDiscovery ? theme.fg(\"accent\", \"[discovery]\") : \"\";\n\t\t\tconst countBadge = theme.fg(\"muted\", `(${p.modelCount} models)`);\n\n\t\t\tconst prefix = isSelected ? theme.fg(\"accent\", \"> \") : \" \";\n\t\t\tconst nameText = isSelected ? theme.fg(\"accent\", p.name) : p.name;\n\n\t\t\tconst parts = [prefix, nameText, \" \", authBadge];\n\t\t\tif (discoveryBadge) parts.push(\" \", discoveryBadge);\n\t\t\tparts.push(\" \", countBadge);\n\n\t\t\tthis.listContainer.addChild(new Text(parts.join(\"\"), 0, 0));\n\t\t}\n\n\t\tif (this.providers.length === 0) {\n\t\t\tthis.listContainer.addChild(new Text(theme.fg(\"muted\", \" No providers configured\"), 0, 0));\n\t\t}\n\t}\n\n\thandleInput(keyData: string): void {\n\t\tconst kb = getEditorKeybindings();\n\n\t\tif (kb.matches(keyData, \"selectUp\")) {\n\t\t\tif (this.providers.length === 0) return;\n\t\t\tthis.selectedIndex = this.selectedIndex === 0 ? this.providers.length - 1 : this.selectedIndex - 1;\n\t\t\tthis.updateList();\n\t\t\tthis.tui.requestRender();\n\t\t} else if (kb.matches(keyData, \"selectDown\")) {\n\t\t\tif (this.providers.length === 0) return;\n\t\t\tthis.selectedIndex = this.selectedIndex === this.providers.length - 1 ? 0 : this.selectedIndex + 1;\n\t\t\tthis.updateList();\n\t\t\tthis.tui.requestRender();\n\t\t} else if (kb.matches(keyData, \"selectCancel\")) {\n\t\t\tthis.onDone();\n\t\t} else if (keyData === \"d\" || keyData === \"D\") {\n\t\t\tconst provider = this.providers[this.selectedIndex];\n\t\t\tif (provider?.supportsDiscovery) {\n\t\t\t\tthis.onDiscover(provider.name);\n\t\t\t}\n\t\t} else if (keyData === \"r\" || keyData === \"R\") {\n\t\t\tconst provider = this.providers[this.selectedIndex];\n\t\t\tif (provider) {\n\t\t\t\tthis.authStorage.remove(provider.name);\n\t\t\t\tthis.modelsJsonWriter.removeProvider(provider.name);\n\t\t\t\tthis.modelRegistry.refresh();\n\t\t\t\tthis.loadProviders();\n\t\t\t\tthis.updateList();\n\t\t\t\tthis.tui.requestRender();\n\t\t\t}\n\t\t}\n\t}\n}\n"]}
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gsd/pi-coding-agent",
3
- "version": "2.54.0",
3
+ "version": "2.55.0",
4
4
  "description": "Coding agent CLI (vendored from pi-mono)",
5
5
  "type": "module",
6
6
  "piConfig": {
@@ -235,7 +235,7 @@ export class ModelRegistry {
235
235
 
236
236
  constructor(
237
237
  readonly authStorage: AuthStorage,
238
- private modelsJsonPath: string | undefined = join(getAgentDir(), "models.json"),
238
+ readonly modelsJsonPath: string | undefined = join(getAgentDir(), "models.json"),
239
239
  ) {
240
240
  this.discoveryCache = new ModelDiscoveryCache();
241
241
 
@@ -14,6 +14,7 @@ import {
14
14
  import type { AuthStorage } from "../../../core/auth-storage.js";
15
15
  import { getDiscoverableProviders } from "../../../core/model-discovery.js";
16
16
  import type { ModelRegistry } from "../../../core/model-registry.js";
17
+ import { ModelsJsonWriter } from "../../../core/models-json-writer.js";
17
18
  import { theme } from "../theme/theme.js";
18
19
  import { rawKeyHint } from "./keybinding-hints.js";
19
20
 
@@ -39,6 +40,7 @@ export class ProviderManagerComponent extends Container implements Focusable {
39
40
  private tui: TUI;
40
41
  private authStorage: AuthStorage;
41
42
  private modelRegistry: ModelRegistry;
43
+ private modelsJsonWriter: ModelsJsonWriter;
42
44
  private onDone: () => void;
43
45
  private onDiscover: (provider: string) => void;
44
46
 
@@ -54,6 +56,7 @@ export class ProviderManagerComponent extends Container implements Focusable {
54
56
  this.tui = tui;
55
57
  this.authStorage = authStorage;
56
58
  this.modelRegistry = modelRegistry;
59
+ this.modelsJsonWriter = new ModelsJsonWriter(this.modelRegistry.modelsJsonPath);
57
60
  this.onDone = onDone;
58
61
  this.onDiscover = onDiscover;
59
62
 
@@ -64,7 +67,7 @@ export class ProviderManagerComponent extends Container implements Focusable {
64
67
  // Hints
65
68
  const hints = [
66
69
  rawKeyHint("d", "discover"),
67
- rawKeyHint("r", "remove auth"),
70
+ rawKeyHint("r", "remove"),
68
71
  rawKeyHint("esc", "close"),
69
72
  ].join(" ");
70
73
  this.addChild(new Text(hints, 0, 0));
@@ -102,6 +105,15 @@ export class ProviderManagerComponent extends Container implements Focusable {
102
105
  supportsDiscovery: discoverableSet.has(name),
103
106
  modelCount: providerModelCounts.get(name) ?? 0,
104
107
  }));
108
+ this.clampSelectedIndex();
109
+ }
110
+
111
+ private clampSelectedIndex(): void {
112
+ if (this.providers.length === 0) {
113
+ this.selectedIndex = 0;
114
+ return;
115
+ }
116
+ this.selectedIndex = Math.min(this.selectedIndex, this.providers.length - 1);
105
117
  }
106
118
 
107
119
  private updateList(): void {
@@ -152,8 +164,10 @@ export class ProviderManagerComponent extends Container implements Focusable {
152
164
  }
153
165
  } else if (keyData === "r" || keyData === "R") {
154
166
  const provider = this.providers[this.selectedIndex];
155
- if (provider?.hasAuth) {
167
+ if (provider) {
156
168
  this.authStorage.remove(provider.name);
169
+ this.modelsJsonWriter.removeProvider(provider.name);
170
+ this.modelRegistry.refresh();
157
171
  this.loadProviders();
158
172
  this.updateList();
159
173
  this.tui.requestRender();
package/pkg/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@glittercowboy/gsd",
3
- "version": "2.54.0",
3
+ "version": "2.55.0",
4
4
  "piConfig": {
5
5
  "name": "gsd",
6
6
  "configDir": ".gsd"
@@ -18,25 +18,6 @@ const { existsSync, statSync, readdirSync } = require('fs')
18
18
  const { resolve, join } = require('path')
19
19
  const { execSync } = require('child_process')
20
20
 
21
- const root = resolve(__dirname, '..')
22
- const packagesDir = join(root, 'packages')
23
-
24
- // Skip if packages/ doesn't exist (published tarball / end-user install)
25
- if (!existsSync(packagesDir)) process.exit(0)
26
-
27
- // Skip in CI — the pipeline runs `npm run build` explicitly
28
- if (process.env.CI === 'true' || process.env.CI === '1') process.exit(0)
29
-
30
- // Workspace packages that need dist/index.js at runtime.
31
- // Order matters: dependencies must build before dependents.
32
- const WORKSPACE_PACKAGES = [
33
- 'native',
34
- 'pi-tui',
35
- 'pi-ai',
36
- 'pi-agent-core',
37
- 'pi-coding-agent',
38
- ]
39
-
40
21
  /**
41
22
  * Returns the most recent mtime (ms) of any .ts file under dir, recursively.
42
23
  * Returns 0 if no .ts files found.
@@ -56,31 +37,54 @@ function newestSrcMtime(dir) {
56
37
  return newest
57
38
  }
58
39
 
59
- const stale = []
60
- for (const pkg of WORKSPACE_PACKAGES) {
61
- const distIndex = join(packagesDir, pkg, 'dist', 'index.js')
62
- if (!existsSync(distIndex)) {
63
- stale.push(pkg)
64
- continue
65
- }
66
- const distMtime = statSync(distIndex).mtimeMs
67
- const srcMtime = newestSrcMtime(join(packagesDir, pkg, 'src'))
68
- if (srcMtime > distMtime) {
69
- stale.push(pkg)
40
+ if (require.main === module) {
41
+ const root = resolve(__dirname, '..')
42
+ const packagesDir = join(root, 'packages')
43
+
44
+ // Skip if packages/ doesn't exist (published tarball / end-user install)
45
+ if (!existsSync(packagesDir)) process.exit(0)
46
+
47
+ // Skip in CI — the pipeline runs `npm run build` explicitly
48
+ if (process.env.CI === 'true' || process.env.CI === '1') process.exit(0)
49
+
50
+ // Workspace packages that need dist/index.js at runtime.
51
+ // Order matters: dependencies must build before dependents.
52
+ const WORKSPACE_PACKAGES = [
53
+ 'native',
54
+ 'pi-tui',
55
+ 'pi-ai',
56
+ 'pi-agent-core',
57
+ 'pi-coding-agent',
58
+ ]
59
+
60
+ const stale = []
61
+ for (const pkg of WORKSPACE_PACKAGES) {
62
+ const distIndex = join(packagesDir, pkg, 'dist', 'index.js')
63
+ if (!existsSync(distIndex)) {
64
+ stale.push(pkg)
65
+ continue
66
+ }
67
+ const distMtime = statSync(distIndex).mtimeMs
68
+ const srcMtime = newestSrcMtime(join(packagesDir, pkg, 'src'))
69
+ if (srcMtime > distMtime) {
70
+ stale.push(pkg)
71
+ }
70
72
  }
71
- }
72
73
 
73
- if (stale.length === 0) process.exit(0)
74
+ if (stale.length === 0) process.exit(0)
74
75
 
75
- process.stderr.write(` Building ${stale.length} workspace package(s) with stale or missing dist/: ${stale.join(', ')}\n`)
76
+ process.stderr.write(` Building ${stale.length} workspace package(s) with stale or missing dist/: ${stale.join(', ')}\n`)
76
77
 
77
- for (const pkg of stale) {
78
- const pkgDir = join(packagesDir, pkg)
79
- try {
80
- execSync('npm run build', { cwd: pkgDir, stdio: 'pipe' })
81
- process.stderr.write(` ✓ ${pkg}\n`)
82
- } catch (err) {
83
- process.stderr.write(` ✗ ${pkg} build failed: ${err.message}\n`)
84
- // Non-fatal — the user can run `npm run build` manually
78
+ for (const pkg of stale) {
79
+ const pkgDir = join(packagesDir, pkg)
80
+ try {
81
+ execSync('npm run build', { cwd: pkgDir, stdio: 'pipe' })
82
+ process.stderr.write(` ✓ ${pkg}\n`)
83
+ } catch (err) {
84
+ process.stderr.write(` ✗ ${pkg} build failed: ${err.message}\n`)
85
+ // Non-fatal — the user can run `npm run build` manually
86
+ }
85
87
  }
86
88
  }
89
+
90
+ module.exports = { newestSrcMtime }
@@ -22,7 +22,7 @@ import {
22
22
  loadManifest,
23
23
  pruneDeadProcesses,
24
24
  } from "./process-manager.js";
25
- import { formatUptime, resolveBgShellPersistenceCwd } from "./utilities.js";
25
+ import { formatUptime, getBgShellLiveCwd, resolveBgShellPersistenceCwd } from "./utilities.js";
26
26
  import { formatTokenCount } from "../shared/format-utils.js";
27
27
 
28
28
  import type { BgShellSharedState } from "./index.js";
@@ -213,7 +213,7 @@ export function registerBgShellLifecycle(pi: ExtensionAPI, state: BgShellSharedS
213
213
  return {
214
214
  render(width: number): string[] {
215
215
  // ── Line 1: pwd (branch) [session] ... bg status ──
216
- let pwd = process.cwd();
216
+ let pwd = getBgShellLiveCwd(state.latestCtx?.cwd);
217
217
  const home = process.env.HOME || process.env.USERPROFILE;
218
218
  if (home && pwd.startsWith(home)) {
219
219
  pwd = `~${pwd.slice(home.length)}`;
@@ -42,16 +42,51 @@ export function formatTimeAgo(timestamp: number): string {
42
42
  return formatDuration(Date.now() - timestamp) + " ago";
43
43
  }
44
44
 
45
+ function deriveProjectRootFromAutoWorktree(cachedCwd?: string): string | undefined {
46
+ if (!cachedCwd) return undefined;
47
+ const match = cachedCwd.match(/^(.*?)[\\/]\.gsd[\\/]worktrees[\\/][^\\/]+(?:[\\/].*)?$/);
48
+ return match?.[1];
49
+ }
50
+
51
+ export function getBgShellLiveCwd(
52
+ cachedCwd?: string,
53
+ pathExists: (path: string) => boolean = existsSync,
54
+ getCwd: () => string = () => process.cwd(),
55
+ chdir: (path: string) => void = (path) => process.chdir(path),
56
+ ): string {
57
+ try {
58
+ return getCwd();
59
+ } catch {
60
+ const projectRoot = deriveProjectRootFromAutoWorktree(cachedCwd);
61
+ const home = process.env.HOME || process.env.USERPROFILE;
62
+ const fallbacks = [projectRoot, cachedCwd, home, "/"].filter(
63
+ (candidate): candidate is string => Boolean(candidate),
64
+ );
65
+
66
+ for (const candidate of fallbacks) {
67
+ if (candidate !== "/" && !pathExists(candidate)) continue;
68
+ try {
69
+ chdir(candidate);
70
+ } catch {
71
+ // Best-effort only. Returning a known-good fallback is enough to avoid crashes.
72
+ }
73
+ return candidate;
74
+ }
75
+
76
+ return "/";
77
+ }
78
+ }
45
79
 
46
80
  export function resolveBgShellPersistenceCwd(
47
81
  cachedCwd: string,
48
- liveCwd = process.cwd(),
82
+ liveCwd: string | undefined = undefined,
49
83
  pathExists: (path: string) => boolean = existsSync,
50
84
  ): string {
85
+ const resolvedLiveCwd = liveCwd ?? getBgShellLiveCwd(cachedCwd, pathExists);
51
86
  const cachedIsAutoWorktree = /(?:^|[\\/])\.gsd[\\/]worktrees[\\/]/.test(cachedCwd);
52
87
  if (!cachedIsAutoWorktree) return cachedCwd;
53
- if (cachedCwd === liveCwd && pathExists(cachedCwd)) return cachedCwd;
54
- if (!pathExists(cachedCwd)) return liveCwd;
55
- if (liveCwd !== cachedCwd) return liveCwd;
88
+ if (cachedCwd === resolvedLiveCwd && pathExists(cachedCwd)) return cachedCwd;
89
+ if (!pathExists(cachedCwd)) return resolvedLiveCwd;
90
+ if (resolvedLiveCwd !== cachedCwd) return resolvedLiveCwd;
56
91
  return cachedCwd;
57
92
  }
@@ -45,6 +45,17 @@ export function _resolveReportBasePath(s: Pick<AutoSession, "originalBasePath" |
45
45
  return s.originalBasePath || s.basePath;
46
46
  }
47
47
 
48
+ /**
49
+ * Resolve the authoritative project base for dispatch guards.
50
+ * Prior-milestone completion lives at the project root, even when the active
51
+ * unit is running inside an auto worktree.
52
+ */
53
+ export function _resolveDispatchGuardBasePath(
54
+ s: Pick<AutoSession, "originalBasePath" | "basePath">,
55
+ ): string {
56
+ return s.originalBasePath || s.basePath;
57
+ }
58
+
48
59
  /**
49
60
  * Generate and write an HTML milestone report snapshot.
50
61
  * Extracted from the milestone-transition block in autoLoop.
@@ -667,9 +678,10 @@ export async function runDispatch(
667
678
  prompt = preDispatchResult.prompt;
668
679
  }
669
680
 
681
+ const guardBasePath = _resolveDispatchGuardBasePath(s);
670
682
  const priorSliceBlocker = deps.getPriorSliceCompletionBlocker(
671
- s.basePath,
672
- deps.getMainBranch(s.basePath),
683
+ guardBasePath,
684
+ deps.getMainBranch(guardBasePath),
673
685
  unitType,
674
686
  unitId,
675
687
  );
@@ -707,8 +719,17 @@ export async function runGuards(
707
719
  const budgetCeiling = prefs?.budget_ceiling;
708
720
  if (budgetCeiling !== undefined && budgetCeiling > 0) {
709
721
  const currentLedger = deps.getLedger() as { units: unknown } | null;
710
- const totalCost = currentLedger
711
- ? deps.getProjectTotals(currentLedger.units).cost
722
+ // In parallel worker mode, only count cost from the current auto-mode session
723
+ // to avoid hitting the ceiling due to historical project-wide spend (#2184).
724
+ let costUnits = currentLedger?.units;
725
+ if (process.env.GSD_PARALLEL_WORKER && s.autoStartTime && Array.isArray(costUnits)) {
726
+ const sessionStartISO = new Date(s.autoStartTime).toISOString();
727
+ costUnits = costUnits.filter(
728
+ (u: { startedAt?: string }) => u.startedAt != null && u.startedAt >= sessionStartISO,
729
+ );
730
+ }
731
+ const totalCost = costUnits
732
+ ? deps.getProjectTotals(costUnits).cost
712
733
  : 0;
713
734
  const budgetPct = totalCost / budgetCeiling;
714
735
  const budgetAlertLevel = deps.getBudgetAlertLevel(budgetPct);
@@ -200,7 +200,7 @@ export const DISPATCH_RULES: DispatchRule[] = [
200
200
  uatContent ?? "",
201
201
  basePath,
202
202
  ),
203
- pauseAfterDispatch: uatType !== "artifact-driven" && uatType !== "browser-executable" && uatType !== "runtime-executable",
203
+ pauseAfterDispatch: !process.env.GSD_HEADLESS && uatType !== "artifact-driven" && uatType !== "browser-executable" && uatType !== "runtime-executable",
204
204
  };
205
205
  },
206
206
  },
@@ -18,6 +18,26 @@ export interface ModelSelectionResult {
18
18
  routing: { tier: string; modelDowngraded: boolean } | null;
19
19
  }
20
20
 
21
+ export function resolvePreferredModelConfig(
22
+ unitType: string,
23
+ autoModeStartModel: { provider: string; id: string } | null,
24
+ ) {
25
+ const explicitConfig = resolveModelWithFallbacksForUnit(unitType);
26
+ if (explicitConfig) return explicitConfig;
27
+
28
+ const routingConfig = resolveDynamicRoutingConfig();
29
+ if (!routingConfig.enabled || !routingConfig.tier_models) return undefined;
30
+
31
+ const ceilingModel = routingConfig.tier_models.heavy
32
+ ?? (autoModeStartModel ? `${autoModeStartModel.provider}/${autoModeStartModel.id}` : undefined);
33
+ if (!ceilingModel) return undefined;
34
+
35
+ return {
36
+ primary: ceilingModel,
37
+ fallbacks: [],
38
+ };
39
+ }
40
+
21
41
  /**
22
42
  * Select and apply the appropriate model for a unit dispatch.
23
43
  * Handles: per-unit-type model preferences, dynamic complexity routing,
@@ -36,7 +56,7 @@ export async function selectAndApplyModel(
36
56
  autoModeStartModel: { provider: string; id: string } | null,
37
57
  retryContext?: { isRetry: boolean; previousTier?: string },
38
58
  ): Promise<ModelSelectionResult> {
39
- const modelConfig = resolveModelWithFallbacksForUnit(unitType);
59
+ const modelConfig = resolvePreferredModelConfig(unitType, autoModeStartModel);
40
60
  let routing: { tier: string; modelDowngraded: boolean } | null = null;
41
61
 
42
62
  if (modelConfig) {
@@ -87,6 +87,11 @@ function buildSourceFilePaths(
87
87
  paths.push(`- **Decisions**: \`${relGsdRootFile("DECISIONS")}\``);
88
88
  }
89
89
 
90
+ const queuePath = resolveGsdRootFile(base, "QUEUE");
91
+ if (existsSync(queuePath)) {
92
+ paths.push(`- **Queue**: \`${relGsdRootFile("QUEUE")}\``);
93
+ }
94
+
90
95
  const contextPath = resolveMilestoneFile(base, mid, "CONTEXT");
91
96
  if (contextPath) {
92
97
  paths.push(`- **Milestone Context**: \`${relMilestoneFile(base, mid, "CONTEXT")}\``);
@@ -915,6 +920,16 @@ export async function buildPlanMilestonePrompt(mid: string, midTitle: string, ba
915
920
  const decisionsInline = await inlineDecisionsFromDb(base, mid, undefined, inlineLevel);
916
921
  if (decisionsInline) inlined.push(decisionsInline);
917
922
  }
923
+ const queuePath = resolveGsdRootFile(base, "QUEUE");
924
+ if (existsSync(queuePath)) {
925
+ const queueInline = await inlineFileSmart(
926
+ queuePath,
927
+ relGsdRootFile("QUEUE"),
928
+ "Project Queue",
929
+ `${mid} ${midTitle}`,
930
+ );
931
+ inlined.push(queueInline);
932
+ }
918
933
  const knowledgeInlinePM = await inlineGsdRootFile(base, "knowledge.md", "Project Knowledge");
919
934
  if (knowledgeInlinePM) inlined.push(knowledgeInlinePM);
920
935
  inlined.push(inlineTemplate("roadmap", "Roadmap"));
@@ -131,6 +131,15 @@ export async function bootstrapAutoSession(
131
131
  return false;
132
132
  }
133
133
 
134
+ // Capture the user's session model before guided-flow dispatch can apply a
135
+ // phase-specific planning model for a discuss turn (#2829).
136
+ const startModelSnapshot = ctx.model
137
+ ? {
138
+ provider: ctx.model.provider,
139
+ id: ctx.model.id,
140
+ }
141
+ : null;
142
+
134
143
  try {
135
144
  // Validate GSD_PROJECT_ID early so the user gets immediate feedback
136
145
  const customProjectId = process.env.GSD_PROJECT_ID;
@@ -576,12 +585,11 @@ export async function bootstrapAutoSession(
576
585
  // Initialize routing history
577
586
  initRoutingHistory(s.basePath);
578
587
 
579
- // Capture session's model at auto-mode start (#650)
580
- const currentModel = ctx.model;
581
- if (currentModel) {
588
+ // Restore the model that was active when auto bootstrap began (#650, #2829).
589
+ if (startModelSnapshot) {
582
590
  s.autoModeStartModel = {
583
- provider: currentModel.provider,
584
- id: currentModel.id,
591
+ provider: startModelSnapshot.provider,
592
+ id: startModelSnapshot.id,
585
593
  };
586
594
  }
587
595
 
@@ -65,6 +65,8 @@ import {
65
65
  } from "./native-git-bridge.js";
66
66
 
67
67
  const gsdHome = process.env.GSD_HOME || join(homedir(), ".gsd");
68
+ const PROJECT_PREFERENCES_FILE = "PREFERENCES.md";
69
+ const LEGACY_PROJECT_PREFERENCES_FILE = "preferences.md";
68
70
 
69
71
  // ─── Shared Constants & Helpers ─────────────────────────────────────────────
70
72
 
@@ -82,7 +84,7 @@ const ROOT_STATE_FILES = [
82
84
  "QUEUE.md",
83
85
  "completed-units.json",
84
86
  "metrics.json",
85
- // NOTE: preferences.md is intentionally NOT in ROOT_STATE_FILES.
87
+ // NOTE: project preferences are intentionally NOT in ROOT_STATE_FILES.
86
88
  // Forward-sync (main → worktree) is handled explicitly in syncGsdStateToWorktree().
87
89
  // Back-sync (worktree → main) must NEVER overwrite the project root's copy
88
90
  // because the project root is authoritative for preferences (#2684).
@@ -196,6 +198,11 @@ export function syncProjectRootToWorktree(
196
198
  const prGsd = join(projectRoot, ".gsd");
197
199
  const wtGsd = join(worktreePath_, ".gsd");
198
200
 
201
+ // When .gsd is a symlink to the same external directory in both locations,
202
+ // cpSync rejects the copy because source === destination (ERR_FS_CP_EINVAL).
203
+ // Compare realpaths and skip when they resolve to the same physical path (#2184).
204
+ if (isSamePath(prGsd, wtGsd)) return;
205
+
199
206
  // Copy milestone directory from project root to worktree — additive only.
200
207
  // force:false prevents cpSync from overwriting existing worktree files.
201
208
  // Without this, worktree-authoritative files (e.g. VALIDATION.md written
@@ -245,6 +252,11 @@ export function syncStateToProjectRoot(
245
252
  const wtGsd = join(worktreePath_, ".gsd");
246
253
  const prGsd = join(projectRoot, ".gsd");
247
254
 
255
+ // When .gsd is a symlink to the same external directory in both locations,
256
+ // cpSync rejects the copy because source === destination (ERR_FS_CP_EINVAL).
257
+ // Compare realpaths and skip when they resolve to the same physical path (#2184).
258
+ if (isSamePath(wtGsd, prGsd)) return;
259
+
248
260
  // 1. STATE.md — the quick-glance status used by initial deriveState()
249
261
  safeCopy(join(wtGsd, "STATE.md"), join(prGsd, "STATE.md"), { force: true });
250
262
 
@@ -439,18 +451,25 @@ export function syncGsdStateToWorktree(
439
451
  }
440
452
  }
441
453
 
442
- // Forward-sync preferences.md from project root to worktree (additive only).
443
- // NOT in ROOT_STATE_FILES because syncWorktreeStateBack() must never overwrite
444
- // the project root's preferences the project root is authoritative (#2684).
454
+ // Forward-sync project preferences from project root to worktree (additive only).
455
+ // Prefer the canonical uppercase file name, but keep the legacy lowercase
456
+ // fallback so older repos still work on case-sensitive filesystems.
445
457
  {
446
- const src = join(mainGsd, "preferences.md");
447
- const dst = join(wtGsd, "preferences.md");
448
- if (existsSync(src) && !existsSync(dst)) {
449
- try {
450
- cpSync(src, dst);
451
- synced.push("preferences.md");
452
- } catch {
453
- /* non-fatal */
458
+ const worktreeHasPreferences = existsSync(join(wtGsd, PROJECT_PREFERENCES_FILE))
459
+ || existsSync(join(wtGsd, LEGACY_PROJECT_PREFERENCES_FILE));
460
+ if (!worktreeHasPreferences) {
461
+ for (const file of [PROJECT_PREFERENCES_FILE, LEGACY_PROJECT_PREFERENCES_FILE] as const) {
462
+ const src = join(mainGsd, file);
463
+ const dst = join(wtGsd, file);
464
+ if (existsSync(src)) {
465
+ try {
466
+ cpSync(src, dst);
467
+ synced.push(file);
468
+ } catch {
469
+ /* non-fatal */
470
+ }
471
+ break;
472
+ }
454
473
  }
455
474
  }
456
475
  }
@@ -985,11 +1004,25 @@ function copyPlanningArtifacts(srcBase: string, wtPath: string): void {
985
1004
  "STATE.md",
986
1005
  "KNOWLEDGE.md",
987
1006
  "OVERRIDES.md",
988
- "preferences.md",
989
1007
  ]) {
990
1008
  safeCopy(join(srcGsd, file), join(dstGsd, file), { force: true });
991
1009
  }
992
1010
 
1011
+ // Seed canonical PREFERENCES.md when available; fall back to legacy lowercase.
1012
+ if (existsSync(join(srcGsd, PROJECT_PREFERENCES_FILE))) {
1013
+ safeCopy(
1014
+ join(srcGsd, PROJECT_PREFERENCES_FILE),
1015
+ join(dstGsd, PROJECT_PREFERENCES_FILE),
1016
+ { force: true },
1017
+ );
1018
+ } else if (existsSync(join(srcGsd, LEGACY_PROJECT_PREFERENCES_FILE))) {
1019
+ safeCopy(
1020
+ join(srcGsd, LEGACY_PROJECT_PREFERENCES_FILE),
1021
+ join(dstGsd, LEGACY_PROJECT_PREFERENCES_FILE),
1022
+ { force: true },
1023
+ );
1024
+ }
1025
+
993
1026
  // Shared WAL (R012): worktrees use the project root's DB directly.
994
1027
  // No longer copy gsd.db into the worktree — the DB path resolver in
995
1028
  // ensureDbOpen() detects the worktree location and opens the root DB.
@@ -7,6 +7,7 @@ import { pauseAutoForProviderError } from "../provider-error-pause.js";
7
7
  import { isSessionSwitchInFlight, resolveAgentEnd } from "../auto-loop.js";
8
8
  import { resolveModelId } from "../auto-model-selection.js";
9
9
  import { clearDiscussionFlowState } from "./write-gate.js";
10
+ import { resumeAutoAfterProviderDelay } from "./provider-error-resume.js";
10
11
  import {
11
12
  classifyError,
12
13
  createRetryState,
@@ -44,10 +45,10 @@ async function pauseTransientWithBackoff(
44
45
  retryAfterMs,
45
46
  resume: allowAutoResume
46
47
  ? () => {
47
- pi.sendMessage(
48
- { customType: "gsd-auto-timeout-recovery", content: "Continue execution provider error recovery delay elapsed.", display: false },
49
- { triggerTurn: true },
50
- );
48
+ void resumeAutoAfterProviderDelay(pi, ctx).catch((err) => {
49
+ const message = err instanceof Error ? err.message : String(err);
50
+ ctx.ui.notify(`Provider error recovery delay elapsed, but auto-mode failed to resume: ${message}`, "error");
51
+ });
51
52
  }
52
53
  : undefined,
53
54
  });