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
@@ -88,6 +88,19 @@ function makeErrorMessage(model, errorMsg) {
88
88
  timestamp: Date.now(),
89
89
  };
90
90
  }
91
+ /**
92
+ * Generator exhaustion without a terminal result means the SDK stream was
93
+ * interrupted mid-turn. Surface it as an error so downstream recovery logic
94
+ * can classify and retry it instead of treating it as a clean completion.
95
+ */
96
+ export function makeStreamExhaustedErrorMessage(model, lastTextContent) {
97
+ const errorMsg = "stream_exhausted_without_result";
98
+ const message = makeErrorMessage(model, errorMsg);
99
+ if (lastTextContent) {
100
+ message.content = [{ type: "text", text: lastTextContent }];
101
+ }
102
+ return message;
103
+ }
91
104
  // ---------------------------------------------------------------------------
92
105
  // streamSimple implementation
93
106
  // ---------------------------------------------------------------------------
@@ -278,25 +291,11 @@ async function pumpSdkMessages(model, context, options, stream) {
278
291
  break;
279
292
  }
280
293
  }
281
- // Generator exhausted without a result message (unexpected)
282
- const fallbackContent = [];
283
- if (lastTextContent) {
284
- fallbackContent.push({ type: "text", text: lastTextContent });
285
- }
286
- if (fallbackContent.length === 0) {
287
- fallbackContent.push({ type: "text", text: "(Claude Code session ended without a response)" });
288
- }
289
- const fallback = {
290
- role: "assistant",
291
- content: fallbackContent,
292
- api: "anthropic-messages",
293
- provider: "claude-code",
294
- model: modelId,
295
- usage: { ...ZERO_USAGE },
296
- stopReason: "stop",
297
- timestamp: Date.now(),
298
- };
299
- stream.push({ type: "done", reason: "stop", message: fallback });
294
+ // Generator exhaustion without a terminal result is a stream interruption,
295
+ // not a successful completion. Emitting an error lets GSD classify it as a
296
+ // transient provider failure instead of advancing auto-mode state.
297
+ const fallback = makeStreamExhaustedErrorMessage(modelId, lastTextContent);
298
+ stream.push({ type: "error", reason: "error", error: fallback });
300
299
  }
