gsd-pi 2.80.0-dev.42bd34838 → 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 (509) 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 +179 -99
  17. package/dist/resources/extensions/gsd/auto/resolve.js +12 -0
  18. package/dist/resources/extensions/gsd/auto/run-unit.js +10 -30
  19. package/dist/resources/extensions/gsd/auto/session.js +8 -0
  20. package/dist/resources/extensions/gsd/auto/workflow-dispatch-claim.js +33 -1
  21. package/dist/resources/extensions/gsd/auto/workflow-worker-heartbeat.js +9 -1
  22. package/dist/resources/extensions/gsd/auto-direct-dispatch.js +5 -32
  23. package/dist/resources/extensions/gsd/auto-dispatch.js +16 -0
  24. package/dist/resources/extensions/gsd/auto-post-unit.js +94 -76
  25. package/dist/resources/extensions/gsd/auto-prompts.js +90 -15
  26. package/dist/resources/extensions/gsd/auto-start.js +238 -12
  27. package/dist/resources/extensions/gsd/auto-worktree.js +209 -81
  28. package/dist/resources/extensions/gsd/auto.js +95 -44
  29. package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +96 -26
  30. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +44 -37
  31. package/dist/resources/extensions/gsd/bootstrap/dynamic-tools.js +37 -10
  32. package/dist/resources/extensions/gsd/bootstrap/exec-tools.js +6 -3
  33. package/dist/resources/extensions/gsd/bootstrap/journal-tools.js +4 -1
  34. package/dist/resources/extensions/gsd/bootstrap/memory-tools.js +6 -4
  35. package/dist/resources/extensions/gsd/bootstrap/query-tools.js +5 -3
  36. package/dist/resources/extensions/gsd/bootstrap/register-extension.js +1 -1
  37. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +298 -54
  38. package/dist/resources/extensions/gsd/bootstrap/sanitize-complete-milestone.js +4 -0
  39. package/dist/resources/extensions/gsd/bootstrap/system-context.js +82 -23
  40. package/dist/resources/extensions/gsd/clean-root-preflight.js +24 -6
  41. package/dist/resources/extensions/gsd/commands/handlers/ops.js +2 -2
  42. package/dist/resources/extensions/gsd/commands-config.js +1 -1
  43. package/dist/resources/extensions/gsd/commands-eval-review.js +2 -2
  44. package/dist/resources/extensions/gsd/commands-handlers.js +23 -9
  45. package/dist/resources/extensions/gsd/dashboard-overlay.js +1 -1
  46. package/dist/resources/extensions/gsd/db/unit-dispatches.js +53 -0
  47. package/dist/resources/extensions/gsd/ecosystem/gsd-extension-api.js +2 -0
  48. package/dist/resources/extensions/gsd/git-service.js +37 -1
  49. package/dist/resources/extensions/gsd/guided-flow.js +61 -32
  50. package/dist/resources/extensions/gsd/init-wizard.js +4 -1
  51. package/dist/resources/extensions/gsd/native-git-bridge.js +32 -8
  52. package/dist/resources/extensions/gsd/orphan-stash-audit.js +101 -0
  53. package/dist/resources/extensions/gsd/parallel-orchestrator.js +13 -3
  54. package/dist/resources/extensions/gsd/pre-execution-checks.js +22 -0
  55. package/dist/resources/extensions/gsd/prompts/complete-milestone.md +8 -4
  56. package/dist/resources/extensions/gsd/prompts/complete-slice.md +1 -1
  57. package/dist/resources/extensions/gsd/prompts/execute-task.md +4 -2
  58. package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  59. package/dist/resources/extensions/gsd/prompts/replan-slice.md +2 -2
  60. package/dist/resources/extensions/gsd/slice-cadence.js +45 -2
  61. package/dist/resources/extensions/gsd/slice-parallel-orchestrator.js +15 -9
  62. package/dist/resources/extensions/gsd/tools/complete-milestone.js +6 -7
  63. package/dist/resources/extensions/gsd/tools/complete-task.js +1 -1
  64. package/dist/resources/extensions/gsd/workflow-protocol.js +131 -0
  65. package/dist/resources/extensions/gsd/worktree-resolver.js +57 -5
  66. package/dist/resources/skills/web-quality-audit/scripts/analyze.sh +0 -0
  67. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  68. package/dist/web/standalone/.next/BUILD_ID +1 -1
  69. package/dist/web/standalone/.next/app-path-routes-manifest.json +11 -11
  70. package/dist/web/standalone/.next/build-manifest.json +3 -3
  71. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  72. package/dist/web/standalone/.next/react-loadable-manifest.json +2 -2
  73. package/dist/web/standalone/.next/required-server-files.json +1 -1
  74. package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  75. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  76. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  77. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  78. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  79. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  80. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  81. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  82. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  83. package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  84. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  85. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  86. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  87. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  88. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  89. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  90. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  91. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  92. package/dist/web/standalone/.next/server/app/index.html +1 -1
  93. package/dist/web/standalone/.next/server/app/index.rsc +2 -2
  94. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  95. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +2 -2
  96. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  97. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  98. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  99. package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  100. package/dist/web/standalone/.next/server/app-paths-manifest.json +11 -11
  101. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  102. package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
  103. package/dist/web/standalone/.next/server/middleware.js +3 -3
  104. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  105. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  106. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  107. package/dist/web/standalone/.next/static/chunks/8359.e059d86b255fce1c.js +10 -0
  108. package/dist/web/standalone/.next/static/chunks/app/{page-fab3ebb85b006001.js → page-752f1e2ebdaa3e45.js} +1 -1
  109. package/dist/web/standalone/.next/static/chunks/{webpack-0481f1221120a7c6.js → webpack-de742b64187e13fe.js} +1 -1
  110. package/dist/web/standalone/server.js +1 -1
  111. package/dist/welcome-screen.d.ts +2 -0
  112. package/dist/welcome-screen.js +9 -7
  113. package/package.json +1 -1
  114. package/packages/pi-agent-core/dist/agent-loop.d.ts.map +1 -1
  115. package/packages/pi-agent-core/dist/agent-loop.js +4 -1
  116. package/packages/pi-agent-core/dist/agent-loop.js.map +1 -1
  117. package/packages/pi-agent-core/dist/agent.d.ts +5 -0
  118. package/packages/pi-agent-core/dist/agent.d.ts.map +1 -1
  119. package/packages/pi-agent-core/dist/agent.js +2 -0
  120. package/packages/pi-agent-core/dist/agent.js.map +1 -1
  121. package/packages/pi-agent-core/dist/index.d.ts +1 -0
  122. package/packages/pi-agent-core/dist/index.d.ts.map +1 -1
  123. package/packages/pi-agent-core/dist/index.js +2 -0
  124. package/packages/pi-agent-core/dist/index.js.map +1 -1
  125. package/packages/pi-agent-core/dist/token-audit.d.ts +47 -0
  126. package/packages/pi-agent-core/dist/token-audit.d.ts.map +1 -0
  127. package/packages/pi-agent-core/dist/token-audit.js +221 -0
  128. package/packages/pi-agent-core/dist/token-audit.js.map +1 -0
  129. package/packages/pi-agent-core/dist/types.d.ts +9 -0
  130. package/packages/pi-agent-core/dist/types.d.ts.map +1 -1
  131. package/packages/pi-agent-core/dist/types.js.map +1 -1
  132. package/packages/pi-agent-core/src/agent-loop.test.ts +128 -0
  133. package/packages/pi-agent-core/src/agent-loop.ts +4 -1
  134. package/packages/pi-agent-core/src/agent.ts +8 -0
  135. package/packages/pi-agent-core/src/index.ts +2 -0
  136. package/packages/pi-agent-core/src/token-audit.test.ts +189 -0
  137. package/packages/pi-agent-core/src/token-audit.ts +287 -0
  138. package/packages/pi-agent-core/src/types.ts +14 -0
  139. package/packages/pi-agent-core/tsconfig.tsbuildinfo +1 -1
  140. package/packages/pi-ai/dist/providers/anthropic-auth.test.js +35 -13
  141. package/packages/pi-ai/dist/providers/anthropic-auth.test.js.map +1 -1
  142. package/packages/pi-ai/dist/providers/anthropic-bearer-auth.test.js +21 -11
  143. package/packages/pi-ai/dist/providers/anthropic-bearer-auth.test.js.map +1 -1
  144. package/packages/pi-ai/dist/providers/anthropic.d.ts +7 -0
  145. package/packages/pi-ai/dist/providers/anthropic.d.ts.map +1 -1
  146. package/packages/pi-ai/dist/providers/anthropic.js +9 -7
  147. package/packages/pi-ai/dist/providers/anthropic.js.map +1 -1
  148. package/packages/pi-ai/dist/providers/minimax-tool-name.test.js +23 -14
  149. package/packages/pi-ai/dist/providers/minimax-tool-name.test.js.map +1 -1
  150. package/packages/pi-ai/dist/utils/oauth/github-copilot.test.js +48 -21
  151. package/packages/pi-ai/dist/utils/oauth/github-copilot.test.js.map +1 -1
  152. package/packages/pi-ai/dist/utils/oauth/google-antigravity.test.js +22 -21
  153. package/packages/pi-ai/dist/utils/oauth/google-antigravity.test.js.map +1 -1
  154. package/packages/pi-ai/dist/utils/oauth/google-gemini-cli.test.js +22 -21
  155. package/packages/pi-ai/dist/utils/oauth/google-gemini-cli.test.js.map +1 -1
  156. package/packages/pi-ai/src/providers/anthropic-auth.test.ts +39 -25
  157. package/packages/pi-ai/src/providers/anthropic-bearer-auth.test.ts +26 -22
  158. package/packages/pi-ai/src/providers/anthropic.ts +22 -9
  159. package/packages/pi-ai/src/providers/minimax-tool-name.test.ts +34 -21
  160. package/packages/pi-ai/src/utils/oauth/github-copilot.test.ts +56 -22
  161. package/packages/pi-ai/src/utils/oauth/google-antigravity.test.ts +24 -28
  162. package/packages/pi-ai/src/utils/oauth/google-gemini-cli.test.ts +24 -28
  163. package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
  164. package/packages/pi-coding-agent/dist/core/agent-session-tool-refresh.test.js +18 -0
  165. package/packages/pi-coding-agent/dist/core/agent-session-tool-refresh.test.js.map +1 -1
  166. package/packages/pi-coding-agent/dist/core/agent-session.d.ts +12 -0
  167. package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
  168. package/packages/pi-coding-agent/dist/core/agent-session.js +36 -7
  169. package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
  170. package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js +3 -1
  171. package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js.map +1 -1
  172. package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts.map +1 -1
  173. package/packages/pi-coding-agent/dist/core/extensions/loader.js +8 -0
  174. package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
  175. package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts +2 -0
  176. package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts.map +1 -1
  177. package/packages/pi-coding-agent/dist/core/extensions/runner.js +3 -6
  178. package/packages/pi-coding-agent/dist/core/extensions/runner.js.map +1 -1
  179. package/packages/pi-coding-agent/dist/core/extensions/runner.test.js +3 -3
  180. package/packages/pi-coding-agent/dist/core/extensions/runner.test.js.map +1 -1
  181. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts +34 -3
  182. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts.map +1 -1
  183. package/packages/pi-coding-agent/dist/core/extensions/types.js.map +1 -1
  184. package/packages/pi-coding-agent/dist/core/hooks-runner.test.js +2 -0
  185. package/packages/pi-coding-agent/dist/core/hooks-runner.test.js.map +1 -1
  186. package/packages/pi-coding-agent/dist/core/sdk-tool-filter.test.d.ts +2 -0
  187. package/packages/pi-coding-agent/dist/core/sdk-tool-filter.test.d.ts.map +1 -0
  188. package/packages/pi-coding-agent/dist/core/sdk-tool-filter.test.js +46 -0
  189. package/packages/pi-coding-agent/dist/core/sdk-tool-filter.test.js.map +1 -0
  190. package/packages/pi-coding-agent/dist/core/sdk.d.ts +10 -2
  191. package/packages/pi-coding-agent/dist/core/sdk.d.ts.map +1 -1
  192. package/packages/pi-coding-agent/dist/core/sdk.js +74 -2
  193. package/packages/pi-coding-agent/dist/core/sdk.js.map +1 -1
  194. package/packages/pi-coding-agent/dist/core/skill-tool.test.js +22 -0
  195. package/packages/pi-coding-agent/dist/core/skill-tool.test.js.map +1 -1
  196. package/packages/pi-coding-agent/dist/core/system-prompt.d.ts +6 -7
  197. package/packages/pi-coding-agent/dist/core/system-prompt.d.ts.map +1 -1
  198. package/packages/pi-coding-agent/dist/core/system-prompt.js +2 -3
  199. package/packages/pi-coding-agent/dist/core/system-prompt.js.map +1 -1
  200. package/packages/pi-coding-agent/dist/core/tools/bash-spawn-windows.test.js +22 -56
  201. package/packages/pi-coding-agent/dist/core/tools/bash-spawn-windows.test.js.map +1 -1
  202. package/packages/pi-coding-agent/dist/core/tools/bash.d.ts +1 -0
  203. package/packages/pi-coding-agent/dist/core/tools/bash.d.ts.map +1 -1
  204. package/packages/pi-coding-agent/dist/core/tools/bash.js +3 -1
  205. package/packages/pi-coding-agent/dist/core/tools/bash.js.map +1 -1
  206. package/packages/pi-coding-agent/dist/core/tools/edit.d.ts +2 -0
  207. package/packages/pi-coding-agent/dist/core/tools/edit.d.ts.map +1 -1
  208. package/packages/pi-coding-agent/dist/core/tools/edit.js +12 -1
  209. package/packages/pi-coding-agent/dist/core/tools/edit.js.map +1 -1
  210. package/packages/pi-coding-agent/dist/core/tools/find.d.ts +2 -0
  211. package/packages/pi-coding-agent/dist/core/tools/find.d.ts.map +1 -1
  212. package/packages/pi-coding-agent/dist/core/tools/find.js +14 -6
  213. package/packages/pi-coding-agent/dist/core/tools/find.js.map +1 -1
  214. package/packages/pi-coding-agent/dist/core/tools/grep.d.ts +2 -0
  215. package/packages/pi-coding-agent/dist/core/tools/grep.d.ts.map +1 -1
  216. package/packages/pi-coding-agent/dist/core/tools/grep.js +12 -3
  217. package/packages/pi-coding-agent/dist/core/tools/grep.js.map +1 -1
  218. package/packages/pi-coding-agent/dist/core/tools/hashline-read.d.ts +2 -0
  219. package/packages/pi-coding-agent/dist/core/tools/hashline-read.d.ts.map +1 -1
  220. package/packages/pi-coding-agent/dist/core/tools/hashline-read.js +3 -1
  221. package/packages/pi-coding-agent/dist/core/tools/hashline-read.js.map +1 -1
  222. package/packages/pi-coding-agent/dist/core/tools/index.d.ts +2 -1
  223. package/packages/pi-coding-agent/dist/core/tools/index.d.ts.map +1 -1
  224. package/packages/pi-coding-agent/dist/core/tools/index.js +1 -0
  225. package/packages/pi-coding-agent/dist/core/tools/index.js.map +1 -1
  226. package/packages/pi-coding-agent/dist/core/tools/ls.d.ts +2 -0
  227. package/packages/pi-coding-agent/dist/core/tools/ls.d.ts.map +1 -1
  228. package/packages/pi-coding-agent/dist/core/tools/ls.js +10 -3
  229. package/packages/pi-coding-agent/dist/core/tools/ls.js.map +1 -1
  230. package/packages/pi-coding-agent/dist/core/tools/read.d.ts +2 -0
  231. package/packages/pi-coding-agent/dist/core/tools/read.d.ts.map +1 -1
  232. package/packages/pi-coding-agent/dist/core/tools/read.js +3 -1
  233. package/packages/pi-coding-agent/dist/core/tools/read.js.map +1 -1
  234. package/packages/pi-coding-agent/dist/core/tools/spawn-shell-windows.test.js +7 -62
  235. package/packages/pi-coding-agent/dist/core/tools/spawn-shell-windows.test.js.map +1 -1
  236. package/packages/pi-coding-agent/dist/core/tools/tool-target-metadata.test.d.ts +2 -0
  237. package/packages/pi-coding-agent/dist/core/tools/tool-target-metadata.test.d.ts.map +1 -0
  238. package/packages/pi-coding-agent/dist/core/tools/tool-target-metadata.test.js +115 -0
  239. package/packages/pi-coding-agent/dist/core/tools/tool-target-metadata.test.js.map +1 -0
  240. package/packages/pi-coding-agent/dist/core/tools/tool-target.d.ts +19 -0
  241. package/packages/pi-coding-agent/dist/core/tools/tool-target.d.ts.map +1 -0
  242. package/packages/pi-coding-agent/dist/core/tools/tool-target.js +20 -0
  243. package/packages/pi-coding-agent/dist/core/tools/tool-target.js.map +1 -0
  244. package/packages/pi-coding-agent/dist/core/tools/write.d.ts +4 -0
  245. package/packages/pi-coding-agent/dist/core/tools/write.d.ts.map +1 -1
  246. package/packages/pi-coding-agent/dist/core/tools/write.js +9 -1
  247. package/packages/pi-coding-agent/dist/core/tools/write.js.map +1 -1
  248. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js +89 -2
  249. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js.map +1 -1
  250. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-card-cleanup-and-success-runtime.test.js +25 -1
  251. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-card-cleanup-and-success-runtime.test.js.map +1 -1
  252. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts +5 -0
  253. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  254. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +153 -8
  255. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
  256. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  257. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +18 -1
  258. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  259. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.test.js +23 -5
  260. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.test.js.map +1 -1
  261. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts +2 -0
  262. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  263. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +19 -0
  264. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  265. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage-safety-guard.test.js +23 -5
  266. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage-safety-guard.test.js.map +1 -1
  267. package/packages/pi-coding-agent/src/core/agent-session-tool-refresh.test.ts +25 -0
  268. package/packages/pi-coding-agent/src/core/agent-session.ts +40 -7
  269. package/packages/pi-coding-agent/src/core/chat-controller-ordering.test.ts +3 -1
  270. package/packages/pi-coding-agent/src/core/extensions/loader.ts +10 -0
  271. package/packages/pi-coding-agent/src/core/extensions/runner.test.ts +3 -3
  272. package/packages/pi-coding-agent/src/core/extensions/runner.ts +5 -5
  273. package/packages/pi-coding-agent/src/core/extensions/types.ts +37 -2
  274. package/packages/pi-coding-agent/src/core/hooks-runner.test.ts +2 -0
  275. package/packages/pi-coding-agent/src/core/sdk-tool-filter.test.ts +60 -0
  276. package/packages/pi-coding-agent/src/core/sdk.ts +85 -3
  277. package/packages/pi-coding-agent/src/core/skill-tool.test.ts +28 -0
  278. package/packages/pi-coding-agent/src/core/system-prompt.ts +8 -10
  279. package/packages/pi-coding-agent/src/core/tools/bash-spawn-windows.test.ts +22 -66
  280. package/packages/pi-coding-agent/src/core/tools/bash.ts +4 -1
  281. package/packages/pi-coding-agent/src/core/tools/edit.ts +13 -1
  282. package/packages/pi-coding-agent/src/core/tools/find.ts +15 -6
  283. package/packages/pi-coding-agent/src/core/tools/grep.ts +13 -3
  284. package/packages/pi-coding-agent/src/core/tools/hashline-read.ts +4 -1
  285. package/packages/pi-coding-agent/src/core/tools/index.ts +8 -0
  286. package/packages/pi-coding-agent/src/core/tools/ls.ts +11 -3
  287. package/packages/pi-coding-agent/src/core/tools/read.ts +4 -1
  288. package/packages/pi-coding-agent/src/core/tools/spawn-shell-windows.test.ts +11 -72
  289. package/packages/pi-coding-agent/src/core/tools/tool-target-metadata.test.ts +127 -0
  290. package/packages/pi-coding-agent/src/core/tools/tool-target.ts +48 -0
  291. package/packages/pi-coding-agent/src/core/tools/write.ts +14 -2
  292. package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/tool-execution.test.ts +119 -2
  293. package/packages/pi-coding-agent/src/modes/interactive/components/tool-card-cleanup-and-success-runtime.test.ts +31 -1
  294. package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +177 -8
  295. package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.test.ts +24 -5
  296. package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +17 -1
  297. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +21 -0
  298. package/packages/pi-coding-agent/src/resources/extensions/memory/storage-safety-guard.test.ts +25 -8
  299. package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
  300. package/src/resources/extensions/claude-code-cli/readiness.ts +25 -7
  301. package/src/resources/extensions/claude-code-cli/stream-adapter.ts +30 -0
  302. package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +26 -0
  303. package/src/resources/extensions/github-sync/sync.ts +8 -1
  304. package/src/resources/extensions/github-sync/tests/sync-source.test.ts +6 -18
  305. package/src/resources/extensions/gsd/auto/loop-deps.ts +2 -2
  306. package/src/resources/extensions/gsd/auto/loop.ts +84 -8
  307. package/src/resources/extensions/gsd/auto/phases.ts +258 -159
  308. package/src/resources/extensions/gsd/auto/resolve.ts +19 -0
  309. package/src/resources/extensions/gsd/auto/run-unit.ts +10 -29
  310. package/src/resources/extensions/gsd/auto/session.ts +8 -0
  311. package/src/resources/extensions/gsd/auto/workflow-dispatch-claim.ts +63 -1
  312. package/src/resources/extensions/gsd/auto/workflow-worker-heartbeat.ts +14 -1
  313. package/src/resources/extensions/gsd/auto-direct-dispatch.ts +8 -34
  314. package/src/resources/extensions/gsd/auto-dispatch.ts +16 -0
  315. package/src/resources/extensions/gsd/auto-post-unit.ts +107 -78
  316. package/src/resources/extensions/gsd/auto-prompts.ts +95 -14
  317. package/src/resources/extensions/gsd/auto-start.ts +286 -15
  318. package/src/resources/extensions/gsd/auto-worktree.ts +241 -72
  319. package/src/resources/extensions/gsd/auto.ts +132 -40
  320. package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +116 -24
  321. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +45 -37
  322. package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +36 -10
  323. package/src/resources/extensions/gsd/bootstrap/exec-tools.ts +8 -3
  324. package/src/resources/extensions/gsd/bootstrap/journal-tools.ts +5 -1
  325. package/src/resources/extensions/gsd/bootstrap/memory-tools.ts +7 -4
  326. package/src/resources/extensions/gsd/bootstrap/query-tools.ts +6 -3
  327. package/src/resources/extensions/gsd/bootstrap/register-extension.ts +1 -1
  328. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +347 -54
  329. package/src/resources/extensions/gsd/bootstrap/sanitize-complete-milestone.ts +4 -0
  330. package/src/resources/extensions/gsd/bootstrap/system-context.ts +90 -22
  331. package/src/resources/extensions/gsd/clean-root-preflight.ts +32 -7
  332. package/src/resources/extensions/gsd/commands/handlers/ops.ts +4 -2
  333. package/src/resources/extensions/gsd/commands-config.ts +1 -1
  334. package/src/resources/extensions/gsd/commands-eval-review.ts +2 -2
  335. package/src/resources/extensions/gsd/commands-handlers.ts +34 -15
  336. package/src/resources/extensions/gsd/dashboard-overlay.ts +1 -1
  337. package/src/resources/extensions/gsd/db/unit-dispatches.ts +66 -0
  338. package/src/resources/extensions/gsd/ecosystem/gsd-extension-api.ts +3 -0
  339. package/src/resources/extensions/gsd/git-service.ts +41 -2
  340. package/src/resources/extensions/gsd/guided-flow.ts +71 -39
  341. package/src/resources/extensions/gsd/init-wizard.ts +5 -1
  342. package/src/resources/extensions/gsd/native-git-bridge.ts +39 -6
  343. package/src/resources/extensions/gsd/orphan-stash-audit.ts +117 -0
  344. package/src/resources/extensions/gsd/parallel-orchestrator.ts +13 -3
  345. package/src/resources/extensions/gsd/pre-execution-checks.ts +23 -0
  346. package/src/resources/extensions/gsd/prompts/complete-milestone.md +8 -4
  347. package/src/resources/extensions/gsd/prompts/complete-slice.md +1 -1
  348. package/src/resources/extensions/gsd/prompts/execute-task.md +4 -2
  349. package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  350. package/src/resources/extensions/gsd/prompts/replan-slice.md +2 -2
  351. package/src/resources/extensions/gsd/slice-cadence.ts +49 -2
  352. package/src/resources/extensions/gsd/slice-parallel-orchestrator.ts +23 -9
  353. package/src/resources/extensions/gsd/tests/agent-end-retry.test.ts +59 -89
  354. package/src/resources/extensions/gsd/tests/artifact-retry-cap.test.ts +47 -172
  355. package/src/resources/extensions/gsd/tests/artifacts-table-preserved-on-cache-invalidate.test.ts +0 -35
  356. package/src/resources/extensions/gsd/tests/auto-dashboard.test.ts +35 -9
  357. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +361 -10
  358. package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +80 -59
  359. package/src/resources/extensions/gsd/tests/auto-paused-session-validation.test.ts +3 -47
  360. package/src/resources/extensions/gsd/tests/auto-paused-ui-cleanup.test.ts +76 -18
  361. package/src/resources/extensions/gsd/tests/auto-phases-lifecycle.test.ts +106 -0
  362. package/src/resources/extensions/gsd/tests/auto-pr-bugs.test.ts +54 -95
  363. package/src/resources/extensions/gsd/tests/auto-project-root-env.test.ts +67 -26
  364. package/src/resources/extensions/gsd/tests/auto-remediate-slice-status.test.ts +32 -30
  365. package/src/resources/extensions/gsd/tests/auto-start-bootstrap-await-3420.test.ts +32 -128
  366. package/src/resources/extensions/gsd/tests/auto-start-clean-runtime-db-gated.test.ts +20 -54
  367. package/src/resources/extensions/gsd/tests/auto-start-cold-db-bootstrap.test.ts +20 -30
  368. package/src/resources/extensions/gsd/tests/auto-start-index-lock.test.ts +17 -29
  369. package/src/resources/extensions/gsd/tests/auto-start-orphan-bootstrap.test.ts +138 -0
  370. package/src/resources/extensions/gsd/tests/auto-start-time-persistence.test.ts +21 -39
  371. package/src/resources/extensions/gsd/tests/auto-start-worktree-db-path.test.ts +15 -24
  372. package/src/resources/extensions/gsd/tests/auto-thinking-restore.test.ts +44 -29
  373. package/src/resources/extensions/gsd/tests/auto-warning-noise-regression.test.ts +39 -51
  374. package/src/resources/extensions/gsd/tests/auto-wrapup-inflight-guard.test.ts +159 -213
  375. package/src/resources/extensions/gsd/tests/bootstrap-derive-state-db-open.test.ts +15 -32
  376. package/src/resources/extensions/gsd/tests/browser-teardown.test.ts +0 -41
  377. package/src/resources/extensions/gsd/tests/clean-root-preflight.test.ts +15 -6
  378. package/src/resources/extensions/gsd/tests/clear-stale-autostart.test.ts +34 -27
  379. package/src/resources/extensions/gsd/tests/cmux.test.ts +51 -53
  380. package/src/resources/extensions/gsd/tests/cold-resume-db-reopen.test.ts +39 -61
  381. package/src/resources/extensions/gsd/tests/commands-config.test.ts +26 -19
  382. package/src/resources/extensions/gsd/tests/complete-milestone-excerpt.test.ts +31 -0
  383. package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +140 -0
  384. package/src/resources/extensions/gsd/tests/complete-slice-composer.test.ts +3 -2
  385. package/src/resources/extensions/gsd/tests/complete-task-normalize-lists.test.ts +29 -33
  386. package/src/resources/extensions/gsd/tests/completed-units-metrics-sync.test.ts +45 -108
  387. package/src/resources/extensions/gsd/tests/context-store.test.ts +7 -1
  388. package/src/resources/extensions/gsd/tests/crash-handler-secondary.test.ts +35 -31
  389. package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +5 -1
  390. package/src/resources/extensions/gsd/tests/cwd-fallback-hardening.test.ts +138 -0
  391. package/src/resources/extensions/gsd/tests/dashboard-custom-engine.test.ts +4 -68
  392. package/src/resources/extensions/gsd/tests/deep-project-auto-loop.test.ts +4 -9
  393. package/src/resources/extensions/gsd/tests/deferred-milestone-dir-4996.test.ts +14 -65
  394. package/src/resources/extensions/gsd/tests/discuss-tool-scoping.test.ts +44 -37
  395. package/src/resources/extensions/gsd/tests/dispatch-complete-milestone-guard.test.ts +58 -40
  396. package/src/resources/extensions/gsd/tests/dispatch-guard-closed-status.test.ts +25 -15
  397. package/src/resources/extensions/gsd/tests/dispatcher-stuck-planning.test.ts +35 -17
  398. package/src/resources/extensions/gsd/tests/error-success-mask.test.ts +16 -21
  399. package/src/resources/extensions/gsd/tests/est-annotation-timeout.test.ts +15 -82
  400. package/src/resources/extensions/gsd/tests/execute-task-rendering.test.ts +5 -2
  401. package/src/resources/extensions/gsd/tests/fast-forward-reused-milestone-branch.test.ts +219 -0
  402. package/src/resources/extensions/gsd/tests/finalize-survivor-branch.test.ts +132 -0
  403. package/src/resources/extensions/gsd/tests/flat-rate-routing-guard.test.ts +2 -20
  404. package/src/resources/extensions/gsd/tests/frontmatter-parse-noise.test.ts +18 -26
  405. package/src/resources/extensions/gsd/tests/init-skip-git.test.ts +9 -12
  406. package/src/resources/extensions/gsd/tests/integration/auto-worktree-milestone-merge.test.ts +40 -0
  407. package/src/resources/extensions/gsd/tests/integration/commands-eval-review.integration.test.ts +4 -2
  408. package/src/resources/extensions/gsd/tests/integration/git-locale.test.ts +31 -20
  409. package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +12 -0
  410. package/src/resources/extensions/gsd/tests/integration/milestone-transition-worktree.test.ts +0 -47
  411. package/src/resources/extensions/gsd/tests/interactive-routing-bypass.test.ts +60 -202
  412. package/src/resources/extensions/gsd/tests/isolation-none-branch-guard.test.ts +13 -56
  413. package/src/resources/extensions/gsd/tests/journal-integration.test.ts +5 -1
  414. package/src/resources/extensions/gsd/tests/journal-query-tool.test.ts +32 -0
  415. package/src/resources/extensions/gsd/tests/knowledge.test.ts +47 -0
  416. package/src/resources/extensions/gsd/tests/lazy-pi-tui-import.test.ts +44 -6
  417. package/src/resources/extensions/gsd/tests/memory-pressure-stuck-state.test.ts +21 -35
  418. package/src/resources/extensions/gsd/tests/merge-conflict-stops-loop.test.ts +1 -0
  419. package/src/resources/extensions/gsd/tests/milestone-merge-stash-restore.test.ts +242 -0
  420. package/src/resources/extensions/gsd/tests/milestone-transition-state-rebuild.test.ts +79 -98
  421. package/src/resources/extensions/gsd/tests/model-unittype-mapping.test.ts +70 -278
  422. package/src/resources/extensions/gsd/tests/native-git-bridge-exec-fallback.test.ts +34 -2
  423. package/src/resources/extensions/gsd/tests/needs-remediation-revalidation.test.ts +37 -30
  424. package/src/resources/extensions/gsd/tests/note-captures-executed.test.ts +32 -28
  425. package/src/resources/extensions/gsd/tests/originalbase-path-comparison.test.ts +3 -0
  426. package/src/resources/extensions/gsd/tests/orphan-merge-bootstrap.test.ts +133 -0
  427. package/src/resources/extensions/gsd/tests/orphan-stash-audit.test.ts +201 -0
  428. package/src/resources/extensions/gsd/tests/parallel-orchestrator-fast-forward.test.ts +113 -0
  429. package/src/resources/extensions/gsd/tests/phantom-ghost-detection.test.ts +24 -37
  430. package/src/resources/extensions/gsd/tests/phantom-milestone-default-queued.test.ts +9 -24
  431. package/src/resources/extensions/gsd/tests/phases-merge-error-stops-auto.test.ts +91 -75
  432. package/src/resources/extensions/gsd/tests/post-unit-state-rebuild.test.ts +36 -22
  433. package/src/resources/extensions/gsd/tests/pre-exec-backtick-strip.test.ts +36 -30
  434. package/src/resources/extensions/gsd/tests/pre-execution-checks.test.ts +45 -5
  435. package/src/resources/extensions/gsd/tests/pre-execution-pause-wiring.test.ts +74 -4
  436. package/src/resources/extensions/gsd/tests/preferences-worktree-sync.test.ts +20 -22
  437. package/src/resources/extensions/gsd/tests/prefs-wizard-coverage.test.ts +130 -32
  438. package/src/resources/extensions/gsd/tests/project-root-cwd-crash.test.ts +18 -36
  439. package/src/resources/extensions/gsd/tests/projection-no-plan-overwrite.test.ts +35 -73
  440. package/src/resources/extensions/gsd/tests/prompt-budget-enforcement.test.ts +76 -138
  441. package/src/resources/extensions/gsd/tests/prompt-duplication-cuts.test.ts +230 -0
  442. package/src/resources/extensions/gsd/tests/prompt-step-ordering.test.ts +70 -125
  443. package/src/resources/extensions/gsd/tests/provider-errors.test.ts +59 -161
  444. package/src/resources/extensions/gsd/tests/query-tools-db-open.test.ts +33 -29
  445. package/src/resources/extensions/gsd/tests/queue-auto-guard.test.ts +22 -196
  446. package/src/resources/extensions/gsd/tests/quick-auto-guard.test.ts +23 -93
  447. package/src/resources/extensions/gsd/tests/quick-turn-end-cleanup.test.ts +50 -79
  448. package/src/resources/extensions/gsd/tests/reassess-default-optin.test.ts +27 -13
  449. package/src/resources/extensions/gsd/tests/remote-questions.test.ts +151 -251
  450. package/src/resources/extensions/gsd/tests/resource-loader-import-path.test.ts +41 -29
  451. package/src/resources/extensions/gsd/tests/restore-tools-after-discuss.test.ts +58 -69
  452. package/src/resources/extensions/gsd/tests/resume-dispatch-worktree.test.ts +32 -164
  453. package/src/resources/extensions/gsd/tests/run-uat-replay-cap.test.ts +57 -41
  454. package/src/resources/extensions/gsd/tests/select-resumable-milestone.test.ts +96 -0
  455. package/src/resources/extensions/gsd/tests/session-model-override.test.ts +14 -9
  456. package/src/resources/extensions/gsd/tests/session-start-footer.test.ts +77 -0
  457. package/src/resources/extensions/gsd/tests/session-switch-abort-misclassification.test.ts +166 -0
  458. package/src/resources/extensions/gsd/tests/show-config-command.test.ts +44 -42
  459. package/src/resources/extensions/gsd/tests/skip-slice-state-rebuild.test.ts +56 -24
  460. package/src/resources/extensions/gsd/tests/skipped-validation-db-atomicity.test.ts +51 -11
  461. package/src/resources/extensions/gsd/tests/slice-cadence.test.ts +23 -0
  462. package/src/resources/extensions/gsd/tests/slice-context-injection.test.ts +66 -50
  463. package/src/resources/extensions/gsd/tests/slice-parallel-orchestrator.test.ts +68 -107
  464. package/src/resources/extensions/gsd/tests/slice-sequence-insert.test.ts +115 -42
  465. package/src/resources/extensions/gsd/tests/smart-entry-complete.test.ts +21 -97
  466. package/src/resources/extensions/gsd/tests/smart-entry-draft.test.ts +25 -116
  467. package/src/resources/extensions/gsd/tests/sqlite-unavailable-gate.test.ts +21 -57
  468. package/src/resources/extensions/gsd/tests/stale-dirlistcache-4648.test.ts +29 -76
  469. package/src/resources/extensions/gsd/tests/stale-lockfile-recovery.test.ts +33 -24
  470. package/src/resources/extensions/gsd/tests/stale-slice-rows.test.ts +39 -30
  471. package/src/resources/extensions/gsd/tests/state-corruption-2945.test.ts +1 -0
  472. package/src/resources/extensions/gsd/tests/status-db-open.test.ts +33 -47
  473. package/src/resources/extensions/gsd/tests/stop-auto-merge-back.test.ts +48 -46
  474. package/src/resources/extensions/gsd/tests/stop-auto-race-null-unit.test.ts +14 -102
  475. package/src/resources/extensions/gsd/tests/subagent-model-dispatch.test.ts +78 -232
  476. package/src/resources/extensions/gsd/tests/sync-worktree-skip-current.test.ts +32 -35
  477. package/src/resources/extensions/gsd/tests/system-context-memory.test.ts +112 -0
  478. package/src/resources/extensions/gsd/tests/system-context-message-routing.test.ts +7 -9
  479. package/src/resources/extensions/gsd/tests/token-profile.test.ts +84 -309
  480. package/src/resources/extensions/gsd/tests/token-tool-gating.test.ts +291 -0
  481. package/src/resources/extensions/gsd/tests/triage-dispatch.test.ts +134 -341
  482. package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +8 -25
  483. package/src/resources/extensions/gsd/tests/unit-dispatches.test.ts +50 -1
  484. package/src/resources/extensions/gsd/tests/unstructured-continue-context-injection.test.ts +5 -99
  485. package/src/resources/extensions/gsd/tests/uok-plan-v2-wiring.test.ts +43 -36
  486. package/src/resources/extensions/gsd/tests/visualizer-data.test.ts +84 -444
  487. package/src/resources/extensions/gsd/tests/workflow-dispatch-claim.test.ts +142 -0
  488. package/src/resources/extensions/gsd/tests/workflow-logger-wiring.test.ts +44 -189
  489. package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +2 -57
  490. package/src/resources/extensions/gsd/tests/workflow-protocol-excerpt.test.ts +99 -0
  491. package/src/resources/extensions/gsd/tests/workflow-worker-heartbeat.test.ts +32 -1
  492. package/src/resources/extensions/gsd/tests/worktree-db-same-file.test.ts +21 -44
  493. package/src/resources/extensions/gsd/tests/worktree-expected-warnings.test.ts +27 -26
  494. package/src/resources/extensions/gsd/tests/worktree-health-dispatch.test.ts +14 -13
  495. package/src/resources/extensions/gsd/tests/worktree-journal-events.test.ts +1 -0
  496. package/src/resources/extensions/gsd/tests/worktree-main-branch.test.ts +20 -18
  497. package/src/resources/extensions/gsd/tests/worktree-path-injection.test.ts +22 -19
  498. package/src/resources/extensions/gsd/tests/worktree-project-root-degrade.test.ts +66 -0
  499. package/src/resources/extensions/gsd/tests/worktree-resolver.test.ts +140 -3
  500. package/src/resources/extensions/gsd/tests/zero-slice-roadmap-guided.test.ts +19 -13
  501. package/src/resources/extensions/gsd/tools/complete-milestone.ts +14 -15
  502. package/src/resources/extensions/gsd/tools/complete-task.ts +1 -1
  503. package/src/resources/extensions/gsd/workflow-protocol.ts +160 -0
  504. package/src/resources/extensions/gsd/worktree-resolver.ts +83 -5
  505. package/src/resources/skills/create-gsd-extension/templates/templates.test.ts +86 -40
  506. package/src/resources/skills/web-quality-audit/scripts/analyze.sh +0 -0
  507. package/dist/web/standalone/.next/static/chunks/8336.631939fb583761fa.js +0 -10
  508. /package/dist/web/standalone/.next/static/{tht0ltP8EIjsohPOA_WZf → G68KoLv5claox_Dyd4pZn}/_buildManifest.js +0 -0
  509. /package/dist/web/standalone/.next/static/{tht0ltP8EIjsohPOA_WZf → G68KoLv5claox_Dyd4pZn}/_ssgManifest.js +0 -0
