gsd-pi 2.51.0 → 2.52.0-dev.655ad8a

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 (419) hide show
  1. package/README.md +59 -36
  2. package/dist/headless-events.d.ts +18 -0
  3. package/dist/headless-events.js +36 -0
  4. package/dist/headless-query.js +1 -1
  5. package/dist/headless-types.d.ts +28 -0
  6. package/dist/headless-types.js +7 -0
  7. package/dist/headless.d.ts +8 -3
  8. package/dist/headless.js +47 -16
  9. package/dist/help-text.js +16 -5
  10. package/dist/onboarding.js +5 -4
  11. package/dist/remote-questions-config.js +1 -1
  12. package/dist/resources/extensions/async-jobs/async-bash-tool.js +29 -17
  13. package/dist/resources/extensions/async-jobs/job-manager.js +4 -1
  14. package/dist/resources/extensions/claude-code-cli/stream-adapter.js +18 -19
  15. package/dist/resources/extensions/get-secrets-from-user.js +7 -0
  16. package/dist/resources/extensions/gsd/auto/phases.js +34 -8
  17. package/dist/resources/extensions/gsd/auto-dispatch.js +23 -1
  18. package/dist/resources/extensions/gsd/auto-start.js +2 -0
  19. package/dist/resources/extensions/gsd/auto-timers.js +24 -2
  20. package/dist/resources/extensions/gsd/auto-tool-tracking.js +25 -7
  21. package/dist/resources/extensions/gsd/auto-worktree.js +91 -14
  22. package/dist/resources/extensions/gsd/auto.js +30 -4
  23. package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +99 -70
  24. package/dist/resources/extensions/gsd/bootstrap/dynamic-tools.js +12 -2
  25. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +1 -1
  26. package/dist/resources/extensions/gsd/claude-import.js +60 -9
  27. package/dist/resources/extensions/gsd/commands/handlers/auto.js +69 -6
  28. package/dist/resources/extensions/gsd/commands-config.js +10 -5
  29. package/dist/resources/extensions/gsd/commands-prefs-wizard.js +4 -4
  30. package/dist/resources/extensions/gsd/detection.js +6 -6
  31. package/dist/resources/extensions/gsd/docs/preferences-reference.md +5 -5
  32. package/dist/resources/extensions/gsd/error-classifier.js +105 -0
  33. package/dist/resources/extensions/gsd/git-service.js +4 -3
  34. package/dist/resources/extensions/gsd/gitignore.js +7 -7
  35. package/dist/resources/extensions/gsd/gsd-db.js +298 -45
  36. package/dist/resources/extensions/gsd/guided-flow.js +4 -3
  37. package/dist/resources/extensions/gsd/init-wizard.js +2 -2
  38. package/dist/resources/extensions/gsd/key-manager.js +7 -16
  39. package/dist/resources/extensions/gsd/markdown-renderer.js +5 -4
  40. package/dist/resources/extensions/gsd/memory-store.js +28 -13
  41. package/dist/resources/extensions/gsd/milestone-actions.js +19 -0
  42. package/dist/resources/extensions/gsd/parallel-orchestrator.js +18 -2
  43. package/dist/resources/extensions/gsd/preferences-models.js +1 -13
  44. package/dist/resources/extensions/gsd/preferences-types.js +1 -1
  45. package/dist/resources/extensions/gsd/preferences.js +13 -13
  46. package/dist/resources/extensions/gsd/prompts/system.md +1 -1
  47. package/dist/resources/extensions/gsd/provider-error-pause.js +0 -44
  48. package/dist/resources/extensions/gsd/rule-registry.js +1 -1
  49. package/dist/resources/extensions/gsd/service-tier.js +13 -2
  50. package/dist/resources/extensions/gsd/state.js +38 -30
  51. package/dist/resources/extensions/gsd/status-guards.js +12 -0
  52. package/dist/resources/extensions/gsd/tools/complete-milestone.js +7 -13
  53. package/dist/resources/extensions/gsd/tools/complete-slice.js +7 -20
  54. package/dist/resources/extensions/gsd/tools/complete-task.js +11 -21
  55. package/dist/resources/extensions/gsd/tools/plan-milestone.js +28 -29
  56. package/dist/resources/extensions/gsd/tools/plan-slice.js +27 -26
  57. package/dist/resources/extensions/gsd/tools/plan-task.js +23 -23
  58. package/dist/resources/extensions/gsd/tools/reassess-roadmap.js +50 -41
  59. package/dist/resources/extensions/gsd/tools/reopen-slice.js +4 -3
  60. package/dist/resources/extensions/gsd/tools/reopen-task.js +5 -4
  61. package/dist/resources/extensions/gsd/tools/replan-slice.js +51 -41
  62. package/dist/resources/extensions/gsd/tools/validate-milestone.js +23 -16
  63. package/dist/resources/extensions/gsd/validation.js +21 -0
  64. package/dist/resources/extensions/gsd/workflow-logger.js +0 -1
  65. package/dist/resources/extensions/remote-questions/config.js +1 -1
  66. package/dist/resources/extensions/remote-questions/remote-command.js +1 -1
  67. package/dist/resources/extensions/search-the-web/native-search.js +1 -1
  68. package/dist/resources/extensions/search-the-web/provider.js +1 -1
  69. package/dist/resources/extensions/shared/rtk.js +14 -4
  70. package/dist/rtk.js +3 -1
  71. package/dist/web/standalone/.next/BUILD_ID +1 -1
  72. package/dist/web/standalone/.next/app-path-routes-manifest.json +11 -11
  73. package/dist/web/standalone/.next/build-manifest.json +4 -4
  74. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  75. package/dist/web/standalone/.next/react-loadable-manifest.json +1 -1
  76. package/dist/web/standalone/.next/required-server-files.json +3 -3
  77. package/dist/web/standalone/.next/server/app/_global-error/page.js +3 -3
  78. package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  79. package/dist/web/standalone/.next/server/app/_global-error.html +2 -2
  80. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  81. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  82. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  83. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  84. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  85. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  86. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  87. package/dist/web/standalone/.next/server/app/_not-found/page.js +2 -2
  88. package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  89. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  90. package/dist/web/standalone/.next/server/app/_not-found.rsc +4 -4
  91. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +4 -4
  92. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  93. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +4 -4
  94. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  95. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  96. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  97. package/dist/web/standalone/.next/server/app/api/boot/route.js +1 -1
  98. package/dist/web/standalone/.next/server/app/api/boot/route_client-reference-manifest.js +1 -1
  99. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js +1 -1
  100. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route_client-reference-manifest.js +1 -1
  101. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js +1 -1
  102. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route_client-reference-manifest.js +1 -1
  103. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js +2 -2
  104. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route_client-reference-manifest.js +1 -1
  105. package/dist/web/standalone/.next/server/app/api/browse-directories/route.js +1 -1
  106. package/dist/web/standalone/.next/server/app/api/browse-directories/route_client-reference-manifest.js +1 -1
  107. package/dist/web/standalone/.next/server/app/api/captures/route.js +1 -1
  108. package/dist/web/standalone/.next/server/app/api/captures/route_client-reference-manifest.js +1 -1
  109. package/dist/web/standalone/.next/server/app/api/cleanup/route.js +1 -1
  110. package/dist/web/standalone/.next/server/app/api/cleanup/route_client-reference-manifest.js +1 -1
  111. package/dist/web/standalone/.next/server/app/api/dev-mode/route.js +1 -1
  112. package/dist/web/standalone/.next/server/app/api/dev-mode/route_client-reference-manifest.js +1 -1
  113. package/dist/web/standalone/.next/server/app/api/doctor/route.js +1 -1
  114. package/dist/web/standalone/.next/server/app/api/doctor/route_client-reference-manifest.js +1 -1
  115. package/dist/web/standalone/.next/server/app/api/experimental/route.js +2 -2
  116. package/dist/web/standalone/.next/server/app/api/experimental/route_client-reference-manifest.js +1 -1
  117. package/dist/web/standalone/.next/server/app/api/export-data/route.js +1 -1
  118. package/dist/web/standalone/.next/server/app/api/export-data/route_client-reference-manifest.js +1 -1
  119. package/dist/web/standalone/.next/server/app/api/files/route.js +1 -1
  120. package/dist/web/standalone/.next/server/app/api/files/route_client-reference-manifest.js +1 -1
  121. package/dist/web/standalone/.next/server/app/api/forensics/route.js +1 -1
  122. package/dist/web/standalone/.next/server/app/api/forensics/route_client-reference-manifest.js +1 -1
  123. package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
  124. package/dist/web/standalone/.next/server/app/api/git/route_client-reference-manifest.js +1 -1
  125. package/dist/web/standalone/.next/server/app/api/history/route.js +1 -1
  126. package/dist/web/standalone/.next/server/app/api/history/route_client-reference-manifest.js +1 -1
  127. package/dist/web/standalone/.next/server/app/api/hooks/route.js +1 -1
  128. package/dist/web/standalone/.next/server/app/api/hooks/route_client-reference-manifest.js +1 -1
  129. package/dist/web/standalone/.next/server/app/api/inspect/route.js +1 -1
  130. package/dist/web/standalone/.next/server/app/api/inspect/route_client-reference-manifest.js +1 -1
  131. package/dist/web/standalone/.next/server/app/api/knowledge/route.js +1 -1
  132. package/dist/web/standalone/.next/server/app/api/knowledge/route_client-reference-manifest.js +1 -1
  133. package/dist/web/standalone/.next/server/app/api/live-state/route.js +1 -1
  134. package/dist/web/standalone/.next/server/app/api/live-state/route_client-reference-manifest.js +1 -1
  135. package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
  136. package/dist/web/standalone/.next/server/app/api/onboarding/route_client-reference-manifest.js +1 -1
  137. package/dist/web/standalone/.next/server/app/api/preferences/route.js +1 -1
  138. package/dist/web/standalone/.next/server/app/api/preferences/route_client-reference-manifest.js +1 -1
  139. package/dist/web/standalone/.next/server/app/api/projects/route.js +1 -1
  140. package/dist/web/standalone/.next/server/app/api/projects/route_client-reference-manifest.js +1 -1
  141. package/dist/web/standalone/.next/server/app/api/recovery/route.js +1 -1
  142. package/dist/web/standalone/.next/server/app/api/recovery/route_client-reference-manifest.js +1 -1
  143. package/dist/web/standalone/.next/server/app/api/remote-questions/route.js +2 -2
  144. package/dist/web/standalone/.next/server/app/api/remote-questions/route_client-reference-manifest.js +1 -1
  145. package/dist/web/standalone/.next/server/app/api/session/browser/route.js +1 -1
  146. package/dist/web/standalone/.next/server/app/api/session/browser/route_client-reference-manifest.js +1 -1
  147. package/dist/web/standalone/.next/server/app/api/session/command/route.js +1 -1
  148. package/dist/web/standalone/.next/server/app/api/session/command/route_client-reference-manifest.js +1 -1
  149. package/dist/web/standalone/.next/server/app/api/session/events/route.js +2 -2
  150. package/dist/web/standalone/.next/server/app/api/session/events/route_client-reference-manifest.js +1 -1
  151. package/dist/web/standalone/.next/server/app/api/session/manage/route.js +1 -1
  152. package/dist/web/standalone/.next/server/app/api/session/manage/route_client-reference-manifest.js +1 -1
  153. package/dist/web/standalone/.next/server/app/api/settings-data/route.js +1 -1
  154. package/dist/web/standalone/.next/server/app/api/settings-data/route_client-reference-manifest.js +1 -1
  155. package/dist/web/standalone/.next/server/app/api/shutdown/route.js +1 -1
  156. package/dist/web/standalone/.next/server/app/api/shutdown/route_client-reference-manifest.js +1 -1
  157. package/dist/web/standalone/.next/server/app/api/skill-health/route.js +1 -1
  158. package/dist/web/standalone/.next/server/app/api/skill-health/route_client-reference-manifest.js +1 -1
  159. package/dist/web/standalone/.next/server/app/api/steer/route.js +1 -1
  160. package/dist/web/standalone/.next/server/app/api/steer/route_client-reference-manifest.js +1 -1
  161. package/dist/web/standalone/.next/server/app/api/switch-root/route.js +1 -1
  162. package/dist/web/standalone/.next/server/app/api/switch-root/route_client-reference-manifest.js +1 -1
  163. package/dist/web/standalone/.next/server/app/api/terminal/input/route.js +2 -2
  164. package/dist/web/standalone/.next/server/app/api/terminal/input/route_client-reference-manifest.js +1 -1
  165. package/dist/web/standalone/.next/server/app/api/terminal/resize/route.js +2 -2
  166. package/dist/web/standalone/.next/server/app/api/terminal/resize/route_client-reference-manifest.js +1 -1
  167. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js +2 -2
  168. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route_client-reference-manifest.js +1 -1
  169. package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js +4 -4
  170. package/dist/web/standalone/.next/server/app/api/terminal/stream/route_client-reference-manifest.js +1 -1
  171. package/dist/web/standalone/.next/server/app/api/terminal/upload/route.js +1 -1
  172. package/dist/web/standalone/.next/server/app/api/terminal/upload/route_client-reference-manifest.js +1 -1
  173. package/dist/web/standalone/.next/server/app/api/undo/route.js +1 -1
  174. package/dist/web/standalone/.next/server/app/api/undo/route_client-reference-manifest.js +1 -1
  175. package/dist/web/standalone/.next/server/app/api/update/route.js +1 -1
  176. package/dist/web/standalone/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
  177. package/dist/web/standalone/.next/server/app/api/visualizer/route.js +1 -1
  178. package/dist/web/standalone/.next/server/app/api/visualizer/route_client-reference-manifest.js +1 -1
  179. package/dist/web/standalone/.next/server/app/index.html +1 -1
  180. package/dist/web/standalone/.next/server/app/index.rsc +5 -5
  181. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  182. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +5 -5
  183. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  184. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +4 -4
  185. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  186. package/dist/web/standalone/.next/server/app/page.js +2 -2
  187. package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  188. package/dist/web/standalone/.next/server/app-paths-manifest.json +11 -11
  189. package/dist/web/standalone/.next/server/chunks/2229.js +3 -3
  190. package/dist/web/standalone/.next/server/chunks/7471.js +3 -3
  191. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  192. package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
  193. package/dist/web/standalone/.next/server/middleware.js +2 -2
  194. package/dist/web/standalone/.next/server/next-font-manifest.js +1 -1
  195. package/dist/web/standalone/.next/server/next-font-manifest.json +1 -1
  196. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  197. package/dist/web/standalone/.next/server/pages/500.html +2 -2
  198. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  199. package/dist/web/standalone/.next/static/chunks/4024.87fd909ae0110f50.js +9 -0
  200. package/dist/web/standalone/.next/static/chunks/app/_not-found/{page-2f24283c162b6ab3.js → page-f2a7482d42a5614b.js} +1 -1
  201. package/dist/web/standalone/.next/static/chunks/app/{layout-9ecfd95f343793f0.js → layout-a16c7a7ecdf0c2cf.js} +1 -1
  202. package/dist/web/standalone/.next/static/chunks/app/page-b950e4e384cc62b3.js +1 -0
  203. package/dist/web/standalone/.next/static/chunks/main-app-fdab67f7802d7832.js +1 -0
  204. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-459824ffb8c323dd.js +1 -0
  205. package/dist/web/standalone/.next/static/chunks/{webpack-cfc9a116e6450a6b.js → webpack-bca0e732db0dcec3.js} +1 -1
  206. package/dist/web/standalone/.next/static/css/a58ef8a151aa0493.css +1 -0
  207. package/dist/web/standalone/node_modules/node-pty/build/Makefile +2 -2
  208. package/dist/web/standalone/node_modules/node-pty/build/Release/pty.node +0 -0
  209. package/dist/web/standalone/node_modules/node-pty/build/pty.target.mk +14 -14
  210. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api.target.mk +14 -14
  211. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_except.target.mk +14 -14
  212. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_maybe.target.mk +14 -14
  213. package/dist/web/standalone/server.js +1 -1
  214. package/dist/wizard.js +4 -1
  215. package/package.json +2 -2
  216. package/packages/mcp-server/README.md +202 -0
  217. package/packages/mcp-server/package.json +36 -0
  218. package/packages/mcp-server/src/cli.ts +68 -0
  219. package/packages/mcp-server/src/index.ts +14 -0
  220. package/packages/mcp-server/src/mcp-server.test.ts +628 -0
  221. package/packages/mcp-server/src/server.ts +278 -0
  222. package/packages/mcp-server/src/session-manager.ts +328 -0
  223. package/packages/mcp-server/src/types.ts +107 -0
  224. package/packages/mcp-server/tsconfig.json +24 -0
  225. package/packages/pi-ai/dist/models.d.ts +14 -3
  226. package/packages/pi-ai/dist/models.d.ts.map +1 -1
  227. package/packages/pi-ai/dist/models.js +53 -10
  228. package/packages/pi-ai/dist/models.js.map +1 -1
  229. package/packages/pi-ai/dist/models.test.js +102 -1
  230. package/packages/pi-ai/dist/models.test.js.map +1 -1
  231. package/packages/pi-ai/dist/types.d.ts +30 -0
  232. package/packages/pi-ai/dist/types.d.ts.map +1 -1
  233. package/packages/pi-ai/dist/types.js.map +1 -1
  234. package/packages/pi-ai/src/models.test.ts +114 -1
  235. package/packages/pi-ai/src/models.ts +70 -13
  236. package/packages/pi-ai/src/types.ts +31 -0
  237. package/packages/pi-coding-agent/dist/cli/args.d.ts +2 -0
  238. package/packages/pi-coding-agent/dist/cli/args.d.ts.map +1 -1
  239. package/packages/pi-coding-agent/dist/cli/args.js +3 -0
  240. package/packages/pi-coding-agent/dist/cli/args.js.map +1 -1
  241. package/packages/pi-coding-agent/dist/core/bash-executor.d.ts.map +1 -1
  242. package/packages/pi-coding-agent/dist/core/bash-executor.js +5 -1
  243. package/packages/pi-coding-agent/dist/core/bash-executor.js.map +1 -1
  244. package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
  245. package/packages/pi-coding-agent/dist/core/model-registry.js +9 -4
  246. package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
  247. package/packages/pi-coding-agent/dist/core/tools/bash-spawn-windows.test.d.ts +19 -0
  248. package/packages/pi-coding-agent/dist/core/tools/bash-spawn-windows.test.d.ts.map +1 -0
  249. package/packages/pi-coding-agent/dist/core/tools/bash-spawn-windows.test.js +83 -0
  250. package/packages/pi-coding-agent/dist/core/tools/bash-spawn-windows.test.js.map +1 -0
  251. package/packages/pi-coding-agent/dist/core/tools/bash.d.ts.map +1 -1
  252. package/packages/pi-coding-agent/dist/core/tools/bash.js +5 -1
  253. package/packages/pi-coding-agent/dist/core/tools/bash.js.map +1 -1
  254. package/packages/pi-coding-agent/dist/index.d.ts +1 -1
  255. package/packages/pi-coding-agent/dist/index.d.ts.map +1 -1
  256. package/packages/pi-coding-agent/dist/index.js.map +1 -1
  257. package/packages/pi-coding-agent/dist/main.d.ts.map +1 -1
  258. package/packages/pi-coding-agent/dist/main.js +5 -3
  259. package/packages/pi-coding-agent/dist/main.js.map +1 -1
  260. package/packages/pi-coding-agent/dist/modes/index.d.ts +1 -1
  261. package/packages/pi-coding-agent/dist/modes/index.d.ts.map +1 -1
  262. package/packages/pi-coding-agent/dist/modes/index.js.map +1 -1
  263. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  264. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +0 -2
  265. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  266. package/packages/pi-coding-agent/dist/modes/rpc/rpc-client.d.ts +28 -1
  267. package/packages/pi-coding-agent/dist/modes/rpc/rpc-client.d.ts.map +1 -1
  268. package/packages/pi-coding-agent/dist/modes/rpc/rpc-client.js +49 -0
  269. package/packages/pi-coding-agent/dist/modes/rpc/rpc-client.js.map +1 -1
  270. package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.d.ts +1 -1
  271. package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  272. package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.js +114 -6
  273. package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.js.map +1 -1
  274. package/packages/pi-coding-agent/dist/modes/rpc/rpc-protocol-v2.test.d.ts +9 -0
  275. package/packages/pi-coding-agent/dist/modes/rpc/rpc-protocol-v2.test.d.ts.map +1 -0
  276. package/packages/pi-coding-agent/dist/modes/rpc/rpc-protocol-v2.test.js +831 -0
  277. package/packages/pi-coding-agent/dist/modes/rpc/rpc-protocol-v2.test.js.map +1 -0
  278. package/packages/pi-coding-agent/dist/modes/rpc/rpc-types.d.ts +66 -0
  279. package/packages/pi-coding-agent/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  280. package/packages/pi-coding-agent/dist/modes/rpc/rpc-types.js.map +1 -1
  281. package/packages/pi-coding-agent/dist/utils/shell.d.ts.map +1 -1
  282. package/packages/pi-coding-agent/dist/utils/shell.js +0 -1
  283. package/packages/pi-coding-agent/dist/utils/shell.js.map +1 -1
  284. package/packages/pi-coding-agent/package.json +1 -1
  285. package/packages/pi-coding-agent/src/cli/args.ts +4 -0
  286. package/packages/pi-coding-agent/src/core/bash-executor.ts +5 -1
  287. package/packages/pi-coding-agent/src/core/model-registry.ts +10 -3
  288. package/packages/pi-coding-agent/src/core/tools/bash-spawn-windows.test.ts +101 -0
  289. package/packages/pi-coding-agent/src/core/tools/bash.ts +5 -1
  290. package/packages/pi-coding-agent/src/index.ts +3 -0
  291. package/packages/pi-coding-agent/src/main.ts +5 -3
  292. package/packages/pi-coding-agent/src/modes/index.ts +8 -1
  293. package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +0 -2
  294. package/packages/pi-coding-agent/src/modes/rpc/rpc-client.ts +54 -1
  295. package/packages/pi-coding-agent/src/modes/rpc/rpc-mode.ts +124 -6
  296. package/packages/pi-coding-agent/src/modes/rpc/rpc-protocol-v2.test.ts +971 -0
  297. package/packages/pi-coding-agent/src/modes/rpc/rpc-types.ts +61 -4
  298. package/packages/pi-coding-agent/src/utils/shell.ts +0 -1
  299. package/packages/rpc-client/package.json +20 -0
  300. package/pkg/package.json +1 -1
  301. package/scripts/ensure-workspace-builds.cjs +36 -8
  302. package/src/resources/extensions/async-jobs/async-bash-tool.ts +22 -11
  303. package/src/resources/extensions/async-jobs/job-manager.ts +4 -1
  304. package/src/resources/extensions/claude-code-cli/stream-adapter.ts +19 -20
  305. package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +21 -0
  306. package/src/resources/extensions/get-secrets-from-user.ts +8 -0
  307. package/src/resources/extensions/gsd/auto/phases.ts +44 -7
  308. package/src/resources/extensions/gsd/auto-dispatch.ts +25 -1
  309. package/src/resources/extensions/gsd/auto-start.ts +2 -0
  310. package/src/resources/extensions/gsd/auto-timers.ts +25 -1
  311. package/src/resources/extensions/gsd/auto-tool-tracking.ts +30 -6
  312. package/src/resources/extensions/gsd/auto-worktree.ts +94 -14
  313. package/src/resources/extensions/gsd/auto.ts +31 -4
  314. package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +118 -73
  315. package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +11 -2
  316. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +1 -1
  317. package/src/resources/extensions/gsd/claude-import.ts +58 -9
  318. package/src/resources/extensions/gsd/commands/handlers/auto.ts +73 -6
  319. package/src/resources/extensions/gsd/commands-config.ts +11 -5
  320. package/src/resources/extensions/gsd/commands-prefs-wizard.ts +4 -4
  321. package/src/resources/extensions/gsd/detection.ts +6 -6
  322. package/src/resources/extensions/gsd/docs/preferences-reference.md +5 -5
  323. package/src/resources/extensions/gsd/error-classifier.ts +139 -0
  324. package/src/resources/extensions/gsd/git-service.ts +4 -3
  325. package/src/resources/extensions/gsd/gitignore.ts +7 -7
  326. package/src/resources/extensions/gsd/gsd-db.ts +355 -63
  327. package/src/resources/extensions/gsd/guided-flow.ts +4 -3
  328. package/src/resources/extensions/gsd/init-wizard.ts +2 -2
  329. package/src/resources/extensions/gsd/key-manager.ts +7 -16
  330. package/src/resources/extensions/gsd/markdown-renderer.ts +5 -4
  331. package/src/resources/extensions/gsd/memory-store.ts +29 -18
  332. package/src/resources/extensions/gsd/milestone-actions.ts +17 -0
  333. package/src/resources/extensions/gsd/parallel-orchestrator.ts +23 -1
  334. package/src/resources/extensions/gsd/preferences-models.ts +1 -13
  335. package/src/resources/extensions/gsd/preferences-types.ts +1 -1
  336. package/src/resources/extensions/gsd/preferences.ts +12 -13
  337. package/src/resources/extensions/gsd/prompts/system.md +1 -1
  338. package/src/resources/extensions/gsd/provider-error-pause.ts +0 -57
  339. package/src/resources/extensions/gsd/rule-registry.ts +1 -1
  340. package/src/resources/extensions/gsd/service-tier.ts +14 -2
  341. package/src/resources/extensions/gsd/state.ts +39 -30
  342. package/src/resources/extensions/gsd/status-guards.ts +13 -0
  343. package/src/resources/extensions/gsd/tests/active-milestone-id-guard.test.ts +91 -0
  344. package/src/resources/extensions/gsd/tests/agent-end-retry.test.ts +1 -1
  345. package/src/resources/extensions/gsd/tests/auto-milestone-target.test.ts +61 -0
  346. package/src/resources/extensions/gsd/tests/auto-stale-lock-self-kill.test.ts +87 -0
  347. package/src/resources/extensions/gsd/tests/auto-worktree-auto-resolve.test.ts +80 -0
  348. package/src/resources/extensions/gsd/tests/auto-worktree-milestone-merge.test.ts +1 -1
  349. package/src/resources/extensions/gsd/tests/claude-import-marketplace-discovery.test.ts +191 -0
  350. package/src/resources/extensions/gsd/tests/claude-import-tui.test.ts +1 -1
  351. package/src/resources/extensions/gsd/tests/collect-from-manifest.test.ts +39 -0
  352. package/src/resources/extensions/gsd/tests/commands-config.test.ts +24 -0
  353. package/src/resources/extensions/gsd/tests/complete-slice.test.ts +2 -2
  354. package/src/resources/extensions/gsd/tests/complete-task-rollback-evidence.test.ts +106 -0
  355. package/src/resources/extensions/gsd/tests/complete-task.test.ts +2 -2
  356. package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +35 -7
  357. package/src/resources/extensions/gsd/tests/detection.test.ts +1 -1
  358. package/src/resources/extensions/gsd/tests/doctor-git.test.ts +4 -4
  359. package/src/resources/extensions/gsd/tests/doctor-proactive.test.ts +1 -1
  360. package/src/resources/extensions/gsd/tests/doctor-providers.test.ts +2 -2
  361. package/src/resources/extensions/gsd/tests/empty-db-reconciliation.test.ts +79 -0
  362. package/src/resources/extensions/gsd/tests/git-service.test.ts +65 -31
  363. package/src/resources/extensions/gsd/tests/gsd-db.test.ts +1 -1
  364. package/src/resources/extensions/gsd/tests/idle-watchdog-stall-override.test.ts +125 -0
  365. package/src/resources/extensions/gsd/tests/init-wizard.test.ts +1 -1
  366. package/src/resources/extensions/gsd/tests/interactive-tool-idle-exemption.test.ts +119 -0
  367. package/src/resources/extensions/gsd/tests/key-manager.test.ts +16 -1
  368. package/src/resources/extensions/gsd/tests/md-importer.test.ts +1 -1
  369. package/src/resources/extensions/gsd/tests/memory-store.test.ts +2 -2
  370. package/src/resources/extensions/gsd/tests/milestone-report-path.test.ts +51 -0
  371. package/src/resources/extensions/gsd/tests/none-mode-gates.test.ts +7 -7
  372. package/src/resources/extensions/gsd/tests/parallel-orchestrator-zombie-cleanup.test.ts +277 -0
  373. package/src/resources/extensions/gsd/tests/park-db-sync.test.ts +85 -0
  374. package/src/resources/extensions/gsd/tests/phases-merge-error-stops-auto.test.ts +103 -0
  375. package/src/resources/extensions/gsd/tests/preferences-worktree-sync.test.ts +91 -0
  376. package/src/resources/extensions/gsd/tests/preferences.test.ts +2 -2
  377. package/src/resources/extensions/gsd/tests/provider-errors.test.ts +77 -70
  378. package/src/resources/extensions/gsd/tests/rate-limit-model-fallback.test.ts +90 -0
  379. package/src/resources/extensions/gsd/tests/remediation-completion-guard.test.ts +110 -0
  380. package/src/resources/extensions/gsd/tests/remote-questions.test.ts +29 -0
  381. package/src/resources/extensions/gsd/tests/session-lock-transient-read.test.ts +9 -8
  382. package/src/resources/extensions/gsd/tests/stash-pop-gsd-conflict.test.ts +125 -0
  383. package/src/resources/extensions/gsd/tests/status-guards.test.ts +30 -0
  384. package/src/resources/extensions/gsd/tests/terminated-transient.test.ts +42 -31
  385. package/src/resources/extensions/gsd/tests/token-cost-display.test.ts +2 -2
  386. package/src/resources/extensions/gsd/tests/vacuous-truth-slices.test.ts +115 -0
  387. package/src/resources/extensions/gsd/tests/validate-milestone-write-order.test.ts +90 -0
  388. package/src/resources/extensions/gsd/tests/validate-milestone.test.ts +12 -2
  389. package/src/resources/extensions/gsd/tests/validation-gate-patterns.test.ts +124 -0
  390. package/src/resources/extensions/gsd/tests/validation.test.ts +72 -0
  391. package/src/resources/extensions/gsd/tests/workflow-logger.test.ts +81 -1
  392. package/src/resources/extensions/gsd/tests/worktree-preferences-sync.test.ts +130 -0
  393. package/src/resources/extensions/gsd/tools/complete-milestone.ts +7 -17
  394. package/src/resources/extensions/gsd/tools/complete-slice.ts +7 -24
  395. package/src/resources/extensions/gsd/tools/complete-task.ts +13 -25
  396. package/src/resources/extensions/gsd/tools/plan-milestone.ts +30 -32
  397. package/src/resources/extensions/gsd/tools/plan-slice.ts +30 -30
  398. package/src/resources/extensions/gsd/tools/plan-task.ts +26 -26
  399. package/src/resources/extensions/gsd/tools/reassess-roadmap.ts +57 -46
  400. package/src/resources/extensions/gsd/tools/reopen-slice.ts +4 -3
  401. package/src/resources/extensions/gsd/tools/reopen-task.ts +5 -4
  402. package/src/resources/extensions/gsd/tools/replan-slice.ts +55 -44
  403. package/src/resources/extensions/gsd/tools/validate-milestone.ts +26 -20
  404. package/src/resources/extensions/gsd/validation.ts +23 -0
  405. package/src/resources/extensions/gsd/workflow-logger.ts +0 -1
  406. package/src/resources/extensions/remote-questions/config.ts +1 -1
  407. package/src/resources/extensions/remote-questions/remote-command.ts +1 -1
  408. package/src/resources/extensions/search-the-web/native-search.ts +1 -1
  409. package/src/resources/extensions/search-the-web/provider.ts +1 -1
  410. package/src/resources/extensions/shared/rtk.ts +22 -4
  411. package/dist/web/standalone/.next/static/chunks/4024.9ad5def014d90ce4.js +0 -9
  412. package/dist/web/standalone/.next/static/chunks/app/page-fbecd1237e2d6d1f.js +0 -1
  413. package/dist/web/standalone/.next/static/chunks/main-app-d3d4c336195465f9.js +0 -1
  414. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-ab5a8926e07ec673.js +0 -1
  415. package/dist/web/standalone/.next/static/css/de141508b083f922.css +0 -1
  416. /package/dist/resources/extensions/gsd/templates/{preferences.md → PREFERENCES.md} +0 -0
  417. /package/dist/web/standalone/.next/static/{vkr67v-utm1dgZnbrBWQh → zpvUPKoW5jRAMB_fWHlPi}/_buildManifest.js +0 -0
  418. /package/dist/web/standalone/.next/static/{vkr67v-utm1dgZnbrBWQh → zpvUPKoW5jRAMB_fWHlPi}/_ssgManifest.js +0 -0
  419. /package/src/resources/extensions/gsd/templates/{preferences.md → PREFERENCES.md} +0 -0
