gsd-pi 2.73.0 → 2.73.1-dev.47ed32a

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 (259) hide show
  1. package/dist/cli.js +0 -47
  2. package/dist/help-text.js +1 -1
  3. package/dist/resource-loader.js +2 -2
  4. package/dist/resources/extensions/claude-code-cli/stream-adapter.js +9 -3
  5. package/dist/resources/extensions/gsd/auto-dispatch.js +5 -3
  6. package/dist/resources/extensions/gsd/auto-model-selection.js +54 -11
  7. package/dist/resources/extensions/gsd/auto-prompts.js +9 -6
  8. package/dist/resources/extensions/gsd/auto-start.js +23 -6
  9. package/dist/resources/extensions/gsd/auto.js +13 -1
  10. package/dist/resources/extensions/gsd/bootstrap/crash-log.js +31 -0
  11. package/dist/resources/extensions/gsd/bootstrap/register-extension.js +18 -7
  12. package/dist/resources/extensions/gsd/bootstrap/system-context.js +6 -1
  13. package/dist/resources/extensions/gsd/commands-handlers.js +8 -2
  14. package/dist/resources/extensions/gsd/crash-recovery.js +51 -0
  15. package/dist/resources/extensions/gsd/gsd-db.js +36 -2
  16. package/dist/resources/extensions/gsd/milestone-actions.js +19 -1
  17. package/dist/resources/extensions/gsd/preferences-models.js +43 -0
  18. package/dist/resources/extensions/gsd/preferences-types.js +1 -0
  19. package/dist/resources/extensions/gsd/preferences-validation.js +22 -0
  20. package/dist/startup-model-validation.js +8 -5
  21. package/dist/update-check.d.ts +1 -0
  22. package/dist/update-check.js +13 -5
  23. package/dist/update-cmd.js +4 -3
  24. package/dist/web/standalone/.next/BUILD_ID +1 -1
  25. package/dist/web/standalone/.next/app-path-routes-manifest.json +13 -13
  26. package/dist/web/standalone/.next/build-manifest.json +3 -3
  27. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  28. package/dist/web/standalone/.next/required-server-files.json +3 -3
  29. package/dist/web/standalone/.next/server/app/_global-error/page.js +3 -3
  30. package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  31. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  32. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  33. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  34. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  35. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  36. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  37. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  38. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  39. package/dist/web/standalone/.next/server/app/_not-found/page.js +2 -2
  40. package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  41. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  42. package/dist/web/standalone/.next/server/app/_not-found.rsc +3 -3
  43. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +3 -3
  44. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  45. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +3 -3
  46. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  47. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  48. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  49. package/dist/web/standalone/.next/server/app/api/boot/route.js +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.js +1 -1
  52. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route_client-reference-manifest.js +1 -1
  53. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js +1 -1
  54. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route_client-reference-manifest.js +1 -1
  55. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js +2 -2
  56. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route_client-reference-manifest.js +1 -1
  57. package/dist/web/standalone/.next/server/app/api/browse-directories/route.js +1 -1
  58. package/dist/web/standalone/.next/server/app/api/browse-directories/route_client-reference-manifest.js +1 -1
  59. package/dist/web/standalone/.next/server/app/api/captures/route.js +1 -1
  60. package/dist/web/standalone/.next/server/app/api/captures/route_client-reference-manifest.js +1 -1
  61. package/dist/web/standalone/.next/server/app/api/cleanup/route.js +1 -1
  62. package/dist/web/standalone/.next/server/app/api/cleanup/route_client-reference-manifest.js +1 -1
  63. package/dist/web/standalone/.next/server/app/api/dev-mode/route.js +1 -1
  64. package/dist/web/standalone/.next/server/app/api/dev-mode/route_client-reference-manifest.js +1 -1
  65. package/dist/web/standalone/.next/server/app/api/doctor/route.js +1 -1
  66. package/dist/web/standalone/.next/server/app/api/doctor/route_client-reference-manifest.js +1 -1
  67. package/dist/web/standalone/.next/server/app/api/experimental/route.js +2 -2
  68. package/dist/web/standalone/.next/server/app/api/experimental/route_client-reference-manifest.js +1 -1
  69. package/dist/web/standalone/.next/server/app/api/export-data/route.js +1 -1
  70. package/dist/web/standalone/.next/server/app/api/export-data/route_client-reference-manifest.js +1 -1
  71. package/dist/web/standalone/.next/server/app/api/files/route.js +1 -1
  72. package/dist/web/standalone/.next/server/app/api/files/route_client-reference-manifest.js +1 -1
  73. package/dist/web/standalone/.next/server/app/api/forensics/route.js +1 -1
  74. package/dist/web/standalone/.next/server/app/api/forensics/route_client-reference-manifest.js +1 -1
  75. package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
  76. package/dist/web/standalone/.next/server/app/api/git/route_client-reference-manifest.js +1 -1
  77. package/dist/web/standalone/.next/server/app/api/history/route.js +1 -1
  78. package/dist/web/standalone/.next/server/app/api/history/route_client-reference-manifest.js +1 -1
  79. package/dist/web/standalone/.next/server/app/api/hooks/route.js +1 -1
  80. package/dist/web/standalone/.next/server/app/api/hooks/route_client-reference-manifest.js +1 -1
  81. package/dist/web/standalone/.next/server/app/api/inspect/route.js +1 -1
  82. package/dist/web/standalone/.next/server/app/api/inspect/route_client-reference-manifest.js +1 -1
  83. package/dist/web/standalone/.next/server/app/api/knowledge/route.js +1 -1
  84. package/dist/web/standalone/.next/server/app/api/knowledge/route_client-reference-manifest.js +1 -1
  85. package/dist/web/standalone/.next/server/app/api/live-state/route.js +1 -1
  86. package/dist/web/standalone/.next/server/app/api/live-state/route_client-reference-manifest.js +1 -1
  87. package/dist/web/standalone/.next/server/app/api/notifications/route.js +2 -2
  88. package/dist/web/standalone/.next/server/app/api/notifications/route_client-reference-manifest.js +1 -1
  89. package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
  90. package/dist/web/standalone/.next/server/app/api/onboarding/route_client-reference-manifest.js +1 -1
  91. package/dist/web/standalone/.next/server/app/api/preferences/route.js +1 -1
  92. package/dist/web/standalone/.next/server/app/api/preferences/route_client-reference-manifest.js +1 -1
  93. package/dist/web/standalone/.next/server/app/api/projects/route.js +1 -1
  94. package/dist/web/standalone/.next/server/app/api/projects/route_client-reference-manifest.js +1 -1
  95. package/dist/web/standalone/.next/server/app/api/recovery/route.js +1 -1
  96. package/dist/web/standalone/.next/server/app/api/recovery/route_client-reference-manifest.js +1 -1
  97. package/dist/web/standalone/.next/server/app/api/remote-questions/route.js +2 -2
  98. package/dist/web/standalone/.next/server/app/api/remote-questions/route_client-reference-manifest.js +1 -1
  99. package/dist/web/standalone/.next/server/app/api/session/browser/route.js +1 -1
  100. package/dist/web/standalone/.next/server/app/api/session/browser/route_client-reference-manifest.js +1 -1
  101. package/dist/web/standalone/.next/server/app/api/session/command/route.js +1 -1
  102. package/dist/web/standalone/.next/server/app/api/session/command/route_client-reference-manifest.js +1 -1
  103. package/dist/web/standalone/.next/server/app/api/session/events/route.js +2 -2
  104. package/dist/web/standalone/.next/server/app/api/session/events/route_client-reference-manifest.js +1 -1
  105. package/dist/web/standalone/.next/server/app/api/session/manage/route.js +1 -1
  106. package/dist/web/standalone/.next/server/app/api/session/manage/route_client-reference-manifest.js +1 -1
  107. package/dist/web/standalone/.next/server/app/api/settings-data/route.js +1 -1
  108. package/dist/web/standalone/.next/server/app/api/settings-data/route_client-reference-manifest.js +1 -1
  109. package/dist/web/standalone/.next/server/app/api/shutdown/route.js +1 -1
  110. package/dist/web/standalone/.next/server/app/api/shutdown/route_client-reference-manifest.js +1 -1
  111. package/dist/web/standalone/.next/server/app/api/skill-health/route.js +1 -1
  112. package/dist/web/standalone/.next/server/app/api/skill-health/route_client-reference-manifest.js +1 -1
  113. package/dist/web/standalone/.next/server/app/api/steer/route.js +1 -1
  114. package/dist/web/standalone/.next/server/app/api/steer/route_client-reference-manifest.js +1 -1
  115. package/dist/web/standalone/.next/server/app/api/switch-root/route.js +1 -1
  116. package/dist/web/standalone/.next/server/app/api/switch-root/route_client-reference-manifest.js +1 -1
  117. package/dist/web/standalone/.next/server/app/api/terminal/input/route.js +2 -2
  118. package/dist/web/standalone/.next/server/app/api/terminal/input/route_client-reference-manifest.js +1 -1
  119. package/dist/web/standalone/.next/server/app/api/terminal/resize/route.js +2 -2
  120. package/dist/web/standalone/.next/server/app/api/terminal/resize/route_client-reference-manifest.js +1 -1
  121. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js +2 -2
  122. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route_client-reference-manifest.js +1 -1
  123. package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js +4 -4
  124. package/dist/web/standalone/.next/server/app/api/terminal/stream/route_client-reference-manifest.js +1 -1
  125. package/dist/web/standalone/.next/server/app/api/terminal/upload/route.js +1 -1
  126. package/dist/web/standalone/.next/server/app/api/terminal/upload/route_client-reference-manifest.js +1 -1
  127. package/dist/web/standalone/.next/server/app/api/undo/route.js +1 -1
  128. package/dist/web/standalone/.next/server/app/api/undo/route_client-reference-manifest.js +1 -1
  129. package/dist/web/standalone/.next/server/app/api/update/route.js +1 -1
  130. package/dist/web/standalone/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
  131. package/dist/web/standalone/.next/server/app/api/visualizer/route.js +1 -1
  132. package/dist/web/standalone/.next/server/app/api/visualizer/route_client-reference-manifest.js +1 -1
  133. package/dist/web/standalone/.next/server/app/index.html +1 -1
  134. package/dist/web/standalone/.next/server/app/index.rsc +4 -4
  135. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  136. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +4 -4
  137. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  138. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +3 -3
  139. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  140. package/dist/web/standalone/.next/server/app/page.js +2 -2
  141. package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  142. package/dist/web/standalone/.next/server/app-paths-manifest.json +13 -13
  143. package/dist/web/standalone/.next/server/chunks/63.js +3 -3
  144. package/dist/web/standalone/.next/server/chunks/6897.js +1 -1
  145. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  146. package/dist/web/standalone/.next/server/middleware-manifest.json +5 -5
  147. package/dist/web/standalone/.next/server/middleware.js +2 -2
  148. package/dist/web/standalone/.next/server/next-font-manifest.js +1 -1
  149. package/dist/web/standalone/.next/server/next-font-manifest.json +1 -1
  150. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  151. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  152. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  153. package/dist/web/standalone/.next/static/chunks/app/_not-found/{page-2f24283c162b6ab3.js → page-f2a7482d42a5614b.js} +1 -1
  154. package/dist/web/standalone/.next/static/chunks/app/{layout-9ecfd95f343793f0.js → layout-a16c7a7ecdf0c2cf.js} +1 -1
  155. package/dist/web/standalone/.next/static/chunks/app/page-f1e30ab6bb269149.js +1 -0
  156. package/dist/web/standalone/.next/static/chunks/main-app-fdab67f7802d7832.js +1 -0
  157. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-459824ffb8c323dd.js +1 -0
  158. package/dist/web/standalone/node_modules/node-pty/build/Makefile +2 -2
  159. package/dist/web/standalone/node_modules/node-pty/build/Release/pty.node +0 -0
  160. package/dist/web/standalone/node_modules/node-pty/build/pty.target.mk +14 -14
  161. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api.target.mk +14 -14
  162. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_except.target.mk +14 -14
  163. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_maybe.target.mk +14 -14
  164. package/dist/web/standalone/server.js +1 -1
  165. package/package.json +1 -1
  166. package/packages/pi-ai/dist/index.d.ts +1 -0
  167. package/packages/pi-ai/dist/index.d.ts.map +1 -1
  168. package/packages/pi-ai/dist/index.js +1 -0
  169. package/packages/pi-ai/dist/index.js.map +1 -1
  170. package/packages/pi-ai/dist/utils/overflow.d.ts.map +1 -1
  171. package/packages/pi-ai/dist/utils/overflow.js +12 -0
  172. package/packages/pi-ai/dist/utils/overflow.js.map +1 -1
  173. package/packages/pi-ai/dist/utils/tests/overflow.test.d.ts +2 -0
  174. package/packages/pi-ai/dist/utils/tests/overflow.test.d.ts.map +1 -0
  175. package/packages/pi-ai/dist/utils/tests/overflow.test.js +50 -0
  176. package/packages/pi-ai/dist/utils/tests/overflow.test.js.map +1 -0
  177. package/packages/pi-ai/src/index.ts +4 -0
  178. package/packages/pi-ai/src/utils/overflow.ts +14 -1
  179. package/packages/pi-ai/src/utils/tests/overflow.test.ts +58 -0
  180. package/packages/pi-coding-agent/dist/core/auth-storage.js +1 -1
  181. package/packages/pi-coding-agent/dist/core/auth-storage.js.map +1 -1
  182. package/packages/pi-coding-agent/dist/core/auth-storage.test.js +27 -0
  183. package/packages/pi-coding-agent/dist/core/auth-storage.test.js.map +1 -1
  184. package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js +313 -8
  185. package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js.map +1 -1
  186. package/packages/pi-coding-agent/dist/core/compaction/utils.js +5 -5
  187. package/packages/pi-coding-agent/dist/core/compaction/utils.js.map +1 -1
  188. package/packages/pi-coding-agent/dist/core/compaction-utils.test.d.ts +2 -0
  189. package/packages/pi-coding-agent/dist/core/compaction-utils.test.d.ts.map +1 -0
  190. package/packages/pi-coding-agent/dist/core/compaction-utils.test.js +45 -0
  191. package/packages/pi-coding-agent/dist/core/compaction-utils.test.js.map +1 -0
  192. package/packages/pi-coding-agent/dist/core/model-resolver.d.ts.map +1 -1
  193. package/packages/pi-coding-agent/dist/core/model-resolver.js +25 -68
  194. package/packages/pi-coding-agent/dist/core/model-resolver.js.map +1 -1
  195. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts +12 -2
  196. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  197. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js +51 -26
  198. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js.map +1 -1
  199. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts +1 -0
  200. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  201. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +116 -25
  202. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  203. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.test.d.ts +2 -0
  204. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.test.d.ts.map +1 -0
  205. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.test.js +63 -0
  206. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.test.js.map +1 -0
  207. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  208. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +6 -2
  209. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  210. package/packages/pi-coding-agent/package.json +1 -1
  211. package/packages/pi-coding-agent/src/core/auth-storage.test.ts +38 -0
  212. package/packages/pi-coding-agent/src/core/auth-storage.ts +1 -1
  213. package/packages/pi-coding-agent/src/core/chat-controller-ordering.test.ts +355 -8
  214. package/packages/pi-coding-agent/src/core/compaction/utils.ts +5 -5
  215. package/packages/pi-coding-agent/src/core/compaction-utils.test.ts +50 -0
  216. package/packages/pi-coding-agent/src/core/model-resolver.ts +26 -70
  217. package/packages/pi-coding-agent/src/modes/interactive/components/assistant-message.ts +62 -26
  218. package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.test.ts +71 -0
  219. package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +136 -30
  220. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +6 -2
  221. package/packages/pi-tui/dist/__tests__/tui.test.js +30 -1
  222. package/packages/pi-tui/dist/__tests__/tui.test.js.map +1 -1
  223. package/packages/pi-tui/dist/tui.d.ts +7 -0
  224. package/packages/pi-tui/dist/tui.d.ts.map +1 -1
  225. package/packages/pi-tui/dist/tui.js +10 -0
  226. package/packages/pi-tui/dist/tui.js.map +1 -1
  227. package/packages/pi-tui/src/__tests__/tui.test.ts +38 -1
  228. package/packages/pi-tui/src/tui.ts +11 -0
  229. package/pkg/package.json +1 -1
  230. package/src/resources/extensions/claude-code-cli/stream-adapter.ts +12 -4
  231. package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +23 -2
  232. package/src/resources/extensions/gsd/auto-dispatch.ts +5 -0
  233. package/src/resources/extensions/gsd/auto-model-selection.ts +85 -11
  234. package/src/resources/extensions/gsd/auto-prompts.ts +9 -3
  235. package/src/resources/extensions/gsd/auto-start.ts +30 -6
  236. package/src/resources/extensions/gsd/auto.ts +10 -0
  237. package/src/resources/extensions/gsd/bootstrap/crash-log.ts +32 -0
  238. package/src/resources/extensions/gsd/bootstrap/register-extension.ts +19 -7
  239. package/src/resources/extensions/gsd/bootstrap/system-context.ts +8 -1
  240. package/src/resources/extensions/gsd/commands-handlers.ts +8 -2
  241. package/src/resources/extensions/gsd/crash-recovery.ts +59 -0
  242. package/src/resources/extensions/gsd/gsd-db.ts +52 -2
  243. package/src/resources/extensions/gsd/milestone-actions.ts +19 -1
  244. package/src/resources/extensions/gsd/preferences-models.ts +41 -0
  245. package/src/resources/extensions/gsd/preferences-types.ts +12 -0
  246. package/src/resources/extensions/gsd/preferences-validation.ts +23 -0
  247. package/src/resources/extensions/gsd/tests/auto-start-model-capture.test.ts +51 -2
  248. package/src/resources/extensions/gsd/tests/crash-handler-secondary.test.ts +235 -0
  249. package/src/resources/extensions/gsd/tests/flat-rate-routing-guard.test.ts +137 -1
  250. package/src/resources/extensions/gsd/tests/gsd-db.test.ts +59 -1
  251. package/src/resources/extensions/gsd/tests/model-isolation.test.ts +91 -2
  252. package/src/resources/extensions/gsd/tests/park-milestone.test.ts +64 -0
  253. package/src/resources/extensions/gsd/tests/preferences.test.ts +47 -0
  254. package/src/resources/extensions/gsd/tests/subagent-model-dispatch.test.ts +267 -0
  255. package/dist/web/standalone/.next/static/chunks/app/page-7115e62689b5fd84.js +0 -1
  256. package/dist/web/standalone/.next/static/chunks/main-app-d3d4c336195465f9.js +0 -1
  257. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-ab5a8926e07ec673.js +0 -1
  258. /package/dist/web/standalone/.next/static/{KSZ2dcC3p4z6lOmUpPpzr → WawMb3TMcYLkGJLTg_x1u}/_buildManifest.js +0 -0
  259. /package/dist/web/standalone/.next/static/{KSZ2dcC3p4z6lOmUpPpzr → WawMb3TMcYLkGJLTg_x1u}/_ssgManifest.js +0 -0
