gsd-pi 2.80.0-dev.3065f7bfa → 2.80.0-dev.488219eb6

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 (376) hide show
  1. package/dist/claude-cli-check.d.ts +30 -0
  2. package/dist/claude-cli-check.js +18 -7
  3. package/dist/cli.js +0 -19
  4. package/dist/headless-query.d.ts +10 -0
  5. package/dist/headless-query.js +6 -4
  6. package/dist/loader-entrypoint.d.ts +8 -0
  7. package/dist/loader-entrypoint.js +27 -0
  8. package/dist/loader.js +2 -11
  9. package/dist/mcp-server.d.ts +1 -0
  10. package/dist/mcp-server.js +6 -3
  11. package/dist/resources/.managed-resources-content-hash +1 -1
  12. package/dist/resources/extensions/claude-code-cli/readiness.js +18 -7
  13. package/dist/resources/extensions/claude-code-cli/stream-adapter.js +29 -0
  14. package/dist/resources/extensions/github-sync/sync.js +4 -1
  15. package/dist/resources/extensions/gsd/auto/loop.js +71 -8
  16. package/dist/resources/extensions/gsd/auto/phases.js +32 -8
  17. package/dist/resources/extensions/gsd/auto/resolve.js +12 -0
  18. package/dist/resources/extensions/gsd/auto/run-unit.js +3 -1
  19. package/dist/resources/extensions/gsd/auto/workflow-dispatch-claim.js +33 -1
  20. package/dist/resources/extensions/gsd/auto/workflow-worker-heartbeat.js +9 -1
  21. package/dist/resources/extensions/gsd/auto-post-unit.js +81 -76
  22. package/dist/resources/extensions/gsd/auto-start.js +41 -6
  23. package/dist/resources/extensions/gsd/auto-worktree.js +98 -80
  24. package/dist/resources/extensions/gsd/auto.js +84 -29
  25. package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +62 -13
  26. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +20 -26
  27. package/dist/resources/extensions/gsd/bootstrap/dynamic-tools.js +29 -12
  28. package/dist/resources/extensions/gsd/bootstrap/exec-tools.js +6 -9
  29. package/dist/resources/extensions/gsd/bootstrap/journal-tools.js +4 -7
  30. package/dist/resources/extensions/gsd/bootstrap/memory-tools.js +6 -10
  31. package/dist/resources/extensions/gsd/bootstrap/query-tools.js +5 -9
  32. package/dist/resources/extensions/gsd/bootstrap/register-extension.js +1 -1
  33. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +60 -26
  34. package/dist/resources/extensions/gsd/bootstrap/sanitize-complete-milestone.js +4 -0
  35. package/dist/resources/extensions/gsd/commands/handlers/ops.js +2 -2
  36. package/dist/resources/extensions/gsd/commands-config.js +1 -1
  37. package/dist/resources/extensions/gsd/commands-eval-review.js +2 -2
  38. package/dist/resources/extensions/gsd/dashboard-overlay.js +1 -1
  39. package/dist/resources/extensions/gsd/db/unit-dispatches.js +53 -0
  40. package/dist/resources/extensions/gsd/git-service.js +37 -1
  41. package/dist/resources/extensions/gsd/guided-flow.js +14 -4
  42. package/dist/resources/extensions/gsd/init-wizard.js +4 -1
  43. package/dist/resources/extensions/gsd/prompts/complete-milestone.md +6 -4
  44. package/dist/resources/extensions/gsd/slice-cadence.js +45 -2
  45. package/dist/resources/extensions/gsd/slice-parallel-orchestrator.js +15 -9
  46. package/dist/resources/extensions/gsd/tools/complete-milestone.js +6 -7
  47. package/dist/resources/extensions/gsd/tools/complete-task.js +1 -1
  48. package/dist/resources/extensions/gsd/worktree-resolver.js +22 -1
  49. package/dist/resources/skills/web-quality-audit/scripts/analyze.sh +0 -0
  50. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  51. package/dist/web/standalone/.next/BUILD_ID +1 -1
  52. package/dist/web/standalone/.next/app-path-routes-manifest.json +17 -17
  53. package/dist/web/standalone/.next/build-manifest.json +3 -3
  54. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  55. package/dist/web/standalone/.next/react-loadable-manifest.json +2 -2
  56. package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  57. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  58. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  59. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  60. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  61. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  62. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  63. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  64. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  65. package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  66. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  67. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  68. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  69. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  70. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  71. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  72. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  73. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  74. package/dist/web/standalone/.next/server/app/index.html +1 -1
  75. package/dist/web/standalone/.next/server/app/index.rsc +2 -2
  76. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  77. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +2 -2
  78. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  79. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  80. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  81. package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  82. package/dist/web/standalone/.next/server/app-paths-manifest.json +17 -17
  83. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  84. package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
  85. package/dist/web/standalone/.next/server/middleware.js +3 -3
  86. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  87. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  88. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  89. package/dist/web/standalone/.next/static/chunks/8359.e059d86b255fce1c.js +10 -0
  90. package/dist/web/standalone/.next/static/chunks/app/{page-fab3ebb85b006001.js → page-752f1e2ebdaa3e45.js} +1 -1
  91. package/dist/web/standalone/.next/static/chunks/{webpack-0481f1221120a7c6.js → webpack-de742b64187e13fe.js} +1 -1
  92. package/dist/welcome-screen.d.ts +2 -0
  93. package/dist/welcome-screen.js +9 -7
  94. package/package.json +1 -1
  95. package/packages/pi-ai/dist/providers/anthropic-auth.test.js +35 -13
  96. package/packages/pi-ai/dist/providers/anthropic-auth.test.js.map +1 -1
  97. package/packages/pi-ai/dist/providers/anthropic-bearer-auth.test.js +21 -11
  98. package/packages/pi-ai/dist/providers/anthropic-bearer-auth.test.js.map +1 -1
  99. package/packages/pi-ai/dist/providers/anthropic.d.ts +7 -0
  100. package/packages/pi-ai/dist/providers/anthropic.d.ts.map +1 -1
  101. package/packages/pi-ai/dist/providers/anthropic.js +9 -7
  102. package/packages/pi-ai/dist/providers/anthropic.js.map +1 -1
  103. package/packages/pi-ai/dist/providers/minimax-tool-name.test.js +23 -14
  104. package/packages/pi-ai/dist/providers/minimax-tool-name.test.js.map +1 -1
  105. package/packages/pi-ai/dist/utils/oauth/github-copilot.test.js +48 -21
  106. package/packages/pi-ai/dist/utils/oauth/github-copilot.test.js.map +1 -1
  107. package/packages/pi-ai/dist/utils/oauth/google-antigravity.test.js +22 -21
  108. package/packages/pi-ai/dist/utils/oauth/google-antigravity.test.js.map +1 -1
  109. package/packages/pi-ai/dist/utils/oauth/google-gemini-cli.test.js +22 -21
  110. package/packages/pi-ai/dist/utils/oauth/google-gemini-cli.test.js.map +1 -1
  111. package/packages/pi-ai/src/providers/anthropic-auth.test.ts +39 -25
  112. package/packages/pi-ai/src/providers/anthropic-bearer-auth.test.ts +26 -22
  113. package/packages/pi-ai/src/providers/anthropic.ts +22 -9
  114. package/packages/pi-ai/src/providers/minimax-tool-name.test.ts +34 -21
  115. package/packages/pi-ai/src/utils/oauth/github-copilot.test.ts +56 -22
  116. package/packages/pi-ai/src/utils/oauth/google-antigravity.test.ts +24 -28
  117. package/packages/pi-ai/src/utils/oauth/google-gemini-cli.test.ts +24 -28
  118. package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
  119. package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js +3 -1
  120. package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js.map +1 -1
  121. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts +2 -2
  122. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts.map +1 -1
  123. package/packages/pi-coding-agent/dist/core/extensions/types.js.map +1 -1
  124. package/packages/pi-coding-agent/dist/core/tools/bash-spawn-windows.test.js +22 -56
  125. package/packages/pi-coding-agent/dist/core/tools/bash-spawn-windows.test.js.map +1 -1
  126. package/packages/pi-coding-agent/dist/core/tools/bash.d.ts +1 -0
  127. package/packages/pi-coding-agent/dist/core/tools/bash.d.ts.map +1 -1
  128. package/packages/pi-coding-agent/dist/core/tools/bash.js +3 -1
  129. package/packages/pi-coding-agent/dist/core/tools/bash.js.map +1 -1
  130. package/packages/pi-coding-agent/dist/core/tools/edit.d.ts +2 -0
  131. package/packages/pi-coding-agent/dist/core/tools/edit.d.ts.map +1 -1
  132. package/packages/pi-coding-agent/dist/core/tools/edit.js +12 -1
  133. package/packages/pi-coding-agent/dist/core/tools/edit.js.map +1 -1
  134. package/packages/pi-coding-agent/dist/core/tools/find.d.ts +2 -0
  135. package/packages/pi-coding-agent/dist/core/tools/find.d.ts.map +1 -1
  136. package/packages/pi-coding-agent/dist/core/tools/find.js +14 -6
  137. package/packages/pi-coding-agent/dist/core/tools/find.js.map +1 -1
  138. package/packages/pi-coding-agent/dist/core/tools/grep.d.ts +2 -0
  139. package/packages/pi-coding-agent/dist/core/tools/grep.d.ts.map +1 -1
  140. package/packages/pi-coding-agent/dist/core/tools/grep.js +12 -3
  141. package/packages/pi-coding-agent/dist/core/tools/grep.js.map +1 -1
  142. package/packages/pi-coding-agent/dist/core/tools/hashline-read.d.ts +2 -0
  143. package/packages/pi-coding-agent/dist/core/tools/hashline-read.d.ts.map +1 -1
  144. package/packages/pi-coding-agent/dist/core/tools/hashline-read.js +3 -1
  145. package/packages/pi-coding-agent/dist/core/tools/hashline-read.js.map +1 -1
  146. package/packages/pi-coding-agent/dist/core/tools/index.d.ts +2 -1
  147. package/packages/pi-coding-agent/dist/core/tools/index.d.ts.map +1 -1
  148. package/packages/pi-coding-agent/dist/core/tools/index.js +1 -0
  149. package/packages/pi-coding-agent/dist/core/tools/index.js.map +1 -1
  150. package/packages/pi-coding-agent/dist/core/tools/ls.d.ts +2 -0
  151. package/packages/pi-coding-agent/dist/core/tools/ls.d.ts.map +1 -1
  152. package/packages/pi-coding-agent/dist/core/tools/ls.js +10 -3
  153. package/packages/pi-coding-agent/dist/core/tools/ls.js.map +1 -1
  154. package/packages/pi-coding-agent/dist/core/tools/read.d.ts +2 -0
  155. package/packages/pi-coding-agent/dist/core/tools/read.d.ts.map +1 -1
  156. package/packages/pi-coding-agent/dist/core/tools/read.js +3 -1
  157. package/packages/pi-coding-agent/dist/core/tools/read.js.map +1 -1
  158. package/packages/pi-coding-agent/dist/core/tools/spawn-shell-windows.test.js +7 -62
  159. package/packages/pi-coding-agent/dist/core/tools/spawn-shell-windows.test.js.map +1 -1
  160. package/packages/pi-coding-agent/dist/core/tools/tool-target-metadata.test.d.ts +2 -0
  161. package/packages/pi-coding-agent/dist/core/tools/tool-target-metadata.test.d.ts.map +1 -0
  162. package/packages/pi-coding-agent/dist/core/tools/tool-target-metadata.test.js +115 -0
  163. package/packages/pi-coding-agent/dist/core/tools/tool-target-metadata.test.js.map +1 -0
  164. package/packages/pi-coding-agent/dist/core/tools/tool-target.d.ts +19 -0
  165. package/packages/pi-coding-agent/dist/core/tools/tool-target.d.ts.map +1 -0
  166. package/packages/pi-coding-agent/dist/core/tools/tool-target.js +20 -0
  167. package/packages/pi-coding-agent/dist/core/tools/tool-target.js.map +1 -0
  168. package/packages/pi-coding-agent/dist/core/tools/write.d.ts +4 -0
  169. package/packages/pi-coding-agent/dist/core/tools/write.d.ts.map +1 -1
  170. package/packages/pi-coding-agent/dist/core/tools/write.js +9 -1
  171. package/packages/pi-coding-agent/dist/core/tools/write.js.map +1 -1
  172. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js +89 -2
  173. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js.map +1 -1
  174. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-card-cleanup-and-success-runtime.test.js +25 -1
  175. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-card-cleanup-and-success-runtime.test.js.map +1 -1
  176. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts +5 -0
  177. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  178. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +153 -8
  179. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
  180. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  181. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +18 -1
  182. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  183. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.test.js +23 -5
  184. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.test.js.map +1 -1
  185. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts +2 -0
  186. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  187. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +19 -0
  188. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  189. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage-safety-guard.test.js +23 -5
  190. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage-safety-guard.test.js.map +1 -1
  191. package/packages/pi-coding-agent/src/core/chat-controller-ordering.test.ts +3 -1
  192. package/packages/pi-coding-agent/src/core/extensions/types.ts +2 -1
  193. package/packages/pi-coding-agent/src/core/tools/bash-spawn-windows.test.ts +22 -66
  194. package/packages/pi-coding-agent/src/core/tools/bash.ts +4 -1
  195. package/packages/pi-coding-agent/src/core/tools/edit.ts +13 -1
  196. package/packages/pi-coding-agent/src/core/tools/find.ts +15 -6
  197. package/packages/pi-coding-agent/src/core/tools/grep.ts +13 -3
  198. package/packages/pi-coding-agent/src/core/tools/hashline-read.ts +4 -1
  199. package/packages/pi-coding-agent/src/core/tools/index.ts +8 -0
  200. package/packages/pi-coding-agent/src/core/tools/ls.ts +11 -3
  201. package/packages/pi-coding-agent/src/core/tools/read.ts +4 -1
  202. package/packages/pi-coding-agent/src/core/tools/spawn-shell-windows.test.ts +11 -72
  203. package/packages/pi-coding-agent/src/core/tools/tool-target-metadata.test.ts +127 -0
  204. package/packages/pi-coding-agent/src/core/tools/tool-target.ts +48 -0
  205. package/packages/pi-coding-agent/src/core/tools/write.ts +14 -2
  206. package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/tool-execution.test.ts +119 -2
  207. package/packages/pi-coding-agent/src/modes/interactive/components/tool-card-cleanup-and-success-runtime.test.ts +31 -1
  208. package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +177 -8
  209. package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.test.ts +24 -5
  210. package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +17 -1
  211. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +21 -0
  212. package/packages/pi-coding-agent/src/resources/extensions/memory/storage-safety-guard.test.ts +25 -8
  213. package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
  214. package/src/resources/extensions/claude-code-cli/readiness.ts +25 -7
  215. package/src/resources/extensions/claude-code-cli/stream-adapter.ts +30 -0
  216. package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +26 -0
  217. package/src/resources/extensions/github-sync/sync.ts +8 -1
  218. package/src/resources/extensions/github-sync/tests/sync-source.test.ts +6 -18
  219. package/src/resources/extensions/gsd/auto/loop.ts +84 -8
  220. package/src/resources/extensions/gsd/auto/phases.ts +43 -8
  221. package/src/resources/extensions/gsd/auto/resolve.ts +19 -0
  222. package/src/resources/extensions/gsd/auto/run-unit.ts +3 -0
  223. package/src/resources/extensions/gsd/auto/workflow-dispatch-claim.ts +63 -1
  224. package/src/resources/extensions/gsd/auto/workflow-worker-heartbeat.ts +14 -1
  225. package/src/resources/extensions/gsd/auto-post-unit.ts +93 -78
  226. package/src/resources/extensions/gsd/auto-start.ts +56 -6
  227. package/src/resources/extensions/gsd/auto-worktree.ts +118 -72
  228. package/src/resources/extensions/gsd/auto.ts +121 -29
  229. package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +76 -12
  230. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +20 -26
  231. package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +27 -12
  232. package/src/resources/extensions/gsd/bootstrap/exec-tools.ts +7 -9
  233. package/src/resources/extensions/gsd/bootstrap/journal-tools.ts +4 -7
  234. package/src/resources/extensions/gsd/bootstrap/memory-tools.ts +6 -10
  235. package/src/resources/extensions/gsd/bootstrap/query-tools.ts +5 -9
  236. package/src/resources/extensions/gsd/bootstrap/register-extension.ts +1 -1
  237. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +64 -26
  238. package/src/resources/extensions/gsd/bootstrap/sanitize-complete-milestone.ts +4 -0
  239. package/src/resources/extensions/gsd/commands/handlers/ops.ts +4 -2
  240. package/src/resources/extensions/gsd/commands-config.ts +1 -1
  241. package/src/resources/extensions/gsd/commands-eval-review.ts +2 -2
  242. package/src/resources/extensions/gsd/dashboard-overlay.ts +1 -1
  243. package/src/resources/extensions/gsd/db/unit-dispatches.ts +66 -0
  244. package/src/resources/extensions/gsd/git-service.ts +41 -2
  245. package/src/resources/extensions/gsd/guided-flow.ts +19 -4
  246. package/src/resources/extensions/gsd/init-wizard.ts +5 -1
  247. package/src/resources/extensions/gsd/prompts/complete-milestone.md +6 -4
  248. package/src/resources/extensions/gsd/slice-cadence.ts +49 -2
  249. package/src/resources/extensions/gsd/slice-parallel-orchestrator.ts +23 -9
  250. package/src/resources/extensions/gsd/tests/agent-end-retry.test.ts +59 -89
  251. package/src/resources/extensions/gsd/tests/artifact-retry-cap.test.ts +47 -172
  252. package/src/resources/extensions/gsd/tests/artifacts-table-preserved-on-cache-invalidate.test.ts +0 -35
  253. package/src/resources/extensions/gsd/tests/auto-dashboard.test.ts +35 -9
  254. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +15 -0
  255. package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +80 -59
  256. package/src/resources/extensions/gsd/tests/auto-paused-session-validation.test.ts +3 -47
  257. package/src/resources/extensions/gsd/tests/auto-paused-ui-cleanup.test.ts +76 -18
  258. package/src/resources/extensions/gsd/tests/auto-phases-lifecycle.test.ts +106 -0
  259. package/src/resources/extensions/gsd/tests/auto-pr-bugs.test.ts +54 -95
  260. package/src/resources/extensions/gsd/tests/auto-project-root-env.test.ts +67 -26
  261. package/src/resources/extensions/gsd/tests/auto-remediate-slice-status.test.ts +32 -30
  262. package/src/resources/extensions/gsd/tests/auto-start-bootstrap-await-3420.test.ts +32 -128
  263. package/src/resources/extensions/gsd/tests/auto-start-clean-runtime-db-gated.test.ts +20 -54
  264. package/src/resources/extensions/gsd/tests/auto-start-cold-db-bootstrap.test.ts +20 -30
  265. package/src/resources/extensions/gsd/tests/auto-start-index-lock.test.ts +17 -29
  266. package/src/resources/extensions/gsd/tests/auto-start-orphan-bootstrap.test.ts +138 -0
  267. package/src/resources/extensions/gsd/tests/auto-start-time-persistence.test.ts +21 -39
  268. package/src/resources/extensions/gsd/tests/auto-start-worktree-db-path.test.ts +15 -24
  269. package/src/resources/extensions/gsd/tests/auto-thinking-restore.test.ts +44 -29
  270. package/src/resources/extensions/gsd/tests/auto-warning-noise-regression.test.ts +39 -51
  271. package/src/resources/extensions/gsd/tests/auto-wrapup-inflight-guard.test.ts +1 -217
  272. package/src/resources/extensions/gsd/tests/bootstrap-derive-state-db-open.test.ts +15 -32
  273. package/src/resources/extensions/gsd/tests/browser-teardown.test.ts +0 -41
  274. package/src/resources/extensions/gsd/tests/clear-stale-autostart.test.ts +34 -27
  275. package/src/resources/extensions/gsd/tests/cmux.test.ts +51 -53
  276. package/src/resources/extensions/gsd/tests/cold-resume-db-reopen.test.ts +39 -61
  277. package/src/resources/extensions/gsd/tests/commands-config.test.ts +26 -19
  278. package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +140 -0
  279. package/src/resources/extensions/gsd/tests/complete-task-normalize-lists.test.ts +29 -33
  280. package/src/resources/extensions/gsd/tests/completed-units-metrics-sync.test.ts +45 -108
  281. package/src/resources/extensions/gsd/tests/crash-handler-secondary.test.ts +35 -31
  282. package/src/resources/extensions/gsd/tests/cwd-fallback-hardening.test.ts +138 -0
  283. package/src/resources/extensions/gsd/tests/dashboard-custom-engine.test.ts +4 -68
  284. package/src/resources/extensions/gsd/tests/deep-project-auto-loop.test.ts +4 -9
  285. package/src/resources/extensions/gsd/tests/deferred-milestone-dir-4996.test.ts +14 -65
  286. package/src/resources/extensions/gsd/tests/discuss-tool-scoping.test.ts +44 -37
  287. package/src/resources/extensions/gsd/tests/dispatch-complete-milestone-guard.test.ts +58 -40
  288. package/src/resources/extensions/gsd/tests/dispatch-guard-closed-status.test.ts +25 -15
  289. package/src/resources/extensions/gsd/tests/dispatcher-stuck-planning.test.ts +35 -17
  290. package/src/resources/extensions/gsd/tests/error-success-mask.test.ts +16 -21
  291. package/src/resources/extensions/gsd/tests/est-annotation-timeout.test.ts +15 -82
  292. package/src/resources/extensions/gsd/tests/flat-rate-routing-guard.test.ts +2 -20
  293. package/src/resources/extensions/gsd/tests/frontmatter-parse-noise.test.ts +18 -26
  294. package/src/resources/extensions/gsd/tests/init-skip-git.test.ts +9 -12
  295. package/src/resources/extensions/gsd/tests/integration/auto-worktree-milestone-merge.test.ts +40 -0
  296. package/src/resources/extensions/gsd/tests/integration/commands-eval-review.integration.test.ts +4 -2
  297. package/src/resources/extensions/gsd/tests/integration/git-locale.test.ts +31 -20
  298. package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +12 -0
  299. package/src/resources/extensions/gsd/tests/integration/milestone-transition-worktree.test.ts +0 -47
  300. package/src/resources/extensions/gsd/tests/interactive-routing-bypass.test.ts +60 -202
  301. package/src/resources/extensions/gsd/tests/isolation-none-branch-guard.test.ts +13 -59
  302. package/src/resources/extensions/gsd/tests/lazy-pi-tui-import.test.ts +44 -6
  303. package/src/resources/extensions/gsd/tests/memory-pressure-stuck-state.test.ts +21 -35
  304. package/src/resources/extensions/gsd/tests/milestone-transition-state-rebuild.test.ts +79 -98
  305. package/src/resources/extensions/gsd/tests/model-unittype-mapping.test.ts +70 -278
  306. package/src/resources/extensions/gsd/tests/needs-remediation-revalidation.test.ts +37 -30
  307. package/src/resources/extensions/gsd/tests/note-captures-executed.test.ts +32 -28
  308. package/src/resources/extensions/gsd/tests/phantom-ghost-detection.test.ts +24 -37
  309. package/src/resources/extensions/gsd/tests/phantom-milestone-default-queued.test.ts +9 -24
  310. package/src/resources/extensions/gsd/tests/phases-merge-error-stops-auto.test.ts +113 -0
  311. package/src/resources/extensions/gsd/tests/post-unit-state-rebuild.test.ts +36 -22
  312. package/src/resources/extensions/gsd/tests/pre-exec-backtick-strip.test.ts +36 -30
  313. package/src/resources/extensions/gsd/tests/pre-execution-pause-wiring.test.ts +74 -4
  314. package/src/resources/extensions/gsd/tests/preferences-worktree-sync.test.ts +20 -22
  315. package/src/resources/extensions/gsd/tests/prefs-wizard-coverage.test.ts +130 -32
  316. package/src/resources/extensions/gsd/tests/project-root-cwd-crash.test.ts +18 -36
  317. package/src/resources/extensions/gsd/tests/projection-no-plan-overwrite.test.ts +35 -73
  318. package/src/resources/extensions/gsd/tests/prompt-budget-enforcement.test.ts +76 -138
  319. package/src/resources/extensions/gsd/tests/prompt-step-ordering.test.ts +70 -125
  320. package/src/resources/extensions/gsd/tests/provider-errors.test.ts +59 -161
  321. package/src/resources/extensions/gsd/tests/query-tools-db-open.test.ts +33 -29
  322. package/src/resources/extensions/gsd/tests/queue-auto-guard.test.ts +22 -196
  323. package/src/resources/extensions/gsd/tests/quick-auto-guard.test.ts +23 -93
  324. package/src/resources/extensions/gsd/tests/quick-turn-end-cleanup.test.ts +50 -79
  325. package/src/resources/extensions/gsd/tests/reassess-default-optin.test.ts +27 -13
  326. package/src/resources/extensions/gsd/tests/remote-questions.test.ts +151 -251
  327. package/src/resources/extensions/gsd/tests/resource-loader-import-path.test.ts +41 -29
  328. package/src/resources/extensions/gsd/tests/restore-tools-after-discuss.test.ts +58 -90
  329. package/src/resources/extensions/gsd/tests/resume-dispatch-worktree.test.ts +32 -164
  330. package/src/resources/extensions/gsd/tests/run-uat-replay-cap.test.ts +57 -41
  331. package/src/resources/extensions/gsd/tests/session-model-override.test.ts +14 -9
  332. package/src/resources/extensions/gsd/tests/session-start-footer.test.ts +77 -0
  333. package/src/resources/extensions/gsd/tests/session-switch-abort-misclassification.test.ts +61 -1
  334. package/src/resources/extensions/gsd/tests/show-config-command.test.ts +44 -42
  335. package/src/resources/extensions/gsd/tests/skip-slice-state-rebuild.test.ts +56 -24
  336. package/src/resources/extensions/gsd/tests/skipped-validation-db-atomicity.test.ts +51 -11
  337. package/src/resources/extensions/gsd/tests/slice-cadence.test.ts +23 -0
  338. package/src/resources/extensions/gsd/tests/slice-context-injection.test.ts +66 -50
  339. package/src/resources/extensions/gsd/tests/slice-parallel-orchestrator.test.ts +68 -107
  340. package/src/resources/extensions/gsd/tests/slice-sequence-insert.test.ts +115 -42
  341. package/src/resources/extensions/gsd/tests/smart-entry-complete.test.ts +21 -97
  342. package/src/resources/extensions/gsd/tests/smart-entry-draft.test.ts +25 -116
  343. package/src/resources/extensions/gsd/tests/sqlite-unavailable-gate.test.ts +21 -57
  344. package/src/resources/extensions/gsd/tests/stale-dirlistcache-4648.test.ts +29 -76
  345. package/src/resources/extensions/gsd/tests/stale-lockfile-recovery.test.ts +33 -24
  346. package/src/resources/extensions/gsd/tests/stale-slice-rows.test.ts +39 -30
  347. package/src/resources/extensions/gsd/tests/status-db-open.test.ts +33 -47
  348. package/src/resources/extensions/gsd/tests/stop-auto-merge-back.test.ts +48 -46
  349. package/src/resources/extensions/gsd/tests/stop-auto-race-null-unit.test.ts +14 -102
  350. package/src/resources/extensions/gsd/tests/subagent-model-dispatch.test.ts +78 -232
  351. package/src/resources/extensions/gsd/tests/sync-worktree-skip-current.test.ts +32 -35
  352. package/src/resources/extensions/gsd/tests/token-profile.test.ts +84 -309
  353. package/src/resources/extensions/gsd/tests/triage-dispatch.test.ts +134 -341
  354. package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +8 -25
  355. package/src/resources/extensions/gsd/tests/unit-dispatches.test.ts +50 -1
  356. package/src/resources/extensions/gsd/tests/unstructured-continue-context-injection.test.ts +6 -101
  357. package/src/resources/extensions/gsd/tests/uok-plan-v2-wiring.test.ts +43 -36
  358. package/src/resources/extensions/gsd/tests/visualizer-data.test.ts +84 -444
  359. package/src/resources/extensions/gsd/tests/workflow-dispatch-claim.test.ts +142 -0
  360. package/src/resources/extensions/gsd/tests/workflow-logger-wiring.test.ts +44 -189
  361. package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +2 -57
  362. package/src/resources/extensions/gsd/tests/workflow-worker-heartbeat.test.ts +32 -1
  363. package/src/resources/extensions/gsd/tests/worktree-db-same-file.test.ts +21 -44
  364. package/src/resources/extensions/gsd/tests/worktree-expected-warnings.test.ts +27 -26
  365. package/src/resources/extensions/gsd/tests/worktree-health-dispatch.test.ts +14 -13
  366. package/src/resources/extensions/gsd/tests/worktree-main-branch.test.ts +20 -18
  367. package/src/resources/extensions/gsd/tests/worktree-resolver.test.ts +36 -0
  368. package/src/resources/extensions/gsd/tests/zero-slice-roadmap-guided.test.ts +19 -13
  369. package/src/resources/extensions/gsd/tools/complete-milestone.ts +14 -15
  370. package/src/resources/extensions/gsd/tools/complete-task.ts +1 -1
  371. package/src/resources/extensions/gsd/worktree-resolver.ts +34 -1
  372. package/src/resources/skills/create-gsd-extension/templates/templates.test.ts +86 -40
  373. package/src/resources/skills/web-quality-audit/scripts/analyze.sh +0 -0
  374. package/dist/web/standalone/.next/static/chunks/8336.631939fb583761fa.js +0 -10
  375. /package/dist/web/standalone/.next/static/{O2WvnXROue6l7nAp_4dhC → G68KoLv5claox_Dyd4pZn}/_buildManifest.js +0 -0
  376. /package/dist/web/standalone/.next/static/{O2WvnXROue6l7nAp_4dhC → G68KoLv5claox_Dyd4pZn}/_ssgManifest.js +0 -0
