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,5 @@
1
+ // Project/App: GSD-2
2
+ // File Purpose: Auto-mode orchestration, session lifecycle, and stop handling.
1
3
  /**
2
4
  * GSD Auto Mode — Fresh Session Per Unit
3
5
  *
@@ -354,6 +356,14 @@ function restoreProjectRootEnv(): void {
354
356
  s.projectRootEnvCaptured = false;
355
357
  }
356
358
 
359
+ export function _captureProjectRootEnvForTest(projectRoot: string): void {
360
+ captureProjectRootEnv(projectRoot);
361
+ }
362
+
363
+ export function _restoreProjectRootEnvForTest(): void {
364
+ restoreProjectRootEnv();
365
+ }
366
+
357
367
  function captureMilestoneLockEnv(milestoneId: string | null): void {
358
368
  if (!s.milestoneLockEnvCaptured) {
359
369
  s.hadMilestoneLockEnv = Object.prototype.hasOwnProperty.call(process.env, "GSD_MILESTONE_LOCK");
@@ -442,6 +452,16 @@ export function _synthesizePausedSessionRecoveryForTest(
442
452
  return synthesizePausedSessionRecovery(basePath, unitType, unitId, sessionFile);
443
453
  }
444
454
 
455
+ export function _resolvePausedResumeBasePathForTest(
456
+ basePath: string,
457
+ pausedWorktreePath: string | null | undefined,
458
+ pathExists: (path: string) => boolean = existsSync,
459
+ ): string {
460
+ return pausedWorktreePath && pathExists(pausedWorktreePath)
461
+ ? pausedWorktreePath
462
+ : basePath;
463
+ }
464
+
445
465
  const DETACHED_AUTO_KEEPALIVE_INTERVAL_MS = 30_000;
446
466
 
447
467
  function withDetachedAutoKeepalive<T>(run: Promise<T>): Promise<T> {
@@ -673,6 +693,30 @@ export function isAutoPaused(): boolean {
673
693
  return s.paused;
674
694
  }
675
695
 
696
+ export interface ResumeResourceRefreshDeps {
697
+ env?: NodeJS.ProcessEnv;
698
+ importModule?: (specifier: string) => Promise<any>;
699
+ openProjectDb?: (basePath: string) => Promise<void>;
700
+ }
701
+
702
+ export async function refreshResumeResourcesAndDb(
703
+ basePath: string,
704
+ deps: ResumeResourceRefreshDeps = {},
705
+ ): Promise<void> {
706
+ const env = deps.env ?? process.env;
707
+ const importModule = deps.importModule ?? ((specifier: string) => import(specifier));
708
+ const agentDir = env.GSD_CODING_AGENT_DIR || join(gsdHome(), "agent");
709
+ const pkgRoot = env.GSD_PKG_ROOT;
710
+ const resourceLoaderPath = pkgRoot
711
+ ? pathToFileURL(join(pkgRoot, "dist", "resource-loader.js")).href
712
+ : new URL("../../../resource-loader.js", import.meta.url).href;
713
+ const { initResources } = await importModule(resourceLoaderPath);
714
+ initResources(agentDir);
715
+ const { primeCache } = await importModule("./prompt-loader.js");
716
+ primeCache();
717
+ await (deps.openProjectDb ?? openProjectDbIfPresent)(basePath);
718
+ }
719
+
676
720
  export function setActiveEngineId(id: string | null): void {
677
721
  s.activeEngineId = id;
678
722
  }
@@ -927,7 +971,23 @@ function handleLostSessionLock(
927
971
  * the stale unit state, progress widget, status badge, and restores CWD so
928
972
  * the dashboard does not show an orphaned timer and the shell is usable.
929
973
  */
930
- function cleanupAfterLoopExit(ctx: ExtensionContext): void {
974
+ export async function rerootCommandSession(
975
+ cmdCtx: Pick<ExtensionCommandContext, "newSession"> | null | undefined,
976
+ workspaceRoot: string,
977
+ ): Promise<{ status: "skipped" | "ok" | "cancelled" | "failed"; error?: string }> {
978
+ if (!cmdCtx || !workspaceRoot) return { status: "skipped" };
979
+ try {
980
+ const result = await cmdCtx.newSession({ workspaceRoot });
981
+ return result.cancelled ? { status: "cancelled" } : { status: "ok" };
982
+ } catch (err) {
983
+ return {
984
+ status: "failed",
985
+ error: err instanceof Error ? err.message : String(err),
986
+ };
987
+ }
988
+ }
989
+
990
+ export async function cleanupAfterLoopExit(ctx: ExtensionContext): Promise<void> {
931
991
  s.currentUnit = null;
932
992
  s.active = false;
933
993
  deactivateGSD();
@@ -965,6 +1025,34 @@ function cleanupAfterLoopExit(ctx: ExtensionContext): void {
965
1025
  logWarning("engine", `chdir failed: ${err instanceof Error ? err.message : String(err)}`, { file: "auto.ts" });
966
1026
  }
967
1027
  }
1028
+
1029
+ if (s.originalBasePath && s.cmdCtx) {
1030
+ const result = await rerootCommandSession(s.cmdCtx, s.basePath);
1031
+ if (result.status === "cancelled") {
1032
+ logWarning("engine", "post-loop session re-root was cancelled", { file: "auto.ts", basePath: s.basePath });
1033
+ } else if (result.status === "failed") {
1034
+ logWarning("engine", `post-loop session re-root failed: ${result.error ?? "unknown"}`, { file: "auto.ts", basePath: s.basePath });
1035
+ }
1036
+ }
1037
+ }
1038
+
1039
+ export function _cleanupAfterLoopExitForTest(ctx: ExtensionContext): Promise<void> {
1040
+ return cleanupAfterLoopExit(ctx);
1041
+ }
1042
+
1043
+ export type AutoWorktreeExitAction = "skip" | "merge" | "preserve";
1044
+
1045
+ export function _resolveAutoWorktreeExitActionForTest(
1046
+ currentMilestoneId: string | null | undefined,
1047
+ milestoneMergedInPhases: boolean,
1048
+ milestoneComplete: boolean,
1049
+ ): AutoWorktreeExitAction {
1050
+ const action = _selectStopAutoWorktreeExit({
1051
+ currentMilestoneId: currentMilestoneId ?? null,
1052
+ milestoneComplete,
1053
+ milestoneMergedInPhases,
1054
+ });
1055
+ return action === "none" ? "skip" : action;
968
1056
  }