package/dist/cli.js CHANGED
@@ -6,7 +6,6 @@ import { initResources, buildResourceLoader, getNewerManagedResourceVersion } fr
6
6
  import { ensureManagedTools } from './tool-bootstrap.js';
7
7
  import { loadStoredEnvKeys } from './wizard.js';
8
8
  import { migratePiCredentials, getPiDefaultModelAndProvider } from './pi-migration.js';
9
- import { shouldMigrateAnthropicToClaudeCode } from './provider-migrations.js';
10
9
  import { shouldRunOnboarding, runOnboarding } from './onboarding.js';
11
10
  import chalk from 'chalk';
12
11
  import { checkForUpdates } from './update-check.js';
@@ -455,29 +454,6 @@ if (isPrintMode) {
455
454
  isClaudeCodeReady: () => modelRegistry.isProviderRequestReady('claude-code'),
456
455
  });
457
456
  markStartup('createAgentSession');
458
- // Migrate anthropic OAuth users to claude-code provider when CLI is available (#3772).
459
- // Anthropic blocks third-party apps from using subscription quotas — routing through
460
- // the local claude CLI binary is TOS-compliant.
461
- if (shouldMigrateAnthropicToClaudeCode({
462
- authStorage,
463
- isClaudeCodeReady: modelRegistry.isProviderRequestReady('claude-code'),
464
- defaultProvider: settingsManager.getDefaultProvider(),
465
- })) {
466
- const currentModelId = settingsManager.getDefaultModel();
467
- if (currentModelId) {
468
- const ccModel = modelRegistry.find('claude-code', currentModelId);
469
- if (ccModel) {
470
- try {
471
- await session.setModel(ccModel);
472
- // Only persist after successful session switch to avoid desync
473
- settingsManager.setDefaultModelAndProvider('claude-code', currentModelId);
474
- }
475
- catch {
476
- // claude-code provider not ready — leave both session and settings unchanged
477
- }
478
- }
479
- }
480
- }
481
457
  // Validate configured model AFTER extensions have registered their models (#2626).