@@ -1,3 +1,16 @@
1
+ /**
2
+ * Spawn the Claude CLI without triggering Node's DEP0190.
3
+ *
4
+ * Passing `args` together with `shell: true` is deprecated in Node 22+
5
+ * because the args are concatenated into the command string without
6
+ * escaping. On Windows we still need a shell to resolve `.cmd` shims, so
7
+ * we invoke `cmd /c <command> <args...>` explicitly. On POSIX we don't
8
+ * need a shell at all.
9
+ */
10
+ export declare function buildClaudeSpawnInvocation(command: string, args: string[], platform?: NodeJS.Platform): {
11
+ command: string;
12
+ args: string[];
13
+ };
1
14
  /**
2
15
  * Platform-correct binary name for the Claude Code CLI.
3
16
  *
@@ -7,7 +20,24 @@
7
20
  * authenticated. Mirrors the `NPM_COMMAND` pattern in
8
21
  * `src/resources/extensions/gsd/pre-execution-checks.ts`.
9
22
  */
23
+ export declare function getClaudeCommand(platform?: NodeJS.Platform): string;
10
24
  export declare const CLAUDE_COMMAND: string;
25
+ /**
26
+ * Ordered list of binary names to probe for the Claude Code CLI.
27
+ *
28
+ * Windows installs vary: npm-global installs produce a `claude.cmd` shim,
29
+ * direct binary installs produce `claude.exe`, and Git Bash wrappers may
30
+ * expose a bare `claude` shim. Try all three so no valid install is missed.
31
+ */
32
+ export declare function getClaudeCommandCandidates(platform?: NodeJS.Platform): string[];
33
+ /**
34
+ * Decide auth state from `claude auth status` output.
35
+ *
36
+ * Newer Claude CLI builds emit JSON with a `loggedIn` boolean. Older builds
37
+ * emit free-form text. Prefer the structured signal; fall back to a text
38
+ * heuristic. The text heuristic only covers English phrasing.
39
+ */
40
+ export declare function parseAuthStatus(output: string): boolean | null;
11
41
  /**
12
42
  * Check if the `claude` binary is installed (regardless of auth state).
13
43
  */