969
1057
 
970
1058
  export async function stopAuto(
@@ -1118,10 +1206,16 @@ export async function stopAuto(
1118
1206
  logWarning("engine", `milestone summary check failed: ${err instanceof Error ? err.message : String(err)}`, { file: "auto.ts" });
1119
1207
  }
1120
1208
 
1121
- if (milestoneComplete) {
1209
+ const exitAction = _selectStopAutoWorktreeExit({
1210
+ currentMilestoneId: s.currentMilestoneId,
1211
+ milestoneComplete,
1212
+ milestoneMergedInPhases: s.milestoneMergedInPhases,
1213
+ });
1214
+
1215
+ if (exitAction === "merge") {
1122
1216
  // Milestone is complete — merge worktree branch back to main
1123
1217
  resolver.mergeAndExit(s.currentMilestoneId, notifyCtx);
1124
- } else {
1218
+ } else if (exitAction === "preserve") {
1125
1219
  // Milestone still in progress — preserve branch for later resumption
1126
1220
  resolver.exitMilestone(s.currentMilestoneId, notifyCtx, {
1127
1221
  preserveBranch: true,
@@ -1129,6 +1223,10 @@ export async function stopAuto(
1129
1223
  }
1130
1224
  }
1131
1225
  } catch (e) {
1226
+ ctx?.ui.notify(
1227
+ `Worktree cleanup failed for ${s.currentMilestoneId ?? "current milestone"}: ${e instanceof Error ? e.message : String(e)}. Resolve the preserved branch/worktree and run /gsd auto to resume.`,
1228
+ "warning",
1229
+ );
1132
1230
  debugLog("stop-cleanup-worktree", { error: e instanceof Error ? e.message : String(e) });
1133
1231
  }
1134
1232
 
@@ -1179,13 +1277,11 @@ export async function stopAuto(
1179
1277
  // its own cwd for tools and system prompt; refresh it before returning to the
1180
1278
  // user so follow-up commands do not target a removed milestone worktree.
1181
1279
  if (s.originalBasePath && ctx && s.cmdCtx) {
1182
- try {
1183
- const result = await s.cmdCtx.newSession({ workspaceRoot: s.basePath });
1184
- if (result.cancelled) {
1185
- logWarning("engine", "post-stop session re-root was cancelled", { file: "auto.ts", basePath: s.basePath });
1186
- }
1187
- } catch (err) {
1188
- logWarning("engine", `post-stop session re-root failed: ${err instanceof Error ? err.message : String(err)}`, { file: "auto.ts", basePath: s.basePath });
1280
+ const result = await rerootCommandSession(s.cmdCtx, s.basePath);
1281
+ if (result.status === "cancelled") {
1282
+ logWarning("engine", "post-stop session re-root was cancelled", { file: "auto.ts", basePath: s.basePath });
1283
+ } else if (result.status === "failed") {
1284
+ logWarning("engine", `post-stop session re-root failed: ${result.error ?? "unknown"}`, { file: "auto.ts", basePath: s.basePath });
1189
1285
  }
1190
1286
  }
1191
1287
 
@@ -1317,6 +1413,17 @@ export async function stopAuto(
1317
1413
  }
1318
1414
  }
1319
1415
 
1416
+ export type StopAutoWorktreeExitAction = "none" | "merge" | "preserve";
1417
+
1418
+ export function _selectStopAutoWorktreeExit(args: {
1419
+ currentMilestoneId: string | null;
1420
+ milestoneComplete: boolean;
1421
+ milestoneMergedInPhases: boolean;
1422
+ }): StopAutoWorktreeExitAction {
1423
+ if (!args.currentMilestoneId || args.milestoneMergedInPhases) return "none";
1424
+ return args.milestoneComplete ? "merge" : "preserve";
1425
+ }
1426
+
1320
1427
  /**
1321
1428
  * Pause auto-mode without destroying state. Context is preserved.
1322
1429
  * The user can interact with the agent, then `/gsd auto` resumes
@@ -1995,9 +2102,7 @@ export async function startAuto(
1995
2102
  { file: "auto.ts", milestoneId: s.currentMilestoneId ?? "" },
1996
2103
  );
1997
2104
  }
1998
- if (resumeWorktreePath && existsSync(resumeWorktreePath)) {
1999
- s.basePath = resumeWorktreePath;
2000
- }
2105
+ s.basePath = _resolvePausedResumeBasePathForTest(base, resumeWorktreePath);
2001
2106
  // Rebuild scope now that s.basePath reflects the actual worktree (or project root).
2002
2107
  rebuildScope(s.basePath, s.currentMilestoneId);
2003
2108
  // Ensure the workflow-logger audit log is pinned to the project root
@@ -2049,20 +2154,7 @@ export async function startAuto(
2049
2154
  // tree; deployed extensions live at ~/.gsd/agent/extensions/gsd/ where the
2050
2155
  // relative path resolves to ~/.gsd/agent/resource-loader.js which doesn't exist.
2051
2156
  // Using GSD_PKG_ROOT constructs a correct absolute path in both contexts (#3949).
2052
- const agentDir = process.env.GSD_CODING_AGENT_DIR || join(gsdHome(), "agent");
2053
- const pkgRoot = process.env.GSD_PKG_ROOT;
2054
- const resourceLoaderPath = pkgRoot
2055
- ? pathToFileURL(join(pkgRoot, "dist", "resource-loader.js")).href
2056
- : new URL("../../../resource-loader.js", import.meta.url).href;
2057
- const { initResources } = await import(resourceLoaderPath);
2058
- initResources(agentDir);
2059
- // initResources() uses synchronous fs APIs, so the prompt-template cache
2060
- // can be primed immediately — no need for the legacy 1s setTimeout deferral.
2061
- const { primeCache } = await import("./prompt-loader.js");
2062
- primeCache();
2063
- // Open the project DB before rebuild/derive so resume uses DB-backed
2064
- // state instead of falling back to stale markdown parsing (#2940).
2065
- await openProjectDbIfPresent(s.basePath);
2157
+ await refreshResumeResourcesAndDb(s.basePath);
2066
2158
  try {
2067
2159
  await rebuildState(s.basePath);
2068
2160
  pi.events.emit(CMUX_CHANNELS.SIDEBAR, { action: "sync" as const, preferences: loadEffectiveGSDPreferences(s.basePath || undefined)?.preferences, state: await deriveState(s.basePath) });
@@ -2134,7 +2226,7 @@ export async function startAuto(
2134
2226
  runKernelLoop: runUokKernelLoop,
2135
2227
  runLegacyLoop: runLegacyAutoLoop,
2136
2228
  });
2137
- cleanupAfterLoopExit(ctx);
2229
+ await cleanupAfterLoopExit(ctx);
2138
2230
  return;
2139
2231
  }
2140
2232
 
@@ -2194,7 +2286,7 @@ export async function startAuto(
2194
2286
  runKernelLoop: runUokKernelLoop,
2195
2287
  runLegacyLoop: runLegacyAutoLoop,
2196
2288
  });
2197
- cleanupAfterLoopExit(ctx);
2289
+ await cleanupAfterLoopExit(ctx);
2198
2290
  }
2199
2291
 
2200
2292
  // describeNextUnit is imported from auto-dashboard.ts and re-exported
@@ -15,7 +15,12 @@ import { clearPathCache } from "../paths.js";
15
15
  import { getAutoDashboardData, getAutoModeStartModel, isAutoActive, pauseAuto, setCurrentDispatchedModelId } from "../auto.js";
16
16
  import { getNextFallbackModel, resolveModelWithFallbacksForUnit } from "../preferences.js";
17
17
  import { pauseAutoForProviderError } from "../provider-error-pause.js";
18
- import { isSessionSwitchInFlight, resolveAgentEnd, resolveAgentEndCancelled } from "../auto/resolve.js";
18
+ import {
19
+ isSessionSwitchAbortGraceActive,
20
+ isSessionSwitchInFlight,
21
+ resolveAgentEnd,
22
+ resolveAgentEndCancelled,
23
+ } from "../auto/resolve.js";
19
24
  import { resolveModelId } from "../auto-model-selection.js";
20
25
  import { resolveProjectRoot } from "../worktree.js";
21
26
  import { clearDiscussionFlowState } from "./write-gate.js";
@@ -77,6 +82,42 @@ export function isUserInitiatedAbortMessage(message: string | undefined | null):
77
82
  return /\b(?:claude code process aborted by user|request aborted by user|process aborted by user)\b/i.test(message);
78
83
  }
79
84
 
85
+ function isBareClaudeCodeSessionSwitchAbortMarker(message: string | undefined | null): boolean {
86
+ if (!message) return false;
87
+ const normalized = message.trim().replace(/\s+/g, " ").toLowerCase();
88
+ return normalized === "claude code process aborted by user"
89
+ || normalized === "request aborted by user"
90
+ || normalized === "process aborted by user"
91
+ || normalized === "claude code stream aborted by caller";
92
+ }
93
+
94
+ function readAssistantTextContent(content: unknown): string {
95
+ if (!Array.isArray(content)) return "";
96
+ return content
97
+ .map((block) => {
98
+ if (!block || typeof block !== "object") return "";
99
+ const text = (block as { text?: unknown }).text;
100
+ return typeof text === "string" ? text : "";
101
+ })
102
+ .filter(Boolean)
103
+ .join("\n");
104
+ }
105
+
106
+ export function isClaudeCodeSessionSwitchAbortMessage(lastMsg: unknown): boolean {
107
+ if (!lastMsg || typeof lastMsg !== "object") return false;
108
+ const m = lastMsg as { stopReason?: unknown; errorMessage?: unknown; content?: unknown };
109
+ const carriers = [
110
+ m.errorMessage ? String(m.errorMessage) : "",
111
+ readAssistantTextContent(m.content),
112
+ ].filter((value) => value.trim().length > 0);
113
+
114
+ if ((m.stopReason === "error" || m.stopReason === "aborted") && carriers.length > 0) {
115
+ return carriers.every(isBareClaudeCodeSessionSwitchAbortMarker);
116
+ }
117
+
118
+ return false;
119
+ }
120
+
80
121
  /**
81
122
  * Resolve an agent_end event observed while a session switch is in flight.
82
123
  *
@@ -89,10 +130,11 @@ export function isUserInitiatedAbortMessage(message: string | undefined | null):
89
130
  * "Auto-mode stopped — Unit aborted: Claude Code process aborted by user"
90
131
  * even though no user input occurred.
91
132
  *
92
- * The user-abort branch is intentionally ignored when the abort fires while
93
- * the session-switch is in flight: the abort is the expected side-effect of
94
- * the transition, not a user signal. Other branches (genuine `stopReason ===
95
- * "aborted"` with content/errorMessage) preserve the prior behavior.
133
+ * Claude Code abort markers are intentionally ignored when the abort fires
134
+ * while the session-switch is in flight: the abort is the expected side-effect
135
+ * of the transition, not a user signal. Other branches (genuine `stopReason
136
+ * === "aborted"` with diagnostic content/errorMessage) preserve the prior
137
+ * behavior.
96
138
  */
97
139
  export function _handleSessionSwitchAgentEnd(
98
140
  lastMsg: unknown,
@@ -101,9 +143,14 @@ export function _handleSessionSwitchAgentEnd(
101
143
  if (!lastMsg || typeof lastMsg !== "object") return;
102
144
  const m = lastMsg as { stopReason?: unknown; errorMessage?: unknown; content?: unknown };
103
145
 
146
+ if (isClaudeCodeSessionSwitchAbortMessage(m)) {
147
+ // Internal abort from in-flight session transition — drop on the floor.
148
+ return;
149
+ }
150
+
104
151
  if (m.stopReason === "error") {
105
152
  const rawErrorMsg = m.errorMessage ? String(m.errorMessage) : "";
106
- if (isUserInitiatedAbortMessage(rawErrorMsg)) {
153
+ if (isBareClaudeCodeSessionSwitchAbortMarker(rawErrorMsg)) {
107
154
  // Internal abort from in-flight session transition — drop on the floor.
108
155
  return;
109
156
  }
@@ -120,6 +167,18 @@ export function _handleSessionSwitchAgentEnd(
120
167
  }
121
168
  }
122
169
 
170
+ export function resolveAgentEndErrorDisplay(
171
+ rawErrorMsg: string,
172
+ content: unknown,
173
+ ): string {
174
+ const isUseless = !rawErrorMsg || /^(success|ok|true|error|unknown)$/i.test(rawErrorMsg.trim());
175
+ if (isUseless && Array.isArray(content)) {
176
+ const textBlock = content.find((b: any) => b.type === "text" && b.text);
177
+ if (textBlock) return (textBlock as any).text.slice(0, 300);
178
+ }
179
+ return rawErrorMsg;
180
+ }
181
+
123
182
  async function pauseTransientWithBackoff(
124
183
  cls: ErrorClass,
125
184
  pi: ExtensionAPI,
@@ -204,6 +263,13 @@ export async function handleAgentEnd(
204
263
  return;
205
264
  }
206
265
 
266
+ if (isSessionSwitchAbortGraceActive() && isClaudeCodeSessionSwitchAbortMessage(lastMsg)) {
267
+ // Claude Code can report the abort from `newSession()` a few hundred ms
268
+ // after the guard drops. That event belongs to the old turn; do not let it
269
+ // cancel the freshly-dispatched unit.
270
+ return;
271
+ }
272
+
207
273
  if (lastMsg && "stopReason" in lastMsg && lastMsg.stopReason === "aborted") {
208
274
  // Empty content with aborted stopReason is a non-fatal agent stop (the LLM
209
275
  // chose to end without producing output). Only pause on genuine fatal aborts
@@ -243,15 +309,13 @@ export async function handleAgentEnd(
243
309
  });
244
310
  return;
245
311
  }
246
- const isUseless = !rawErrorMsg || /^(success|ok|true|error|unknown)$/i.test(rawErrorMsg.trim());
247
312
  // #3588: When errorMessage is uninformative, extract the real error from
248
313
  // the assistant message text content for display purposes only.
249
314
  // Classification still uses rawErrorMsg to avoid false positives from prose.
250
- let displayMsg = rawErrorMsg;
251
- if (isUseless && "content" in lastMsg && Array.isArray(lastMsg.content)) {
252
- const textBlock = lastMsg.content.find((b: any) => b.type === "text" && b.text);
253
- if (textBlock) displayMsg = (textBlock as any).text.slice(0, 300);
254
- }
315
+ const displayMsg = resolveAgentEndErrorDisplay(
316
+ rawErrorMsg,
317
+ "content" in lastMsg ? lastMsg.content : undefined,
318
+ );
255
319
  const errorDetail = displayMsg ? `: ${displayMsg}` : "";
256
320
  const explicitRetryAfterMs = ("retryAfterMs" in lastMsg && typeof lastMsg.retryAfterMs === "number") ? lastMsg.retryAfterMs : undefined;
257
321
 
@@ -5,7 +5,7 @@ import type { ExtensionAPI } from "@gsd/pi-coding-agent";
5
5
  import { Text } from "@gsd/pi-tui";
6
6
 
7
7
  import { loadEffectiveGSDPreferences } from "../preferences.js";
8
- import { ensureDbOpen } from "./dynamic-tools.js";
8
+ import { ensureDbOpen, resolveCtxCwd } from "./dynamic-tools.js";
9
9
  import { loadWriteGateSnapshot, shouldBlockRootArtifactSaveInSnapshot } from "./write-gate.js";
10
10
  import { StringEnum } from "@gsd/pi-ai";
11
11
  import { logError } from "../workflow-logger.js";
@@ -16,12 +16,6 @@ async function loadWorkflowExecutors(): Promise<typeof import("../tools/workflow
16
16
  return import("../tools/workflow-tool-executors.js");
17
17
  }
18
18
 
19
- function toolWorkspaceRoot(ctx: unknown): string {
20
- if (ctx && typeof ctx === "object" && typeof (ctx as { cwd?: unknown }).cwd === "string") {
21
- return (ctx as { cwd: string }).cwd;
22
- }
23
- return process.cwd();
24
- }
25
19
 
26
20
  /**
27
21
  * Register an alias tool that shares the same execute function as its canonical counterpart.
@@ -72,7 +66,7 @@ export function registerDbTools(pi: ExtensionAPI): void {
72
66
  // ─── gsd_decision_save (formerly gsd_save_decision) ─────────────────────
73
67
 
74
68
  const decisionSaveExecute = async (_toolCallId: string, params: any, _signal: AbortSignal | undefined, _onUpdate: unknown, _ctx: unknown) => {
75
- const basePath = toolWorkspaceRoot(_ctx);
69
+ const basePath = resolveCtxCwd(_ctx);
76
70
  const dbAvailable = await ensureDbOpen(basePath);
77
71
  if (!dbAvailable) {
78
72
  return {
@@ -160,7 +154,7 @@ export function registerDbTools(pi: ExtensionAPI): void {
160
154
  // ─── gsd_requirement_update (formerly gsd_update_requirement) ───────────
161
155
 
162
156
  const requirementUpdateExecute = async (_toolCallId: string, params: any, _signal: AbortSignal | undefined, _onUpdate: unknown, _ctx: unknown) => {
163
- const basePath = toolWorkspaceRoot(_ctx);
157
+ const basePath = resolveCtxCwd(_ctx);
164
158
  const gateBlock = requirementRootWriteGuard("update_requirement", basePath);
165
159
  if (gateBlock) return gateBlock;
166
160
  const dbAvailable = await ensureDbOpen(basePath);
@@ -241,7 +235,7 @@ export function registerDbTools(pi: ExtensionAPI): void {
241
235
  // ─── gsd_requirement_save ─────────────────────────────────────────────
242
236
 
243
237
  const requirementSaveExecute = async (_toolCallId: string, params: any, _signal: AbortSignal | undefined, _onUpdate: unknown, _ctx: unknown) => {
244
- const basePath = toolWorkspaceRoot(_ctx);
238
+ const basePath = resolveCtxCwd(_ctx);
245
239
  const gateBlock = requirementRootWriteGuard("save_requirement", basePath);
246
240
  if (gateBlock) return gateBlock;
247
241
  const dbAvailable = await ensureDbOpen(basePath);
@@ -345,7 +339,7 @@ export function registerDbTools(pi: ExtensionAPI): void {
345
339
 
346
340
  const summarySaveExecute = async (_toolCallId: string, params: any, _signal: AbortSignal | undefined, _onUpdate: unknown, _ctx: unknown) => {
347
341
  const { executeSummarySave } = await loadWorkflowExecutors();
348
- return executeSummarySave(params, toolWorkspaceRoot(_ctx));
342
+ return executeSummarySave(params, resolveCtxCwd(_ctx));
349
343
  };
350
344
 
351
345
  const summarySaveTool = {
@@ -396,7 +390,7 @@ export function registerDbTools(pi: ExtensionAPI): void {
396
390
 
397
391
  const milestoneGenerateIdExecute = async (_toolCallId: string, _params: any, _signal: AbortSignal | undefined, _onUpdate: unknown, _ctx: unknown) => {
398
392
  try {
399
- const basePath = toolWorkspaceRoot(_ctx);
393
+ const basePath = resolveCtxCwd(_ctx);
400
394
  // Claim a reserved ID if the guided-flow already previewed one to the user.
401
395
  // This guarantees the ID shown in the UI matches the one materialised on disk.
402
396
  const { claimReservedId, findMilestoneIds, getReservedMilestoneIds, nextMilestoneId } = await import("../guided-flow.js");
@@ -481,7 +475,7 @@ export function registerDbTools(pi: ExtensionAPI): void {
481
475
 
482
476
  const planMilestoneExecute = async (_toolCallId: string, params: any, _signal: AbortSignal | undefined, _onUpdate: unknown, _ctx: unknown) => {
483
477
  const { executePlanMilestone } = await loadWorkflowExecutors();
484
- return executePlanMilestone(params, toolWorkspaceRoot(_ctx));
478
+ return executePlanMilestone(params, resolveCtxCwd(_ctx));
485
479
  };
486
480
 
487
481
  const planMilestoneTool = {
@@ -551,7 +545,7 @@ export function registerDbTools(pi: ExtensionAPI): void {
551
545
 
552
546
  const planSliceExecute = async (_toolCallId: string, params: any, _signal: AbortSignal | undefined, _onUpdate: unknown, _ctx: unknown) => {
553
547
  const { executePlanSlice } = await loadWorkflowExecutors();
554
- return executePlanSlice(params, toolWorkspaceRoot(_ctx));
548
+ return executePlanSlice(params, resolveCtxCwd(_ctx));
555
549
  };
556
550
 
557
551
  const planSliceTool = {
@@ -600,7 +594,7 @@ export function registerDbTools(pi: ExtensionAPI): void {
600
594
  // ─── gsd_plan_task (gsd_task_plan alias) ───────────────────────────────
601
595
 
602
596
  const planTaskExecute = async (_toolCallId: string, params: any, _signal: AbortSignal | undefined, _onUpdate: unknown, _ctx: unknown) => {
603
- const basePath = toolWorkspaceRoot(_ctx);
597
+ const basePath = resolveCtxCwd(_ctx);
604
598
  const dbAvailable = await ensureDbOpen(basePath);
605
599
  if (!dbAvailable) {
606
600
  return {
@@ -675,7 +669,7 @@ export function registerDbTools(pi: ExtensionAPI): void {
675
669
 
676
670
  const taskCompleteExecute = async (_toolCallId: string, params: any, _signal: AbortSignal | undefined, _onUpdate: unknown, _ctx: unknown) => {
677
671
  const { executeTaskComplete } = await loadWorkflowExecutors();
678
- return executeTaskComplete(params, toolWorkspaceRoot(_ctx));
672
+ return executeTaskComplete(params, resolveCtxCwd(_ctx));
679
673
  };
680
674
 
681
675
  const taskCompleteTool = {
@@ -746,7 +740,7 @@ export function registerDbTools(pi: ExtensionAPI): void {
746
740
 
747
741
  const sliceCompleteExecute = async (_toolCallId: string, params: any, _signal: AbortSignal | undefined, _onUpdate: unknown, _ctx: unknown) => {
748
742
  const { executeSliceComplete } = await loadWorkflowExecutors();
749
- return executeSliceComplete(params, toolWorkspaceRoot(_ctx));
743
+ return executeSliceComplete(params, resolveCtxCwd(_ctx));
750
744
  };
751
745
 
752
746
  const sliceCompleteTool = {
@@ -846,7 +840,7 @@ export function registerDbTools(pi: ExtensionAPI): void {
846
840
  // ─── gsd_skip_slice (#3477 / #3487) ───────────────────────────────────
847
841
 
848
842
  const skipSliceExecute = async (_toolCallId: string, params: any, _signal: AbortSignal | undefined, _onUpdate: unknown, _ctx: unknown) => {
849
- const basePath = toolWorkspaceRoot(_ctx);
843
+ const basePath = resolveCtxCwd(_ctx);
850
844
  const dbAvailable = await ensureDbOpen(basePath);
851
845
  if (!dbAvailable) {
852
846
  return {
@@ -939,7 +933,7 @@ export function registerDbTools(pi: ExtensionAPI): void {
939
933
 
940
934
  const milestoneCompleteExecute = async (_toolCallId: string, params: any, _signal: AbortSignal | undefined, _onUpdate: unknown, _ctx: unknown) => {
941
935
  const { executeCompleteMilestone } = await loadWorkflowExecutors();
942
- return executeCompleteMilestone(params, toolWorkspaceRoot(_ctx));
936
+ return executeCompleteMilestone(params, resolveCtxCwd(_ctx));
943
937
  };
944
938
 
945
939
  const milestoneCompleteTool = {
@@ -985,7 +979,7 @@ export function registerDbTools(pi: ExtensionAPI): void {
985
979
 
986
980
  const milestoneValidateExecute = async (_toolCallId: string, params: any, _signal: AbortSignal | undefined, _onUpdate: unknown, _ctx: unknown) => {
987
981
  const { executeValidateMilestone } = await loadWorkflowExecutors();
988
- return executeValidateMilestone(params, toolWorkspaceRoot(_ctx));
982
+ return executeValidateMilestone(params, resolveCtxCwd(_ctx));
989
983
  };
990
984
 
991
985
  const milestoneValidateTool = {
@@ -1023,7 +1017,7 @@ export function registerDbTools(pi: ExtensionAPI): void {
1023
1017
 
1024
1018
  const replanSliceExecute = async (_toolCallId: string, params: any, _signal: AbortSignal | undefined, _onUpdate: unknown, _ctx: unknown) => {
1025
1019
  const { executeReplanSlice } = await loadWorkflowExecutors();
1026
- return executeReplanSlice(params, toolWorkspaceRoot(_ctx));
1020
+ return executeReplanSlice(params, resolveCtxCwd(_ctx));
1027
1021
  };
1028
1022
 
1029
1023
  const replanSliceTool = {
@@ -1074,7 +1068,7 @@ export function registerDbTools(pi: ExtensionAPI): void {
1074
1068
 
1075
1069
  const reassessRoadmapExecute = async (_toolCallId: string, params: any, _signal: AbortSignal | undefined, _onUpdate: unknown, _ctx: unknown) => {
1076
1070
  const { executeReassessRoadmap } = await loadWorkflowExecutors();
1077
- return executeReassessRoadmap(params, toolWorkspaceRoot(_ctx));
1071
+ return executeReassessRoadmap(params, resolveCtxCwd(_ctx));
1078
1072
  };
1079
1073
 
1080
1074
  const reassessRoadmapTool = {
@@ -1133,7 +1127,7 @@ export function registerDbTools(pi: ExtensionAPI): void {
1133
1127
  // Single-writer v3, Stream 3: reversibility tools for closed units.
1134
1128
 
1135
1129
  const reopenTaskExecute = async (_toolCallId: string, params: any, _signal: AbortSignal | undefined, _onUpdate: unknown, _ctx: unknown) => {
1136
- const basePath = toolWorkspaceRoot(_ctx);
1130
+ const basePath = resolveCtxCwd(_ctx);
1137
1131
  const dbAvailable = await ensureDbOpen(basePath);
1138
1132
  if (!dbAvailable) {
1139
1133
  return {
@@ -1200,7 +1194,7 @@ export function registerDbTools(pi: ExtensionAPI): void {
1200
1194
  // ─── gsd_slice_reopen (gsd_reopen_slice alias) ─────────────────────────
1201
1195
 
1202
1196
  const reopenSliceExecute = async (_toolCallId: string, params: any, _signal: AbortSignal | undefined, _onUpdate: unknown, _ctx: unknown) => {
1203
- const basePath = toolWorkspaceRoot(_ctx);
1197
+ const basePath = resolveCtxCwd(_ctx);
1204
1198
  const dbAvailable = await ensureDbOpen(basePath);
1205
1199
  if (!dbAvailable) {
1206
1200
  return {
@@ -1267,7 +1261,7 @@ export function registerDbTools(pi: ExtensionAPI): void {
1267
1261
  // ─── gsd_milestone_reopen (gsd_reopen_milestone alias) ─────────────────
1268
1262
 
1269
1263
  const reopenMilestoneExecute = async (_toolCallId: string, params: any, _signal: AbortSignal | undefined, _onUpdate: unknown, _ctx: unknown) => {
1270
- const basePath = toolWorkspaceRoot(_ctx);
1264
+ const basePath = resolveCtxCwd(_ctx);
1271
1265
  const dbAvailable = await ensureDbOpen(basePath);
1272
1266
  if (!dbAvailable) {
1273
1267
  return {
@@ -1333,7 +1327,7 @@ export function registerDbTools(pi: ExtensionAPI): void {
1333
1327
 
1334
1328
  const saveGateResultExecute = async (_toolCallId: string, params: any, _signal: AbortSignal | undefined, _onUpdate: unknown, _ctx: unknown) => {
1335
1329
  const { executeSaveGateResult } = await loadWorkflowExecutors();
1336
- return executeSaveGateResult(params, toolWorkspaceRoot(_ctx));
1330
+ return executeSaveGateResult(params, resolveCtxCwd(_ctx));
1337
1331
  };
1338
1332
 
1339
1333
  const saveGateResultTool = {
@@ -1,4 +1,7 @@
1
+ // Project/App: GSD-2
2
+ // File Purpose: Registers workspace-aware dynamic filesystem and shell tools.
1
3
  import { existsSync } from "node:fs";
4
+ import { homedir } from "node:os";
2
5
  import { dirname } from "node:path";
3
6
 
4
7
  import type { ExtensionAPI } from "@gsd/pi-coding-agent";
@@ -8,11 +11,22 @@ import { DEFAULT_BASH_TIMEOUT_SECS } from "../constants.js";
8
11
  import { setLogBasePath, logWarning } from "../workflow-logger.js";
9
12
  import { resolveGsdPathContract } from "../paths.js";
10
13
 
11
- function resolveToolWorkspaceRoot(ctx?: unknown): string {
14
+ export function safeWorkspaceCwd(): string {
15
+ try {
16
+ return process.cwd();
17
+ } catch {
18
+ const projectRoot = process.env.GSD_PROJECT_ROOT;
19
+ if (projectRoot && existsSync(projectRoot)) return projectRoot;
20
+ return homedir();
21
+ }
22
+ }
23
+
24
+ export function resolveCtxCwd(ctx?: unknown): string {
12
25
  if (ctx && typeof ctx === "object" && typeof (ctx as { cwd?: unknown }).cwd === "string") {
13
- return (ctx as { cwd: string }).cwd;
26
+ const cwd = (ctx as { cwd: string }).cwd;
27
+ if (existsSync(cwd)) return cwd;
14
28
  }
15
- return process.cwd();
29
+ return safeWorkspaceCwd();
16
30
  }
17
31
 
18
32
  /**
@@ -25,7 +39,7 @@ export function resolveProjectRootDbPath(basePath: string): string {
25
39
  return resolveGsdPathContract(basePath).projectDb;
26
40
  }
27
41
 
28
- export async function ensureDbOpen(basePath: string = process.cwd()): Promise<boolean> {
42
+ export async function ensureDbOpen(basePath: string = safeWorkspaceCwd()): Promise<boolean> {
29
43
  try {
30
44
  const db = await import("../gsd-db.js");
31
45
  const contract = resolveGsdPathContract(basePath);
@@ -57,7 +71,8 @@ export async function ensureDbOpen(basePath: string = process.cwd()): Promise<bo
57
71
  }
58
72
 
59
73
  export function registerDynamicTools(pi: ExtensionAPI): void {
60
- const baseBash = createBashTool(process.cwd(), {
74
+ const fallbackRoot = safeWorkspaceCwd();
75
+ const baseBash = createBashTool(fallbackRoot, {
61
76
  spawnHook: (ctx) => ctx,
62
77
  });
63
78
  const dynamicBash = {
@@ -69,7 +84,7 @@ export function registerDynamicTools(pi: ExtensionAPI): void {
69
84
  onUpdate?: unknown,
70
85
  ctx?: unknown,
71
86
  ) => {
72
- const basePath = resolveToolWorkspaceRoot(ctx);
87
+ const basePath = resolveCtxCwd(ctx);
73
88
  const fresh = createBashTool(basePath, {
74
89
  spawnHook: (spawnCtx) => ({ ...spawnCtx, cwd: basePath }),
75
90
  });
@@ -82,7 +97,7 @@ export function registerDynamicTools(pi: ExtensionAPI): void {
82
97
  };
83
98
  pi.registerTool(dynamicBash as any);
84
99
 
85
- const baseWrite = createWriteTool(process.cwd());
100
+ const baseWrite = createWriteTool(fallbackRoot);
86
101
  pi.registerTool({
87
102
  ...baseWrite,
88
103
  execute: async (
@@ -92,12 +107,12 @@ export function registerDynamicTools(pi: ExtensionAPI): void {
92
107
  onUpdate?: unknown,
93
108
  ctx?: unknown,
94
109
  ) => {
95
- const fresh = createWriteTool(resolveToolWorkspaceRoot(ctx));
110
+ const fresh = createWriteTool(resolveCtxCwd(ctx));
96
111
  return (fresh as any).execute(toolCallId, params, signal, onUpdate, ctx);
97
112
  },
98
113
  } as any);
99
114
 
100
- const baseRead = createReadTool(process.cwd());
115
+ const baseRead = createReadTool(fallbackRoot);
101
116
  pi.registerTool({
102
117
  ...baseRead,
103
118
  execute: async (
@@ -107,12 +122,12 @@ export function registerDynamicTools(pi: ExtensionAPI): void {
107
122
  onUpdate?: unknown,
108
123
  ctx?: unknown,
109
124
  ) => {
110
- const fresh = createReadTool(resolveToolWorkspaceRoot(ctx));
125
+ const fresh = createReadTool(resolveCtxCwd(ctx));
111
126
  return (fresh as any).execute(toolCallId, params, signal, onUpdate, ctx);
112
127
  },
113
128
  } as any);
114
129
 
115
- const baseEdit = createEditTool(process.cwd());
130
+ const baseEdit = createEditTool(fallbackRoot);
116
131
  pi.registerTool({
117
132
  ...baseEdit,
118
133
  execute: async (
@@ -122,7 +137,7 @@ export function registerDynamicTools(pi: ExtensionAPI): void {
122
137
  onUpdate?: unknown,
123
138
  ctx?: unknown,
124
139
  ) => {
125
- const fresh = createEditTool(resolveToolWorkspaceRoot(ctx));
140
+ const fresh = createEditTool(resolveCtxCwd(ctx));
126
141
  return (fresh as any).execute(toolCallId, params, signal, onUpdate, ctx);
127
142
  },
128
143
  } as any);