gsd-pi 2.66.1 → 2.67.0-dev.46f9884

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 (384) hide show
  1. package/dist/claude-cli-check.d.ts +8 -0
  2. package/dist/claude-cli-check.js +36 -0
  3. package/dist/cli.js +40 -0
  4. package/dist/onboarding.js +19 -2
  5. package/dist/resources/extensions/ask-user-questions.js +79 -11
  6. package/dist/resources/extensions/claude-code-cli/partial-builder.js +4 -3
  7. package/dist/resources/extensions/claude-code-cli/readiness.js +63 -12
  8. package/dist/resources/extensions/claude-code-cli/stream-adapter.js +10 -3
  9. package/dist/resources/extensions/gsd/auto/loop.js +13 -1
  10. package/dist/resources/extensions/gsd/auto/phases.js +22 -3
  11. package/dist/resources/extensions/gsd/auto/run-unit.js +10 -2
  12. package/dist/resources/extensions/gsd/auto/session.js +1 -1
  13. package/dist/resources/extensions/gsd/auto-dashboard.js +65 -15
  14. package/dist/resources/extensions/gsd/auto-dispatch.js +30 -28
  15. package/dist/resources/extensions/gsd/auto-model-selection.js +12 -3
  16. package/dist/resources/extensions/gsd/auto-prompts.js +173 -25
  17. package/dist/resources/extensions/gsd/auto-recovery.js +11 -12
  18. package/dist/resources/extensions/gsd/auto.js +13 -1
  19. package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +32 -1
  20. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +18 -6
  21. package/dist/resources/extensions/gsd/bootstrap/provider-error-resume.js +5 -0
  22. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +59 -5
  23. package/dist/resources/extensions/gsd/bootstrap/register-shortcuts.js +8 -5
  24. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +186 -14
  25. package/dist/resources/extensions/gsd/codebase-generator.js +4 -0
  26. package/dist/resources/extensions/gsd/commands/handlers/core.js +3 -3
  27. package/dist/resources/extensions/gsd/commands-prefs-wizard.js +10 -4
  28. package/dist/resources/extensions/gsd/context-store.js +134 -2
  29. package/dist/resources/extensions/gsd/custom-workflow-engine.js +3 -1
  30. package/dist/resources/extensions/gsd/detection.js +6 -0
  31. package/dist/resources/extensions/gsd/files.js +19 -2
  32. package/dist/resources/extensions/gsd/guided-flow.js +12 -8
  33. package/dist/resources/extensions/gsd/index.js +1 -1
  34. package/dist/resources/extensions/gsd/parallel-monitor-overlay.js +2 -0
  35. package/dist/resources/extensions/gsd/parsers-legacy.js +3 -1
  36. package/dist/resources/extensions/gsd/preferences.js +6 -1
  37. package/dist/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
  38. package/dist/resources/extensions/gsd/prompts/discuss-prepared.md +7 -7
  39. package/dist/resources/extensions/gsd/prompts/discuss.md +3 -3
  40. package/dist/resources/extensions/gsd/prompts/guided-discuss-milestone.md +3 -3
  41. package/dist/resources/extensions/gsd/prompts/guided-discuss-slice.md +3 -1
  42. package/dist/resources/extensions/gsd/prompts/rethink.md +6 -2
  43. package/dist/resources/extensions/gsd/prompts/system.md +1 -1
  44. package/dist/resources/extensions/gsd/prompts/triage-captures.md +1 -1
  45. package/dist/resources/extensions/gsd/prompts/validate-milestone.md +4 -4
  46. package/dist/resources/extensions/gsd/prompts/worktree-merge.md +3 -1
  47. package/dist/resources/extensions/gsd/safety/file-change-validator.js +2 -1
  48. package/dist/resources/extensions/gsd/state.js +2 -1
  49. package/dist/resources/extensions/gsd/visualizer-overlay.js +27 -26
  50. package/dist/resources/extensions/gsd/workflow-reconcile.js +46 -7
  51. package/dist/resources/extensions/remote-questions/manager.js +8 -0
  52. package/dist/resources/extensions/shared/interview-ui.js +10 -0
  53. package/dist/web/standalone/.next/BUILD_ID +1 -1
  54. package/dist/web/standalone/.next/app-path-routes-manifest.json +15 -15
  55. package/dist/web/standalone/.next/build-manifest.json +3 -3
  56. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  57. package/dist/web/standalone/.next/required-server-files.json +3 -3
  58. package/dist/web/standalone/.next/server/app/_global-error/page.js +3 -3
  59. package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  60. package/dist/web/standalone/.next/server/app/_global-error.html +2 -2
  61. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  62. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  63. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  64. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  65. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  66. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  67. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  68. package/dist/web/standalone/.next/server/app/_not-found/page.js +2 -2
  69. package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  70. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  71. package/dist/web/standalone/.next/server/app/_not-found.rsc +3 -3
  72. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +3 -3
  73. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  74. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +3 -3
  75. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  76. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  77. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  78. package/dist/web/standalone/.next/server/app/api/boot/route.js +1 -1
  79. package/dist/web/standalone/.next/server/app/api/boot/route_client-reference-manifest.js +1 -1
  80. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js +1 -1
  81. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route_client-reference-manifest.js +1 -1
  82. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js +1 -1
  83. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route_client-reference-manifest.js +1 -1
  84. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js +2 -2
  85. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route_client-reference-manifest.js +1 -1
  86. package/dist/web/standalone/.next/server/app/api/browse-directories/route.js +1 -1
  87. package/dist/web/standalone/.next/server/app/api/browse-directories/route_client-reference-manifest.js +1 -1
  88. package/dist/web/standalone/.next/server/app/api/captures/route.js +1 -1
  89. package/dist/web/standalone/.next/server/app/api/captures/route_client-reference-manifest.js +1 -1
  90. package/dist/web/standalone/.next/server/app/api/cleanup/route.js +1 -1
  91. package/dist/web/standalone/.next/server/app/api/cleanup/route_client-reference-manifest.js +1 -1
  92. package/dist/web/standalone/.next/server/app/api/dev-mode/route.js +1 -1
  93. package/dist/web/standalone/.next/server/app/api/dev-mode/route_client-reference-manifest.js +1 -1
  94. package/dist/web/standalone/.next/server/app/api/doctor/route.js +1 -1
  95. package/dist/web/standalone/.next/server/app/api/doctor/route_client-reference-manifest.js +1 -1
  96. package/dist/web/standalone/.next/server/app/api/experimental/route.js +2 -2
  97. package/dist/web/standalone/.next/server/app/api/experimental/route_client-reference-manifest.js +1 -1
  98. package/dist/web/standalone/.next/server/app/api/export-data/route.js +1 -1
  99. package/dist/web/standalone/.next/server/app/api/export-data/route_client-reference-manifest.js +1 -1
  100. package/dist/web/standalone/.next/server/app/api/files/route.js +1 -1
  101. package/dist/web/standalone/.next/server/app/api/files/route_client-reference-manifest.js +1 -1
  102. package/dist/web/standalone/.next/server/app/api/forensics/route.js +1 -1
  103. package/dist/web/standalone/.next/server/app/api/forensics/route_client-reference-manifest.js +1 -1
  104. package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
  105. package/dist/web/standalone/.next/server/app/api/git/route_client-reference-manifest.js +1 -1
  106. package/dist/web/standalone/.next/server/app/api/history/route.js +1 -1
  107. package/dist/web/standalone/.next/server/app/api/history/route_client-reference-manifest.js +1 -1
  108. package/dist/web/standalone/.next/server/app/api/hooks/route.js +1 -1
  109. package/dist/web/standalone/.next/server/app/api/hooks/route_client-reference-manifest.js +1 -1
  110. package/dist/web/standalone/.next/server/app/api/inspect/route.js +1 -1
  111. package/dist/web/standalone/.next/server/app/api/inspect/route_client-reference-manifest.js +1 -1
  112. package/dist/web/standalone/.next/server/app/api/knowledge/route.js +1 -1
  113. package/dist/web/standalone/.next/server/app/api/knowledge/route_client-reference-manifest.js +1 -1
  114. package/dist/web/standalone/.next/server/app/api/live-state/route.js +1 -1
  115. package/dist/web/standalone/.next/server/app/api/live-state/route_client-reference-manifest.js +1 -1
  116. package/dist/web/standalone/.next/server/app/api/notifications/route.js +2 -2
  117. package/dist/web/standalone/.next/server/app/api/notifications/route_client-reference-manifest.js +1 -1
  118. package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
  119. package/dist/web/standalone/.next/server/app/api/onboarding/route_client-reference-manifest.js +1 -1
  120. package/dist/web/standalone/.next/server/app/api/preferences/route.js +1 -1
  121. package/dist/web/standalone/.next/server/app/api/preferences/route_client-reference-manifest.js +1 -1
  122. package/dist/web/standalone/.next/server/app/api/projects/route.js +1 -1
  123. package/dist/web/standalone/.next/server/app/api/projects/route_client-reference-manifest.js +1 -1
  124. package/dist/web/standalone/.next/server/app/api/recovery/route.js +1 -1
  125. package/dist/web/standalone/.next/server/app/api/recovery/route_client-reference-manifest.js +1 -1
  126. package/dist/web/standalone/.next/server/app/api/remote-questions/route.js +2 -2
  127. package/dist/web/standalone/.next/server/app/api/remote-questions/route_client-reference-manifest.js +1 -1
  128. package/dist/web/standalone/.next/server/app/api/session/browser/route.js +1 -1
  129. package/dist/web/standalone/.next/server/app/api/session/browser/route_client-reference-manifest.js +1 -1
  130. package/dist/web/standalone/.next/server/app/api/session/command/route.js +1 -1
  131. package/dist/web/standalone/.next/server/app/api/session/command/route_client-reference-manifest.js +1 -1
  132. package/dist/web/standalone/.next/server/app/api/session/events/route.js +2 -2
  133. package/dist/web/standalone/.next/server/app/api/session/events/route_client-reference-manifest.js +1 -1
  134. package/dist/web/standalone/.next/server/app/api/session/manage/route.js +1 -1
  135. package/dist/web/standalone/.next/server/app/api/session/manage/route_client-reference-manifest.js +1 -1
  136. package/dist/web/standalone/.next/server/app/api/settings-data/route.js +1 -1
  137. package/dist/web/standalone/.next/server/app/api/settings-data/route_client-reference-manifest.js +1 -1
  138. package/dist/web/standalone/.next/server/app/api/shutdown/route.js +1 -1
  139. package/dist/web/standalone/.next/server/app/api/shutdown/route_client-reference-manifest.js +1 -1
  140. package/dist/web/standalone/.next/server/app/api/skill-health/route.js +1 -1
  141. package/dist/web/standalone/.next/server/app/api/skill-health/route_client-reference-manifest.js +1 -1
  142. package/dist/web/standalone/.next/server/app/api/steer/route.js +1 -1
  143. package/dist/web/standalone/.next/server/app/api/steer/route_client-reference-manifest.js +1 -1
  144. package/dist/web/standalone/.next/server/app/api/switch-root/route.js +1 -1
  145. package/dist/web/standalone/.next/server/app/api/switch-root/route_client-reference-manifest.js +1 -1
  146. package/dist/web/standalone/.next/server/app/api/terminal/input/route.js +2 -2
  147. package/dist/web/standalone/.next/server/app/api/terminal/input/route_client-reference-manifest.js +1 -1
  148. package/dist/web/standalone/.next/server/app/api/terminal/resize/route.js +2 -2
  149. package/dist/web/standalone/.next/server/app/api/terminal/resize/route_client-reference-manifest.js +1 -1
  150. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js +2 -2
  151. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route_client-reference-manifest.js +1 -1
  152. package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js +4 -4
  153. package/dist/web/standalone/.next/server/app/api/terminal/stream/route_client-reference-manifest.js +1 -1
  154. package/dist/web/standalone/.next/server/app/api/terminal/upload/route.js +1 -1
  155. package/dist/web/standalone/.next/server/app/api/terminal/upload/route_client-reference-manifest.js +1 -1
  156. package/dist/web/standalone/.next/server/app/api/undo/route.js +1 -1
  157. package/dist/web/standalone/.next/server/app/api/undo/route_client-reference-manifest.js +1 -1
  158. package/dist/web/standalone/.next/server/app/api/update/route.js +1 -1
  159. package/dist/web/standalone/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
  160. package/dist/web/standalone/.next/server/app/api/visualizer/route.js +1 -1
  161. package/dist/web/standalone/.next/server/app/api/visualizer/route_client-reference-manifest.js +1 -1
  162. package/dist/web/standalone/.next/server/app/index.html +1 -1
  163. package/dist/web/standalone/.next/server/app/index.rsc +4 -4
  164. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  165. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +4 -4
  166. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  167. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +3 -3
  168. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  169. package/dist/web/standalone/.next/server/app/page.js +2 -2
  170. package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  171. package/dist/web/standalone/.next/server/app-paths-manifest.json +15 -15
  172. package/dist/web/standalone/.next/server/chunks/6897.js +1 -1
  173. package/dist/web/standalone/.next/server/chunks/7471.js +3 -3
  174. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  175. package/dist/web/standalone/.next/server/middleware.js +2 -2
  176. package/dist/web/standalone/.next/server/next-font-manifest.js +1 -1
  177. package/dist/web/standalone/.next/server/next-font-manifest.json +1 -1
  178. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  179. package/dist/web/standalone/.next/server/pages/500.html +2 -2
  180. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  181. package/dist/web/standalone/.next/static/chunks/app/_not-found/{page-2f24283c162b6ab3.js → page-f2a7482d42a5614b.js} +1 -1
  182. package/dist/web/standalone/.next/static/chunks/app/{layout-9ecfd95f343793f0.js → layout-a16c7a7ecdf0c2cf.js} +1 -1
  183. package/dist/web/standalone/.next/static/chunks/app/page-0c485498795110d6.js +1 -0
  184. package/dist/web/standalone/.next/static/chunks/main-app-fdab67f7802d7832.js +1 -0
  185. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-459824ffb8c323dd.js +1 -0
  186. package/dist/web/standalone/node_modules/node-pty/build/Makefile +2 -2
  187. package/dist/web/standalone/node_modules/node-pty/build/Release/pty.node +0 -0
  188. package/dist/web/standalone/node_modules/node-pty/build/pty.target.mk +14 -14
  189. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api.target.mk +14 -14
  190. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_except.target.mk +14 -14
  191. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_maybe.target.mk +14 -14
  192. package/dist/web/standalone/server.js +1 -1
  193. package/package.json +1 -1
  194. package/packages/pi-ai/dist/providers/anthropic-shared.d.ts.map +1 -1
  195. package/packages/pi-ai/dist/providers/anthropic-shared.js +4 -3
  196. package/packages/pi-ai/dist/providers/anthropic-shared.js.map +1 -1
  197. package/packages/pi-ai/dist/utils/json-parse.d.ts.map +1 -1
  198. package/packages/pi-ai/dist/utils/json-parse.js +11 -1
  199. package/packages/pi-ai/dist/utils/json-parse.js.map +1 -1
  200. package/packages/pi-ai/dist/utils/repair-tool-json.d.ts.map +1 -1
  201. package/packages/pi-ai/dist/utils/repair-tool-json.js +60 -1
  202. package/packages/pi-ai/dist/utils/repair-tool-json.js.map +1 -1
  203. package/packages/pi-ai/dist/utils/tests/json-parse.test.d.ts +2 -0
  204. package/packages/pi-ai/dist/utils/tests/json-parse.test.d.ts.map +1 -0
  205. package/packages/pi-ai/dist/utils/tests/json-parse.test.js +14 -0
  206. package/packages/pi-ai/dist/utils/tests/json-parse.test.js.map +1 -0
  207. package/packages/pi-ai/dist/utils/tests/repair-tool-json.test.js +10 -0
  208. package/packages/pi-ai/dist/utils/tests/repair-tool-json.test.js.map +1 -1
  209. package/packages/pi-ai/src/providers/anthropic-shared.ts +4 -3
  210. package/packages/pi-ai/src/utils/json-parse.ts +11 -1
  211. package/packages/pi-ai/src/utils/repair-tool-json.ts +69 -1
  212. package/packages/pi-ai/src/utils/tests/json-parse.test.ts +17 -0
  213. package/packages/pi-ai/src/utils/tests/repair-tool-json.test.ts +13 -0
  214. package/packages/pi-coding-agent/dist/core/agent-session.d.ts +3 -0
  215. package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
  216. package/packages/pi-coding-agent/dist/core/agent-session.js +1 -0
  217. package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
  218. package/packages/pi-coding-agent/dist/core/retry-handler.d.ts +16 -0
  219. package/packages/pi-coding-agent/dist/core/retry-handler.d.ts.map +1 -1
  220. package/packages/pi-coding-agent/dist/core/retry-handler.js +58 -1
  221. package/packages/pi-coding-agent/dist/core/retry-handler.js.map +1 -1
  222. package/packages/pi-coding-agent/dist/core/retry-handler.test.js +58 -0
  223. package/packages/pi-coding-agent/dist/core/retry-handler.test.js.map +1 -1
  224. package/packages/pi-coding-agent/dist/core/sdk.d.ts +3 -0
  225. package/packages/pi-coding-agent/dist/core/sdk.d.ts.map +1 -1
  226. package/packages/pi-coding-agent/dist/core/sdk.js +1 -0
  227. package/packages/pi-coding-agent/dist/core/sdk.js.map +1 -1
  228. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/provider-display-name.test.d.ts +2 -0
  229. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/provider-display-name.test.d.ts.map +1 -0
  230. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/provider-display-name.test.js +17 -0
  231. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/provider-display-name.test.js.map +1 -0
  232. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.d.ts.map +1 -1
  233. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js +2 -1
  234. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js.map +1 -1
  235. package/packages/pi-coding-agent/dist/modes/interactive/components/model-selector.d.ts +1 -0
  236. package/packages/pi-coding-agent/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
  237. package/packages/pi-coding-agent/dist/modes/interactive/components/model-selector.js +9 -2
  238. package/packages/pi-coding-agent/dist/modes/interactive/components/model-selector.js.map +1 -1
  239. package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.d.ts.map +1 -1
  240. package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.js +2 -1
  241. package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.js.map +1 -1
  242. package/packages/pi-coding-agent/dist/modes/interactive/components/scoped-models-selector.d.ts.map +1 -1
  243. package/packages/pi-coding-agent/dist/modes/interactive/components/scoped-models-selector.js +2 -1
  244. package/packages/pi-coding-agent/dist/modes/interactive/components/scoped-models-selector.js.map +1 -1
  245. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +2 -2
  246. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  247. package/packages/pi-coding-agent/package.json +1 -1
  248. package/packages/pi-coding-agent/src/core/agent-session.ts +4 -0
  249. package/packages/pi-coding-agent/src/core/retry-handler.test.ts +69 -0
  250. package/packages/pi-coding-agent/src/core/retry-handler.ts +66 -1
  251. package/packages/pi-coding-agent/src/core/sdk.ts +5 -0
  252. package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/provider-display-name.test.ts +18 -0
  253. package/packages/pi-coding-agent/src/modes/interactive/components/footer.ts +2 -1
  254. package/packages/pi-coding-agent/src/modes/interactive/components/model-selector.ts +11 -2
  255. package/packages/pi-coding-agent/src/modes/interactive/components/provider-manager.ts +2 -1
  256. package/packages/pi-coding-agent/src/modes/interactive/components/scoped-models-selector.ts +2 -1
  257. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +2 -2
  258. package/packages/pi-tui/dist/__tests__/autocomplete.test.js +13 -0
  259. package/packages/pi-tui/dist/__tests__/autocomplete.test.js.map +1 -1
  260. package/packages/pi-tui/dist/__tests__/stdin-buffer.test.d.ts +2 -0
  261. package/packages/pi-tui/dist/__tests__/stdin-buffer.test.d.ts.map +1 -0
  262. package/packages/pi-tui/dist/__tests__/stdin-buffer.test.js +35 -0
  263. package/packages/pi-tui/dist/__tests__/stdin-buffer.test.js.map +1 -0
  264. package/packages/pi-tui/dist/__tests__/tui.test.d.ts +2 -0
  265. package/packages/pi-tui/dist/__tests__/tui.test.d.ts.map +1 -0
  266. package/packages/pi-tui/dist/__tests__/tui.test.js +43 -0
  267. package/packages/pi-tui/dist/__tests__/tui.test.js.map +1 -0
  268. package/packages/pi-tui/dist/autocomplete.d.ts.map +1 -1
  269. package/packages/pi-tui/dist/autocomplete.js +9 -7
  270. package/packages/pi-tui/dist/autocomplete.js.map +1 -1
  271. package/packages/pi-tui/dist/components/__tests__/editor.test.d.ts +2 -0
  272. package/packages/pi-tui/dist/components/__tests__/editor.test.d.ts.map +1 -0
  273. package/packages/pi-tui/dist/components/__tests__/editor.test.js +54 -0
  274. package/packages/pi-tui/dist/components/__tests__/editor.test.js.map +1 -0
  275. package/packages/pi-tui/dist/components/editor.d.ts +3 -1
  276. package/packages/pi-tui/dist/components/editor.d.ts.map +1 -1
  277. package/packages/pi-tui/dist/components/editor.js +14 -3
  278. package/packages/pi-tui/dist/components/editor.js.map +1 -1
  279. package/packages/pi-tui/dist/stdin-buffer.d.ts.map +1 -1
  280. package/packages/pi-tui/dist/stdin-buffer.js +6 -0
  281. package/packages/pi-tui/dist/stdin-buffer.js.map +1 -1
  282. package/packages/pi-tui/dist/tui.d.ts.map +1 -1
  283. package/packages/pi-tui/dist/tui.js +8 -0
  284. package/packages/pi-tui/dist/tui.js.map +1 -1
  285. package/packages/pi-tui/src/__tests__/autocomplete.test.ts +15 -0
  286. package/packages/pi-tui/src/__tests__/stdin-buffer.test.ts +43 -0
  287. package/packages/pi-tui/src/__tests__/tui.test.ts +50 -0
  288. package/packages/pi-tui/src/autocomplete.ts +9 -7
  289. package/packages/pi-tui/src/components/__tests__/editor.test.ts +64 -0
  290. package/packages/pi-tui/src/components/editor.ts +14 -3
  291. package/packages/pi-tui/src/stdin-buffer.ts +7 -0
  292. package/packages/pi-tui/src/tui.ts +9 -0
  293. package/pkg/package.json +1 -1
  294. package/src/resources/extensions/ask-user-questions.ts +103 -11
  295. package/src/resources/extensions/claude-code-cli/partial-builder.ts +4 -3
  296. package/src/resources/extensions/claude-code-cli/readiness.ts +67 -12
  297. package/src/resources/extensions/claude-code-cli/stream-adapter.ts +12 -3
  298. package/src/resources/extensions/claude-code-cli/tests/partial-builder.test.ts +17 -0
  299. package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +18 -0
  300. package/src/resources/extensions/gsd/auto/loop-deps.ts +2 -1
  301. package/src/resources/extensions/gsd/auto/loop.ts +14 -1
  302. package/src/resources/extensions/gsd/auto/phases.ts +27 -4
  303. package/src/resources/extensions/gsd/auto/run-unit.ts +14 -2
  304. package/src/resources/extensions/gsd/auto/session.ts +1 -1
  305. package/src/resources/extensions/gsd/auto-dashboard.ts +76 -16
  306. package/src/resources/extensions/gsd/auto-dispatch.ts +36 -35
  307. package/src/resources/extensions/gsd/auto-model-selection.ts +12 -3
  308. package/src/resources/extensions/gsd/auto-prompts.ts +195 -25
  309. package/src/resources/extensions/gsd/auto-recovery.ts +15 -15
  310. package/src/resources/extensions/gsd/auto.ts +12 -1
  311. package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +34 -1
  312. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +27 -6
  313. package/src/resources/extensions/gsd/bootstrap/provider-error-resume.ts +6 -0
  314. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +67 -6
  315. package/src/resources/extensions/gsd/bootstrap/register-shortcuts.ts +11 -8
  316. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +209 -16
  317. package/src/resources/extensions/gsd/codebase-generator.ts +4 -0
  318. package/src/resources/extensions/gsd/commands/handlers/core.ts +6 -6
  319. package/src/resources/extensions/gsd/commands-prefs-wizard.ts +11 -4
  320. package/src/resources/extensions/gsd/context-store.ts +167 -2
  321. package/src/resources/extensions/gsd/custom-workflow-engine.ts +3 -1
  322. package/src/resources/extensions/gsd/detection.ts +6 -0
  323. package/src/resources/extensions/gsd/files.ts +21 -2
  324. package/src/resources/extensions/gsd/guided-flow.ts +15 -8
  325. package/src/resources/extensions/gsd/index.ts +6 -0
  326. package/src/resources/extensions/gsd/parallel-monitor-overlay.ts +2 -0
  327. package/src/resources/extensions/gsd/parsers-legacy.ts +3 -1
  328. package/src/resources/extensions/gsd/preferences.ts +6 -1
  329. package/src/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
  330. package/src/resources/extensions/gsd/prompts/discuss-prepared.md +7 -7
  331. package/src/resources/extensions/gsd/prompts/discuss.md +3 -3
  332. package/src/resources/extensions/gsd/prompts/guided-discuss-milestone.md +3 -3
  333. package/src/resources/extensions/gsd/prompts/guided-discuss-slice.md +3 -1
  334. package/src/resources/extensions/gsd/prompts/rethink.md +6 -2
  335. package/src/resources/extensions/gsd/prompts/system.md +1 -1
  336. package/src/resources/extensions/gsd/prompts/triage-captures.md +1 -1
  337. package/src/resources/extensions/gsd/prompts/validate-milestone.md +4 -4
  338. package/src/resources/extensions/gsd/prompts/worktree-merge.md +3 -1
  339. package/src/resources/extensions/gsd/safety/file-change-validator.ts +4 -1
  340. package/src/resources/extensions/gsd/state.ts +2 -1
  341. package/src/resources/extensions/gsd/tests/auto-dashboard.test.ts +52 -1
  342. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +50 -2
  343. package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +21 -7
  344. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +48 -0
  345. package/src/resources/extensions/gsd/tests/codebase-generator.test.ts +22 -0
  346. package/src/resources/extensions/gsd/tests/context-store.test.ts +176 -0
  347. package/src/resources/extensions/gsd/tests/core-overlay-fallback.test.ts +44 -0
  348. package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +7 -1
  349. package/src/resources/extensions/gsd/tests/custom-workflow-engine.test.ts +31 -0
  350. package/src/resources/extensions/gsd/tests/decision-scope-cascade.test.ts +370 -0
  351. package/src/resources/extensions/gsd/tests/detection.test.ts +37 -0
  352. package/src/resources/extensions/gsd/tests/file-change-validator.test.ts +50 -0
  353. package/src/resources/extensions/gsd/tests/gsd-tools.test.ts +35 -0
  354. package/src/resources/extensions/gsd/tests/guided-flow-session-isolation.test.ts +34 -0
  355. package/src/resources/extensions/gsd/tests/health-widget.test.ts +45 -0
  356. package/src/resources/extensions/gsd/tests/integration/auto-recovery.test.ts +53 -13
  357. package/src/resources/extensions/gsd/tests/integration/state-machine-runtime-failures.test.ts +2 -2
  358. package/src/resources/extensions/gsd/tests/journal-integration.test.ts +3 -3
  359. package/src/resources/extensions/gsd/tests/measurement.test.ts +531 -0
  360. package/src/resources/extensions/gsd/tests/migrate-writer-integration.test.ts +3 -4
  361. package/src/resources/extensions/gsd/tests/parallel-monitor-overlay.test.ts +21 -0
  362. package/src/resources/extensions/gsd/tests/parallel-research-dispatch.test.ts +71 -2
  363. package/src/resources/extensions/gsd/tests/parsers.test.ts +25 -0
  364. package/src/resources/extensions/gsd/tests/preferences.test.ts +20 -0
  365. package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +8 -1
  366. package/src/resources/extensions/gsd/tests/provider-errors.test.ts +60 -0
  367. package/src/resources/extensions/gsd/tests/queue-execution-guard.test.ts +9 -0
  368. package/src/resources/extensions/gsd/tests/reactive-graph.test.ts +19 -0
  369. package/src/resources/extensions/gsd/tests/register-shortcuts.test.ts +73 -0
  370. package/src/resources/extensions/gsd/tests/remote-questions.test.ts +98 -0
  371. package/src/resources/extensions/gsd/tests/smart-entry-complete.test.ts +2 -2
  372. package/src/resources/extensions/gsd/tests/validate-milestone.test.ts +26 -0
  373. package/src/resources/extensions/gsd/tests/visualizer-overlay.test.ts +59 -0
  374. package/src/resources/extensions/gsd/tests/workflow-reconcile.test.ts +91 -0
  375. package/src/resources/extensions/gsd/tests/write-gate.test.ts +210 -35
  376. package/src/resources/extensions/gsd/visualizer-overlay.ts +31 -27
  377. package/src/resources/extensions/gsd/workflow-reconcile.ts +59 -8
  378. package/src/resources/extensions/remote-questions/manager.ts +9 -0
  379. package/src/resources/extensions/shared/interview-ui.ts +13 -0
  380. package/dist/web/standalone/.next/static/chunks/app/page-62be3b5fa91e4c8f.js +0 -1
  381. package/dist/web/standalone/.next/static/chunks/main-app-d3d4c336195465f9.js +0 -1
  382. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-ab5a8926e07ec673.js +0 -1
  383. /package/dist/web/standalone/.next/static/{y5P0reMrCMs-4-gswdawm → FRT6f5ou3wPxpZ7ojoB7E}/_buildManifest.js +0 -0
  384. /package/dist/web/standalone/.next/static/{y5P0reMrCMs-4-gswdawm → FRT6f5ou3wPxpZ7ojoB7E}/_ssgManifest.js +0 -0
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Check if the `claude` binary is installed (regardless of auth state).
3
+ */
4
+ export declare function isClaudeBinaryInstalled(): boolean;
5
+ /**
6
+ * Check if the `claude` CLI is installed AND authenticated.
7
+ */
8
+ export declare function isClaudeCliReady(): boolean;
@@ -0,0 +1,36 @@
1
+ // GSD2 — Claude CLI binary detection for onboarding
2
+ // Lightweight check used at onboarding time (before extensions load).
3
+ // The full readiness check with caching lives in the claude-code-cli extension.
4
+ import { execFileSync } from 'node:child_process';
5
+ /**
6
+ * Check if the `claude` binary is installed (regardless of auth state).
7
+ */
8
+ export function isClaudeBinaryInstalled() {
9
+ try {
10
+ execFileSync('claude', ['--version'], { timeout: 5_000, stdio: 'pipe' });
11
+ return true;
12
+ }
13
+ catch {
14
+ return false;
15
+ }
16
+ }
17
+ /**
18
+ * Check if the `claude` CLI is installed AND authenticated.
19
+ */
20
+ export function isClaudeCliReady() {
21
+ try {
22
+ execFileSync('claude', ['--version'], { timeout: 5_000, stdio: 'pipe' });
23
+ }
24
+ catch {
25
+ return false;
26
+ }
27
+ try {
28
+ const output = execFileSync('claude', ['auth', 'status'], { timeout: 5_000, stdio: 'pipe' })
29
+ .toString()
30
+ .toLowerCase();
31
+ return !(/not logged in|no credentials|unauthenticated|not authenticated/i.test(output));
32
+ }
33
+ catch {
34
+ return false;
35
+ }
36
+ }
package/dist/cli.js CHANGED
@@ -395,8 +395,28 @@ if (isPrintMode) {
395
395
  settingsManager,
396
396
  sessionManager,
397
397
  resourceLoader,
398
+ isClaudeCodeReady: () => modelRegistry.isProviderRequestReady('claude-code'),
398
399
  });