@@ -14,11 +14,15 @@ import { execFileSync } from 'node:child_process';
14
14
  * we invoke `cmd /c <command> <args...>` explicitly. On POSIX we don't
15
15
  * need a shell at all.
16
16
  */
17
- function spawnClaude(command, args, opts) {
18
- if (process.platform === 'win32') {
19
- return execFileSync('cmd', ['/c', command, ...args], opts);
17
+ export function buildClaudeSpawnInvocation(command, args, platform = process.platform) {
18
+ if (platform === 'win32') {
19
+ return { command: 'cmd', args: ['/c', command, ...args] };
20
20
  }
21
- return execFileSync(command, args, opts);
21
+ return { command, args };
22
+ }
23
+ function spawnClaude(command, args, opts) {
24
+ const invocation = buildClaudeSpawnInvocation(command, args);
25
+ return execFileSync(invocation.command, invocation.args, opts);
22
26
  }
23
27
  /**
24
28
  * Platform-correct binary name for the Claude Code CLI.
@@ -29,7 +33,10 @@ function spawnClaude(command, args, opts) {
29
33
  * authenticated. Mirrors the `NPM_COMMAND` pattern in
30
34
  * `src/resources/extensions/gsd/pre-execution-checks.ts`.
31
35
  */
32
- export const CLAUDE_COMMAND = process.platform === 'win32' ? 'claude.cmd' : 'claude';
36
+ export function getClaudeCommand(platform = process.platform) {
37
+ return platform === 'win32' ? 'claude.cmd' : 'claude';
38
+ }
39
+ export const CLAUDE_COMMAND = getClaudeCommand();
33
40
  /**
34
41
  * Ordered list of binary names to probe for the Claude Code CLI.
35
42
  *
@@ -37,7 +44,11 @@ export const CLAUDE_COMMAND = process.platform === 'win32' ? 'claude.cmd' : 'cla
37
44
  * direct binary installs produce `claude.exe`, and Git Bash wrappers may
38
45
  * expose a bare `claude` shim. Try all three so no valid install is missed.
39
46
  */
40
- const CLAUDE_COMMAND_CANDIDATES = process.platform === 'win32' ? [CLAUDE_COMMAND, 'claude.exe', 'claude'] : [CLAUDE_COMMAND];
47
+ export function getClaudeCommandCandidates(platform = process.platform) {
48
+ const command = getClaudeCommand(platform);
49
+ return platform === 'win32' ? [command, 'claude.exe', 'claude'] : [command];
50
+ }
51
+ const CLAUDE_COMMAND_CANDIDATES = getClaudeCommandCandidates();
41
52
  const VERSION_TIMEOUT_MS = 5_000;
42
53
  // Auth probe needs more headroom on Windows because the spawn goes through
43
54
  // cmd.exe → claude.cmd → node → Claude CLI.
@@ -80,7 +91,7 @@ function findWorkingCommand() {
80
91
  * emit free-form text. Prefer the structured signal; fall back to a text
81
92
  * heuristic. The text heuristic only covers English phrasing.
82
93
  */
83
- function parseAuthStatus(output) {
94
+ export function parseAuthStatus(output) {
84
95
  const trimmed = output.trim();
85
96
  if (!trimmed)
86
97
  return null;
package/dist/cli.js CHANGED
@@ -760,25 +760,6 @@ if (!process.stdin.isTTY || !process.stdout.isTTY) {
760
760
  : 'stdout is';
761
761
  printNonTtyErrorAndExit(missing, true);
762
762
  }
763
- // Welcome screen — shown on every fresh interactive session before TUI takes over.
764
- // Skip when the first-run banner was already printed in loader.ts (prevents double banner).
765
- if (!process.env.GSD_FIRST_RUN_BANNER) {
766
- const { printWelcomeScreen } = await import('./welcome-screen.js');
767
- let remoteChannel;
768
- try {
769
- const { resolveRemoteConfig } = await import('./resources/extensions/remote-questions/config.js');
770
- const rc = resolveRemoteConfig();
771
- if (rc)
772
- remoteChannel = rc.channel;
773
- }
774
- catch { /* non-fatal */ }
775
- printWelcomeScreen({
776
- version: process.env.GSD_VERSION || '0.0.0',
777
- modelName: settingsManager.getDefaultModel() || undefined,
778
- provider: settingsManager.getDefaultProvider() || undefined,
779
- remoteChannel,
780
- });
781
- }
782
763
  const interactiveMode = new InteractiveMode(session);
783
764
  markStartup('InteractiveMode');
784
765
  printStartupTimings();
@@ -36,6 +36,13 @@ export declare function shouldUseAgentExtensionsDir(opts: {
36
36
  agentDir: string;
37
37
  useAgentDir: boolean;
38
38
  };
39
+ declare function loadExtensionModules(): Promise<{
40
+ openProjectDbIfPresent: (basePath: string) => Promise<void>;
41
+ deriveState: (basePath: string) => Promise<GSDState>;
42
+ resolveDispatch: (opts: any) => Promise<any>;
43
+ readAllSessionStatuses: (basePath: string) => any[];
44
+ loadEffectiveGSDPreferences: () => any;
45
+ }>;
39
46
  export interface QuerySnapshot {
40
47
  state: GSDState;
41
48
  next: {
@@ -59,4 +66,7 @@ export interface QueryResult {
59
66
  exitCode: number;
60
67
  data?: QuerySnapshot;
61
68
  }
69
+ type HeadlessQueryModules = Awaited<ReturnType<typeof loadExtensionModules>>;
70
+ export declare function runHeadlessQuery(basePath: string, modules: HeadlessQueryModules, writeOutput?: (text: string) => void): Promise<QueryResult>;
62
71
  export declare function handleQuery(basePath: string): Promise<QueryResult>;
72
+ export {};
@@ -77,9 +77,8 @@ async function loadExtensionModules() {
77
77
  loadEffectiveGSDPreferences: prefsModule.loadEffectiveGSDPreferences,
78
78
  };
79
79
  }
80
- // ─── Implementation ─────────────────────────────────────────────────────────
81
- export async function handleQuery(basePath) {
82
- const { openProjectDbIfPresent, deriveState, resolveDispatch, readAllSessionStatuses, loadEffectiveGSDPreferences, } = await loadExtensionModules();
80
+ export async function runHeadlessQuery(basePath, modules, writeOutput = (text) => process.stdout.write(text)) {
81
+ const { openProjectDbIfPresent, deriveState, resolveDispatch, readAllSessionStatuses, loadEffectiveGSDPreferences, } = modules;
83
82
  await openProjectDbIfPresent(basePath);
84
83
  const state = await deriveState(basePath);
85
84
  // Derive next dispatch action
@@ -120,6 +119,9 @@ export async function handleQuery(basePath) {
120
119
  next,
121
120
  cost: { workers, total: workers.reduce((sum, w) => sum + w.cost, 0) },
122
121
  };
123
- process.stdout.write(JSON.stringify(snapshot) + '\n');
122
+ writeOutput(JSON.stringify(snapshot) + '\n');
124
123
  return { exitCode: 0, data: snapshot };
125
124
  }
125
+ export async function handleQuery(basePath) {
126
+ return runHeadlessQuery(basePath, await loadExtensionModules());
127
+ }
@@ -0,0 +1,8 @@
1
+ export interface LoaderEntrypointOptions {
2
+ gsdRoot: string;
3
+ invokedBinPath: string | undefined;
4
+ env?: NodeJS.ProcessEnv;
5
+ existsSync?: (path: string) => boolean;
6
+ }
7
+ export declare function resolveLoaderCliEntrypoint({ gsdRoot, invokedBinPath, env, existsSync, }: LoaderEntrypointOptions): string | undefined;
8
+ export declare function applyLoaderCliEntrypointEnv(env: NodeJS.ProcessEnv, options: LoaderEntrypointOptions): string | undefined;
@@ -0,0 +1,27 @@
1
+ // GSD-2 - Loader child-process entrypoint resolution helpers.
2
+ import { existsSync as defaultExistsSync } from "node:fs";
3
+ import { join, resolve } from "node:path";
4
+ export function resolveLoaderCliEntrypoint({ gsdRoot, invokedBinPath, env = process.env, existsSync = defaultExistsSync, }) {
5
+ const sourceLoaderPath = join(gsdRoot, "src", "loader.ts");
6
+ const devCliPath = env.GSD_DEV_CLI_PATH?.trim() || join(gsdRoot, "scripts", "dev-cli.js");
7
+ const explicitCliPath = env.GSD_CLI_PATH?.trim() || env.GSD_BIN_PATH?.trim();
8
+ const isSourceLoader = Boolean(invokedBinPath && resolve(invokedBinPath) === sourceLoaderPath);
9
+ const rawGsdBinPath = explicitCliPath || (isSourceLoader && existsSync(devCliPath) ? devCliPath : invokedBinPath);
10
+ return rawGsdBinPath ? resolve(rawGsdBinPath) : undefined;
11
+ }
12
+ export function applyLoaderCliEntrypointEnv(env, options) {
13
+ const resolvedGsdBinPath = resolveLoaderCliEntrypoint({ ...options, env });
14
+ if (resolvedGsdBinPath) {
15
+ env.GSD_BIN_PATH = resolvedGsdBinPath;
16
+ if (!env.GSD_CLI_PATH) {
17
+ env.GSD_CLI_PATH = resolvedGsdBinPath;
18
+ }
19
+ }
20
+ else {
21
+ delete env.GSD_BIN_PATH;
22
+ if (!env.GSD_CLI_PATH) {
23
+ delete env.GSD_CLI_PATH;
24
+ }
25
+ }
26
+ return resolvedGsdBinPath;
27
+ }
package/dist/loader.js CHANGED
@@ -63,6 +63,7 @@ import { serializeBundledExtensionPaths } from './bundled-extension-paths.js';
63
63
  import { resolveBundledResourcesDirFromPackageRoot } from './bundled-resource-path.js';
64
64
  import { discoverExtensionEntryPaths } from './extension-discovery.js';
65
65
  import { loadRegistry, readManifestFromEntryPath, isExtensionEnabled } from './extension-registry.js';
66
+ import { applyLoaderCliEntrypointEnv } from './loader-entrypoint.js';
66
67
  import { renderLogo } from './logo.js';
67
68
  // pkg/ is a shim directory: contains gsd's piConfig (package.json) and pi's
68
69
  // theme assets (dist/modes/interactive/theme/) without a src/ directory.
@@ -117,17 +118,7 @@ process.env.GSD_VERSION = gsdVersion;
117
118
  // subagent/parallel workers to spawn gsd instead of pi when dispatching
118
119
  // workflow tasks. In source-dev mode this must remain scripts/dev-cli.js, not
119
120
  // src/loader.ts, because child processes need the --import resolve-ts wrapper.
120
- const invokedBinPath = process.argv[1];
121
- const sourceLoaderPath = join(gsdRoot, 'src', 'loader.ts');
122
- const devCliPath = process.env.GSD_DEV_CLI_PATH?.trim() || join(gsdRoot, 'scripts', 'dev-cli.js');
123
- const explicitCliPath = process.env.GSD_CLI_PATH?.trim() || process.env.GSD_BIN_PATH?.trim();
124
- const isSourceLoader = invokedBinPath && resolve(invokedBinPath) === sourceLoaderPath;
125
- const rawGsdBinPath = explicitCliPath || (isSourceLoader && existsSync(devCliPath) ? devCliPath : invokedBinPath);
126
- const resolvedGsdBinPath = rawGsdBinPath ? resolve(rawGsdBinPath) : undefined;
127
- process.env.GSD_BIN_PATH = resolvedGsdBinPath;
128
- if (!process.env.GSD_CLI_PATH) {
129
- process.env.GSD_CLI_PATH = resolvedGsdBinPath;
130
- }
121
+ applyLoaderCliEntrypointEnv(process.env, { gsdRoot, invokedBinPath: process.argv[1] });
131
122
  // GSD_WORKFLOW_PATH — absolute path to bundled GSD-WORKFLOW.md, used by patched gsd extension
132
123
  // when dispatching workflow prompts. Prefers dist/resources/ (stable, set at build time)
133
124
  // over src/resources/ (live working tree) — see resource-loader.ts for rationale.
@@ -22,6 +22,7 @@ export interface McpToolDef {
22
22
  isError?: boolean;
23
23
  }>;
24
24
  }
25
+ export declare function mcpSdkSpecifier(subpath: 'server/index' | 'server/stdio' | 'types'): string;
25
26
  /**
26
27
  * Starts a native MCP (Model Context Protocol) server over stdin/stdout.
27
28
  *
@@ -29,6 +29,9 @@ function isPlainObject(value) {
29
29
  // built via a template string so TypeScript's NodeNext resolver treats them as
30
30
  // `any` and skips static checking.
31
31
  const MCP_PKG = '@modelcontextprotocol/sdk';
32
+ export function mcpSdkSpecifier(subpath) {
33
+ return `${MCP_PKG}/${subpath}.js`;
34
+ }
32
35
  /**
33
36
  * Starts a native MCP (Model Context Protocol) server over stdin/stdout.
34
37
  *
@@ -45,9 +48,9 @@ const MCP_PKG = '@modelcontextprotocol/sdk';
45
48
  */
46
49
  export async function startMcpServer(options) {
47
50
  const { tools, version = '0.0.0' } = options;
48
- const serverMod = await import(`${MCP_PKG}/server/index.js`);
49
- const stdioMod = await import(`${MCP_PKG}/server/stdio.js`);
50
- const typesMod = await import(`${MCP_PKG}/types.js`);
51
+ const serverMod = await import(mcpSdkSpecifier('server/index'));
52
+ const stdioMod = await import(mcpSdkSpecifier('server/stdio'));
53
+ const typesMod = await import(mcpSdkSpecifier('types'));
51
54
  const Server = serverMod.Server;
52
55
  const StdioServerTransport = stdioMod.StdioServerTransport;
53
56
  const { ListToolsRequestSchema, CallToolRequestSchema } = typesMod;
@@ -1 +1 @@
1
- 89938c18ffd18359
1
+ 186fe07f8b8d9487
@@ -23,11 +23,15 @@ import { execFileSync } from "node:child_process";
23
23
  * we invoke `cmd /c <command> <args...>` explicitly. On POSIX we don't
24
24
  * need a shell at all.
25
25
  */
26
- function spawnClaude(command, args, opts) {
27
- if (process.platform === "win32") {
28
- return execFileSync("cmd", ["/c", command, ...args], opts);
26
+ export function buildClaudeSpawnInvocation(command, args, platform = process.platform) {
27
+ if (platform === "win32") {
28
+ return { command: "cmd", args: ["/c", command, ...args] };
29
29
  }
30
- return execFileSync(command, args, opts);
30
+ return { command, args };
31
+ }
32
+ function spawnClaude(command, args, opts) {
33
+ const invocation = buildClaudeSpawnInvocation(command, args);
34
+ return execFileSync(invocation.command, invocation.args, opts);
31
35
  }
32
36
  /**
33
37
  * Candidate executable names for the Claude Code CLI.
@@ -35,14 +39,21 @@ function spawnClaude(command, args, opts) {
35
39
  * Keep the explicit win32 ternary selector for regression coverage (Issue #4424):
36
40
  * Node's execFileSync must target `claude.cmd` directly on Windows.
37
41
  */
38
- const CLAUDE_COMMAND = process.platform === "win32" ? "claude.cmd" : "claude";
42
+ export function getClaudeCommand(platform = process.platform) {
43
+ return platform === "win32" ? "claude.cmd" : "claude";
44
+ }
45
+ const CLAUDE_COMMAND = getClaudeCommand();
39
46
  /**
40
47
  * Windows installs vary: some environments expose `claude.cmd` (npm shim),
41
48
  * `claude.exe` (direct binary install), or a bare `claude` shim on PATH
42
49
  * (for example Git Bash wrappers). Try all three to avoid false "not
43
50
  * installed" results in readiness checks.
44
51
  */
45
- const CLAUDE_COMMAND_CANDIDATES = process.platform === "win32" ? [CLAUDE_COMMAND, "claude.exe", "claude"] : [CLAUDE_COMMAND];
52
+ export function getClaudeCommandCandidates(platform = process.platform) {
53
+ const command = getClaudeCommand(platform);
54
+ return platform === "win32" ? [command, "claude.exe", "claude"] : [command];
55
+ }
56
+ const CLAUDE_COMMAND_CANDIDATES = getClaudeCommandCandidates();
46
57
  // Keep the version probe snappy — `claude --version` is a quick path.
47
58
  const VERSION_TIMEOUT_MS = 5_000;
48
59
  // Auth status can be much slower on Windows because the spawn goes through
@@ -90,7 +101,7 @@ function findWorkingCommand() {
90
101
  * back to a text heuristic. Note: the text heuristic only covers English
91
102
  * phrasing — the JSON path is the durable signal.
92
103
  */
93
- function parseAuthStatus(output) {
104
+ export function parseAuthStatus(output) {
94
105
  const trimmed = output.trim();
95
106
  if (!trimmed)
96
107
  return null;
@@ -261,6 +261,26 @@ function makeErrorMessage(model, errorMsg) {
261
261
  timestamp: Date.now(),
262
262
  };
263
263
  }
264
+ export function isClaudeCodeAbortErrorMessage(message) {
265
+ if (!message)
266
+ return false;
267
+ return /\b(?:claude code process aborted by user|request aborted by user|process aborted by user)\b/i.test(message);
268
+ }
269
+ function isBareClaudeCodeAbortErrorMessage(message) {
270
+ if (!message)
271
+ return false;
272
+ const normalized = message.trim().replace(/\s+/g, " ").toLowerCase();
273
+ return normalized === "claude code process aborted by user"
274
+ || normalized === "request aborted by user"
275
+ || normalized === "process aborted by user";
276
+ }
277
+ export function resolveClaudeCodeAbortedMessageText(errorMsg, lastTextContent) {
278
+ const trimmedError = errorMsg.trim();
279
+ if (trimmedError && !isBareClaudeCodeAbortErrorMessage(trimmedError)) {
280
+ return trimmedError;
281
+ }
282
+ return lastTextContent;
283
+ }
264
284
  /**
265
285
  * Generator exhaustion without a terminal result means the SDK stream was
266
286
  * interrupted mid-turn. Surface it as an error so downstream recovery logic
@@ -1512,6 +1532,15 @@ async function pumpSdkMessages(model, context, options, stream) {
1512
1532
  }
1513
1533
  catch (err) {
1514
1534
  const errorMsg = err instanceof Error ? err.message : String(err);
1535
+ if (options?.signal?.aborted || isClaudeCodeAbortErrorMessage(errorMsg)) {
1536
+ const abortedText = resolveClaudeCodeAbortedMessageText(errorMsg, lastTextContent);
1537
+ stream.push({
1538
+ type: "error",
1539
+ reason: "aborted",
1540
+ error: makeAbortedMessage(modelId, abortedText),
1541
+ });
1542
+ return;
1543
+ }
1515
1544
  stream.push({
1516
1545
  type: "error",
1517
1546
  reason: "error",
@@ -79,6 +79,9 @@ export async function runGitHubSync(basePath, unitType, unitId) {
79
79
  debugLog("github-sync", { error: String(err) });
80
80
  }
81
81
  }
82
+ export function shouldCreateSlicePrForSyncEvent(unitType, config) {
83
+ return unitType === "complete-slice" && config.slice_prs !== false;
84
+ }
82
85
  // ─── Per-Event Sync Functions ───────────────────────────────────────────────
83
86
  async function syncMilestonePlan(basePath, mapping, config, mid) {
84
87
  // Skip if already synced
@@ -307,7 +310,7 @@ async function syncSliceComplete(basePath, mapping, config, mid, sid) {
307
310
  }
308
311
  if (!sliceRecord || sliceRecord.state === "closed")
309
312
  return;
310
- if (!sliceRecord.prNumber && config.slice_prs !== false) {
313
+ if (!sliceRecord.prNumber && shouldCreateSlicePrForSyncEvent("complete-slice", config)) {
311
314
  await ensureSlicePullRequest(basePath, mapping, mid, sid);
312
315
  sliceRecord = getSliceRecord(mapping, mid, sid);
313
316
  if (!sliceRecord || !sliceRecord.prNumber)
@@ -16,7 +16,7 @@ import { ModelPolicyDispatchBlockedError } from "../auto-model-selection.js";
16
16
  import { resolveEngine } from "../engine-resolver.js";
17
17
  import { logWarning } from "../workflow-logger.js";
18
18
  import { recordDispatchClaim, markRunning as markDispatchRunning, markCompleted as markDispatchCompleted, markFailed as markDispatchFailed, getRecentForUnit as getRecentDispatchesForUnit, getRecentUnitKeysForProjectRoot, } from "../db/unit-dispatches.js";
19
- import { refreshMilestoneLease } from "../db/milestone-leases.js";
19
+ import { claimMilestoneLease, refreshMilestoneLease } from "../db/milestone-leases.js";
20
20
  import { heartbeatAutoWorker } from "../db/auto-workers.js";
21
21
  import { getRuntimeKv, setRuntimeKv } from "../db/runtime-kv.js";
22
22
  import { resolveUokFlags } from "../uok/flags.js";
@@ -27,7 +27,7 @@ import { hydrateCustomVerifyRetryCounts, saveCustomVerifyRetryCounts, } from "./
27
27
  import { settleDispatchCompleted, settleDispatchFailed, } from "./workflow-dispatch-ledger.js";
28
28
  import { emitOpenUnitEndForUnit } from "../crash-recovery.js";
29
29
  import { writeUnitRuntimeRecord } from "../unit-runtime.js";
30
- import { openDispatchClaim } from "./workflow-dispatch-claim.js";
30
+ import { ensureDispatchLease, openDispatchClaim } from "./workflow-dispatch-claim.js";
31
31
  import { completeWorkflowIteration } from "./workflow-iteration-completion.js";
32
32
  import { createWorkflowJournalReporter } from "./workflow-journal-reporter.js";
33
33
  import { createWorkflowPhaseReporter } from "./workflow-phase-reporter.js";
@@ -105,6 +105,18 @@ function logDispatchClaimFailed(err) {
105
105
  error: err instanceof Error ? err.message : String(err),
106
106
  });
107
107
  }
108
+ function logDispatchLeaseRecovered(details) {
109
+ debugLog("autoLoop", {
110
+ phase: details.recovered ? "dispatch-lease-recovered" : "dispatch-lease-acquired",
111
+ ...details,
112
+ });
113
+ }
114
+ function logDispatchLeaseRecoveryFailed(details) {
115
+ debugLog("autoLoop", {
116
+ phase: "dispatch-lease-recovery-failed",
117
+ ...details,
118
+ });
119
+ }
108
120
  function logCustomVerifyRetryLoadFailure(err) {
109
121
  debugLog("autoLoop", {
110
122
  phase: "load-custom-verify-retries-failed",
@@ -186,6 +198,10 @@ export async function autoLoop(ctx, pi, s, deps, options) {
186
198
  phase: "heartbeat-failed",
187
199
  error: err instanceof Error ? err.message : String(err),
188
200
  }),
201
+ logLeaseRefreshMiss: details => debugLog("autoLoop", {
202
+ phase: "lease-refresh-missed",
203
+ ...details,
204
+ }),
189
205
  });
190
206
  // ── Journal: per-iteration flow grouping ──
191
207
  const flowId = randomUUID();
@@ -581,23 +597,70 @@ export async function autoLoop(ctx, pi, s, deps, options) {
581
597
  await enforceMinRequestInterval(s, prefs);
582
598
  // Phase B: claim a unit_dispatches row before invoking the unit. The
583
599
  // partial unique index idx_unit_dispatches_active_per_unit prevents
584
- // a second worker from claiming the same unit concurrently. Returns
585
- // null when DB unavailable, no worker registered, or no active lease
586
- // those degraded paths fall through to the existing single-worker
587
- // semantics with no ledger entry, preserving back-compat.
588
- const dispatchClaim = openDispatchClaim(s, flowId, turnId, iterData, {
600
+ // a second worker from claiming the same unit concurrently. When this
601
+ // process has a worker identity, make the milestone lease explicit before
602
+ // claiming so a step-mode handoff cannot leave us running with a stale
603
+ // in-memory token and no backing lease row.
604
+ const leaseBeforeClaim = ensureDispatchLease(s, iterData.mid, {
605
+ claimMilestoneLease,
606
+ logLeaseRecovered: logDispatchLeaseRecovered,
607
+ logLeaseRecoveryFailed: logDispatchLeaseRecoveryFailed,
608
+ });
609
+ if (leaseBeforeClaim.kind === "blocked" || leaseBeforeClaim.kind === "failed") {
610
+ const msg = `Lost milestone lease for ${iterData.mid ?? "unknown"} before dispatching ${iterData.unitType} ${iterData.unitId}: ${leaseBeforeClaim.reason}`;
611
+ ctx.ui.notify(msg, "error");
612
+ finishTurn("stopped", "execution", msg);
613
+ await deps.stopAuto(ctx, pi, msg);
614
+ break;
615
+ }
616
+ let dispatchClaim = openDispatchClaim(s, flowId, turnId, iterData, {
589
617
  getRecentDispatchesForUnit,
590
618
  recordDispatchClaim,
591
619
  markDispatchRunning,
592
620
  logClaimRejected: logDispatchClaimRejected,
593
621
  logClaimFailed: logDispatchClaimFailed,
594
622
  });
595
- const dispatchDecision = decideDispatchClaim(dispatchClaim.kind === "opened"
623
+ let dispatchDecision = decideDispatchClaim(dispatchClaim.kind === "opened"
596
624
  ? { kind: "opened", dispatchId: dispatchClaim.dispatchId }
597
625
  : dispatchClaim.kind === "skip"
598
626
  ? { kind: "skip", reason: dispatchClaim.reason }
599
627
  : { kind: "degraded" });
628
+ if (dispatchDecision.action === "skip" && dispatchDecision.reason === "stale-lease") {
629
+ const leaseRecovery = ensureDispatchLease(s, iterData.mid, {
630
+ claimMilestoneLease,
631
+ logLeaseRecovered: logDispatchLeaseRecovered,
632
+ logLeaseRecoveryFailed: logDispatchLeaseRecoveryFailed,
633
+ }, { forceReclaim: true });
634
+ if (leaseRecovery.kind === "ready") {
635
+ dispatchClaim = openDispatchClaim(s, flowId, turnId, iterData, {
636
+ getRecentDispatchesForUnit,
637
+ recordDispatchClaim,
638
+ markDispatchRunning,
639
+ logClaimRejected: logDispatchClaimRejected,
640
+ logClaimFailed: logDispatchClaimFailed,
641
+ });
642
+ dispatchDecision = decideDispatchClaim(dispatchClaim.kind === "opened"
643
+ ? { kind: "opened", dispatchId: dispatchClaim.dispatchId }
644
+ : dispatchClaim.kind === "skip"
645
+ ? { kind: "skip", reason: dispatchClaim.reason }
646
+ : { kind: "degraded" });
647
+ }
648
+ else {
649
+ const msg = `Lost milestone lease for ${iterData.mid ?? "unknown"} while claiming ${iterData.unitType} ${iterData.unitId}: ${leaseRecovery.reason}`;
650
+ ctx.ui.notify(msg, "error");
651
+ finishTurn("stopped", "execution", msg);
652
+ await deps.stopAuto(ctx, pi, msg);
653
+ break;
654
+ }
655
+ }
600
656
  if (dispatchDecision.action === "skip") {
657
+ if (dispatchDecision.reason === "stale-lease") {
658
+ const msg = `Lost milestone lease for ${iterData.mid ?? "unknown"} while claiming ${iterData.unitType} ${iterData.unitId}; dispatch claim still failed after recovery.`;
659
+ ctx.ui.notify(msg, "error");
660
+ finishTurn("stopped", "execution", msg);
661
+ await deps.stopAuto(ctx, pi, msg);
662
+ break;
663
+ }
601
664
  finishTurn("skipped", "execution", dispatchDecision.reason);
602
665
  continue;
603
666
  }
@@ -1,3 +1,5 @@
1
+ // Project/App: GSD-2
2
+ // File Purpose: Auto-loop pipeline phases, merge closeout, and finalize handling.
1
3
  /**
2
4
  * auto/phases.ts — Pipeline phases for the auto-loop.
3
5
  *
@@ -76,9 +78,15 @@ const PLAN_V2_GATE_PHASES = new Set([
76
78
  "validating-milestone",
77
79
  "completing-milestone",
78
80
  ]);
79
- function shouldRunPlanV2Gate(phase) {
81
+ export function shouldRunPlanV2Gate(phase) {
80
82
  return PLAN_V2_GATE_PHASES.has(phase);
81
83
  }
84
+ export function _shouldProceedWithInvalidRepoClassificationForTest(reason, hasGit) {
85
+ return reason === "missing .git" && hasGit;
86
+ }
87
+ export function _resolveCurrentUnitStartedAtForTest(currentUnit) {
88
+ return currentUnit?.startedAt;
89
+ }
82
90
  /**
83
91
  * Generate and write an HTML milestone report snapshot.
84
92
  * Extracted from the milestone-transition block in autoLoop.
@@ -202,6 +210,17 @@ export async function _runMilestoneMergeWithStashRestore(ic, milestoneId) {
202
210
  }
203
211
  return null;
204
212
  }
213
+ export async function _runMilestoneMergeOnceWithStashRestore(ic, milestoneId) {
214
+ if (ic.s.milestoneMergedInPhases) {
215
+ debugLog("autoLoop", {
216
+ phase: "milestone-merge-skip",
217
+ reason: "already-merged-in-phases",
218
+ milestoneId,
219
+ });
220
+ return null;
221
+ }
222
+ return _runMilestoneMergeWithStashRestore(ic, milestoneId);
223
+ }
205
224
  async function emitCancelledUnitEnd(ic, unitType, unitId, unitStartSeq, errorContext) {
206
225
  ic.deps.emitJournalEvent({
207
226
  ts: new Date().toISOString(),
@@ -546,7 +565,7 @@ export async function runPreDispatch(ic, loopState) {
546
565
  // Worktree lifecycle on milestone transition — merge current, enter next.
547
566
  // #2909 / #5538-followup: preflight stash + always-on postflight pop.
548
567
  {
549
- const stop = await _runMilestoneMergeWithStashRestore(ic, s.currentMilestoneId);
568
+ const stop = await _runMilestoneMergeOnceWithStashRestore(ic, s.currentMilestoneId);
550
569
  if (stop)
551
570
  return stop;
552
571
  }
@@ -605,7 +624,7 @@ export async function runPreDispatch(ic, loopState) {
605
624
  // All milestones complete — merge milestone branch before stopping.
606
625
  if (s.currentMilestoneId) {
607
626
  // #2909 / #5538-followup: preflight stash + always-on postflight pop.
608
- const stop = await _runMilestoneMergeWithStashRestore(ic, s.currentMilestoneId);
627
+ const stop = await _runMilestoneMergeOnceWithStashRestore(ic, s.currentMilestoneId);
609
628
  if (stop)
610
629
  return stop;
611
630
  // PR creation (auto_pr) is handled inside mergeMilestoneToMain (#2302)
@@ -673,7 +692,7 @@ export async function runPreDispatch(ic, loopState) {
673
692
  // Milestone merge on complete (before closeout so branch state is clean).
674
693
  if (s.currentMilestoneId) {
675
694
  // #2909 / #5538-followup: preflight stash + always-on postflight pop.
676
- const stop = await _runMilestoneMergeWithStashRestore(ic, s.currentMilestoneId);
695
+ const stop = await _runMilestoneMergeOnceWithStashRestore(ic, s.currentMilestoneId);
677
696
  if (stop)
678
697
  return stop;
679
698
  // PR creation (auto_pr) is handled inside mergeMilestoneToMain (#2302)
@@ -1145,7 +1164,7 @@ export async function runUnitPhase(ic, iterData, loopState, sidecarItem) {
1145
1164
  if (projectClassification.kind === "invalid-repo") {
1146
1165
  const msg = `Worktree health check failed: ${s.basePath} classified as invalid-repo (${projectClassification.reason}) — refusing to dispatch ${unitType} ${unitId}`;
1147
1166
  debugLog("runUnitPhase", { phase: "worktree-health-invalid-repo", basePath: s.basePath, classification: projectClassification });
1148
- if (projectClassification.reason === "missing .git" && hasGit) {
1167
+ if (_shouldProceedWithInvalidRepoClassificationForTest(projectClassification.reason, hasGit)) {
1149
1168
  ctx.ui.notify(`Warning: ${s.basePath} project classification could not confirm .git; assuming it has no project content yet — proceeding as greenfield project because worktree health reported .git present`, "warning");
1150
1169
  }
1151
1170
  else {
@@ -1527,7 +1546,7 @@ export async function runUnitPhase(ic, iterData, loopState, sidecarItem) {
1527
1546
  {
1528
1547
  const currentLedger = deps.getLedger();
1529
1548
  if (currentLedger?.units) {
1530
- const lastUnit = [...currentLedger.units].reverse().find((u) => u.type === unitType && u.id === unitId && u.startedAt === s.currentUnit?.startedAt);
1549
+ const lastUnit = [...currentLedger.units].reverse().find((u) => u.type === unitType && u.id === unitId && u.startedAt === _resolveCurrentUnitStartedAtForTest(s.currentUnit));
1531
1550
  if (lastUnit && lastUnit.toolCalls === 0) {
1532
1551
  if (USER_DRIVEN_DEEP_UNITS.has(unitType) && isAwaitingUserInput(s.lastUnitAgentEndMessages ?? undefined)) {
1533
1552
  debugLog("runUnitPhase", {
@@ -1546,7 +1565,7 @@ export async function runUnitPhase(ic, iterData, loopState, sidecarItem) {
1546
1565
  ctx.ui.notify(`${unitType} ${unitId} completed with 0 tool calls — context exhaustion, will retry`, "warning");
1547
1566
  // Fall through to next iteration where dispatch will re-derive
1548
1567
  // and re-dispatch this unit.
1549
- return { action: "next", data: { unitStartedAt: s.currentUnit?.startedAt, requestDispatchedAt: unitResult.requestDispatchedAt } };
1568
+ return { action: "next", data: { unitStartedAt: _resolveCurrentUnitStartedAtForTest(s.currentUnit), requestDispatchedAt: unitResult.requestDispatchedAt } };
1550
1569
  }
1551
1570
  }
1552
1571
  }
@@ -1600,7 +1619,7 @@ export async function runUnitPhase(ic, iterData, loopState, sidecarItem) {
1600
1619
  }
1601
1620
  s.checkpointSha = null;
1602
1621
  }
1603
- return { action: "next", data: { unitStartedAt: s.currentUnit?.startedAt, requestDispatchedAt: unitResult.requestDispatchedAt } };
1622
+ return { action: "next", data: { unitStartedAt: _resolveCurrentUnitStartedAtForTest(s.currentUnit), requestDispatchedAt: unitResult.requestDispatchedAt } };
1604
1623
  }
1605
1624
  // ─── runFinalize ──────────────────────────────────────────────────────────────
1606
1625
  /**
@@ -1733,6 +1752,11 @@ export async function runFinalize(ic, iterData, loopState, sidecarItem) {
1733
1752
  debugLog("autoLoop", { phase: "exit", reason: "step-wizard" });
1734
1753
  return { action: "break", reason: "step-wizard" };
1735
1754
  }
1755
+ if (preUnitSnapshot?.type === "complete-milestone" && s.currentMilestoneId) {
1756
+ const stop = await _runMilestoneMergeOnceWithStashRestore(ic, s.currentMilestoneId);
1757
+ if (stop)
1758
+ return stop;
1759
+ }
1736
1760
  // Both pre and post verification completed without timeout — reset counter
1737
1761
  loopState.consecutiveFinalizeTimeouts = 0;
1738
1762
  if (preUnitSnapshot) {