@@ -1,12 +1,38 @@
1
1
  import { checkAutoStartAfterDiscuss } from "../guided-flow.js";
2
2
  import { getAutoDashboardData, getAutoModeStartModel, isAutoActive, pauseAuto } from "../auto.js";
3
- import { getNextFallbackModel, isTransientNetworkError, resolveModelWithFallbacksForUnit } from "../preferences.js";
4
- import { classifyProviderError, pauseAutoForProviderError } from "../provider-error-pause.js";
3
+ import { getNextFallbackModel, resolveModelWithFallbacksForUnit } from "../preferences.js";
4
+ import { pauseAutoForProviderError } from "../provider-error-pause.js";
5
5
  import { isSessionSwitchInFlight, resolveAgentEnd } from "../auto-loop.js";
6
+ import { resolveModelId } from "../auto-model-selection.js";
6
7
  import { clearDiscussionFlowState } from "./write-gate.js";
7
- const networkRetryCounters = new Map();
8
+ import { classifyError, createRetryState, resetRetryState, isTransient, } from "../error-classifier.js";
9
+ const retryState = createRetryState();
10
+ const MAX_NETWORK_RETRIES = 2;
8
11
  const MAX_TRANSIENT_AUTO_RESUMES = 3;
9
- let consecutiveTransientErrors = 0;
12
+ async function pauseTransientWithBackoff(cls, pi, ctx, errorDetail, isRateLimit) {
13
+ retryState.consecutiveTransientCount += 1;
14
+ const baseRetryAfterMs = "retryAfterMs" in cls ? cls.retryAfterMs : 15_000;
15
+ const retryAfterMs = baseRetryAfterMs * 2 ** Math.max(0, retryState.consecutiveTransientCount - 1);
16
+ const allowAutoResume = retryState.consecutiveTransientCount <= MAX_TRANSIENT_AUTO_RESUMES;
17
+ if (!allowAutoResume) {
18
+ ctx.ui.notify(`Transient provider errors persisted after ${MAX_TRANSIENT_AUTO_RESUMES} auto-resume attempts. Pausing for manual review.`, "warning");
19
+ }
20
+ await pauseAutoForProviderError(ctx.ui, errorDetail, () => pauseAuto(ctx, pi, {
21
+ message: `Provider error: ${errorDetail}`,
22
+ category: "provider",
23
+ isTransient: allowAutoResume,
24
+ retryAfterMs,
25
+ }), {
26
+ isRateLimit,
27
+ isTransient: allowAutoResume,
28
+ retryAfterMs,
29
+ resume: allowAutoResume
30
+ ? () => {
31
+ pi.sendMessage({ customType: "gsd-auto-timeout-recovery", content: "Continue execution — provider error recovery delay elapsed.", display: false }, { triggerTurn: true });
32
+ }
33
+ : undefined,
34
+ });
35
+ }
10
36
  export async function handleAgentEnd(pi, event, ctx) {
11
37
  if (checkAutoStartAfterDiscuss()) {
12
38
  clearDiscussionFlowState();
@@ -24,93 +50,96 @@ export async function handleAgentEnd(pi, event, ctx) {
24
50
  if (lastMsg && "stopReason" in lastMsg && lastMsg.stopReason === "error") {
25
51
  const errorDetail = "errorMessage" in lastMsg && lastMsg.errorMessage ? `: ${lastMsg.errorMessage}` : "";
26
52
  const errorMsg = ("errorMessage" in lastMsg && lastMsg.errorMessage) ? String(lastMsg.errorMessage) : "";
27
- if (isTransientNetworkError(errorMsg)) {
53
+ const explicitRetryAfterMs = ("retryAfterMs" in lastMsg && typeof lastMsg.retryAfterMs === "number") ? lastMsg.retryAfterMs : undefined;
54
+ // ── 1. Classify ──────────────────────────────────────────────────────
55
+ const cls = classifyError(errorMsg, explicitRetryAfterMs);
56
+ // ── 2. Decide & Act ──────────────────────────────────────────────────
57
+ // --- Network errors: same-model retry with backoff ---
58
+ if (cls.kind === "network") {
28
59
  const currentModelId = ctx.model?.id ?? "unknown";
29
- const retryKey = `network-retry:${currentModelId}`;
30
- const currentRetries = networkRetryCounters.get(retryKey) ?? 0;
31
- const maxRetries = 2;
32
- if (currentRetries < maxRetries) {
33
- networkRetryCounters.set(retryKey, currentRetries + 1);
34
- const attempt = currentRetries + 1;
35
- const delayMs = attempt * 3000;
36
- ctx.ui.notify(`Network error on ${currentModelId}${errorDetail}. Retry ${attempt}/${maxRetries} in ${delayMs / 1000}s...`, "warning");
60
+ if (retryState.currentRetryModelId !== currentModelId) {
61
+ retryState.networkRetryCount = 0;
62
+ retryState.currentRetryModelId = currentModelId;
63
+ }
64
+ if (retryState.networkRetryCount < MAX_NETWORK_RETRIES) {
65
+ retryState.networkRetryCount += 1;
66
+ retryState.consecutiveTransientCount += 1;
67
+ const attempt = retryState.networkRetryCount;
68
+ const delayMs = attempt * cls.retryAfterMs;
69
+ ctx.ui.notify(`Network error on ${currentModelId}${errorDetail}. Retry ${attempt}/${MAX_NETWORK_RETRIES} in ${delayMs / 1000}s...`, "warning");
37
70
  setTimeout(() => {
38
71
  pi.sendMessage({ customType: "gsd-auto-timeout-recovery", content: "Continue execution — retrying after transient network error.", display: false }, { triggerTurn: true });
39
72
  }, delayMs);
40
73
  return;
41
74
  }
42
- networkRetryCounters.delete(retryKey);
75
+ // Network retries exhausted — fall through to model fallback
76
+ retryState.networkRetryCount = 0;
77
+ retryState.currentRetryModelId = undefined;
43
78
  ctx.ui.notify(`Network retries exhausted for ${currentModelId}. Attempting model fallback.`, "warning");
44
79
  }
45
- const dash = getAutoDashboardData();
46
- if (dash.currentUnit) {
47
- const modelConfig = resolveModelWithFallbacksForUnit(dash.currentUnit.type);
48
- if (modelConfig && modelConfig.fallbacks.length > 0) {
49
- const availableModels = ctx.modelRegistry.getAvailable();
50
- const nextModelId = getNextFallbackModel(ctx.model?.id, modelConfig);
51
- if (nextModelId) {
52
- networkRetryCounters.clear();
53
- const slashIdx = nextModelId.indexOf("/");
54
- const modelToSet = slashIdx !== -1
55
- ? availableModels.find((m) => m.provider.toLowerCase() === nextModelId.substring(0, slashIdx).toLowerCase() && m.id.toLowerCase() === nextModelId.substring(slashIdx + 1).toLowerCase())
56
- : (availableModels.find((m) => m.id === nextModelId && m.provider === ctx.model?.provider) ?? availableModels.find((m) => m.id === nextModelId));
57
- if (modelToSet) {
58
- const ok = await pi.setModel(modelToSet, { persist: false });
59
- if (ok) {
60
- ctx.ui.notify(`Model error${errorDetail}. Switched to fallback: ${nextModelId} and resuming.`, "warning");
61
- pi.sendMessage({ customType: "gsd-auto-timeout-recovery", content: "Continue execution.", display: false }, { triggerTurn: true });
62
- return;
80
+ // --- Transient errors: try model fallback first, then pause ---
81
+ // Rate limits are often per-model, so switching models can bypass them.
82
+ if (cls.kind === "rate-limit" || cls.kind === "network" || cls.kind === "server" || cls.kind === "connection" || cls.kind === "stream") {
83
+ // Try model fallback
84
+ const dash = getAutoDashboardData();
85
+ if (dash.currentUnit) {
86
+ const modelConfig = resolveModelWithFallbacksForUnit(dash.currentUnit.type);
87
+ if (modelConfig && modelConfig.fallbacks.length > 0) {
88
+ const availableModels = ctx.modelRegistry.getAvailable();
89
+ const nextModelId = getNextFallbackModel(ctx.model?.id, modelConfig);
90
+ if (nextModelId) {
91
+ retryState.networkRetryCount = 0;
92
+ retryState.currentRetryModelId = undefined;
93
+ const modelToSet = resolveModelId(nextModelId, availableModels, ctx.model?.provider);
94
+ if (modelToSet) {
95
+ const ok = await pi.setModel(modelToSet, { persist: false });
96
+ if (ok) {
97
+ ctx.ui.notify(`Model error${errorDetail}. Switched to fallback: ${nextModelId} and resuming.`, "warning");
98
+ pi.sendMessage({ customType: "gsd-auto-timeout-recovery", content: "Continue execution.", display: false }, { triggerTurn: true });
99
+ return;
100
+ }
63
101
  }
64
102
  }
65
103
  }
66
104
  }
67
- }
68
- const sessionModel = getAutoModeStartModel();
69
- if (sessionModel) {
70
- if (ctx.model?.id !== sessionModel.id || ctx.model?.provider !== sessionModel.provider) {
71
- const startModel = ctx.modelRegistry.getAvailable().find((m) => m.provider === sessionModel.provider && m.id === sessionModel.id);
72
- if (startModel) {
73
- const ok = await pi.setModel(startModel, { persist: false });
74
- if (ok) {
75
- networkRetryCounters.clear();
76
- ctx.ui.notify(`Model error${errorDetail}. Restored session model: ${sessionModel.provider}/${sessionModel.id} and resuming.`, "warning");
77
- pi.sendMessage({ customType: "gsd-auto-timeout-recovery", content: "Continue execution.", display: false }, { triggerTurn: true });
78
- return;
105
+ // Try restoring session model
106
+ const sessionModel = getAutoModeStartModel();
107
+ if (sessionModel) {
108
+ if (ctx.model?.id !== sessionModel.id || ctx.model?.provider !== sessionModel.provider) {
109
+ const startModel = ctx.modelRegistry.getAvailable().find((m) => m.provider === sessionModel.provider && m.id === sessionModel.id);
110
+ if (startModel) {
111
+ const ok = await pi.setModel(startModel, { persist: false });
112
+ if (ok) {
113
+ retryState.networkRetryCount = 0;
114
+ retryState.currentRetryModelId = undefined;
115
+ ctx.ui.notify(`Model error${errorDetail}. Restored session model: ${sessionModel.provider}/${sessionModel.id} and resuming.`, "warning");
116
+ pi.sendMessage({ customType: "gsd-auto-timeout-recovery", content: "Continue execution.", display: false }, { triggerTurn: true });
117
+ return;
118
+ }
79
119
  }
80
120
  }
81
121
  }
82
122
  }
83
- const classification = classifyProviderError(errorMsg);
84
- const explicitRetryAfterMs = ("retryAfterMs" in lastMsg && typeof lastMsg.retryAfterMs === "number") ? lastMsg.retryAfterMs : undefined;
85
- if (classification.isTransient) {
86
- consecutiveTransientErrors += 1;
87
- }
88
- else {
89
- consecutiveTransientErrors = 0;
123
+ // --- Transient fallback: pause with auto-resume ---
124
+ if (isTransient(cls)) {
125
+ await pauseTransientWithBackoff(cls, pi, ctx, errorDetail, cls.kind === "rate-limit");
126
+ return;
90
127
  }
91
- const baseRetryAfterMs = explicitRetryAfterMs ?? classification.suggestedDelayMs;
92
- const retryAfterMs = classification.isTransient
93
- ? baseRetryAfterMs * 2 ** Math.max(0, consecutiveTransientErrors - 1)
94
- : baseRetryAfterMs;
95
- const allowAutoResume = classification.isTransient && consecutiveTransientErrors <= MAX_TRANSIENT_AUTO_RESUMES;
96
- if (classification.isTransient && !allowAutoResume) {
97
- ctx.ui.notify(`Transient provider errors persisted after ${MAX_TRANSIENT_AUTO_RESUMES} auto-resume attempts. Pausing for manual review.`, "warning");
98
- }
99
- await pauseAutoForProviderError(ctx.ui, errorDetail, () => pauseAuto(ctx, pi), {
100
- isRateLimit: classification.isRateLimit,
101
- isTransient: allowAutoResume,
102
- retryAfterMs,
103
- resume: allowAutoResume
104
- ? () => {
105
- pi.sendMessage({ customType: "gsd-auto-timeout-recovery", content: "Continue execution — provider error recovery delay elapsed.", display: false }, { triggerTurn: true });
106
- }
107
- : undefined,
128
+ // --- Permanent / unknown: pause indefinitely ---
129
+ await pauseAutoForProviderError(ctx.ui, errorDetail, () => pauseAuto(ctx, pi, {
130
+ message: `Provider error: ${errorDetail}`,
131
+ category: "provider",
132
+ isTransient: false,
133
+ }), {
134
+ isRateLimit: false,
135
+ isTransient: false,
136
+ retryAfterMs: 0,
108
137
  });
109
138
  return;
110
139
  }
140
+ // ── Success path ─────────────────────────────────────────────────────────
111
141
  try {
112
- consecutiveTransientErrors = 0;
113
- networkRetryCounters.clear();
142
+ resetRetryState(retryState);
114
143
  resolveAgentEnd(event);
115
144
  }
116
145
  catch (err) {
@@ -2,6 +2,7 @@ import { existsSync } from "node:fs";
2
2
  import { join, sep } from "node:path";
3
3
  import { createBashTool, createEditTool, createReadTool, createWriteTool } from "@gsd/pi-coding-agent";
4
4
  import { DEFAULT_BASH_TIMEOUT_SECS } from "../constants.js";
5
+ import { setLogBasePath } from "../workflow-logger.js";
5
6
  /**
6
7
  * Resolve the correct DB path for the current working directory.
7
8
  * If `basePath` is inside a `.gsd/worktrees/<MID>/` directory, returns
@@ -35,9 +36,14 @@ export async function ensureDbOpen() {
35
36
  const basePath = process.cwd();
36
37
  const dbPath = resolveProjectRootDbPath(basePath);
37
38
  const gsdDir = join(basePath, ".gsd");
39
+ // Derive the project root from the DB path (strip .gsd/gsd.db)
40
+ const projectRoot = join(dbPath, "..", "..");
38
41
  // Open existing DB file (may be at project root for worktrees)
39
42
  if (existsSync(dbPath)) {
40
- return db.openDatabase(dbPath);
43
+ const opened = db.openDatabase(dbPath);
44
+ if (opened)
45
+ setLogBasePath(projectRoot);
46
+ return opened;
41
47
  }
42
48
  // No DB file — create + migrate from Markdown if .gsd/ has content
43
49
  if (existsSync(gsdDir)) {
@@ -47,6 +53,7 @@ export async function ensureDbOpen() {
47
53
  if (hasDecisions || hasRequirements || hasMilestones) {
48
54
  const opened = db.openDatabase(dbPath);
49
55
  if (opened) {
56
+ setLogBasePath(projectRoot);
50
57
  try {
51
58
  const { migrateFromMarkdown } = await import("../md-importer.js");
52
59
  migrateFromMarkdown(basePath);
@@ -58,7 +65,10 @@ export async function ensureDbOpen() {
58
65
  return opened;
59
66
  }
60
67
  // .gsd/ exists but has no Markdown content (fresh project) — create empty DB
61
- return db.openDatabase(dbPath);
68
+ const opened = db.openDatabase(dbPath);
69
+ if (opened)
70
+ setLogBasePath(projectRoot);
71
+ return opened;
62
72
  }
63
73
  return false;
64
74
  }
@@ -227,7 +227,7 @@ export function registerHooks(pi) {
227
227
  pi.on("tool_execution_start", async (event) => {
228
228
  if (!isAutoActive())
229
229
  return;
230
- markToolStart(event.toolCallId);
230
+ markToolStart(event.toolCallId, event.toolName);
231
231
  });
232
232
  pi.on("tool_execution_end", async (event) => {
233
233
  markToolEnd(event.toolCallId);
@@ -79,16 +79,50 @@ function isMarketplacePath(pluginPath) {
79
79
  }
80
80
  /**
81
81
  * Detect which plugin roots are marketplaces and which are legacy flat paths.
82
+ *
83
+ * Claude Code stores marketplace sources under ~/.claude/plugins/marketplaces/.
84
+ * Each subdirectory (e.g. marketplaces/confluent/) is a marketplace repo that
85
+ * contains .claude-plugin/marketplace.json. The parent directory itself does not
86
+ * have a marketplace.json, so we scan one level deeper when the root isn't
87
+ * directly a marketplace.
82
88
  */
83
- function categorizePluginRoots(pluginRoots) {
89
+ export function categorizePluginRoots(pluginRoots) {
84
90
  const marketplaces = [];
85
91
  const flat = [];
92
+ const seen = new Set();
86
93
  for (const root of pluginRoots) {
87
94
  if (isMarketplacePath(root)) {
88
- marketplaces.push(root);
95
+ if (!seen.has(root)) {
96
+ marketplaces.push(root);
97
+ seen.add(root);
98
+ }
89
99
  }
90
100
  else {
91
- flat.push(root);
101
+ // The root itself isn't a marketplace — check if it's a container of
102
+ // marketplaces (e.g. ~/.claude/plugins/marketplaces/ contains subdirs
103
+ // like confluent/, claude-hud/, each with their own marketplace.json).
104
+ let foundChild = false;
105
+ try {
106
+ const entries = readdirSync(root, { withFileTypes: true });
107
+ for (const entry of entries) {
108
+ if (!entry.isDirectory())
109
+ continue;
110
+ if (SKIP_DIRS.has(entry.name))
111
+ continue;
112
+ const childPath = join(root, entry.name);
113
+ if (isMarketplacePath(childPath) && !seen.has(childPath)) {
114
+ marketplaces.push(childPath);
115
+ seen.add(childPath);
116
+ foundChild = true;
117
+ }
118
+ }
119
+ }
120
+ catch {
121
+ // Can't read directory — fall through to flat
122
+ }
123
+ if (!foundChild) {
124
+ flat.push(root);
125
+ }
92
126
  }
93
127
  }
94
128
  return { marketplaces, flat };
@@ -145,20 +179,37 @@ export function discoverClaudePlugins(cwd) {
145
179
  const seen = new Set();
146
180
  for (const root of pluginRoots) {
147
181
  walkDirs(root, (dir) => {
182
+ // Recognize both npm-style plugins (package.json) and Claude Code plugins
183
+ // (.claude-plugin/plugin.json). Claude marketplace-installed plugins use
184
+ // the latter format exclusively.
148
185
  const pkgPath = join(dir, "package.json");
149
- if (!existsSync(pkgPath))
186
+ const claudePluginPath = join(dir, ".claude-plugin", "plugin.json");
187
+ const hasPkg = existsSync(pkgPath);
188
+ const hasClaudePlugin = existsSync(claudePluginPath);
189
+ if (!hasPkg && !hasClaudePlugin)
150
190
  return;
151
191
  const resolvedDir = resolve(dir);
152
192
  if (seen.has(resolvedDir))
153
193
  return;
154
194
  seen.add(resolvedDir);
155
195
  let packageName;
156
- try {
157
- const pkg = JSON.parse(readFileSync(pkgPath, "utf8"));
158
- packageName = pkg.name;
196
+ if (hasPkg) {
197
+ try {
198
+ const pkg = JSON.parse(readFileSync(pkgPath, "utf8"));
199
+ packageName = pkg.name;
200
+ }
201
+ catch {
202
+ packageName = undefined;
203
+ }
159
204
  }
160
- catch {
161
- packageName = undefined;
205
+ else if (hasClaudePlugin) {
206
+ try {
207
+ const manifest = JSON.parse(readFileSync(claudePluginPath, "utf8"));
208
+ packageName = manifest.name;
209
+ }
210
+ catch {
211
+ packageName = undefined;
212
+ }
162
213
  }
163
214
  results.push({
164
215
  type: "plugin",
@@ -4,6 +4,7 @@ import { enableDebug } from "../../debug-logger.js";
4
4
  import { isAutoActive, isAutoPaused, pauseAuto, startAuto, stopAuto, stopAutoRemote } from "../../auto.js";
5
5
  import { handleRate } from "../../commands-rate.js";
6
6
  import { guardRemoteSession, projectRoot } from "../context.js";
7
+ import { findMilestoneIds } from "../../milestone-id-utils.js";
7
8
  /**
8
9
  * Parse --yolo flag and optional file path from the auto command string.
9
10
  * Supports: `/gsd auto --yolo path/to/file.md` or `/gsd auto -y path/to/file.md`
@@ -22,6 +23,40 @@ function parseYoloFlag(trimmed) {
22
23
  const rest = trimmed.replace(match[0], "").replace(/\s+/g, " ").trim();
23
24
  return { yoloSeedFile: filePath, rest };
24
25
  }
26
+ /**
27
+ * Extract a milestone ID (e.g. M016 or M001-a3b4c5) from the command string.
28
+ * Returns the matched ID and the remaining string with the ID removed.
29
+ * The milestone ID pattern matches the format used by findMilestoneIds: M\d+ with
30
+ * an optional -[a-z0-9]{6} suffix for unique milestone IDs.
31
+ */
32
+ export function parseMilestoneTarget(input) {
33
+ const match = input.match(/\b(M\d+(?:-[a-z0-9]{6})?)\b/);
34
+ if (!match)
35
+ return { milestoneId: null, rest: input };
36
+ const rest = input.replace(match[0], "").replace(/\s+/g, " ").trim();
37
+ return { milestoneId: match[1], rest };
38
+ }
39
+ /**
40
+ * Set GSD_MILESTONE_LOCK to target a specific milestone, then run `fn`.
41
+ * Clears the env var when `fn` resolves or rejects, so the lock does not
42
+ * leak into subsequent commands in the same process.
43
+ */
44
+ async function withMilestoneLock(milestoneId, fn) {
45
+ const previous = process.env.GSD_MILESTONE_LOCK;
46
+ process.env.GSD_MILESTONE_LOCK = milestoneId;
47
+ try {
48
+ await fn();
49
+ }
50
+ finally {
51
+ // Restore previous value (undefined → delete, else restore).
52
+ if (previous === undefined) {
53
+ delete process.env.GSD_MILESTONE_LOCK;
54
+ }
55
+ else {
56
+ process.env.GSD_MILESTONE_LOCK = previous;
57
+ }
58
+ }
59
+ }
25
60
  export async function handleAutoCommand(trimmed, ctx, pi) {
26
61
  if (trimmed === "next" || trimmed.startsWith("next ")) {
27
62
  if (trimmed.includes("--dry-run")) {
@@ -29,23 +64,46 @@ export async function handleAutoCommand(trimmed, ctx, pi) {
29
64
  await handleDryRun(ctx, projectRoot());
30
65
  return true;
31
66
  }
32
- const verboseMode = trimmed.includes("--verbose");
33
- const debugMode = trimmed.includes("--debug");
67
+ const { milestoneId, rest: afterMilestone } = parseMilestoneTarget(trimmed);
68
+ const verboseMode = afterMilestone.includes("--verbose");
69
+ const debugMode = afterMilestone.includes("--debug");
34
70
  if (debugMode)
35
71
  enableDebug(projectRoot());
36
72
  if (!(await guardRemoteSession(ctx, pi)))
37
73
  return true;
38
- await startAuto(ctx, pi, projectRoot(), verboseMode, { step: true });
74
+ // Validate the milestone target exists and is not already complete.
75
+ if (milestoneId) {
76
+ const allIds = findMilestoneIds(projectRoot());
77
+ if (!allIds.includes(milestoneId)) {
78
+ ctx.ui.notify(`Milestone ${milestoneId} does not exist. Available: ${allIds.join(", ") || "(none)"}`, "error");
79
+ return true;
80
+ }
81
+ }
82
+ if (milestoneId) {
83
+ await withMilestoneLock(milestoneId, () => startAuto(ctx, pi, projectRoot(), verboseMode, { step: true }));
84
+ }
85
+ else {
86
+ await startAuto(ctx, pi, projectRoot(), verboseMode, { step: true });
87
+ }
39
88
  return true;
40
89
  }
41
90
  if (trimmed === "auto" || trimmed.startsWith("auto ")) {
42
- const { yoloSeedFile, rest } = parseYoloFlag(trimmed);
43
- const verboseMode = rest.includes("--verbose");
44
- const debugMode = rest.includes("--debug");
91
+ const { yoloSeedFile, rest: afterYolo } = parseYoloFlag(trimmed);
92
+ const { milestoneId, rest: afterMilestone } = parseMilestoneTarget(afterYolo);
93
+ const verboseMode = afterMilestone.includes("--verbose");
94
+ const debugMode = afterMilestone.includes("--debug");
45
95
  if (debugMode)
46
96
  enableDebug(projectRoot());
47
97
  if (!(await guardRemoteSession(ctx, pi)))
48
98
  return true;
99
+ // Validate the milestone target exists and is not already complete.
100
+ if (milestoneId) {
101
+ const allIds = findMilestoneIds(projectRoot());
102
+ if (!allIds.includes(milestoneId)) {
103
+ ctx.ui.notify(`Milestone ${milestoneId} does not exist. Available: ${allIds.join(", ") || "(none)"}`, "error");
104
+ return true;
105
+ }
106
+ }
49
107
  if (yoloSeedFile) {
50
108
  const resolved = resolve(projectRoot(), yoloSeedFile);
51
109
  if (!existsSync(resolved)) {
@@ -63,6 +121,11 @@ export async function handleAutoCommand(trimmed, ctx, pi) {
63
121
  const { showHeadlessMilestoneCreation } = await import("../../guided-flow.js");
64
122
  await showHeadlessMilestoneCreation(ctx, pi, projectRoot(), seedContent);
65
123
  }
124
+ else if (milestoneId) {
125
+ // Target a specific milestone — use GSD_MILESTONE_LOCK so state
126
+ // derivation only sees this milestone (#2521).
127
+ await withMilestoneLock(milestoneId, () => startAuto(ctx, pi, projectRoot(), verboseMode));
128
+ }
66
129
  else {
67
130
  await startAuto(ctx, pi, projectRoot(), verboseMode);
68
131
  }
@@ -18,6 +18,11 @@ export const TOOL_KEYS = [
18
18
  { id: "jina", env: "JINA_API_KEY", label: "Jina Page Extract", hint: "jina.ai/api" },
19
19
  { id: "groq", env: "GROQ_API_KEY", label: "Groq Voice", hint: "console.groq.com" },
20
20
  ];
21
+ function getStoredToolKey(auth, providerId) {
22
+ const creds = auth.getCredentialsForProvider(providerId);
23
+ const cred = creds.find((c) => c.type === "api_key" && c.key);
24
+ return cred?.type === "api_key" ? cred.key : undefined;
25
+ }
21
26
  /**
22
27
  * Load tool API keys from auth.json into environment variables.
23
28
  * Called at session startup to ensure tools have access to their credentials.
@@ -29,9 +34,9 @@ export function loadToolApiKeys() {
29
34
  return;
30
35
  const auth = AuthStorage.create(authPath);
31
36
  for (const tool of TOOL_KEYS) {
32
- const cred = auth.get(tool.id);
33
- if (cred && cred.type === "api_key" && cred.key && !process.env[tool.env]) {
34
- process.env[tool.env] = cred.key;
37
+ const key = getStoredToolKey(auth, tool.id);
38
+ if (key && !process.env[tool.env]) {
39
+ process.env[tool.env] = key;
35
40
  }
36
41
  }
37
42
  }
@@ -49,13 +54,13 @@ export async function handleConfig(ctx) {
49
54
  // Show current status
50
55
  const statusLines = ["GSD Tool Configuration\n"];
51
56
  for (const tool of TOOL_KEYS) {
52
- const hasKey = !!process.env[tool.env] || !!auth.get(tool.id)?.key;
57
+ const hasKey = !!process.env[tool.env] || !!getStoredToolKey(auth, tool.id);
53
58
  statusLines.push(` ${hasKey ? "\u2713" : "\u2717"} ${tool.label}${hasKey ? "" : ` \u2014 get key at ${tool.hint}`}`);
54
59
  }
55
60
  ctx.ui.notify(statusLines.join("\n"), "info");
56
61
  // Ask which tools to configure
57
62
  const options = TOOL_KEYS.map(t => {
58
- const hasKey = !!process.env[t.env] || !!auth.get(t.id)?.key;
63
+ const hasKey = !!process.env[t.env] || !!getStoredToolKey(auth, t.id);
59
64
  return `${t.label} ${hasKey ? "(configured \u2713)" : "(not set)"}`;
60
65
  });
61
66
  options.push("(done)");
@@ -337,7 +337,7 @@ async function configureGit(ctx, prefs) {
337
337
  const gitBooleanFields = [
338
338
  { key: "auto_push", label: "Auto-push commits after committing", defaultVal: false },
339
339
  { key: "push_branches", label: "Push milestone branches to remote", defaultVal: false },
340
- { key: "snapshots", label: "Create WIP snapshot commits during long tasks", defaultVal: false },
340
+ { key: "snapshots", label: "Create WIP snapshot commits during long tasks", defaultVal: true },
341
341
  ];
342
342
  for (const field of gitBooleanFields) {
343
343
  const current = git[field.key];
@@ -361,7 +361,7 @@ async function configureGit(ctx, prefs) {
361
361
  }
362
362
  // pre_merge_check
363
363
  const currentPreMerge = git.pre_merge_check !== undefined ? String(git.pre_merge_check) : "";
364
- const preMergeChoice = await ctx.ui.select(`Pre-merge check${currentPreMerge ? ` (current: ${currentPreMerge})` : " (default: false)"}:`, ["true", "false", "auto", "(keep current)"]);
364
+ const preMergeChoice = await ctx.ui.select(`Pre-merge check${currentPreMerge ? ` (current: ${currentPreMerge})` : " (default: auto)"}:`, ["true", "false", "auto", "(keep current)"]);
365
365
  if (preMergeChoice && preMergeChoice !== "(keep current)") {
366
366
  if (preMergeChoice === "auto") {
367
367
  git.pre_merge_check = "auto";
@@ -487,7 +487,7 @@ export async function configureMode(ctx, prefs) {
487
487
  if (modeStr && modeStr !== "(keep current)") {
488
488
  if (modeStr.startsWith("solo")) {
489
489
  prefs.mode = "solo";
490
- ctx.ui.notify("Mode: solo — defaults: auto_push=true, push_branches=false, pre_merge_check=false, merge_strategy=squash, isolation=worktree, unique_milestone_ids=false", "info");
490
+ ctx.ui.notify("Mode: solo — defaults: auto_push=true, push_branches=false, pre_merge_check=auto, merge_strategy=squash, isolation=worktree, unique_milestone_ids=false", "info");
491
491
  }
492
492
  else if (modeStr.startsWith("team")) {
493
493
  prefs.mode = "team";
@@ -650,7 +650,7 @@ export function serializePreferencesToFrontmatter(prefs) {
650
650
  }
651
651
  export async function ensurePreferencesFile(path, ctx, scope) {
652
652
  if (!existsSync(path)) {
653
- const template = await loadFile(join(dirname(fileURLToPath(import.meta.url)), "templates", "preferences.md"));
653
+ const template = await loadFile(join(dirname(fileURLToPath(import.meta.url)), "templates", "PREFERENCES.md"));
654
654
  if (!template) {
655
655
  ctx.ui.notify("Could not load GSD preferences template.", "error");
656
656
  return;
@@ -277,8 +277,8 @@ function detectV2Gsd(basePath) {
277
277
  const gsdPath = gsdRoot(basePath);
278
278
  if (!existsSync(gsdPath))
279
279
  return null;
280
- const hasPreferences = existsSync(join(gsdPath, "preferences.md")) ||
281
- existsSync(join(gsdPath, "PREFERENCES.md"));
280
+ const hasPreferences = existsSync(join(gsdPath, "PREFERENCES.md")) ||
281
+ existsSync(join(gsdPath, "preferences.md"));
282
282
  const hasContext = existsSync(join(gsdPath, "CONTEXT.md"));
283
283
  let milestoneCount = 0;
284
284
  const milestonesPath = join(gsdPath, "milestones");
@@ -596,8 +596,8 @@ function detectVerificationCommands(basePath, detectedFiles, packageManager) {
596
596
  * Check if global GSD setup exists (has ~/.gsd/ with preferences).
597
597
  */
598
598
  export function hasGlobalSetup() {
599
- return (existsSync(join(gsdHome, "preferences.md")) ||
600
- existsSync(join(gsdHome, "PREFERENCES.md")));
599
+ return (existsSync(join(gsdHome, "PREFERENCES.md")) ||
600
+ existsSync(join(gsdHome, "preferences.md")));
601
601
  }
602
602
  /**
603
603
  * Check if this is the very first time GSD has been used on this machine.
@@ -607,8 +607,8 @@ export function isFirstEverLaunch() {
607
607
  if (!existsSync(gsdHome))
608
608
  return true;
609
609
  // If we have preferences, not first launch
610
- if (existsSync(join(gsdHome, "preferences.md")) ||
611
- existsSync(join(gsdHome, "PREFERENCES.md"))) {
610
+ if (existsSync(join(gsdHome, "PREFERENCES.md")) ||
611
+ existsSync(join(gsdHome, "preferences.md"))) {
612
612
  return false;
613
613
  }
614
614
  // If we have auth.json, not first launch (onboarding.ts already ran)
@@ -1,6 +1,6 @@
1
1
  # GSD Preferences Reference
2
2
 
3
- Full documentation for `~/.gsd/preferences.md` (global) and `.gsd/preferences.md` (project).
3
+ Full documentation for `~/.gsd/PREFERENCES.md` (global) and `.gsd/PREFERENCES.md` (project).
4
4
 
5
5
  ---
6
6
 
@@ -51,8 +51,8 @@ skill_rules: []
51
51
 
52
52
  Preferences are loaded from two locations and merged:
53
53
 
54
- 1. **Global:** `~/.gsd/preferences.md` — applies to all projects
55
- 2. **Project:** `.gsd/preferences.md` — applies to the current project only
54
+ 1. **Global:** `~/.gsd/PREFERENCES.md` — applies to all projects
55
+ 2. **Project:** `.gsd/PREFERENCES.md` — applies to the current project only
56
56
 
57
57
  **Merge behavior** (see `mergePreferences()` in `preferences.ts`):
58
58
 
@@ -126,8 +126,8 @@ Setting `prefer_skills: []` does **not** disable skill discovery — it just mea
126
126
  - `auto_push`: boolean — automatically push commits to the remote after committing. Default: `false`.
127
127
  - `push_branches`: boolean — push the milestone branch to the remote after commits. Default: `false`.
128
128
  - `remote`: string — git remote name to push to. Default: `"origin"`.
129
- - `snapshots`: boolean — create snapshot commits (WIP saves) during long-running tasks. Default: `false`.
130
- - `pre_merge_check`: boolean or `"auto"` — run pre-merge checks before merging a worktree back to the integration branch. `true` always runs, `false` never runs, `"auto"` runs when CI is detected. Default: `false`.
129
+ - `snapshots`: boolean — create snapshot commits (WIP saves) during long-running tasks. Default: `true`.
130
+ - `pre_merge_check`: boolean or `"auto"` — run pre-merge checks before merging a worktree back to the integration branch. `true` always runs, `false` never runs, `"auto"` runs when CI is detected. Default: `"auto"`.
131
131
  - `commit_type`: string — override the conventional commit type prefix. Must be one of: `feat`, `fix`, `refactor`, `docs`, `test`, `chore`, `perf`, `ci`, `build`, `style`. Default: inferred from diff content.
132
132
  - `main_branch`: string — the primary branch name for new git repos (e.g., `"main"`, `"master"`, `"trunk"`). Also used by `getMainBranch()` as the preferred branch when auto-detection is ambiguous. Default: `"main"`.
133
133
  - `merge_strategy`: `"squash"` or `"merge"` — controls how worktree branches are merged back. `"squash"` combines all commits into one; `"merge"` preserves individual commits. Default: `"squash"`.