399
400
  markStartup('createAgentSession');
401
+ // Migrate anthropic OAuth users to claude-code provider when CLI is available (#3772).
402
+ // Anthropic blocks third-party apps from using subscription quotas — routing through
403
+ // the local claude CLI binary is TOS-compliant.
404
+ if (modelRegistry.isProviderRequestReady('claude-code') && settingsManager.getDefaultProvider() === 'anthropic') {
405
+ const currentModelId = settingsManager.getDefaultModel();
406
+ if (currentModelId) {
407
+ const ccModel = modelRegistry.find('claude-code', currentModelId);
408
+ if (ccModel) {
409
+ try {
410
+ await session.setModel(ccModel);
411
+ // Only persist after successful session switch to avoid desync
412
+ settingsManager.setDefaultModelAndProvider('claude-code', currentModelId);
413
+ }
414
+ catch {
415
+ // claude-code provider not ready — leave both session and settings unchanged
416
+ }
417
+ }
418
+ }
419
+ }
400
420
  // Validate configured model AFTER extensions have registered their models (#2626).
401
421
  // Before this, extension-provided models (e.g. claude-code/*) were not yet in the
402
422
  // registry, causing the user's valid choice to be silently overwritten.
@@ -550,8 +570,28 @@ const { session, extensionsResult, modelFallbackMessage: interactiveFallbackMsg
550
570
  settingsManager,
551
571
  sessionManager,
552
572
  resourceLoader,
573
+ isClaudeCodeReady: () => modelRegistry.isProviderRequestReady('claude-code'),
553
574
  });