482
458
  // Before this, extension-provided models (e.g. claude-code/*) were not yet in the
483
459
  // registry, causing the user's valid choice to be silently overwritten.
@@ -647,29 +623,6 @@ const { session, extensionsResult, modelFallbackMessage: interactiveFallbackMsg
647
623
  isClaudeCodeReady: () => modelRegistry.isProviderRequestReady('claude-code'),
648
624
  });
649
625
  markStartup('createAgentSession');
650
- // Migrate anthropic OAuth users to claude-code provider when CLI is available (#3772).
651
- // Anthropic blocks third-party apps from using subscription quotas — routing through
652
- // the local claude CLI binary is TOS-compliant.
653
- if (shouldMigrateAnthropicToClaudeCode({
654
- authStorage,
655
- isClaudeCodeReady: modelRegistry.isProviderRequestReady('claude-code'),
656
- defaultProvider: settingsManager.getDefaultProvider(),
657
- })) {
658
- const currentModelId = settingsManager.getDefaultModel();
659
- if (currentModelId) {
660
- const ccModel = modelRegistry.find('claude-code', currentModelId);
661
- if (ccModel) {
662
- try {
663
- await session.setModel(ccModel);
664
- // Only persist after successful session switch to avoid desync
665
- settingsManager.setDefaultModelAndProvider('claude-code', currentModelId);
666
- }
667
- catch {
668
- // claude-code provider not ready — leave both session and settings unchanged
669
- }
670
- }
671
- }
672
- }
673
626
  // Validate configured model AFTER extensions have registered their models (#2626).