@@ -1,38 +1,39 @@
1
- /**
2
- * worktree-expected-warnings.test.ts — #3665
3
- *
4
- * Verify that auto-worktree.ts and worktree-manager.ts suppress expected
5
- * ENOENT and EISDIR conditions instead of logging misleading warnings.
6
- */
1
+ // GSD-2 — Expected worktree condition warning suppression tests.
7
2
 
8
3
  import { describe, test } from "node:test";
9
4
  import assert from "node:assert/strict";
10
- import { readFileSync } from "node:fs";
11
- import { join, dirname } from "node:path";
12
- import { fileURLToPath } from "node:url";
5
+ import { mkdtempSync, mkdirSync, rmSync, writeFileSync } from "node:fs";
6
+ import { join, resolve } from "node:path";
7
+ import { tmpdir } from "node:os";
13
8
 
14
- const __dirname = dirname(fileURLToPath(import.meta.url));
15
- const autoWorktreeFile = join(__dirname, "..", "auto-worktree.ts");
16
- const worktreeManagerFile = join(__dirname, "..", "worktree-manager.ts");
9
+ import { _isExpectedWorktreeUnlinkErrorForTest } from "../auto-worktree.ts";
10
+ import { resolveGitDir } from "../worktree-manager.ts";
17
11
 