554
575
  markStartup('createAgentSession');
576
+ // Migrate anthropic OAuth users to claude-code provider when CLI is available (#3772).
577
+ // Anthropic blocks third-party apps from using subscription quotas — routing through
578
+ // the local claude CLI binary is TOS-compliant.
579
+ if (modelRegistry.isProviderRequestReady('claude-code') && settingsManager.getDefaultProvider() === 'anthropic') {
580
+ const currentModelId = settingsManager.getDefaultModel();
581
+ if (currentModelId) {
582
+ const ccModel = modelRegistry.find('claude-code', currentModelId);
583
+ if (ccModel) {
584
+ try {
585
+ await session.setModel(ccModel);
586
+ // Only persist after successful session switch to avoid desync
587
+ settingsManager.setDefaultModelAndProvider('claude-code', currentModelId);
588
+ }
589
+ catch {
590
+ // claude-code provider not ready — leave both session and settings unchanged
591
+ }
592
+ }
593
+ }
594
+ }
555
595
  // Validate configured model AFTER extensions have registered their models (#2626).
556
596
  // Before this, extension-provided models (e.g. claude-code/*) were not yet in the
557
597
  // registry, causing the user's valid choice to be silently overwritten.
@@ -14,6 +14,7 @@ import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
14
14
  import { dirname, join } from 'node:path';