674
627
  // Before this, extension-provided models (e.g. claude-code/*) were not yet in the
675
628
  // registry, causing the user's valid choice to be silently overwritten.
package/dist/help-text.js CHANGED
@@ -148,7 +148,7 @@ export function printHelp(version) {
148
148
  process.stdout.write(' --print, -p Single-shot print mode\n');
149
149
  process.stdout.write(' --continue, -c Resume the most recent session\n');
150
150
  process.stdout.write(' --worktree, -w [name] Start in an isolated worktree (auto-named if omitted)\n');
151
- process.stdout.write(' --model <id> Override model (e.g. claude-opus-4-6)\n');
151
+ process.stdout.write(' --model <id> Override model (e.g. provider/model-id)\n');
152
152
  process.stdout.write(' --no-session Disable session persistence\n');
153
153
  process.stdout.write(' --extension <path> Load additional extension\n');
154
154
  process.stdout.write(' --tools <a,b,c> Restrict available tools\n');
@@ -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";
@@ -437,6 +437,7 @@ export async function resolveClaudePermissionMode(env = process.env) {
437
437
  * behaviour pass `permissionMode: "bypassPermissions"` explicitly.
438
438
  */
439
439
  export function buildSdkOptions(modelId, prompt, overrides, extraOptions = {}) {
440
+ const { reasoning, ...sdkExtraOptions } = extraOptions;
440
441
  const mcpServers = buildWorkflowMcpServers();
441
442
  const permissionMode = overrides?.permissionMode ?? "bypassPermissions";
442
443
  const disallowedTools = ["AskUserQuestion"];
@@ -455,6 +456,9 @@ export function buildSdkOptions(modelId, prompt, overrides, extraOptions = {}) {
455
456
  "Bash(pwd)",
456
457
  ...(mcpServers ? Object.keys(mcpServers).map((serverName) => `mcp__${serverName}__*`) : []),
457
458
  ];
459
+ const effort = reasoning && supportsAdaptiveThinking(modelId)
460
+ ? mapThinkingLevelToEffort(reasoning, modelId)
461
+ : undefined;
458
462
  return {
459
463
  pathToClaudeCodeExecutable: getClaudePath(),
460
464
  model: modelId,
@@ -469,7 +473,8 @@ export function buildSdkOptions(modelId, prompt, overrides, extraOptions = {}) {
469
473
  ...(allowedTools.length > 0 ? { allowedTools } : {}),
470
474
  ...(mcpServers ? { mcpServers } : {}),
471
475
  betas: modelId.includes("sonnet") ? ["context-1m-2025-08-07"] : [],
472
- ...extraOptions,
476
+ ...(effort ? { effort } : {}),
477
+ ...sdkExtraOptions,
473
478
  };
474
479
  }
475
480
  function normalizeToolResultContent(content) {
@@ -620,9 +625,10 @@ async function pumpSdkMessages(model, context, options, stream) {
620
625
  const permissionMode = await resolveClaudePermissionMode();
621
626
  const sdkOpts = buildSdkOptions(modelId, prompt, { permissionMode }, typeof options?.extensionUIContext === "object"
622
627
  ? {
628
+ reasoning: options?.reasoning,
623
629
  onElicitation: createClaudeCodeElicitationHandler(options?.extensionUIContext),
624
630
  }
625
- : {});
631
+ : { reasoning: options?.reasoning });
626
632
  const queryResult = sdk.query({
627
633
  prompt,
628
634
  options: {
@@ -18,6 +18,7 @@ import { logWarning, logError } from "./workflow-logger.js";
18
18
  import { join } from "node:path";
19
19
  import { hasImplementationArtifacts } from "./auto-recovery.js";
20
20
  import { buildDiscussMilestonePrompt, buildResearchMilestonePrompt, buildPlanMilestonePrompt, buildResearchSlicePrompt, buildPlanSlicePrompt, buildExecuteTaskPrompt, buildCompleteSlicePrompt, buildCompleteMilestonePrompt, buildValidateMilestonePrompt, buildReplanSlicePrompt, buildRunUatPrompt, buildReassessRoadmapPrompt, buildRewriteDocsPrompt, buildReactiveExecutePrompt, buildGateEvaluatePrompt, buildParallelResearchSlicesPrompt, checkNeedsReassessment, checkNeedsRunUat, } from "./auto-prompts.js";
21
+ import { resolveModelWithFallbacksForUnit } from "./preferences-models.js";
21
22
  function missingSliceStop(mid, phase) {
22
23
  return {
23
24
  action: "stop",
@@ -330,7 +331,7 @@ export const DISPATCH_RULES = [
330
331
  action: "dispatch",
331
332
  unitType: "research-slice",
332
333
  unitId: `${mid}/parallel-research`,
333
- prompt: await buildParallelResearchSlicesPrompt(mid, midTitle, researchReadySlices, basePath),
334
+ prompt: await buildParallelResearchSlicesPrompt(mid, midTitle, researchReadySlices, basePath, resolveModelWithFallbacksForUnit("subagent")?.primary),
334
335
  };
335
336
  },
336
337
  },
@@ -401,7 +402,7 @@ export const DISPATCH_RULES = [
401
402
  action: "dispatch",
402
403
  unitType: "gate-evaluate",
403
404
  unitId: `${mid}/${sid}/gates+${pending.map(g => g.gate_id).join(",")}`,
404
- prompt: await buildGateEvaluatePrompt(mid, midTitle, sid, sTitle, basePath),
405
+ prompt: await buildGateEvaluatePrompt(mid, midTitle, sid, sTitle, basePath, resolveModelWithFallbacksForUnit("subagent")?.primary),
405
406
  };
406
407
  },
407
408
  },
@@ -436,6 +437,7 @@ export const DISPATCH_RULES = [
436
437
  const sid = state.activeSlice.id;
437
438
  const sTitle = state.activeSlice.title;
438
439
  const maxParallel = reactiveConfig.max_parallel ?? 2;
440
+ const subagentModel = reactiveConfig.subagent_model ?? resolveModelWithFallbacksForUnit("subagent")?.primary;
439
441
  // Dry-run mode: max_parallel=1 means graph is derived and logged but
440
442
  // execution remains sequential
441
443
  if (maxParallel <= 1)
@@ -478,7 +480,7 @@ export const DISPATCH_RULES = [
478
480
  action: "dispatch",
479
481
  unitType: "reactive-execute",
480
482
  unitId: `${mid}/${sid}/reactive+${batchSuffix}`,
481
- prompt: await buildReactiveExecutePrompt(mid, midTitle, sid, sTitle, selected, basePath),
483
+ prompt: await buildReactiveExecutePrompt(mid, midTitle, sid, sTitle, selected, basePath, subagentModel),
482
484
  };
483
485
  }
484
486
  catch (err) {
@@ -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
- export function resolvePreferredModelConfig(unitType, autoModeStartModel,
13
- /** When false, only return explicit per-phase model configs — do not
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
- if (isFlatRateProvider(primaryModel.provider)) {
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 FLAT_RATE_PROVIDERS = new Set(["github-copilot", "copilot", "claude-code"]);
335
- export function isFlatRateProvider(provider) {
336
- return FLAT_RATE_PROVIDERS.has(provider.toLowerCase());
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
  }
@@ -1712,7 +1712,7 @@ export async function buildReassessRoadmapPrompt(mid, midTitle, completedSliceId
1712
1712
  });
1713
1713
  }
1714
1714
  // ─── Reactive Execute Prompt ──────────────────────────────────────────────
1715
- export async function buildReactiveExecutePrompt(mid, midTitle, sid, sTitle, readyTaskIds, base) {
1715
+ export async function buildReactiveExecutePrompt(mid, midTitle, sid, sTitle, readyTaskIds, base, subagentModel) {
1716
1716
  const { loadSliceTaskIO, deriveTaskGraph, graphMetrics } = await import("./reactive-graph.js");
1717
1717
  // Build graph for context
1718
1718
  const taskIO = await loadSliceTaskIO(base, mid, sid);
@@ -1744,10 +1744,11 @@ export async function buildReactiveExecutePrompt(mid, midTitle, sid, sTitle, rea
1744
1744
  const depPaths = await getDependencyTaskSummaryPaths(mid, sid, tid, node?.dependsOn ?? [], base);
1745
1745
  // Build a full execute-task prompt with dependency-based carry-forward
1746
1746
  const taskPrompt = await buildExecuteTaskPrompt(mid, sid, sTitle, tid, tTitle, base, { carryForwardPaths: depPaths });
1747
+ const modelSuffix = subagentModel ? ` with model: "${subagentModel}"` : "";
1747
1748
  subagentSections.push([
1748
1749
  `### ${tid}: ${tTitle}`,
1749
1750
  "",
1750
- "Use this as the prompt for a `subagent` call:",
1751
+ `Use this as the prompt for a \`subagent\` call${modelSuffix}:`,
1751
1752
  "",
1752
1753
  "```",
1753
1754
  taskPrompt,
@@ -1806,15 +1807,16 @@ function renderGatesToCloseBlock(gates, opts) {
1806
1807
  }
1807
1808
  return lines.join("\n").trimEnd();
1808
1809
  }
1809
- export async function buildParallelResearchSlicesPrompt(mid, midTitle, slices, basePath) {
1810
+ export async function buildParallelResearchSlicesPrompt(mid, midTitle, slices, basePath, subagentModel) {
1810
1811
  // Build individual research-slice prompts for each slice
1811
1812
  const subagentSections = [];
1813
+ const modelSuffix = subagentModel ? ` with model: "${subagentModel}"` : "";
1812
1814
  for (const slice of slices) {
1813
1815
  const slicePrompt = await buildResearchSlicePrompt(mid, midTitle, slice.id, slice.title, basePath);
1814
1816
  subagentSections.push([
1815
1817
  `### ${slice.id}: ${slice.title}`,
1816
1818
  "",
1817
- "Use this as the prompt for a `subagent` call (agent: `gsd-executor` or the default agent):",
1819
+ `Use this as the prompt for a \`subagent\` call${modelSuffix} (agent: \`gsd-executor\` or the default agent):`,
1818
1820
  "",
1819
1821
  "```",
1820
1822
  slicePrompt,
@@ -1829,7 +1831,7 @@ export async function buildParallelResearchSlicesPrompt(mid, midTitle, slices, b
1829
1831
  subagentPrompts: subagentSections.join("\n\n---\n\n"),
1830
1832
  });
1831
1833
  }
1832
- export async function buildGateEvaluatePrompt(mid, midTitle, sid, sTitle, base) {
1834
+ export async function buildGateEvaluatePrompt(mid, midTitle, sid, sTitle, base, subagentModel) {
1833
1835
  // Pull only the gates this turn actually owns (Q3/Q4). Filter via the
1834
1836
  // registry so that scope:"slice" gates owned by other turns (Q8) can't
1835
1837
  // leak into this prompt and can't block dispatch via silent skip.
@@ -1873,10 +1875,11 @@ export async function buildGateEvaluatePrompt(mid, midTitle, sid, sTitle, base)
1873
1875
  "- `rationale`: one-sentence justification",
1874
1876
  "- `findings`: detailed markdown findings (or empty if omitted)",
1875
1877
  ].join("\n");
1878
+ const modelSuffix = subagentModel ? ` with model: "${subagentModel}"` : "";
1876
1879
  subagentSections.push([
1877
1880
  `### ${def.id}: ${def.question}`,
1878
1881
  "",
1879
- "Use this as the prompt for a `subagent` call:",
1882
+ `Use this as the prompt for a \`subagent\` call${modelSuffix}:`,
1880
1883
  "",
1881
1884
  "```",
1882
1885
  subPrompt,
@@ -38,7 +38,7 @@ import { existsSync, mkdirSync, readdirSync, rmSync, statSync, unlinkSync, } fro
38
38
  import { join } from "node:path";
39
39
  import { sep as pathSep } from "node:path";
40
40
  import { resolveProjectRootDbPath } from "./bootstrap/dynamic-tools.js";
41
- import { resolveDefaultSessionModel, resolveDynamicRoutingConfig } from "./preferences-models.js";
41
+ import { isCustomProvider, resolveDefaultSessionModel, resolveDynamicRoutingConfig, } from "./preferences-models.js";
42
42
  import { getSessionModelOverride } from "./session-model-override.js";
43
43
  /**
44
44
  * Bootstrap a fresh auto-mode session. Handles everything from git init
@@ -195,8 +195,18 @@ export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, reques
195
195
  //
196
196
  // This preserves #3517 defaults while honoring explicit runtime model
197
197
  // selection for subsequent /gsd runs in the same session.
198
+ //
199
+ // Exception (#4122): when the session provider is a custom provider declared
200
+ // in ~/.gsd/agent/models.json (Ollama, vLLM, OpenAI-compatible proxy, etc.),
201
+ // PREFERENCES.md is skipped entirely. PREFERENCES.md cannot reference custom
202
+ // providers, so honoring it would silently reroute auto-mode to a built-in
203
+ // provider the user is not logged into and surface as "Not logged in · Please
204
+ // run /login" before pausing and resetting to claude-code/claude-sonnet-4-6.
198
205
  const manualSessionOverride = getSessionModelOverride(ctx.sessionManager.getSessionId());
199
- const preferredModel = resolveDefaultSessionModel(ctx.model?.provider);
206
+ const sessionProviderIsCustom = isCustomProvider(ctx.model?.provider);
207
+ const preferredModel = sessionProviderIsCustom
208
+ ? null
209
+ : resolveDefaultSessionModel(ctx.model?.provider);
200
210
  // Validate the preferred model against the live registry + provider auth so
201
211
  // an unconfigured PREFERENCES.md entry (no API key / OAuth) can't become the
202
212
  // start-model snapshot. Without this, every subsequent unit would try to
@@ -622,6 +632,9 @@ export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, reques
622
632
  }
623
633
  ctx.ui.setStatus("gsd-auto", s.stepMode ? "next" : "auto");
624
634
  ctx.ui.setFooter(hideFooter);
635
+ // Hide gsd-health during AUTO — gsd-progress is the single source of truth
636
+ // for last-commit / cost / health signal while auto is running.
637
+ ctx.ui.setWidget("gsd-health", undefined);
625
638
  const modeLabel = s.stepMode ? "Step-mode" : "Auto-mode";
626
639
  const pendingCount = (state.registry ?? []).filter((m) => m.status !== "complete" && m.status !== "parked").length;
627
640
  const scopeMsg = pendingCount > 1
@@ -636,12 +649,16 @@ export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, reques
636
649
  const startModelLabel = s.autoModeStartModel
637
650
  ? `${s.autoModeStartModel.provider}/${s.autoModeStartModel.id}`
638
651
  : ctx.model ? `${ctx.model.provider}/${ctx.model.id}` : "default";
639
- // Flat-rate providers (e.g. GitHub Copilot, claude-code) suppress routing
640
- // at dispatch time (#3453) reflect that in the banner.
641
- const { isFlatRateProvider } = await import("./auto-model-selection.js");
652
+ // Flat-rate providers (e.g. GitHub Copilot, claude-code, user-declared
653
+ // subscription proxies, externalCli CLIs) suppress routing at dispatch
654
+ // time (#3453) reflect that in the banner. Thread the same
655
+ // FlatRateContext used by selectAndApplyModel so user-declared
656
+ // flat-rate providers and externalCli auto-detection are respected.
657
+ const { isFlatRateProvider, buildFlatRateContext } = await import("./auto-model-selection.js");
658
+ const bannerPrefs = loadEffectiveGSDPreferences()?.preferences;
642
659
  const effectiveProvider = s.autoModeStartModel?.provider ?? ctx.model?.provider;
643
660
  const effectivelyEnabled = routingConfig.enabled
644
- && !(effectiveProvider && isFlatRateProvider(effectiveProvider));
661
+ && !(effectiveProvider && isFlatRateProvider(effectiveProvider, buildFlatRateContext(effectiveProvider, ctx, bannerPrefs)));
645
662
  // The actual ceiling may come from tier_models.heavy, not the start model.
646
663
  const effectiveCeiling = (routingConfig.enabled && routingConfig.tier_models?.heavy)
647
664
  ? routingConfig.tier_models.heavy
@@ -19,7 +19,7 @@ import { gsdRoot, resolveMilestoneFile, resolveMilestonePath, resolveDir, milest
19
19
  import { invalidateAllCaches } from "./cache.js";
20
20
  import { clearActivityLogState } from "./activity-log.js";
21
21
  import { synthesizeCrashRecovery, getDeepDiagnostic, readActiveMilestoneId, } from "./session-forensics.js";
22
- import { writeLock, clearLock, readCrashLock, isLockProcessAlive, formatCrashInfo, } from "./crash-recovery.js";
22
+ import { writeLock, clearLock, readCrashLock, isLockProcessAlive, formatCrashInfo, emitCrashRecoveredUnitEnd, } from "./crash-recovery.js";
23
23
  import { acquireSessionLock, getSessionLockStatus, releaseSessionLock, updateSessionLock, } from "./session-lock.js";
24
24
  import { resolveAutoSupervisorConfig, loadEffectiveGSDPreferences, getIsolationMode, } from "./preferences.js";
25
25
  import { sendDesktopNotification } from "./notifications.js";
@@ -63,6 +63,7 @@ import { startUnitSupervision } from "./auto-timers.js";
63
63
  import { runPostUnitVerification } from "./auto-verification.js";
64
64
  import { postUnitPreVerification, postUnitPostVerification, } from "./auto-post-unit.js";
65
65
  import { bootstrapAutoSession, openProjectDbIfPresent } from "./auto-start.js";
66
+ import { initHealthWidget } from "./health-widget.js";
66
67
  import { autoLoop, resolveAgentEnd, resolveAgentEndCancelled, _resetPendingResolve, isSessionSwitchInFlight } from "./auto-loop.js";
67
68
  import { WorktreeResolver, } from "./worktree-resolver.js";
68
69
  import { reorderForCaching } from "./prompt-ordering.js";
@@ -397,6 +398,8 @@ function handleLostSessionLock(ctx, lockStatus) {
397
398
  ctx?.ui.setStatus("gsd-auto", undefined);
398
399
  ctx?.ui.setWidget("gsd-progress", undefined);
399
400
  ctx?.ui.setFooter(undefined);
401
+ if (ctx)
402
+ initHealthWidget(ctx);
400
403
  }
401
404
  /**
402
405
  * Lightweight cleanup after autoLoop exits via step-wizard break.
@@ -431,6 +434,7 @@ function cleanupAfterLoopExit(ctx) {
431
434
  ctx.ui.setStatus("gsd-auto", undefined);
432
435
  ctx.ui.setWidget("gsd-progress", undefined);
433
436
  ctx.ui.setFooter(undefined);
437
+ initHealthWidget(ctx);
434
438
  }
435
439
  // Restore CWD out of worktree back to original project root
436
440
  if (s.originalBasePath) {
@@ -676,6 +680,8 @@ export async function stopAuto(ctx, pi, reason) {
676
680
  ctx?.ui.setStatus("gsd-auto", undefined);
677
681
  ctx?.ui.setWidget("gsd-progress", undefined);
678
682
  ctx?.ui.setFooter(undefined);
683
+ if (ctx)
684
+ initHealthWidget(ctx);
679
685
  restoreProjectRootEnv();
680
686
  restoreMilestoneLockEnv();
681
687
  // Reset all session state in one call
@@ -762,6 +768,8 @@ export async function pauseAuto(ctx, _pi, _errorContext) {
762
768
  ctx?.ui.setStatus("gsd-auto", "paused");
763
769
  ctx?.ui.setWidget("gsd-progress", undefined);
764
770
  ctx?.ui.setFooter(undefined);
771
+ if (ctx)
772
+ initHealthWidget(ctx);
765
773
  const resumeCmd = s.stepMode ? "/gsd next" : "/gsd auto";
766
774
  ctx?.ui.notify(`${s.stepMode ? "Step" : "Auto"}-mode paused (Escape). Type to interact, or ${resumeCmd} to resume.`, "info");
767
775
  }
@@ -1014,6 +1022,10 @@ export async function startAuto(ctx, pi, base, verboseMode, options) {
1014
1022
  s.stepMode = requestedStepMode;
1015
1023
  }
1016
1024
  if (freshStartAssessment.lock) {
1025
+ // Emit a synthetic unit-end for any unit-start that has no closing event.
1026
+ // This closes the journal gap reported in #3348 where the worker wrote side
1027
+ // effects (SUMMARY.md, DB updates) but died before emitting unit-end.
1028
+ emitCrashRecoveredUnitEnd(base, freshStartAssessment.lock);
1017
1029
  clearLock(base);
1018
1030
  }
1019
1031
  if (!s.paused) {
@@ -0,0 +1,31 @@
1
+ /**
2
+ * crash-log.ts — Write crash diagnostics to ~/.gsd/crash/<timestamp>.log
3
+ *
4
+ * Zero cross-dependencies: only uses Node.js built-ins so it can be imported
5
+ * safely from uncaughtException / unhandledRejection handlers and from tests
6
+ * without pulling in the full extension dependency tree.
7
+ */
8
+ import { appendFileSync, mkdirSync } from "node:fs";
9
+ import { homedir } from "node:os";
10
+ import { join } from "node:path";
11
+ /**
12
+ * Write a crash log to ~/.gsd/crash/<timestamp>.log (or $GSD_HOME/crash/).
13
+ * Never throws — must be safe to call from any error handler.
14
+ */
15
+ export function writeCrashLog(err, source) {
16
+ try {
17
+ const crashDir = join(process.env.GSD_HOME ?? join(homedir(), ".gsd"), "crash");
18
+ mkdirSync(crashDir, { recursive: true });
19
+ const ts = new Date().toISOString().replace(/[:.]/g, "-");
20
+ const logPath = join(crashDir, `${ts}.log`);
21
+ const lines = [
22
+ `[gsd] ${source}: ${err.message}`,
23
+ `timestamp: ${new Date().toISOString()}`,
24
+ `pid: ${process.pid}`,
25
+ err.stack ?? "(no stack trace available)",
26
+ "",
27
+ ];
28
+ appendFileSync(logPath, lines.join("\n"));
29
+ }
30
+ catch { /* never throw from crash handler */ }
31
+ }
@@ -8,6 +8,8 @@ import { registerJournalTools } from "./journal-tools.js";
8
8
  import { registerQueryTools } from "./query-tools.js";
9
9
  import { registerHooks } from "./register-hooks.js";
10
10
  import { registerShortcuts } from "./register-shortcuts.js";
11
+ import { writeCrashLog } from "./crash-log.js";
12
+ export { writeCrashLog } from "./crash-log.js";
11
13
  export function handleRecoverableExtensionProcessError(err) {
12
14
  if (err.code === "EPIPE") {
13
15
  process.exit(0);
@@ -28,17 +30,26 @@ export function handleRecoverableExtensionProcessError(err) {
28
30
  function installEpipeGuard() {
29
31
  if (!process.listeners("uncaughtException").some((listener) => listener.name === "_gsdEpipeGuard")) {
30
32
  const _gsdEpipeGuard = (err) => {
31
- if (handleRecoverableExtensionProcessError(err)) {
33
+ if (handleRecoverableExtensionProcessError(err))
32
34
  return;
33
- }
34
- // Log unhandled errors instead of re-throwing throwing inside an
35
- // uncaughtException handler is a fatal double-fault in Node.js (#3163).
36
- process.stderr.write(`[gsd] uncaught extension error (non-fatal): ${err.message}\n`);
37
- if (err.stack)
38
- process.stderr.write(`${err.stack}\n`);
35
+ // Write crash log and exit cleanly for unrecoverable errors.
36
+ // Logging and continuing was the original double-fault fix (#3163), but
37
+ // continuing in an indeterminate state is worse than a clean exit (#3348).
38
+ writeCrashLog(err, "uncaughtException");
39
+ process.exit(1);
39
40
  };
40
41
  process.on("uncaughtException", _gsdEpipeGuard);
41
42
  }
43
+ if (!process.listeners("unhandledRejection").some((listener) => listener.name === "_gsdRejectionGuard")) {
44
+ const _gsdRejectionGuard = (reason, _promise) => {
45
+ const err = reason instanceof Error ? reason : new Error(String(reason));
46
+ if (handleRecoverableExtensionProcessError(err))
47
+ return;
48
+ writeCrashLog(err, "unhandledRejection");
49
+ process.exit(1);
50
+ };
51
+ process.on("unhandledRejection", _gsdRejectionGuard);
52
+ }
42
53
  }
43
54
  export function registerGsdExtension(pi) {
44
55
  registerGSDCommand(pi);
@@ -6,6 +6,7 @@ import { debugTime } from "../debug-logger.js";
6
6
  import { loadPrompt, getTemplatesDir } from "../prompt-loader.js";
7
7
  import { readForensicsMarker } from "../forensics.js";
8
8
  import { resolveAllSkillReferences, renderPreferencesForSystemPrompt, loadEffectiveGSDPreferences } from "../preferences.js";
9
+ import { resolveModelWithFallbacksForUnit } from "../preferences-models.js";
9
10
  import { resolveSkillReference } from "../preferences-skills.js";
10
11
  import { resolveGsdRootFile, resolveSliceFile, resolveSlicePath, resolveTaskFile, resolveTaskFiles, resolveTasksDir, relSliceFile, relSlicePath, relTaskFile } from "../paths.js";
11
12
  import { ensureCodebaseMapFresh, readCodebaseMap } from "../codebase-generator.js";
@@ -147,7 +148,11 @@ export async function buildBeforeAgentStartResult(event, ctx) {
147
148
  // Re-inject forensics context on follow-up turns (#2941)
148
149
  const forensicsInjection = !injection ? buildForensicsContextInjection(process.cwd(), event.prompt) : null;
149
150
  const worktreeBlock = buildWorktreeContextBlock();
150
- const fullSystem = `${event.systemPrompt}\n\n[SYSTEM CONTEXT — GSD]\n\n${systemContent}${preferenceBlock}${knowledgeBlock}${codebaseBlock}${memoryBlock}${newSkillsBlock}${worktreeBlock}`;
151
+ const subagentModelConfig = resolveModelWithFallbacksForUnit("subagent");
152
+ const subagentModelBlock = subagentModelConfig
153
+ ? `\n\n## Subagent Model\n\nWhen spawning subagents via the \`subagent\` tool, always pass \`model: "${subagentModelConfig.primary}"\` in the tool call parameters. Never omit this — always specify it explicitly.`
154
+ : "";
155
+ const fullSystem = `${event.systemPrompt}\n\n[SYSTEM CONTEXT — GSD]\n\n${systemContent}${preferenceBlock}${knowledgeBlock}${codebaseBlock}${memoryBlock}${newSkillsBlock}${worktreeBlock}${subagentModelBlock}`;
151
156
  stopContextTimer({
152
157
  systemPromptSize: fullSystem.length,
153
158
  injectionSize: injection?.length ?? forensicsInjection?.length ?? 0,
@@ -17,6 +17,11 @@ import { projectRoot } from "./commands/context.js";
17
17
  import { loadPrompt } from "./prompt-loader.js";
18
18
  const UPDATE_REGISTRY_URL = "https://registry.npmjs.org/gsd-pi/latest";
19
19
  const UPDATE_FETCH_TIMEOUT_MS = 5000;
20
+ function resolveInstallCommand(pkg) {
21
+ if ('bun' in process.versions)
22
+ return `bun add -g ${pkg}`;
23
+ return `npm install -g ${pkg}`;
24
+ }
20
25
  async function fetchLatestVersionForCommand() {
21
26
  const controller = new AbortController();
22
27
  const timeout = setTimeout(() => controller.abort(), UPDATE_FETCH_TIMEOUT_MS);
@@ -344,13 +349,14 @@ export async function handleUpdate(ctx) {
344
349
  return;
345
350
  }
346
351
  ctx.ui.notify(`Updating: v${current} → v${latest}...`, "info");
352
+ const installCmd = resolveInstallCommand(`${NPM_PACKAGE}@latest`);
347
353
  try {
348
- execSync(`npm install -g ${NPM_PACKAGE}@latest`, {
354
+ execSync(installCmd, {
349
355
  stdio: ["ignore", "pipe", "ignore"],
350
356
  });
351
357
  ctx.ui.notify(`Updated to v${latest}. Restart your GSD session to use the new version.`, "info");
352
358
  }
353
359
  catch {
354
- ctx.ui.notify(`Update failed. Try manually: npm install -g ${NPM_PACKAGE}@latest`, "error");
360
+ ctx.ui.notify(`Update failed. Try manually: ${installCmd}`, "error");
355
361
  }
356
362
  }