301
300
  catch (err) {
302
301
  const errorMsg = err instanceof Error ? err.message : String(err);
@@ -25,6 +25,11 @@ function maskPreview(value) {
25
25
  function shellEscapeSingle(value) {
26
26
  return `'${value.replace(/'/g, `'\\''`)}'`;
27
27
  }
28
+ function hydrateProcessEnv(key, value) {
29
+ // Make newly collected secrets immediately visible to the current session.
30
+ // Some extensions read process.env directly and do not reload .env on every call.
31
+ process.env[key] = value;
32
+ }
28
33
  async function writeEnvKey(filePath, key, value) {
29
34
  let content = "";
30
35
  try {
@@ -246,6 +251,7 @@ async function applySecrets(provided, destination, opts) {
246
251
  try {
247
252
  await writeEnvKey(opts.envFilePath, key, value);
248
253
  applied.push(key);
254
+ hydrateProcessEnv(key, value);
249
255
  }
250
256
  catch (err) {
251
257
  errors.push(`${key}: ${err.message}`);
@@ -265,6 +271,7 @@ async function applySecrets(provided, destination, opts) {
265
271
  }
266
272
  else {
267
273
  applied.push(key);
274
+ hydrateProcessEnv(key, value);
268
275
  }
269
276
  }
270
277
  catch (err) {
@@ -15,12 +15,20 @@ import { PROJECT_FILES } from "../detection.js";
15
15
  import { MergeConflictError } from "../git-service.js";
16
16
  import { join } from "node:path";
17
17
  import { existsSync, cpSync } from "node:fs";
18
- import { logWarning } from "../workflow-logger.js";
18
+ import { logWarning, logError } from "../workflow-logger.js";
19
19
  import { gsdRoot } from "../paths.js";
20
20
  import { atomicWriteSync } from "../atomic-write.js";
21
21
  import { verifyExpectedArtifact } from "../auto-recovery.js";
22
22
  import { writeUnitRuntimeRecord } from "../unit-runtime.js";
23
23
  // ─── generateMilestoneReport ──────────────────────────────────────────────────
24
+ /**
25
+ * Resolve the base path for milestone reports.
26
+ * Prefers originalBasePath (project root) over basePath (which may be a worktree).
27
+ * Exported for testing as _resolveReportBasePath.
28
+ */
29
+ export function _resolveReportBasePath(s) {
30
+ return s.originalBasePath || s.basePath;
31
+ }
24
32
  /**
25
33
  * Generate and write an HTML milestone report snapshot.
26
34
  * Extracted from the milestone-transition block in autoLoop.
@@ -30,18 +38,19 @@ async function generateMilestoneReport(s, ctx, milestoneId) {
30
38
  const { generateHtmlReport } = await importExtensionModule(import.meta.url, "../export-html.js");
31
39
  const { writeReportSnapshot } = await importExtensionModule(import.meta.url, "../reports.js");
32
40
  const { basename } = await import("node:path");
33
- const snapData = await loadVisualizerData(s.basePath);
41
+ const reportBasePath = _resolveReportBasePath(s);
42
+ const snapData = await loadVisualizerData(reportBasePath);
34
43
  const completedMs = snapData.milestones.find((m) => m.id === milestoneId);
35
44
  const msTitle = completedMs?.title ?? milestoneId;
36
45
  const gsdVersion = process.env.GSD_VERSION ?? "0.0.0";
37
- const projName = basename(s.basePath);
46
+ const projName = basename(reportBasePath);
38
47
  const doneSlices = snapData.milestones.reduce((acc, m) => acc + m.slices.filter((sl) => sl.done).length, 0);
39
48
  const totalSlices = snapData.milestones.reduce((acc, m) => acc + m.slices.length, 0);
40
49
  const outPath = writeReportSnapshot({
41
- basePath: s.basePath,
50
+ basePath: reportBasePath,
42
51
  html: generateHtmlReport(snapData, {
43
52
  projectName: projName,
44
- projectPath: s.basePath,
53
+ projectPath: reportBasePath,
45
54
  gsdVersion,
46
55
  milestoneId,
47
56
  indexRelPath: "index.html",
@@ -50,7 +59,7 @@ async function generateMilestoneReport(s, ctx, milestoneId) {
50
59
  milestoneTitle: msTitle,
51
60
  kind: "milestone",
52
61
  projectName: projName,
53
- projectPath: s.basePath,
62
+ projectPath: reportBasePath,
54
63
  gsdVersion,
55
64
  totalCost: snapData.totals?.cost ?? 0,
56
65
  totalTokens: snapData.totals?.tokens.total ?? 0,
@@ -160,8 +169,11 @@ export async function runPreDispatch(ic, loopState) {
160
169
  await deps.stopAuto(ctx, pi, `Merge conflict on milestone ${s.currentMilestoneId}`);
161
170
  return { action: "break", reason: "merge-conflict" };
162
171
  }
163
- // Non-conflict merge errors — log and continue
164
- logWarning("engine", "Milestone merge failed with non-conflict error", { milestone: s.currentMilestoneId, error: String(mergeErr) });
172
+ // Non-conflict merge errors — stop auto to avoid advancing with unmerged work
173
+ logError("engine", "Milestone merge failed with non-conflict error", { milestone: s.currentMilestoneId, error: String(mergeErr) });
174
+ ctx.ui.notify(`Merge failed: ${mergeErr instanceof Error ? mergeErr.message : String(mergeErr)}. Resolve and run /gsd auto to resume.`, "error");
175
+ await deps.stopAuto(ctx, pi, `Merge error on milestone ${s.currentMilestoneId}: ${String(mergeErr)}`);
176
+ return { action: "break", reason: "merge-failed" };
165
177
  }
166
178
  // PR creation (auto_pr) is handled inside mergeMilestoneToMain (#2302)
167
179
  deps.invalidateAllCaches();
@@ -228,6 +240,10 @@ export async function runPreDispatch(ic, loopState) {
228
240
  await deps.stopAuto(ctx, pi, `Merge conflict on milestone ${s.currentMilestoneId}`);
229
241
  return { action: "break", reason: "merge-conflict" };
230
242
  }
243
+ logError("engine", "Milestone merge failed with non-conflict error", { milestone: s.currentMilestoneId, error: String(mergeErr) });
244
+ ctx.ui.notify(`Merge failed: ${mergeErr instanceof Error ? mergeErr.message : String(mergeErr)}. Resolve and run /gsd auto to resume.`, "error");
245
+ await deps.stopAuto(ctx, pi, `Merge error on milestone ${s.currentMilestoneId}: ${String(mergeErr)}`);
246
+ return { action: "break", reason: "merge-failed" };
231
247
  }
232
248
  // PR creation (auto_pr) is handled inside mergeMilestoneToMain (#2302)
233
249
  }
@@ -295,6 +311,10 @@ export async function runPreDispatch(ic, loopState) {
295
311
  await deps.stopAuto(ctx, pi, `Merge conflict on milestone ${s.currentMilestoneId}`);
296
312
  return { action: "break", reason: "merge-conflict" };
297
313
  }
314
+ logError("engine", "Milestone merge failed with non-conflict error", { milestone: s.currentMilestoneId, error: String(mergeErr) });
315
+ ctx.ui.notify(`Merge failed: ${mergeErr instanceof Error ? mergeErr.message : String(mergeErr)}. Resolve and run /gsd auto to resume.`, "error");
316
+ await deps.stopAuto(ctx, pi, `Merge error on milestone ${s.currentMilestoneId}: ${String(mergeErr)}`);
317
+ return { action: "break", reason: "merge-failed" };
298
318
  }
299
319
  // PR creation (auto_pr) is handled inside mergeMilestoneToMain (#2302)
300
320
  }
@@ -753,6 +773,12 @@ export async function runUnitPhase(ic, iterData, loopState, sidecarItem) {
753
773
  }
754
774
  }
755
775
  if (unitResult.status === "cancelled") {
776
+ // Provider-error pause: pauseAuto already handled cleanup and scheduled
777
+ // recovery. Don't hard-stop — just break out of the loop (#2762).
778
+ if (unitResult.errorContext?.category === "provider") {
779
+ debugLog("autoLoop", { phase: "exit", reason: "provider-pause", isTransient: unitResult.errorContext.isTransient });
780
+ return { action: "break", reason: "provider-pause" };
781
+ }
756
782
  ctx.ui.notify(`Session creation timed out or was cancelled for ${unitType} ${unitId}. Will retry.`, "warning");
757
783
  await deps.stopAuto(ctx, pi, "Session creation failed");
758
784
  debugLog("autoLoop", { phase: "exit", reason: "session-failed" });
@@ -483,6 +483,24 @@ export const DISPATCH_RULES = [
483
483
  match: async ({ state, mid, midTitle, basePath }) => {
484
484
  if (state.phase !== "completing-milestone")
485
485
  return null;
486
+ // Safety guard (#2675): block completion when VALIDATION verdict is
487
+ // needs-remediation. The state machine treats needs-remediation as
488
+ // terminal (to prevent validate-milestone loops per #832), but
489
+ // completing-milestone should NOT proceed — remediation work is needed.
490
+ const validationFile = resolveMilestoneFile(basePath, mid, "VALIDATION");
491
+ if (validationFile) {
492
+ const validationContent = await loadFile(validationFile);
493
+ if (validationContent) {
494
+ const verdict = extractVerdict(validationContent);
495
+ if (verdict === "needs-remediation") {
496
+ return {
497
+ action: "stop",
498
+ reason: `Cannot complete milestone ${mid}: VALIDATION verdict is "needs-remediation". Address the remediation findings and re-run validation, or update the verdict manually.`,
499
+ level: "warning",
500
+ };
501
+ }
502
+ }
503
+ }
486
504
  // Safety guard (#1368): verify all roadmap slices have SUMMARY files.
487
505
  const missingSlices = findMissingSummaries(basePath, mid);
488
506
  if (missingSlices.length > 0) {
@@ -513,8 +531,12 @@ export const DISPATCH_RULES = [
513
531
  if (validationPath) {
514
532
  const validationContent = await loadFile(validationPath);
515
533
  if (validationContent) {
516
- const hasOperationalCheck = validationContent.includes("Operational") &&
534
+ // Accept either the structured template format (table with MET/N/A)
535
+ // or prose evidence patterns the validation agent may emit.
536
+ const structuredMatch = validationContent.includes("Operational") &&
517
537
  (validationContent.includes("MET") || validationContent.includes("N/A"));
538
+ const proseMatch = /[Oo]perational[\s:][^\n]*(?:pass|verified|confirmed|met|complete|true|yes|addressed|covered|n\/a|not\s+applicable)/i.test(validationContent);
539
+ const hasOperationalCheck = structuredMatch || proseMatch;
518
540
  if (!hasOperationalCheck) {
519
541
  return {
520
542
  action: "stop",
@@ -34,6 +34,7 @@ import { isDbAvailable, getMilestone } from "./gsd-db.js";
34
34
  import { hideFooter } from "./auto-dashboard.js";
35
35
  import { debugLog, enableDebug, isDebugEnabled, getDebugLogPath, } from "./debug-logger.js";
36
36
  import { parseUnitId } from "./unit-id.js";
37
+ import { setLogBasePath } from "./workflow-logger.js";
37
38
  import { existsSync, mkdirSync, readdirSync, statSync, unlinkSync, } from "node:fs";
38
39
  import { join } from "node:path";
39
40
  import { sep as pathSep } from "node:path";
@@ -312,6 +313,7 @@ export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, reques
312
313
  s.verbose = verboseMode;
313
314
  s.cmdCtx = ctx;
314
315
  s.basePath = base;
316
+ setLogBasePath(base);
315
317
  s.unitDispatchCount.clear();
316
318
  s.unitRecoveryCount.clear();
317
319
  s.lastBudgetAlertLevel = 0;
@@ -9,7 +9,7 @@ import { readUnitRuntimeRecord, writeUnitRuntimeRecord } from "./unit-runtime.js
9
9
  import { isDbAvailable, getMilestoneSlices, getSliceTasks } from "./gsd-db.js";
10
10
  import { resolveAutoSupervisorConfig } from "./preferences.js";
11
11
  import { computeBudgets, resolveExecutorContextWindow } from "./context-budget.js";
12
- import { getInFlightToolCount, getOldestInFlightToolStart, } from "./auto-tool-tracking.js";
12
+ import { getInFlightToolCount, getOldestInFlightToolStart, clearInFlightTools, hasInteractiveToolInFlight, } from "./auto-tool-tracking.js";
13
13
  import { detectWorkingTreeActivity } from "./auto-supervisor.js";
14
14
  import { closeoutUnit } from "./auto-unit-closeout.js";
15
15
  import { saveActivityLog } from "./activity-log.js";
@@ -116,7 +116,17 @@ export function startUnitSupervision(sctx) {
116
116
  return;
117
117
  // Agent has tool calls currently executing — not idle, just waiting.
118
118
  // But only suppress recovery if the tool started recently.
119
+ let stalledToolDetected = false;
119
120
  if (getInFlightToolCount() > 0) {
121
+ // User-interactive tools (ask_user_questions, secure_env_collect) block
122
+ // waiting for human input by design — never treat them as stalled (#2676).
123
+ if (hasInteractiveToolInFlight()) {
124
+ writeUnitRuntimeRecord(s.basePath, unitType, unitId, s.currentUnit.startedAt, {
125
+ lastProgressAt: Date.now(),
126
+ lastProgressKind: "interactive-tool-waiting",
127
+ });
128
+ return;
129
+ }
120
130
  const oldestStart = getOldestInFlightToolStart();
121
131
  const toolAgeMs = Date.now() - oldestStart;
122
132
  if (toolAgeMs < idleTimeoutMs) {
@@ -126,10 +136,18 @@ export function startUnitSupervision(sctx) {
126
136
  });
127
137
  return;
128
138
  }
139
+ // Tool has been in-flight longer than idle timeout — treat as hung.
140
+ // Clear the stale entries so subsequent ticks don't re-detect them,
141
+ // and set the flag so the filesystem-activity check below does not
142
+ // override the stall verdict (#2527).
143
+ stalledToolDetected = true;
144
+ clearInFlightTools();
129
145
  ctx.ui.notify(`Stalled tool detected: a tool has been in-flight for ${Math.round(toolAgeMs / 60000)}min. Treating as hung — attempting idle recovery.`, "warning");
130
146
  }
131
147
  // Check if the agent is producing work on disk.
132
- if (detectWorkingTreeActivity(s.basePath)) {
148
+ // Skip this when a stalled tool was just detected — filesystem changes
149
+ // from earlier in the task should not override the stall verdict (#2527).
150
+ if (!stalledToolDetected && detectWorkingTreeActivity(s.basePath)) {
133
151
  writeUnitRuntimeRecord(s.basePath, unitType, unitId, s.currentUnit.startedAt, {
134
152
  lastProgressAt: Date.now(),
135
153
  lastProgressKind: "filesystem-activity",
@@ -145,6 +163,10 @@ export function startUnitSupervision(sctx) {
145
163
  const recovery = await recoverTimedOutUnit(ctx, pi, unitType, unitId, "idle", buildRecoveryContext());
146
164
  if (recovery === "recovered")
147
165
  return;
166
+ // Guard: recoverTimedOutUnit is async — pauseAuto/stopAuto may have
167
+ // set s.currentUnit = null during the await (#2527).
168
+ if (!s.currentUnit)
169
+ return;
148
170
  writeUnitRuntimeRecord(s.basePath, unitType, unitId, s.currentUnit.startedAt, {
149
171
  phase: "paused",
150
172
  });
@@ -4,14 +4,20 @@
4
4
  * can distinguish "waiting for tool completion" from "truly idle".
5
5
  */
6
6
  const inFlightTools = new Map();
7
+ /**
8
+ * Tools that block waiting for human input by design.
9
+ * The idle watchdog must not treat these as stalled.
10
+ */
11
+ const INTERACTIVE_TOOLS = new Set(["ask_user_questions", "secure_env_collect"]);
7
12
  /**
8
13
  * Mark a tool execution as in-flight.
9
- * Records start time so the idle watchdog can detect tools hung longer than the idle timeout.
14
+ * Records start time and tool name so the idle watchdog can detect tools
15
+ * hung longer than the idle timeout while exempting interactive tools.
10
16
  */
11
- export function markToolStart(toolCallId, isActive) {
17
+ export function markToolStart(toolCallId, isActive, toolName) {
12
18
  if (!isActive)
13
19
  return;
14
- inFlightTools.set(toolCallId, Date.now());
20
+ inFlightTools.set(toolCallId, { startedAt: Date.now(), toolName: toolName ?? "unknown" });
15
21
  }
16
22
  /**
17
23
  * Mark a tool execution as completed.
@@ -27,8 +33,8 @@ export function getOldestInFlightToolAgeMs() {
27
33
  return 0;
28
34
  let oldestStart = Infinity;
29
35
  for (const t of inFlightTools.values()) {
30
- if (t < oldestStart)
31
- oldestStart = t;
36
+ if (t.startedAt < oldestStart)
37
+ oldestStart = t.startedAt;
32
38
  }
33
39
  return Date.now() - oldestStart;
34
40
  }
@@ -46,11 +52,23 @@ export function getOldestInFlightToolStart() {
46
52
  return undefined;
47
53
  let oldest = Infinity;
48
54
  for (const t of inFlightTools.values()) {
49
- if (t < oldest)
50
- oldest = t;
55
+ if (t.startedAt < oldest)
56
+ oldest = t.startedAt;
51
57
  }
52
58
  return oldest;
53
59
  }
60
+ /**
61
+ * Returns true if any currently in-flight tool is a user-interactive tool
62
+ * (e.g. ask_user_questions, secure_env_collect) that blocks waiting for
63
+ * human input. These must be exempt from idle stall detection.
64
+ */
65
+ export function hasInteractiveToolInFlight() {
66
+ for (const { toolName } of inFlightTools.values()) {
67
+ if (INTERACTIVE_TOOLS.has(toolName))
68
+ return true;
69
+ }
70
+ return false;
71
+ }
54
72
  /**
55
73
  * Clear all in-flight tool tracking state.
56
74
  */
@@ -37,6 +37,10 @@ const ROOT_STATE_FILES = [
37
37
  "QUEUE.md",
38
38
  "completed-units.json",
39
39
  "metrics.json",
40
+ // NOTE: preferences.md is intentionally NOT in ROOT_STATE_FILES.
41
+ // Forward-sync (main → worktree) is handled explicitly in syncGsdStateToWorktree().
42
+ // Back-sync (worktree → main) must NEVER overwrite the project root's copy
43
+ // because the project root is authoritative for preferences (#2684).
40
44
  ];
41
45
  /**
42
46
  * Check if two filesystem paths resolve to the same real location.
@@ -100,6 +104,21 @@ function clearProjectRootStateFiles(basePath, milestoneId) {
100
104
  }
101
105
  }
102
106
  }
107
+ // ─── Build Artifact Auto-Resolve ─────────────────────────────────────────────
108
+ /** Patterns for machine-generated build artifacts that can be safely
109
+ * auto-resolved by accepting --theirs during merge. These files are
110
+ * regenerable and never contain meaningful manual edits. */
111
+ export const SAFE_AUTO_RESOLVE_PATTERNS = [
112
+ /\.tsbuildinfo$/,
113
+ /\.pyc$/,
114
+ /\/__pycache__\//,
115
+ /\.DS_Store$/,
116
+ /\.map$/,
117
+ ];
118
+ /** Returns true if the file path is safe to auto-resolve during merge.
119
+ * Covers `.gsd/` state files and common build artifacts. */
120
+ export const isSafeToAutoResolve = (filePath) => filePath.startsWith(".gsd/") ||
121
+ SAFE_AUTO_RESOLVE_PATTERNS.some((re) => re.test(filePath));
103
122
  // ─── Dispatch-Level Sync (project root ↔ worktree) ──────────────────────────
104
123
  /**
105
124
  * Sync milestone artifacts from project root INTO worktree before deriveState.
@@ -319,6 +338,22 @@ export function syncGsdStateToWorktree(mainBasePath, worktreePath_) {
319
338
  }
320
339
  }
321
340
  }
341
+ // Forward-sync preferences.md from project root to worktree (additive only).
342
+ // NOT in ROOT_STATE_FILES because syncWorktreeStateBack() must never overwrite
343
+ // the project root's preferences — the project root is authoritative (#2684).
344
+ {
345
+ const src = join(mainGsd, "preferences.md");
346
+ const dst = join(wtGsd, "preferences.md");
347
+ if (existsSync(src) && !existsSync(dst)) {
348
+ try {
349
+ cpSync(src, dst);
350
+ synced.push("preferences.md");
351
+ }
352
+ catch {
353
+ /* non-fatal */
354
+ }
355
+ }
356
+ }
322
357
  // Sync milestones: copy entire milestone directories that are missing
323
358
  const mainMilestonesDir = join(mainGsd, "milestones");
324
359
  const wtMilestonesDir = join(wtGsd, "milestones");
@@ -801,6 +836,7 @@ function copyPlanningArtifacts(srcBase, wtPath) {
801
836
  "STATE.md",
802
837
  "KNOWLEDGE.md",
803
838
  "OVERRIDES.md",
839
+ "preferences.md",
804
840
  ]) {
805
841
  safeCopy(join(srcGsd, file), join(dstGsd, file), { force: true });
806
842
  }
@@ -1170,27 +1206,27 @@ export function mergeMilestoneToMain(originalBasePath_, milestoneId, roadmapCont
1170
1206
  ? mergeResult.conflicts
1171
1207
  : nativeConflictFiles(originalBasePath_);
1172
1208
  if (conflictedFiles.length > 0) {
1173
- // Separate .gsd/ state file conflicts from real code conflicts.
1174
- // GSD state files (STATE.md, auto.lock, etc.)
1175
- // diverge between branches during normal operation always prefer the
1176
- // milestone branch version since it has the latest execution state.
1177
- const gsdConflicts = conflictedFiles.filter((f) => f.startsWith(".gsd/"));
1178
- const codeConflicts = conflictedFiles.filter((f) => !f.startsWith(".gsd/"));
1179
- // Auto-resolve .gsd/ conflicts by accepting the milestone branch version
1180
- if (gsdConflicts.length > 0) {
1181
- for (const gsdFile of gsdConflicts) {
1209
+ // Separate auto-resolvable conflicts (GSD state files + build artifacts)
1210
+ // from real code conflicts. GSD state files diverge between branches
1211
+ // during normal operation. Build artifacts are machine-generated and
1212
+ // regenerable. Both are safe to accept from the milestone branch.
1213
+ const autoResolvable = conflictedFiles.filter(isSafeToAutoResolve);
1214
+ const codeConflicts = conflictedFiles.filter((f) => !isSafeToAutoResolve(f));
1215
+ // Auto-resolve safe conflicts by accepting the milestone branch version
1216
+ if (autoResolvable.length > 0) {
1217
+ for (const safeFile of autoResolvable) {
1182
1218
  try {
1183
- nativeCheckoutTheirs(originalBasePath_, [gsdFile]);
1184
- nativeAddPaths(originalBasePath_, [gsdFile]);
1219
+ nativeCheckoutTheirs(originalBasePath_, [safeFile]);
1220
+ nativeAddPaths(originalBasePath_, [safeFile]);
1185
1221
  }
1186
1222
  catch {
1187
1223
  // If checkout --theirs fails, try removing the file from the merge
1188
1224
  // (it's a runtime file that shouldn't be committed anyway)
1189
- nativeRmForce(originalBasePath_, [gsdFile]);
1225
+ nativeRmForce(originalBasePath_, [safeFile]);
1190
1226
  }
1191
1227
  }
1192
1228
  }
1193
- // If there are still non-.gsd conflicts, escalate
1229
+ // If there are still real code conflicts, escalate
1194
1230
  if (codeConflicts.length > 0) {
1195
1231
  // Pop stash before throwing so local work is not lost (#2151).
1196
1232
  if (stashed) {
@@ -1235,7 +1271,48 @@ export function mergeMilestoneToMain(originalBasePath_, milestoneId, roadmapCont
1235
1271
  });
1236
1272
  }
1237
1273
  catch {
1238
- // Stash pop conflict is non-fatal stash entry persists for manual resolution.
1274
+ // Stash pop after squash merge can conflict on .gsd/ state files that
1275
+ // diverged between branches. Left unresolved, these UU entries block
1276
+ // every subsequent merge. Auto-resolve them the same way we handle
1277
+ // .gsd/ conflicts during the merge itself: accept HEAD (the just-committed
1278
+ // version) and drop the now-applied stash.
1279
+ const uu = nativeConflictFiles(originalBasePath_);
1280
+ const gsdUU = uu.filter((f) => f.startsWith(".gsd/"));
1281
+ const nonGsdUU = uu.filter((f) => !f.startsWith(".gsd/"));
1282
+ if (gsdUU.length > 0) {
1283
+ for (const f of gsdUU) {
1284
+ try {
1285
+ // Accept the committed (HEAD) version of the state file
1286
+ execFileSync("git", ["checkout", "HEAD", "--", f], {
1287
+ cwd: originalBasePath_,
1288
+ stdio: ["ignore", "pipe", "pipe"],
1289
+ encoding: "utf-8",
1290
+ });
1291
+ nativeAddPaths(originalBasePath_, [f]);
1292
+ }
1293
+ catch {
1294
+ // Last resort: remove the conflicted state file
1295
+ nativeRmForce(originalBasePath_, [f]);
1296
+ }
1297
+ }
1298
+ }
1299
+ if (nonGsdUU.length === 0) {
1300
+ // All conflicts were .gsd/ files — safe to drop the stash
1301
+ try {
1302
+ execFileSync("git", ["stash", "drop"], {
1303
+ cwd: originalBasePath_,
1304
+ stdio: ["ignore", "pipe", "pipe"],
1305
+ encoding: "utf-8",
1306
+ });
1307
+ }
1308
+ catch { /* stash may already be consumed */ }
1309
+ }
1310
+ else {
1311
+ // Non-.gsd conflicts remain — leave stash for manual resolution
1312
+ logWarning("reconcile", "Stash pop conflict on non-.gsd files after merge", {
1313
+ files: nonGsdUU.join(", "),
1314
+ });
1315
+ }
1239
1316
  }
1240
1317
  }
1241
1318
  // 9b. Safety check (#1792): if nothing was committed, verify the milestone
@@ -34,6 +34,7 @@ import { clearSkillSnapshot } from "./skill-discovery.js";
34
34
  import { captureAvailableSkills, resetSkillTelemetry, } from "./skill-telemetry.js";
35
35
  import { getRtkSessionSavings } from "../shared/rtk-session-stats.js";
36
36
  import { initMetrics, resetMetrics, getLedger, getProjectTotals, formatCost, formatTokenCount, } from "./metrics.js";
37
+ import { setLogBasePath } from "./workflow-logger.js";
37
38
  import { join } from "node:path";
38
39
  import { readFileSync, existsSync, mkdirSync, writeFileSync, unlinkSync } from "node:fs";
39
40
  import { atomicWriteSync } from "./atomic-write.js";
@@ -184,8 +185,8 @@ export function getAutoModeStartModel() {
184
185
  return s.autoModeStartModel;
185
186
  }
186
187
  // Tool tracking — delegates to auto-tool-tracking.ts
187
- export function markToolStart(toolCallId) {
188
- _markToolStart(toolCallId, s.active);
188
+ export function markToolStart(toolCallId, toolName) {
189
+ _markToolStart(toolCallId, s.active, toolName);
189
190
  }
190
191
  export function markToolEnd(toolCallId) {
191
192
  _markToolEnd(toolCallId);
@@ -214,6 +215,12 @@ export function stopAutoRemote(projectRoot) {
214
215
  const lock = readCrashLock(projectRoot);
215
216
  if (!lock)
216
217
  return { found: false };
218
+ // Never SIGTERM ourselves — a stale lock with our own PID is not a remote
219
+ // session, it is leftover from a prior loop exit in this process. (#2730)
220
+ if (lock.pid === process.pid) {
221
+ clearLock(projectRoot);
222
+ return { found: false };
223
+ }
217
224
  if (!isLockProcessAlive(lock)) {
218
225
  // Stale lock — clean it up
219
226
  clearLock(projectRoot);
@@ -238,6 +245,10 @@ export function checkRemoteAutoSession(projectRoot) {
238
245
  const lock = readCrashLock(projectRoot);
239
246
  if (!lock)
240
247
  return { running: false };
248
+ // Our own PID is not a "remote" session — it is a stale lock left by this
249
+ // process (e.g. after step-mode exit without full cleanup). (#2730)
250
+ if (lock.pid === process.pid)
251
+ return { running: false };
241
252
  if (!isLockProcessAlive(lock)) {
242
253
  // Stale lock from a dead process — not a live remote session
243
254
  return { running: false };
@@ -320,6 +331,18 @@ function cleanupAfterLoopExit(ctx) {
320
331
  s.currentUnit = null;
321
332
  s.active = false;
322
333
  clearUnitTimeout();
334
+ // Clear crash lock and release session lock so the next `/gsd next` does
335
+ // not see a stale lock with the current PID and treat it as a "remote"
336
+ // session (which would cause it to SIGTERM itself). (#2730)
337
+ try {
338
+ if (lockBase())
339
+ clearLock(lockBase());
340
+ if (lockBase())
341
+ releaseSessionLock(lockBase());
342
+ }
343
+ catch {
344
+ /* best-effort — mirror stopAuto cleanup */
345
+ }
323
346
  ctx.ui.setStatus("gsd-auto", undefined);
324
347
  ctx.ui.setWidget("gsd-progress", undefined);
325
348
  ctx.ui.setFooter(undefined);
@@ -553,12 +576,14 @@ export async function stopAuto(ctx, pi, reason) {
553
576
  * The user can interact with the agent, then `/gsd auto` resumes
554
577
  * from disk state. Called when the user presses Escape during auto-mode.
555
578
  */
556
- export async function pauseAuto(ctx, _pi) {
579
+ export async function pauseAuto(ctx, _pi, _errorContext) {
557
580
  if (!s.active)
558
581
  return;
559
582
  clearUnitTimeout();
560
583
  // Unblock any pending unit promise so the auto-loop is not orphaned.
561
- resolveAgentEndCancelled();
584
+ // Pass errorContext so runUnitPhase can distinguish user-initiated pause
585
+ // from provider-error pause and avoid hard-stopping (#2762).
586
+ resolveAgentEndCancelled(_errorContext);
562
587
  s.pausedSessionFile = ctx?.sessionManager?.getSessionFile() ?? null;
563
588
  // Persist paused-session metadata so resume survives /exit (#1383).
564
589
  // The fresh-start bootstrap checks for this file and restores worktree context.
@@ -815,6 +840,7 @@ export async function startAuto(ctx, pi, base, verboseMode, options) {
815
840
  s.stepMode = requestedStepMode;
816
841
  s.cmdCtx = ctx;
817
842
  s.basePath = base;
843
+ setLogBasePath(base);
818
844
  s.unitDispatchCount.clear();
819
845
  s.unitLifetimeDispatches.clear();
820
846
  if (!getLedger())