15
15
  import { renderLogo } from './logo.js';
16
16
  import { agentDir } from './app-paths.js';
17
+ import { isClaudeCliReady } from './claude-cli-check.js';
17
18
  // ─── Constants ────────────────────────────────────────────────────────────────
18
19
  const TOOL_KEYS = [
19
20
  {
@@ -39,6 +40,7 @@ const TOOL_KEYS = [
39
40
  const LLM_PROVIDER_IDS = [
40
41
  'anthropic',
41
42
  'anthropic-vertex',
43
+ 'claude-code',
42
44
  'openai',
43
45
  'github-copilot',
44
46
  'openai-codex',
@@ -255,7 +257,12 @@ async function runLlmStep(p, pc, authStorage) {
255
257
  if (existingAuth) {
256
258
  authOptions.push({ value: 'keep', label: `Keep current (${existingAuth})`, hint: 'already configured' });
257
259
  }
258
- authOptions.push({ value: 'browser', label: 'Sign in with your browser', hint: 'recommended same login as claude.ai / ChatGPT' }, { value: 'api-key', label: 'Paste an API key', hint: 'from your provider dashboard' }, { value: 'skip', label: 'Skip for now', hint: 'use /login inside GSD later' });
260
+ // Show Claude Code CLI option at the top when the CLI is installed and authenticated (#3772).
261
+ // This is the only TOS-compliant path for Anthropic subscription users.
262
+ if (isClaudeCliReady()) {
263
+ authOptions.push({ value: 'claude-cli', label: 'Use Claude Code CLI', hint: 'recommended — uses your existing Claude subscription' });
264
+ }
265
+ authOptions.push({ value: 'browser', label: 'Sign in with your browser', hint: 'GitHub Copilot, ChatGPT, Google, etc.' }, { value: 'api-key', label: 'Paste an API key', hint: 'from your provider dashboard' }, { value: 'skip', label: 'Skip for now', hint: 'use /login inside GSD later' });
259
266
  const method = await p.select({
260
267
  message: existingAuth ? `LLM provider: ${existingAuth} — change it?` : 'How do you want to sign in?',
261
268
  options: authOptions,
@@ -264,12 +271,22 @@ async function runLlmStep(p, pc, authStorage) {
264
271
  return false;
265
272
  if (method === 'keep')
266
273
  return true;
274
+ // ── Claude Code CLI path (#3772) ────────────────────────────────────────
275
+ if (method === 'claude-cli') {
276
+ p.log.success('Claude Code CLI detected — routing through local CLI (TOS-compliant)');
277
+ p.log.info('Your Claude subscription will be used for inference. No API key needed.');
278
+ // Store sentinel so hasAuth('claude-code') returns true on future boots
279
+ authStorage.set('claude-code', { type: 'api_key', key: 'cli' });
280
+ return true;
281
+ }
267
282
  // ── Step 2: Which provider? ──────────────────────────────────────────────
268
283
  if (method === 'browser') {
284
+ // Anthropic OAuth is removed from browser auth — it violates Anthropic TOS for
285
+ // third-party apps (#3772). Anthropic subscription users should use the Claude
286
+ // Code CLI path (shown above when CLI is installed) or paste an API key.
269
287
  const provider = await p.select({
270
288
  message: 'Choose provider',
271
289
  options: [
272
- { value: 'anthropic', label: 'Anthropic (Claude)', hint: 'recommended' },
273
290
  { value: 'github-copilot', label: 'GitHub Copilot' },
274
291
  { value: 'openai-codex', label: 'ChatGPT Plus/Pro (Codex)' },
275
292
  { value: 'google-gemini-cli', label: 'Google Gemini CLI' },
@@ -58,6 +58,51 @@ export function questionSignature(questions) {
58
58
  export function resetAskUserQuestionsCache() {
59
59
  turnCache.clear();
60
60
  }
61
+ /**
62
+ * Race a remote channel dispatch against the local TUI. The first to produce
63
+ * a valid (non-error, non-timeout) result wins. The loser is cancelled via
64
+ * the shared AbortController.
65
+ *
66
+ * If the local TUI responds first, the remote poll is aborted (the message
67
+ * stays in Discord/Slack but polling stops). If remote responds first, the
68
+ * local TUI prompt is cancelled.
69
+ *
70
+ * Returns null only when both sides fail or are cancelled.
71
+ */
72
+ async function raceRemoteAndLocal(startRemote, startLocal, controller, questions) {
73
+ // Wrap local TUI result into the same shape as remote results
74
+ const localPromise = startLocal().then((result) => {
75
+ if (!result || Object.keys(result.answers).length === 0)
76
+ return null;
77
+ return {
78
+ content: [{ type: "text", text: formatForLLM(result) }],
79
+ details: { questions, response: result, cancelled: false },
80
+ };
81
+ }).catch(() => null);
82
+ const remotePromise = startRemote().then((result) => {
83
+ if (!result)
84
+ return null;
85
+ const details = result.details;
86
+ // Treat timeouts and errors as non-wins — let the local TUI win instead
87
+ if (details?.timed_out || details?.error)
88
+ return null;
89
+ return result;
90
+ }).catch(() => null);
91
+ // Race: first non-null result wins
92
+ const winner = await Promise.race([
93
+ localPromise.then((r) => r ? { source: "local", result: r } : null),
94
+ remotePromise.then((r) => r ? { source: "remote", result: r } : null),
95
+ ]);
96
+ if (winner) {
97
+ // Cancel the loser
98
+ controller.abort();
99
+ return winner.result;
100
+ }
101
+ // First to resolve was null — wait for the other
102
+ const [localResult, remoteResult] = await Promise.all([localPromise, remotePromise]);
103
+ controller.abort();
104
+ return localResult ?? remoteResult;
105
+ }
61
106
  // ─── Helpers ──────────────────────────────────────────────────────────────────
62
107
  const OTHER_OPTION_LABEL = "None of the above";
63
108
  function errorResult(message, questions = []) {
@@ -116,19 +161,42 @@ export default function AskUserQuestions(pi) {
116
161
  return errorResult(`Error: ask_user_questions requires non-empty options for every question (question "${q.id}" has none)`, params.questions);
117
162
  }
118
163
  }
119
- // Try remote first if configured (works in both interactive and headless modes).
120
- // tryRemoteQuestions returns null when no remote channel is configured, so
121
- // this is a no-op when the user has not set up Slack/Discord/Telegram.
122
- const { tryRemoteQuestions } = await import("./remote-questions/manager.js");
123
- const remoteResult = await tryRemoteQuestions(params.questions, signal);
124
- if (remoteResult) {
125
- // Cache successful remote results to prevent duplicate Discord dispatches
126
- const remoteDetails = remoteResult.details;
127
- if (remoteDetails && !remoteDetails.timed_out && !remoteDetails.error) {
128
- turnCache.set(sig, remoteResult);
164
+ // ── Routing: race remote + local, remote-only, or local-only ────────
165
+ const { tryRemoteQuestions, isRemoteConfigured } = await import("./remote-questions/manager.js");
166
+ const hasRemote = isRemoteConfigured();
167
+ // Case 1: Both remote and local UI available — race them.
168
+ // The first response wins; the loser is cancelled via AbortController.
169
+ if (hasRemote && ctx.hasUI) {
170
+ const raceController = new AbortController();
171
+ // Merge the parent signal so external cancellation propagates.
172
+ const onParentAbort = () => raceController.abort();
173
+ signal?.addEventListener("abort", onParentAbort, { once: true });
174
+ const raceSignal = raceController.signal;
175
+ const raceResult = await raceRemoteAndLocal(() => tryRemoteQuestions(params.questions, raceSignal), () => showInterviewRound(params.questions, { signal: raceSignal }, ctx), raceController, params.questions);
176
+ signal?.removeEventListener("abort", onParentAbort);
177
+ if (raceResult) {
178
+ const details = raceResult.details;
179
+ if (details && !details.timed_out && !details.error && !details.cancelled) {
180
+ turnCache.set(sig, raceResult);
181
+ }
182
+ return { ...raceResult, details: raceResult.details };
183
+ }
184
+ // Both sides failed/cancelled — fall through to error
185
+ return errorResult("ask_user_questions: no response received from local UI or remote channel", params.questions);
186
+ }
187
+ // Case 2: Remote configured but no local UI (headless) — remote only.
188
+ if (hasRemote && !ctx.hasUI) {
189
+ const remoteResult = await tryRemoteQuestions(params.questions, signal);
190
+ if (remoteResult) {
191
+ const remoteDetails = remoteResult.details;
192
+ if (remoteDetails && !remoteDetails.timed_out && !remoteDetails.error) {
193
+ turnCache.set(sig, remoteResult);
194
+ }
195
+ return { ...remoteResult, details: remoteResult.details };
129
196
  }
130
- return { ...remoteResult, details: remoteResult.details };
197
+ return errorResult("Error: remote channel configured but returned no result", params.questions);
131
198
  }
199
+ // Case 3: No remote — local UI only.
132
200
  if (!ctx.hasUI) {
133
201
  return errorResult("Error: UI not available (non-interactive mode)", params.questions);
134
202
  }
@@ -4,7 +4,7 @@
4
4
  * Translates the Claude Agent SDK's `BetaRawMessageStreamEvent` sequence
5
5
  * into GSD's `AssistantMessageEvent` deltas for incremental TUI rendering.
6
6
  */
7
- import { repairToolJson } from "@gsd/pi-ai";
7
+ import { hasXmlParameterTags, repairToolJson } from "@gsd/pi-ai";
8
8
  // ---------------------------------------------------------------------------
9
9
  // Content-block mapping helpers
10
10
  // ---------------------------------------------------------------------------
@@ -207,14 +207,15 @@ export class PartialMessageBuilder {
207
207
  }
208
208
  if (block.type === "toolCall") {
209
209
  const jsonStr = this.toolJsonAccum.get(streamIndex) ?? "{}";
210
+ const jsonForParse = hasXmlParameterTags(jsonStr) ? repairToolJson(jsonStr) : jsonStr;
210
211
  try {
211
- block.arguments = JSON.parse(jsonStr);
212
+ block.arguments = JSON.parse(jsonForParse);
212
213
  }
213
214
  catch {
214
215
  // JSON.parse failed — attempt repair for YAML-style bullet
215
216
  // lists that LLMs copy from template formatting (#2660).
216
217
  try {
217
- block.arguments = JSON.parse(repairToolJson(jsonStr));
218
+ block.arguments = JSON.parse(repairToolJson(jsonForParse));
218
219
  }
219
220
  catch {
220
221
  // Repair also failed — stream was truncated or garbage.
@@ -1,26 +1,77 @@
1
1
  /**
2
2
  * Readiness check for the Claude Code CLI provider.
3
3
  *
4
- * Verifies the `claude` binary is installed and responsive.
5
- * Result is cached for 30 seconds to avoid shelling out on every
4
+ * Verifies the `claude` binary is installed, responsive, AND authenticated.
5
+ * Results are cached for 30 seconds to avoid shelling out on every
6
6
  * model-availability check.
7
+ *
8
+ * Auth verification follows the T3 Code pattern: run `claude auth status`
9
+ * and check the exit code + output for an authenticated session.
7
10
  */
8
- import { execSync } from "node:child_process";
9
- let cachedReady = null;
11
+ import { execFileSync } from "node:child_process";
12
+ let cachedBinaryPresent = null;
13
+ let cachedAuthed = null;
10
14
  let lastCheckMs = 0;
11
15
  const CHECK_INTERVAL_MS = 30_000;
12
- export function isClaudeCodeReady() {
16
+ function refreshCache() {
13
17
  const now = Date.now();
14
- if (cachedReady !== null && now - lastCheckMs < CHECK_INTERVAL_MS) {
15
- return cachedReady;
18
+ if (cachedBinaryPresent !== null && now - lastCheckMs < CHECK_INTERVAL_MS) {
19
+ return;
16
20
  }
21
+ // Set timestamp first to prevent re-entrant checks during the same window
22
+ lastCheckMs = now;
23
+ // Check binary presence
17
24
  try {
18
- execSync("claude --version", { timeout: 5_000, stdio: "pipe" });
19
- cachedReady = true;
25
+ execFileSync("claude", ["--version"], { timeout: 5_000, stdio: "pipe" });
26
+ cachedBinaryPresent = true;
20
27
  }
21
28
  catch {
22
- cachedReady = false;
29
+ cachedBinaryPresent = false;
30
+ cachedAuthed = false;
31
+ return;
23
32
  }
24
- lastCheckMs = now;
25
- return cachedReady;
33
+ // Check auth status — exit code 0 with non-error output means authenticated
34
+ try {
35
+ const output = execFileSync("claude", ["auth", "status"], { timeout: 5_000, stdio: "pipe" })
36
+ .toString()
37
+ .toLowerCase();
38
+ // The CLI outputs "not logged in", "no credentials", or similar when unauthenticated
39
+ cachedAuthed = !(/not logged in|no credentials|unauthenticated|not authenticated/i.test(output));
40
+ }
41
+ catch {
42
+ // Non-zero exit code means not authenticated
43
+ cachedAuthed = false;
44
+ }
45
+ }
46
+ /**
47
+ * Whether the `claude` binary is installed (regardless of auth state).
48
+ */
49
+ export function isClaudeBinaryPresent() {
50
+ refreshCache();
51
+ return cachedBinaryPresent ?? false;
52
+ }
53
+ /**
54
+ * Whether the `claude` CLI is authenticated with a valid session.
55
+ * Returns false if the binary is not installed.
56
+ */
57
+ export function isClaudeCodeAuthed() {
58
+ refreshCache();
59
+ return (cachedBinaryPresent ?? false) && (cachedAuthed ?? false);
60
+ }
61
+ /**
62
+ * Full readiness check: binary installed AND authenticated.
63
+ * This is the gating function used by the provider registration.
64
+ */
65
+ export function isClaudeCodeReady() {
66
+ refreshCache();
67
+ return (cachedBinaryPresent ?? false) && (cachedAuthed ?? false);
68
+ }
69
+ /**
70
+ * Force-clear the cached readiness state.
71
+ * Useful after the user completes auth setup so the next check is fresh.
72
+ */
73
+ export function clearReadinessCache() {
74
+ cachedBinaryPresent = null;
75
+ cachedAuthed = null;
76
+ lastCheckMs = 0;
26
77
  }
@@ -29,6 +29,15 @@ function createAssistantStream() {
29
29
  // Claude binary resolution
30
30
  // ---------------------------------------------------------------------------
31
31
  let cachedClaudePath = null;
32
+ export function getClaudeLookupCommand(platform = process.platform) {
33
+ return platform === "win32" ? "where claude" : "which claude";
34
+ }
35
+ export function parseClaudeLookupOutput(output) {
36
+ return output
37
+ .toString()
38
+ .trim()
39
+ .split(/\r?\n/)[0] ?? "";
40
+ }
32
41
  /**
33
42
  * Resolve the path to the system-installed `claude` binary.
34
43
  * The SDK defaults to a bundled cli.js which doesn't exist when
@@ -38,9 +47,7 @@ function getClaudePath() {
38
47
  if (cachedClaudePath)
39
48
  return cachedClaudePath;
40
49
  try {
41
- cachedClaudePath = execSync("which claude", { timeout: 5_000, stdio: "pipe" })
42
- .toString()
43
- .trim();
50
+ cachedClaudePath = parseClaudeLookupOutput(execSync(getClaudeLookupCommand(), { timeout: 5_000, stdio: "pipe" }));
44
51
  }
45
52
  catch {
46
53
  cachedClaudePath = "claude"; // fall back to PATH resolution
@@ -150,7 +150,7 @@ export async function autoLoop(ctx, pi, s, deps) {
150
150
  }
151
151
  // Verification passed — mark step complete
152
152
  debugLog("autoLoop", { phase: "custom-engine-reconcile", iteration, unitId: iterData.unitId });
153
- await engine.reconcile(engineState, {
153
+ const reconcileResult = await engine.reconcile(engineState, {
154
154
  unitType: iterData.unitType,
155
155
  unitId: iterData.unitId,
156
156
  startedAt: s.currentUnit?.startedAt ?? Date.now(),
@@ -161,6 +161,18 @@ export async function autoLoop(ctx, pi, s, deps) {
161
161
  recentErrorMessages.length = 0;
162
162
  deps.emitJournalEvent({ ts: new Date().toISOString(), flowId, seq: nextSeq(), eventType: "iteration-end", data: { iteration } });
163
163
  debugLog("autoLoop", { phase: "iteration-complete", iteration });
164
+ if (reconcileResult.outcome === "milestone-complete") {
165
+ await deps.stopAuto(ctx, pi, "Workflow complete");
166
+ break;
167
+ }
168
+ if (reconcileResult.outcome === "pause") {
169
+ await deps.pauseAuto(ctx, pi);
170
+ break;
171
+ }
172
+ if (reconcileResult.outcome === "stop") {
173
+ await deps.stopAuto(ctx, pi, reconcileResult.reason ?? "Engine stopped");
174
+ break;
175
+ }
164
176
  continue;
165
177
  }
166
178
  if (!sidecarItem) {
@@ -338,7 +338,13 @@ export async function runPreDispatch(ic, loopState) {
338
338
  ctx.ui.notify(`Milestone ${mid} has no title in roadmap — using ID as fallback.`, "warning");
339
339
  }
340
340
  // Mid-merge safety check
341
- if (deps.reconcileMergeState(s.basePath, ctx)) {
341
+ const mergeReconcileResult = deps.reconcileMergeState(s.basePath, ctx);
342
+ if (mergeReconcileResult === "blocked") {
343
+ await deps.pauseAuto(ctx, pi);
344
+ debugLog("autoLoop", { phase: "exit", reason: "merge-reconciliation-blocked" });
345
+ return { action: "break", reason: "merge-reconciliation-blocked" };
346
+ }
347
+ if (mergeReconcileResult === "reconciled") {
342
348
  deps.invalidateAllCaches();
343
349
  state = await deps.deriveState(s.basePath);
344
350
  mid = state.activeMilestone?.id;
@@ -947,8 +953,21 @@ export async function runUnitPhase(ic, iterData, loopState, sidecarItem) {
947
953
  debugLog("autoLoop", { phase: "exit", reason: "provider-pause", isTransient: unitResult.errorContext.isTransient });
948
954
  return { action: "break", reason: "provider-pause" };
949
955
  }
950
- ctx.ui.notify(`Session creation timed out or was cancelled for ${unitType} ${unitId}. Will retry.`, "warning");
951
- await deps.stopAuto(ctx, pi, "Session creation failed");
956
+ // Session creation timeout (not a structural error): pause auto-mode
957
+ // and let the provider-error-resume timer handle recovery (#3767). This
958
+ // matches the provider-pause path — break out cleanly, don't hard-stop.
959
+ // Structural errors (TypeError, is not a function) are NOT transient
960
+ // and must hard-stop to avoid infinite retry loops.
961
+ if (unitResult.errorContext?.isTransient &&
962
+ unitResult.errorContext?.category === "timeout") {
963
+ ctx.ui.notify(`Session creation timed out for ${unitType} ${unitId}. Pausing auto-mode (recoverable).`, "warning");
964
+ debugLog("autoLoop", { phase: "session-timeout-pause", unitType, unitId });
965
+ await deps.pauseAuto(ctx, pi);
966
+ return { action: "break", reason: "session-timeout" };
967
+ }
968
+ // All other cancelled states (structural errors, non-transient failures): hard stop
969
+ ctx.ui.notify(`Session creation failed for ${unitType} ${unitId}: ${unitResult.errorContext?.message ?? "unknown"}. Stopping auto-mode.`, "warning");
970
+ await deps.stopAuto(ctx, pi, `Session creation failed: ${unitResult.errorContext?.message ?? "unknown"}`);
952
971
  debugLog("autoLoop", { phase: "exit", reason: "session-failed" });
953
972
  return { action: "break", reason: "session-failed" };
954
973
  }
@@ -7,6 +7,10 @@ import { NEW_SESSION_TIMEOUT_MS } from "./session.js";
7
7
  import { _setCurrentResolve, _setSessionSwitchInFlight } from "./resolve.js";
8
8
  import { debugLog } from "../debug-logger.js";
9
9
  import { logWarning } from "../workflow-logger.js";
10
+ import { resolveAutoSupervisorConfig } from "../preferences.js";
11
+ // Tracks the latest session-switch attempt so a late timeout settlement from an
12
+ // older runUnit() call cannot clear the guard for a newer one.
13
+ let sessionSwitchGeneration = 0;
10
14
  /**
11
15
  * Execute a single unit: create a new session, send the prompt, and await
12
16
  * the agent_end promise. Returns a UnitResult describing what happened.
@@ -21,10 +25,13 @@ export async function runUnit(ctx, pi, s, unitType, unitId, prompt) {
21
25
  debugLog("runUnit", { phase: "session-create", unitType, unitId });
22
26
  let sessionResult;
23
27
  let sessionTimeoutHandle;
28
+ const mySessionSwitchGeneration = ++sessionSwitchGeneration;
24
29
  _setSessionSwitchInFlight(true);
25
30
  try {
26
31
  const sessionPromise = s.cmdCtx.newSession().finally(() => {
27
- _setSessionSwitchInFlight(false);
32
+ if (sessionSwitchGeneration === mySessionSwitchGeneration) {
33
+ _setSessionSwitchInFlight(false);
34
+ }
28
35
  });
29
36
  const timeoutPromise = new Promise((resolve) => {
30
37
  sessionTimeoutHandle = setTimeout(() => resolve({ cancelled: true }), NEW_SESSION_TIMEOUT_MS);
@@ -83,7 +90,8 @@ export async function runUnit(ctx, pi, s, unitType, unitId, prompt) {
83
90
  // If supervision fails to resolve unitPromise within 30s, treat as cancelled.
84
91
  // Without this, a crashed agent that never emits agent_end hangs the loop (#3161).
85
92
  debugLog("runUnit", { phase: "awaiting-agent-end", unitType, unitId });
86
- const UNIT_HARD_TIMEOUT_MS = 30_000;
93
+ const supervisor = resolveAutoSupervisorConfig();
94
+ const UNIT_HARD_TIMEOUT_MS = Math.max(30_000, ((supervisor.hard_timeout_minutes ?? 30) * 60 * 1000) + 30_000);
87
95
  let unitTimeoutHandle;
88
96
  const timeoutResult = new Promise((resolve) => {
89
97
  unitTimeoutHandle = setTimeout(() => {
@@ -19,7 +19,7 @@
19
19
  export const MAX_UNIT_DISPATCHES = 3;
20
20
  export const STUB_RECOVERY_THRESHOLD = 2;
21
21
  export const MAX_LIFETIME_DISPATCHES = 6;
22
- export const NEW_SESSION_TIMEOUT_MS = 30_000;
22
+ export const NEW_SESSION_TIMEOUT_MS = 120_000;
23
23
  // ─── AutoSession ─────────────────────────────────────────────────────────────
24
24
  export class AutoSession {
25
25
  // ── Lifecycle ────────────────────────────────────────────────────────────