18
12
  describe("worktree expected-condition warning suppression (#3665)", () => {
19
- const autoSource = readFileSync(autoWorktreeFile, "utf-8");
20
-
21
- test("auto-worktree.ts checks for ENOENT before logging unlink warning", () => {
22
- assert.match(autoSource, /code\s*!==\s*["']ENOENT["']/);
23
- });
24
-
25
- test("auto-worktree.ts checks for EISDIR before logging unlink warning", () => {
26
- assert.match(autoSource, /code\s*!==\s*["']EISDIR["']/);
13
+ test("known unlink races are classified as expected", () => {
14
+ assert.equal(_isExpectedWorktreeUnlinkErrorForTest("ENOENT"), true);
15
+ assert.equal(_isExpectedWorktreeUnlinkErrorForTest("EISDIR"), true);
16
+ assert.equal(_isExpectedWorktreeUnlinkErrorForTest("EACCES"), false);
27
17
  });
28
18
 
29
- test("auto-worktree.ts references issue #3597", () => {
30
- assert.match(autoSource, /#3597/);
19
+ test("resolveGitDir returns .git directory without reading it as a file", () => {
20
+ const base = mkdtempSync(join(tmpdir(), "gsd-resolve-gitdir-"));
21
+ try {
22
+ mkdirSync(join(base, ".git"), { recursive: true });
23
+ assert.equal(resolveGitDir(base), join(base, ".git"));
24
+ } finally {
25
+ rmSync(base, { recursive: true, force: true });
26
+ }
31
27
  });
32
28
 
33
- const managerSource = readFileSync(worktreeManagerFile, "utf-8");
34
-
35
- test("worktree-manager.ts checks isDirectory() before reading .git file", () => {
36
- assert.match(managerSource, /lstatSync\(gitPath\)\.isDirectory\(\)/);
29
+ test("resolveGitDir resolves worktree .git file targets", () => {
30
+ const base = mkdtempSync(join(tmpdir(), "gsd-resolve-worktree-gitdir-"));
31
+ try {
32
+ mkdirSync(join(base, ".gitdir"), { recursive: true });
33
+ writeFileSync(join(base, ".git"), "gitdir: .gitdir\n");
34
+ assert.equal(resolveGitDir(base), resolve(base, ".gitdir"));
35
+ } finally {
36
+ rmSync(base, { recursive: true, force: true });
37
+ }
37
38
  });
38
39
  });
@@ -9,12 +9,13 @@
9
9
 
10
10
  import { describe, test, beforeEach, afterEach } from "node:test";
11
11
  import assert from "node:assert/strict";
12
- import { existsSync, mkdtempSync, mkdirSync, readFileSync, writeFileSync, rmSync, readdirSync } from "node:fs";
12
+ import { existsSync, mkdtempSync, mkdirSync, writeFileSync, rmSync, readdirSync } from "node:fs";
13
13
  import { join } from "node:path";
14
14
  import { tmpdir } from "node:os";
15
15
  import { execSync } from "node:child_process";
16
16
 
17
17
  import { PROJECT_FILES, classifyProject } from "../detection.js";
18
+ import { _shouldProceedWithInvalidRepoClassificationForTest } from "../auto/phases.ts";
18
19
 
19
20
  // ─── Helpers ─────────────────────────────────────────────────────────────────
20
21
 
@@ -86,19 +87,19 @@ test("PROJECT_FILES is exported and contains expected multi-ecosystem entries",
86
87
  assert.ok(PROJECT_FILES.includes("Package.swift"), "includes Swift marker");
87
88
  });
88
89
 
89
- test("runUnitPhase fails closed when classification returns invalid-repo", () => {
90
- const source = readFileSync(join(process.cwd(), "src/resources/extensions/gsd/auto/phases.ts"), "utf-8");
91
- const invalidRepoBranch = source.slice(
92
- source.indexOf('projectClassification.kind === "invalid-repo"'),
93
- source.indexOf('projectClassification.kind === "greenfield"'),
90
+ test("invalid-repo classification only proceeds when the git marker was already confirmed", () => {
91
+ assert.equal(
92
+ _shouldProceedWithInvalidRepoClassificationForTest("missing .git", true),
93
+ true,
94
+ );
95
+ assert.equal(
96
+ _shouldProceedWithInvalidRepoClassificationForTest("missing .git", false),
97
+ false,
98
+ );
99
+ assert.equal(
100
+ _shouldProceedWithInvalidRepoClassificationForTest("permission denied", true),
101
+ false,
94
102
  );
95
-
96
- assert.match(invalidRepoBranch, /projectClassification\.reason === "missing \.git" && hasGit/);
97
- assert.match(invalidRepoBranch, /project classification could not confirm \.git/);
98
- assert.match(invalidRepoBranch, /ctx\.ui\.notify\(msg,\s*"error"\)/);
99
- assert.match(invalidRepoBranch, /await deps\.stopAuto\(ctx,\s*pi,\s*msg\)/);
100
- assert.match(invalidRepoBranch, /return \{ action: "break", reason: "worktree-invalid" \}/);
101
- assert.match(invalidRepoBranch, /classified as invalid-repo/);
102
103
  });
103
104
 
104
105
  describe("health check with git repo", () => {
@@ -39,6 +39,7 @@ function makeDeps(
39
39
  getAutoWorktreePath: () => null,
40
40
  autoCommitCurrentBranch: () => {},
41
41
  getCurrentBranch: () => "main",
42
+ checkoutBranch: () => {},
42
43
  autoWorktreeBranch: (milestoneId: string) => `milestone/${milestoneId}`,
43
44
  resolveMilestoneFile: (_basePath: string, milestoneId: string) =>
44
45
  `/project/.gsd/milestones/${milestoneId}/${milestoneId}-ROADMAP.md`,
@@ -1,25 +1,27 @@
1
- /**
2
- * Regression test for #3461: createAutoWorktree must use git.main_branch
3
- * preference when META.json integration branch is absent.
4
- */
1
+ // GSD-2 — Auto-worktree main branch preference regression tests.
2
+
5
3
  import { test } from "node:test";
6
4
  import assert from "node:assert/strict";
7
- import { readFileSync } from "node:fs";
8
- import { join } from "node:path";
9
5
 
10
- test("auto-worktree.ts includes main_branch preference in startPoint fallback (#3461)", () => {
11
- const src = readFileSync(
12
- join(import.meta.dirname, "..", "auto-worktree.ts"),
13
- "utf-8",
6
+ import { _resolveAutoWorktreeStartPointForTest } from "../auto-worktree.ts";
7
+
8
+ test("auto-worktree start point prefers milestone integration branch", () => {
9
+ const startPoint = _resolveAutoWorktreeStartPointForTest(
10
+ "release/integration",
11
+ "dev",
12
+ () => true,
14
13
  );
15
- // The fix adds gitPrefs?.main_branch to the startPoint fallback chain
16
- assert.ok(
17
- src.includes("gitPrefs?.main_branch") || src.includes("prefs.main_branch"),
18
- "createAutoWorktree must check git.main_branch preference before falling back to nativeDetectMainBranch",
14
+
15
+ assert.equal(startPoint, "release/integration");
16
+ });
17
+
18
+ test("auto-worktree start point uses git.main_branch only when it exists", () => {
19
+ assert.equal(
20
+ _resolveAutoWorktreeStartPointForTest(null, "dev", (branch) => branch === "dev"),
21
+ "dev",
19
22
  );
20
- assert.match(
21
- src,
22
- /nativeBranchExists\(basePath,\s*gitPrefs\.main_branch\)/,
23
- "createAutoWorktree must validate git.main_branch exists before using it",
23
+ assert.equal(
24
+ _resolveAutoWorktreeStartPointForTest(null, "stale", () => false),
25
+ undefined,
24
26
  );
25
27
  });
@@ -79,7 +79,7 @@ async function waitFor(condition: () => boolean, label: string): Promise<void> {
79
79
  assert.fail(`Timed out waiting for ${label} after ${timeoutMs}ms`);
80
80
  }
81
81
 
82
- test("runUnit changes cwd to basePath before creating a new session", async (t) => {
82
+ test("runUnit passes basePath as workspaceRoot without changing process cwd", async (t) => {
83
83
  _resetPendingResolve();
84
84
 
85
85
  const originalCwd = process.cwd();
@@ -93,13 +93,15 @@ test("runUnit changes cwd to basePath before creating a new session", async (t)
93
93
 
94
94
  process.chdir(drifted);
95
95
 
96
+ let newSessionWorkspaceRoot: string | undefined;
96
97
  let cwdAtNewSession: string | undefined;
97
98
  const session = {
98
99
  active: true,
99
100
  basePath: base,
100
101
  verbose: false,
101
102
  cmdCtx: {
102
- newSession: () => {
103
+ newSession: (options?: { workspaceRoot?: string }) => {
104
+ newSessionWorkspaceRoot = options?.workspaceRoot;
103
105
  cwdAtNewSession = process.cwd();
104
106
  return Promise.resolve({ cancelled: false });
105
107
  },
@@ -119,10 +121,12 @@ test("runUnit changes cwd to basePath before creating a new session", async (t)
119
121
 
120
122
  const result = await resultPromise;
121
123
  assert.equal(result.status, "completed");
122
- assert.equal(cwdAtNewSession, base);
124
+ assert.equal(newSessionWorkspaceRoot, base);
125
+ assert.equal(cwdAtNewSession, drifted);
126
+ assert.equal(process.cwd(), drifted);
123
127
  });
124
128
 
125
- test("runUnit cancels before creating a session when basePath chdir fails", async (t) => {
129
+ test("runUnit does not chdir or cancel when basePath is not a live directory", async (t) => {
126
130
  _resetPendingResolve();
127
131
 
128
132
  const originalCwd = process.cwd();
@@ -136,14 +140,14 @@ test("runUnit cancels before creating a session when basePath chdir fails", asyn
136
140
 
137
141
  process.chdir(drifted);
138
142
 
139
- let newSessionCalled = false;
143
+ let newSessionWorkspaceRoot: string | undefined;
140
144
  const session = {
141
145
  active: true,
142
146
  basePath: base,
143
147
  verbose: false,
144
148
  cmdCtx: {
145
- newSession: () => {
146
- newSessionCalled = true;
149
+ newSession: (options?: { workspaceRoot?: string }) => {
150
+ newSessionWorkspaceRoot = options?.workspaceRoot;
147
151
  return Promise.resolve({ cancelled: false });
148
152
  },
149
153
  },
@@ -156,15 +160,14 @@ test("runUnit cancels before creating a session when basePath chdir fails", asyn
156
160
  } as any;
157
161
  const ctx = { ui: { notify: () => {} }, model: { id: "test-model" } } as any;
158
162
 
159
- const result = await runUnit(ctx, pi, session, "task", "T01", "prompt");
163
+ const resultPromise = runUnit(ctx, pi, session, "task", "T01", "prompt");
164
+ await waitFor(() => pi.calls.length === 1, "runUnit dispatch");
165
+ resolveAgentEnd({ messages: [{ role: "assistant" }] });
160
166
 
161
- assert.equal(result.status, "cancelled");
162
- assert.equal(result.errorContext?.category, "session-failed");
163
- assert.equal(result.errorContext?.isTransient, true);
164
- assert.match(result.errorContext?.message ?? "", /Failed to chdir to basePath before newSession/);
165
- assert.ok(result.errorContext?.message.includes(base), "error should include the failed basePath");
166
- assert.equal(newSessionCalled, false, "newSession must not run after chdir failure");
167
- assert.equal(pi.calls.length, 0, "unit must not dispatch after chdir failure");
167
+ const result = await resultPromise;
168
+ assert.equal(result.status, "completed");
169
+ assert.equal(newSessionWorkspaceRoot, base);
170
+ assert.equal(process.cwd(), drifted);
168
171
  });
169
172
 
170
173
  test("direct dispatch redirects to the canonical milestone worktree before newSession", async (t) => {
@@ -185,12 +188,12 @@ test("direct dispatch redirects to the canonical milestone worktree before newSe
185
188
 
186
189
  process.chdir(drifted);
187
190
 
188
- let cwdAtNewSession: string | undefined;
191
+ let newSessionWorkspaceRoot: string | undefined;
189
192
  let sentPrompt: string | undefined;
190
193
  const ctx = {
191
194
  ui: { notify: () => {} },
192
- newSession: async () => {
193
- cwdAtNewSession = process.cwd();
195
+ newSession: async (options?: { workspaceRoot?: string }) => {
196
+ newSessionWorkspaceRoot = options?.workspaceRoot;
194
197
  return { cancelled: false };
195
198
  },
196
199
  } as any;
@@ -202,7 +205,7 @@ test("direct dispatch redirects to the canonical milestone worktree before newSe
202
205
 
203
206
  await dispatchDirectPhase(ctx, pi, "research-milestone", base);
204
207
 
205
- assert.equal(cwdAtNewSession, worktreeRoot);
208
+ assert.equal(newSessionWorkspaceRoot, worktreeRoot);
206
209
  assert.equal(process.cwd(), drifted);
207
210
  assert.ok(sentPrompt?.includes(worktreeRoot), "prompt should name the canonical worktree root");
208
211
  });
@@ -0,0 +1,66 @@
1
+ // GSD-2 + Worktree dispatch guard: degrade empty worktrees over real project roots.
2
+
3
+ import { describe, test } from "node:test";
4
+ import assert from "node:assert/strict";
5
+
6
+ import { shouldDegradeEmptyWorktreeToProjectRoot } from "../auto/phases.ts";
7
+ import type { ProjectClassification } from "../detection.ts";
8
+
9
+ function classification(kind: ProjectClassification["kind"]): ProjectClassification {
10
+ return {
11
+ kind,
12
+ signals: {
13
+ detectedFiles: [],
14
+ isGitRepo: true,
15
+ isMonorepo: false,
16
+ xcodePlatforms: [],
17
+ hasCI: false,
18
+ hasTests: false,
19
+ verificationCommands: [],
20
+ },
21
+ trackedFiles: [],
22
+ untrackedFiles: [],
23
+ contentFiles: [],
24
+ markers: [],
25
+ reason: kind,
26
+ };
27
+ }
28
+
29
+ describe("worktree project-root degradation", () => {
30
+ test("degrades when worktree is greenfield but project root has content", () => {
31
+ assert.equal(
32
+ shouldDegradeEmptyWorktreeToProjectRoot(
33
+ classification("greenfield"),
34
+ classification("typed-existing"),
35
+ ),
36
+ true,
37
+ );
38
+ assert.equal(
39
+ shouldDegradeEmptyWorktreeToProjectRoot(
40
+ classification("greenfield"),
41
+ classification("untyped-existing"),
42
+ ),
43
+ true,
44
+ );
45
+ });
46
+
47
+ test("keeps true greenfield worktrees in worktree mode", () => {
48
+ assert.equal(
49
+ shouldDegradeEmptyWorktreeToProjectRoot(
50
+ classification("greenfield"),
51
+ classification("greenfield"),
52
+ ),
53
+ false,
54
+ );
55
+ });
56
+
57
+ test("does not degrade when project root classification is invalid", () => {
58
+ assert.equal(
59
+ shouldDegradeEmptyWorktreeToProjectRoot(
60
+ classification("greenfield"),
61
+ classification("invalid-repo"),
62
+ ),
63
+ false,
64
+ );
65
+ });
66
+ });
@@ -118,6 +118,9 @@ function makeDeps(
118
118
  calls.push({ fn: "getCurrentBranch", args: [basePath] });
119
119
  return "main";
120
120
  },
121
+ checkoutBranch: (basePath: string, branch: string) => {
122
+ calls.push({ fn: "checkoutBranch", args: [basePath, branch] });
123
+ },
121
124
  autoWorktreeBranch: (milestoneId: string) => {
122
125
  calls.push({ fn: "autoWorktreeBranch", args: [milestoneId] });
123
126
  return `milestone/${milestoneId}`;
@@ -526,6 +529,42 @@ test("exitMilestone commits, tears down, and resets basePath", () => {
526
529
  assert.equal(findCalls(deps.calls, "invalidateAllCaches").length, 1);
527
530
  });
528
531
 
532
+ test("exitMilestone moves cwd to project root before teardown", (t) => {
533
+ const originalCwd = process.cwd();
534
+ const base = realpathSync(mkdtempSync(join(tmpdir(), "gsd-exit-cwd-")));
535
+ const wtPath = join(base, ".gsd", "worktrees", "M001");
536
+ mkdirSync(wtPath, { recursive: true });
537
+ t.after(() => {
538
+ process.chdir(originalCwd);
539
+ rmSync(base, { recursive: true, force: true });
540
+ });
541
+
542
+ process.chdir(wtPath);
543
+ const s = makeSession({
544
+ basePath: wtPath,
545
+ originalBasePath: base,
546
+ });
547
+ const deps = makeDeps({
548
+ isInAutoWorktree: () => true,
549
+ });
550
+ deps.teardownAutoWorktree = (
551
+ teardownBasePath: string,
552
+ milestoneId: string,
553
+ opts?: { preserveBranch?: boolean },
554
+ ) => {
555
+ deps.calls.push({ fn: "teardownAutoWorktree", args: [teardownBasePath, milestoneId, opts] });
556
+ assert.equal(process.cwd(), base);
557
+ rmSync(wtPath, { recursive: true, force: true });
558
+ };
559
+ const ctx = makeNotifyCtx();
560
+ const resolver = new WorktreeResolver(s, deps);
561
+
562
+ resolver.exitMilestone("M001", ctx);
563
+
564
+ assert.equal(process.cwd(), base);
565
+ assert.equal(s.basePath, base);
566
+ });
567
+
529
568
  test("exitMilestone is no-op when not in worktree", () => {
530
569
  const s = makeSession();
531
570
  const deps = makeDeps({
@@ -802,21 +841,92 @@ test("mergeAndExit in branch mode merges when on milestone branch", () => {
802
841
  assert.ok(ctx.messages.some((m) => m.msg.includes("branch mode")));
803
842
  });
804
843
 
805
- test("mergeAndExit in branch mode skips when not on milestone branch", () => {
844
+ test("mergeAndExit in branch mode checks out the milestone branch and merges (#5538-followup)", () => {
845
+ // Regression: previously this case silently returned without merging,
846
+ // stranding the milestone's commits on the branch (the test12345 repro).
847
+ // The fix forces a checkout first; merge proceeds when checkout succeeds.
806
848
  const s = makeSession({ basePath: "/project", originalBasePath: "/project" });
849
+ let currentBranch = "main";
850
+ const checkoutInvocations: Array<{ basePath: string; branch: string }> = [];
807
851
  const deps = makeDeps({
808
852
  isInAutoWorktree: () => false,
809
853
  getIsolationMode: () => "branch",
810
- getCurrentBranch: () => "main",
854
+ getCurrentBranch: () => currentBranch,
811
855
  autoWorktreeBranch: () => "milestone/M001",
856
+ checkoutBranch: (basePath: string, branch: string) => {
857
+ checkoutInvocations.push({ basePath, branch });
858
+ currentBranch = branch;
859
+ },
812
860
  });
813
861
  const ctx = makeNotifyCtx();
814
862
  const resolver = new WorktreeResolver(s, deps);
815
863
 
816
864
  resolver.mergeAndExit("M001", ctx);
817
865
 
866
+ assert.equal(checkoutInvocations.length, 1, "must attempt checkout when on wrong branch");
867
+ assert.deepEqual(checkoutInvocations[0], { basePath: "/project", branch: "milestone/M001" });
868
+ assert.equal(findCalls(deps.calls, "mergeMilestoneToMain").length, 1);
869
+ });
870
+
871
+ test("mergeAndExit in branch mode throws when checkout fails", () => {
872
+ // Regression for the silent-skip bug: if the working tree is on the wrong
873
+ // branch and checkout fails, we must throw so the caller pauses auto-mode
874
+ // — never silently advance with the milestone unmerged.
875
+ const s = makeSession({ basePath: "/project", originalBasePath: "/project" });
876
+ const deps = makeDeps({
877
+ isInAutoWorktree: () => false,
878
+ getIsolationMode: () => "branch",
879
+ getCurrentBranch: () => "main",
880
+ autoWorktreeBranch: () => "milestone/M001",
881
+ checkoutBranch: () => {
882
+ throw new Error("dirty working tree blocks checkout");
883
+ },
884
+ });
885
+ const ctx = makeNotifyCtx();
886
+ const resolver = new WorktreeResolver(s, deps);
887
+
888
+ assert.throws(
889
+ () => resolver.mergeAndExit("M001", ctx),
890
+ /dirty working tree blocks checkout/,
891
+ );
892
+ assert.equal(
893
+ findCalls(deps.calls, "mergeMilestoneToMain").length,
894
+ 0,
895
+ "merge must not run when checkout failed",
896
+ );
897
+ const errorNotify = ctx.messages.find((m) => m.level === "error");
898
+ assert.ok(errorNotify, "an error notification must be emitted");
899
+ assert.match(errorNotify!.msg, /milestone\/M001 failed/);
900
+ assert.match(errorNotify!.msg, /Resolve manually/);
901
+ assert.equal(
902
+ ctx.messages.some((m) => m.level === "warning" && m.msg.includes("Milestone merge failed")),
903
+ false,
904
+ "checkout failures with explicit recovery guidance must not emit a duplicate warning",
905
+ );
906
+ });
907
+
908
+ test("mergeAndExit in branch mode throws when checkout reports success but HEAD is still wrong", () => {
909
+ // Defense in depth: even if checkoutBranch returns without throwing, we
910
+ // re-verify and throw if HEAD didn't actually move. Prevents merging on
911
+ // top of the wrong branch on platforms where the checkout is a no-op.
912
+ const s = makeSession({ basePath: "/project", originalBasePath: "/project" });
913
+ const deps = makeDeps({
914
+ isInAutoWorktree: () => false,
915
+ getIsolationMode: () => "branch",
916
+ getCurrentBranch: () => "main", // never changes — simulates no-op checkout
917
+ autoWorktreeBranch: () => "milestone/M001",
918
+ checkoutBranch: () => {
919
+ // Pretend success — but getCurrentBranch will still return "main".
920
+ },
921
+ });
922
+ const ctx = makeNotifyCtx();
923
+ const resolver = new WorktreeResolver(s, deps);
924
+
925
+ assert.throws(
926
+ () => resolver.mergeAndExit("M001", ctx),
927
+ /reported success but current branch is main/,
928
+ );
818
929
  assert.equal(findCalls(deps.calls, "mergeMilestoneToMain").length, 0);
819
- assert.equal(ctx.messages.length, 0);
820
930
  });
821
931
 
822
932
  test("mergeAndExit in branch mode handles merge failure gracefully", () => {
@@ -1039,6 +1149,33 @@ test("mergeAndEnterNext enters next milestone even if merge fails", () => {
1039
1149
  );
1040
1150
  });
1041
1151
 
1152
+ test("mergeAndEnterNext halts after branch-mode user-notified checkout failure", () => {
1153
+ const s = makeSession({ basePath: "/project", originalBasePath: "/project" });
1154
+ const deps = makeDeps({
1155
+ isInAutoWorktree: () => false,
1156
+ getIsolationMode: () => "branch",
1157
+ getCurrentBranch: () => "main",
1158
+ autoWorktreeBranch: () => "milestone/M001",
1159
+ checkoutBranch: () => {
1160
+ throw new Error("dirty working tree blocks checkout");
1161
+ },
1162
+ });
1163
+ const ctx = makeNotifyCtx();
1164
+ const resolver = new WorktreeResolver(s, deps);
1165
+
1166
+ assert.throws(
1167
+ () => resolver.mergeAndEnterNext("M001", "M002", ctx),
1168
+ /dirty working tree blocks checkout/,
1169
+ );
1170
+ assert.equal(
1171
+ findCalls(deps.calls, "enterBranchModeForMilestone").length,
1172
+ 0,
1173
+ "must not enter the next milestone after a user-notified branch-mode failure",
1174
+ );
1175
+ assert.equal(findCalls(deps.calls, "mergeMilestoneToMain").length, 0);
1176
+ assert.ok(ctx.messages.some((m) => m.level === "error" && m.msg.includes("Resolve manually")));
1177
+ });
1178
+
1042
1179
  // ─── GitService Rebuild Atomicity ────────────────────────────────────────────
1043
1180
 
1044
1181
  test("GitService is rebuilt with the NEW basePath after enterMilestone", () => {
@@ -1,19 +1,25 @@
1
- /**
2
- * Regression test for #3441: guided flow must treat a roadmap with zero
3
- * parseable slices the same as no roadmap — offer "Create roadmap" not "Go auto".
4
- */
1
+ // GSD-2 — Guided roadmap slice detection regression tests.
2
+
5
3
  import { test } from "node:test";
6
4
  import assert from "node:assert/strict";
7
- import { readFileSync } from "node:fs";
8
- import { join } from "node:path";
9
5
 
10
- test("guided-flow checks roadmap slice count before offering auto (#3441)", () => {
11
- const src = readFileSync(
12
- join(import.meta.dirname, "..", "guided-flow.ts"),
13
- "utf-8",
6
+ import { _roadmapHasParseableSlicesForTest } from "../guided-flow.ts";
7
+
8
+ test("guided flow treats placeholder roadmaps with zero slices as not runnable", () => {
9
+ assert.equal(
10
+ _roadmapHasParseableSlicesForTest("# M001 Roadmap\n\nPlanning notes only.\n"),
11
+ false,
14
12
  );
15
- assert.ok(
16
- src.includes("roadmapHasSlices") || src.includes("parseRoadmapSlices"),
17
- "Guided flow must parse roadmap for slices before deciding which options to show",
13
+ });
14
+
15
+ test("guided flow accepts roadmaps with parseable slices", () => {
16
+ assert.equal(
17
+ _roadmapHasParseableSlicesForTest([
18
+ "# M001 Roadmap",
19
+ "",
20
+ "## Slices",
21
+ "- [ ] **S01: First slice** `risk:low` `depends:[]`",
22
+ ].join("\n")),
23
+ true,
18
24
  );
19
25
  });
@@ -32,21 +32,21 @@ export interface CompleteMilestoneParams {
32
32
  oneLiner: string;
33
33
  narrative: string;
34
34
  verificationPassed: boolean;
35
- /** @optional — defaults to "Not provided." when omitted by models with limited tool-calling */
35
+ /** @optional — empty/omitted renders as "Not provided." */
36
36
  successCriteriaResults?: string;
37
- /** @optional — defaults to "Not provided." when omitted */
37
+ /** @optional — empty/omitted renders as "Not provided." */
38
38
  definitionOfDoneResults?: string;
39
- /** @optional — defaults to "Not provided." when omitted */
39
+ /** @optional — empty/omitted renders as "Not provided." */
40
40
  requirementOutcomes?: string;
41
- /** @optional — defaults to [] when omitted */
41
+ /** @optional — empty/omitted renders as "(none)" */
42
42
  keyDecisions?: string[];
43
- /** @optional — defaults to [] when omitted */
43
+ /** @optional — empty/omitted renders as "(none)" */
44
44
  keyFiles?: string[];
45
- /** @optional — defaults to [] when omitted */
45
+ /** @optional — empty/omitted renders as "(none)" */
46
46
  lessonsLearned?: string[];
47
- /** @optional — defaults to "None." when omitted */
47
+ /** @optional — empty/omitted renders as "None." */
48
48
  followUps?: string;
49
- /** @optional — defaults to "None." when omitted */
49
+ /** @optional — empty/omitted renders as "None." */
50
50
  deviations?: string;
51
51
  /** Optional caller-provided identity for audit trail */
52
52
  actorName?: string;
@@ -61,8 +61,7 @@ export interface CompleteMilestoneResult {
61
61
  alreadyComplete?: boolean;
62
62
  }
63
63
 
64
- function renderMilestoneSummaryMarkdown(params: CompleteMilestoneParams): string {
65
- const now = new Date().toISOString();
64
+ function renderMilestoneSummaryMarkdown(params: CompleteMilestoneParams, completedAt: string): string {
66
65
  const displayTitle = stripIdPrefix(params.title, params.milestoneId);
67
66
 
68
67
  // Apply defaults for optional enrichment fields (#2771)
@@ -86,7 +85,7 @@ function renderMilestoneSummaryMarkdown(params: CompleteMilestoneParams): string
86
85
  id: ${params.milestoneId}
87
86
  title: "${displayTitle}"
88
87
  status: complete
89
- completed_at: ${now}
88
+ completed_at: ${completedAt}
90
89
  key_decisions:
91
90
  ${keyDecisionsYaml}
92
91
  key_files:
@@ -105,15 +104,15 @@ ${params.narrative}
105
104
 
106
105
  ## Success Criteria Results
107
106
 
108
- ${params.successCriteriaResults ?? "Not provided."}
107
+ ${params.successCriteriaResults || "Not provided."}
109
108
 
110
109
  ## Definition of Done Results
111
110
 
112
- ${params.definitionOfDoneResults ?? "Not provided."}
111
+ ${params.definitionOfDoneResults || "Not provided."}
113
112
 
114
113
  ## Requirement Outcomes
115
114
 
116
- ${params.requirementOutcomes ?? "Not provided."}
115
+ ${params.requirementOutcomes || "Not provided."}
117
116
 
118
117
  ## Deviations
119
118
 
@@ -193,7 +192,7 @@ export async function handleCompleteMilestone(
193
192
  }
194
193
 
195
194
  // ── Filesystem operations (outside transaction) ─────────────────────────
196
- const summaryMd = renderMilestoneSummaryMarkdown(params);
195
+ const summaryMd = renderMilestoneSummaryMarkdown(params, completedAt);
197
196
 
198
197
  let summaryPath: string;
199
198
  const milestoneDir = resolveMilestonePath(basePath, params.milestoneId);
@@ -85,7 +85,7 @@ function taskGateFieldForId(
85
85
  * Normalize a list parameter that may arrive as a string (newline-delimited
86
86
  * bullet list from the LLM) into a string array (#3361).
87
87
  */
88
- function normalizeListParam(value: unknown): string[] {
88
+ export function normalizeListParam(value: unknown): string[] {
89
89
  if (Array.isArray(value)) return value.map(String);
90
90
  if (typeof value === "string" && value.trim()) {
91
91
  return value.split(/\n/).map(s => s.replace(/^[\s\-*•]+/, "").trim()).filter(Boolean);