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,20 +1,20 @@
1
- /**
2
- * Structural tests for slice-level parallel orchestrator.
3
- * Verifies the orchestrator module exists and has the correct shape,
4
- * env var usage, and preference gating.
5
- */
1
+ // GSD-2 — Slice parallel orchestrator behavior tests.
6
2
 
7
3
  import { describe, it } from "node:test";
8
4
  import assert from "node:assert/strict";
9
5
  import { execFileSync, spawn } from "node:child_process";
10
6
  import { existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
11
- import { join, dirname } from "node:path";
7
+ import { join } from "node:path";
12
8
  import { tmpdir } from "node:os";
13
- import { fileURLToPath } from "node:url";
14
- import { restoreSliceState, SLICE_WORKER_AUTO_ARGS } from "../slice-parallel-orchestrator.ts";
15
9
 
16
- const __dirname = dirname(fileURLToPath(import.meta.url));
17
- const gsdDir = join(__dirname, "..");
10
+ import { deriveState } from "../state.js";
11
+ import { validatePreferences } from "../preferences-validation.ts";
12
+ import {
13
+ _buildSliceWorkerEnvForTest,
14
+ _resolveSliceParallelMaxWorkersForTest,
15
+ restoreSliceState,
16
+ SLICE_WORKER_AUTO_ARGS,
17
+ } from "../slice-parallel-orchestrator.ts";
18
18
 
19
19
  function readLinuxProcessStartFingerprint(pid: number): string | null {
20
20
  try {
@@ -83,81 +83,31 @@ function writeSliceOrchestratorState(
83
83
  );
84
84
  }
85
85
 
86
- describe("slice-parallel-orchestrator structural tests", () => {
87
- it("orchestrator uses GSD_SLICE_LOCK env var", () => {
88
- const source = readFileSync(join(gsdDir, "slice-parallel-orchestrator.ts"), "utf-8");
89
- assert.ok(
90
- source.includes("GSD_SLICE_LOCK"),
91
- "Orchestrator must use GSD_SLICE_LOCK env var to isolate slice workers",
92
- );
93
- });
94
-
95
- it("orchestrator sets GSD_PARALLEL_WORKER=1 to prevent nesting", () => {
96
- const source = readFileSync(join(gsdDir, "slice-parallel-orchestrator.ts"), "utf-8");
97
- assert.ok(
98
- source.includes("GSD_PARALLEL_WORKER"),
99
- "Orchestrator must set GSD_PARALLEL_WORKER to prevent nested parallel",
100
- );
101
- });
102
-
103
- it("slice workers use headless auto instead of print-mode slash commands", () => {
104
- const args: readonly string[] = SLICE_WORKER_AUTO_ARGS;
105
- assert.deepEqual([...args], ["headless", "--json", "auto"]);
106
- assert.equal(args.includes("--print"), false);
107
- });
108
-
109
- it("maxWorkers default is 2", () => {
110
- const source = readFileSync(join(gsdDir, "slice-parallel-orchestrator.ts"), "utf-8");
111
- // Check that default max workers is 2 (in opts.maxWorkers ?? 2 or similar)
112
- assert.ok(
113
- source.includes("maxWorkers") && source.includes("2"),
114
- "Default maxWorkers should be 2",
115
- );
116
- });
117
-
118
- it("orchestrator imports GSD_MILESTONE_LOCK for milestone isolation", () => {
119
- const source = readFileSync(join(gsdDir, "slice-parallel-orchestrator.ts"), "utf-8");
120
- assert.ok(
121
- source.includes("GSD_MILESTONE_LOCK"),
122
- "Orchestrator must also pass GSD_MILESTONE_LOCK for milestone context",
123
- );
86
+ describe("slice worker launch contract", () => {
87
+ it("uses headless auto instead of print-mode slash commands", () => {
88
+ assert.deepEqual([...SLICE_WORKER_AUTO_ARGS], ["headless", "--json", "auto"]);
89
+ assert.equal(SLICE_WORKER_AUTO_ARGS.includes("--print" as never), false);
124
90
  });
125
91
 
126
- it("recovery preserves terminal workers for coordinator-side collection", () => {
127
- const source = readFileSync(join(gsdDir, "slice-parallel-orchestrator.ts"), "utf-8");
128
- assert.ok(
129
- source.includes('} else if (w.state === "running")') &&
130
- source.includes("survivors.push(w);"),
131
- "Recovery must only prune dead running workers, not stopped/error workers",
92
+ it("builds isolated worker environment", () => {
93
+ const env = _buildSliceWorkerEnvForTest(
94
+ "/repo",
95
+ "M001",
96
+ "S02",
97
+ "worker-token",
98
+ { PATH: "/bin" } as NodeJS.ProcessEnv,
132
99
  );
133
- });
134
100
 
135
- it("recovered PID-only workers are validated before signaling", () => {
136
- const source = readFileSync(join(gsdDir, "slice-parallel-orchestrator.ts"), "utf-8");
137
- assert.ok(
138
- source.includes("isRecoveredSliceWorkerAlive(worker)") &&
139
- source.includes('process.kill(worker.pid, "SIGTERM")'),
140
- "stopSliceParallel must validate recovered worker identity before signaling a PID",
141
- );
101
+ assert.equal(env.GSD_SLICE_LOCK, "S02");
102
+ assert.equal(env.GSD_MILESTONE_LOCK, "M001");
103
+ assert.equal(env.GSD_PROJECT_ROOT, "/repo");
104
+ assert.equal(env.GSD_PARALLEL_WORKER, "1");
105
+ assert.equal(env.GSD_SLICE_WORKER_TOKEN, "worker-token");
142
106
  });
143
107
 
144
- it("persists worker identity for crash recovery", () => {
145
- const source = readFileSync(join(gsdDir, "slice-parallel-orchestrator.ts"), "utf-8");
146
- assert.ok(
147
- source.includes("workerToken") &&
148
- source.includes("processStartFingerprint") &&
149
- source.includes("GSD_SLICE_WORKER_TOKEN"),
150
- "Orchestrator must persist stable worker identity metadata for recovered workers",
151
- );
152
- });
153
-
154
- it("spawn failures remove stale worker state and worktree", () => {
155
- const source = readFileSync(join(gsdDir, "slice-parallel-orchestrator.ts"), "utf-8");
156
- assert.ok(
157
- source.includes("sliceState.workers.delete(slice.id)") &&
158
- source.includes("removeWorktree(basePath, wtName, { deleteBranch: true, force: true })"),
159
- "Failed slice worker spawns must remove stale worker state and clean up the worktree",
160
- );
108
+ it("defaults to two workers unless explicitly configured", () => {
109
+ assert.equal(_resolveSliceParallelMaxWorkersForTest(), 2);
110
+ assert.equal(_resolveSliceParallelMaxWorkersForTest(4), 4);
161
111
  });
162
112
  });
163
113
 
@@ -217,36 +167,47 @@ describe("slice-parallel-orchestrator recovery identity", () => {
217
167
  });
218
168
  });
219
169
 
220
- describe("slice_parallel preference gating", () => {
221
- it("preferences-types.ts includes slice_parallel in interface", () => {
222
- const source = readFileSync(join(gsdDir, "preferences-types.ts"), "utf-8");
223
- assert.ok(
224
- source.includes("slice_parallel"),
225
- "GSDPreferences should have slice_parallel field",
226
- );
227
- });
228
-
229
- it("slice_parallel is in KNOWN_PREFERENCE_KEYS", () => {
230
- const source = readFileSync(join(gsdDir, "preferences-types.ts"), "utf-8");
231
- assert.ok(
232
- source.includes('"slice_parallel"'),
233
- 'KNOWN_PREFERENCE_KEYS should include "slice_parallel"',
234
- );
170
+ describe("slice_parallel preference and state gating", () => {
171
+ it("validates slice_parallel preferences", () => {
172
+ const result = validatePreferences({
173
+ slice_parallel: { enabled: true, max_workers: 3 },
174
+ });
175
+
176
+ assert.equal(result.errors.length, 0);
177
+ assert.deepEqual(result.preferences.slice_parallel, {
178
+ enabled: true,
179
+ max_workers: 3,
180
+ });
235
181
  });
236
182
 
237
- it("state.ts checks GSD_SLICE_LOCK for slice isolation", () => {
238
- const source = readFileSync(join(gsdDir, "state.ts"), "utf-8");
239
- assert.ok(
240
- source.includes("GSD_SLICE_LOCK"),
241
- "State derivation should check GSD_SLICE_LOCK for slice-level parallel isolation",
242
- );
243
- });
183
+ it("derives the locked slice for parallel workers", async () => {
184
+ const basePath = makeTempProject();
185
+ const oldWorker = process.env.GSD_PARALLEL_WORKER;
186
+ const oldSlice = process.env.GSD_SLICE_LOCK;
187
+ try {
188
+ const msDir = join(basePath, ".gsd", "milestones", "M001");
189
+ mkdirSync(msDir, { recursive: true });
190
+ writeFileSync(
191
+ join(msDir, "M001-ROADMAP.md"),
192
+ [
193
+ "# M001",
194
+ "",
195
+ "## Slices",
196
+ "- [ ] **S01: First** `risk:low` `depends:[]`",
197
+ "- [ ] **S02: Second** `risk:low` `depends:[]`",
198
+ ].join("\n"),
199
+ );
200
+ process.env.GSD_PARALLEL_WORKER = "1";
201
+ process.env.GSD_SLICE_LOCK = "S02";
244
202
 
245
- it("auto.ts imports slice parallel orchestrator when enabled", () => {
246
- const source = readFileSync(join(gsdDir, "auto.ts"), "utf-8");
247
- assert.ok(
248
- source.includes("slice_parallel") || source.includes("slice-parallel"),
249
- "auto.ts should reference slice_parallel for dispatch gating",
250
- );
203
+ const state = await deriveState(basePath);
204
+ assert.equal(state.activeSlice?.id, "S02");
205
+ } finally {
206
+ if (oldWorker === undefined) delete process.env.GSD_PARALLEL_WORKER;
207
+ else process.env.GSD_PARALLEL_WORKER = oldWorker;
208
+ if (oldSlice === undefined) delete process.env.GSD_SLICE_LOCK;
209
+ else process.env.GSD_SLICE_LOCK = oldSlice;
210
+ rmSync(basePath, { recursive: true, force: true });
211
+ }
251
212
  });
252
213
  });
@@ -1,51 +1,124 @@
1
1
  /**
2
- * Regression test for #3697 — set slice sequence on insert
3
- *
4
- * All three insertSlice call sites must pass a sequence value so slices
5
- * are ordered correctly instead of defaulting to 0.
2
+ * Regression test for #3697 — set slice sequence on insert.
6
3
  */
7
4
 
8
- import { describe, test } from 'node:test';
9
- import assert from 'node:assert/strict';
10
- import { readFileSync } from 'node:fs';
11
- import { fileURLToPath } from 'node:url';
12
- import { dirname, join } from 'node:path';
13
-
14
- const __filename = fileURLToPath(import.meta.url);
15
- const __dirname = dirname(__filename);
16
-
17
- const planMilestoneSrc = readFileSync(
18
- join(__dirname, '..', 'tools', 'plan-milestone.ts'),
19
- 'utf-8',
20
- );
21
- const reassessRoadmapSrc = readFileSync(
22
- join(__dirname, '..', 'tools', 'reassess-roadmap.ts'),
23
- 'utf-8',
24
- );
25
- const mdImporterSrc = readFileSync(
26
- join(__dirname, '..', 'md-importer.ts'),
27
- 'utf-8',
28
- );
29
-
30
- describe('slice sequence on insert (#3697)', () => {
31
- test('plan-milestone.ts passes sequence to insertSlice', () => {
32
- assert.match(planMilestoneSrc, /insertSlice\(/,
33
- 'plan-milestone.ts should call insertSlice');
34
- assert.match(planMilestoneSrc, /sequence:\s*i\s*\+\s*1/,
35
- 'plan-milestone.ts should pass sequence: i + 1');
5
+ import { describe, test, afterEach } from "node:test";
6
+ import assert from "node:assert/strict";
7
+ import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
8
+ import { join } from "node:path";
9
+ import { tmpdir } from "node:os";
10
+
11
+ import { handlePlanMilestone } from "../tools/plan-milestone.ts";
12
+ import { handleReassessRoadmap } from "../tools/reassess-roadmap.ts";
13
+ import { migrateHierarchyToDb } from "../md-importer.ts";
14
+ import {
15
+ closeDatabase,
16
+ getMilestoneSlices,
17
+ insertMilestone,
18
+ insertSlice,
19
+ openDatabase,
20
+ } from "../gsd-db.ts";
21
+
22
+ let tempBase: string | null = null;
23
+
24
+ afterEach(() => {
25
+ closeDatabase();
26
+ if (tempBase) rmSync(tempBase, { recursive: true, force: true });
27
+ tempBase = null;
28
+ });
29
+
30
+ function makeBase(name: string): string {
31
+ tempBase = mkdtempSync(join(tmpdir(), name));
32
+ mkdirSync(join(tempBase, ".gsd", "milestones"), { recursive: true });
33
+ openDatabase(join(tempBase, ".gsd", "gsd.db"));
34
+ return tempBase;
35
+ }
36
+
37
+ function slice(sliceId: string, title: string) {
38
+ return {
39
+ sliceId,
40
+ title,
41
+ risk: "low",
42
+ depends: [],
43
+ demo: `${title} demo`,
44
+ goal: `${title} goal`,
45
+ successCriteria: `${title} success`,
46
+ proofLevel: "unit",
47
+ integrationClosure: "covered",
48
+ observabilityImpact: "none",
49
+ };
50
+ }
51
+
52
+ describe("slice sequence on insert (#3697)", () => {
53
+ test("plan milestone persists slices in agent-provided order", async () => {
54
+ const base = makeBase("gsd-sequence-plan-");
55
+
56
+ const result = await handlePlanMilestone({
57
+ milestoneId: "M001",
58
+ title: "Sequence",
59
+ vision: "Preserve slice order",
60
+ slices: [slice("S01", "First"), slice("S02", "Second"), slice("S03", "Third")],
61
+ }, base);
62
+
63
+ assert.ok(!("error" in result), JSON.stringify(result));
64
+ assert.deepEqual(
65
+ getMilestoneSlices("M001").map((row) => [row.id, row.sequence]),
66
+ [["S01", 1], ["S02", 2], ["S03", 3]],
67
+ );
36
68
  });
37
69
 
38
- test('reassess-roadmap.ts passes sequence to insertSlice', () => {
39
- assert.match(reassessRoadmapSrc, /insertSlice\(/,
40
- 'reassess-roadmap.ts should call insertSlice');
41
- assert.match(reassessRoadmapSrc, /sequence:\s*existingCount\s*\+\s*i\s*\+\s*1/,
42
- 'reassess-roadmap.ts should pass sequence: existingCount + i + 1');
70
+ test("reassess roadmap appends new slices after existing slices", async () => {
71
+ const base = makeBase("gsd-sequence-reassess-");
72
+ insertMilestone({ id: "M001", title: "Sequence", status: "active", depends_on: [] });
73
+ insertSlice({ id: "S01", milestoneId: "M001", title: "Done", status: "complete", risk: "low", depends: [], demo: "", sequence: 1 });
74
+ insertSlice({ id: "S02", milestoneId: "M001", title: "Existing", status: "pending", risk: "low", depends: [], demo: "", sequence: 2 });
75
+
76
+ const result = await handleReassessRoadmap({
77
+ milestoneId: "M001",
78
+ completedSliceId: "S01",
79
+ verdict: "pass",
80
+ assessment: "Add follow-up slices.",
81
+ sliceChanges: {
82
+ modified: [],
83
+ added: [
84
+ { sliceId: "S03", title: "Added 1", risk: "low", depends: [], demo: "" },
85
+ { sliceId: "S04", title: "Added 2", risk: "low", depends: [], demo: "" },
86
+ ],
87
+ removed: [],
88
+ },
89
+ }, base);
90
+
91
+ assert.ok(!("error" in result), JSON.stringify(result));
92
+ assert.deepEqual(
93
+ getMilestoneSlices("M001").map((row) => [row.id, row.sequence]),
94
+ [["S01", 1], ["S02", 2], ["S03", 3], ["S04", 4]],
95
+ );
43
96
  });
44
97
 
45
- test('md-importer.ts passes sequence to insertSlice', () => {
46
- assert.match(mdImporterSrc, /insertSlice\(/,
47
- 'md-importer.ts should call insertSlice');
48
- assert.match(mdImporterSrc, /sequence:\s*si\s*\+\s*1/,
49
- 'md-importer.ts should pass sequence: si + 1');
98
+ test("markdown importer preserves roadmap order in sequence values", () => {
99
+ const base = makeBase("gsd-sequence-import-");
100
+ const milestoneDir = join(base, ".gsd", "milestones", "M001");
101
+ mkdirSync(milestoneDir, { recursive: true });
102
+ writeFileSync(
103
+ join(milestoneDir, "M001-ROADMAP.md"),
104
+ [
105
+ "# M001: Imported",
106
+ "",
107
+ "## Slices",
108
+ "- [ ] **S01: First** `risk:low`",
109
+ " Demo: first.",
110
+ "- [ ] **S02: Second** `risk:low`",
111
+ " Demo: second.",
112
+ ].join("\n"),
113
+ "utf-8",
114
+ );
115
+
116
+ const result = migrateHierarchyToDb(base);
117
+
118
+ assert.equal(result.slices, 2);
119
+ assert.deepEqual(
120
+ getMilestoneSlices("M001").map((row) => [row.id, row.sequence]),
121
+ [["S01", 1], ["S02", 2]],
122
+ );
50
123
  });
51
124
  });
@@ -1,34 +1,33 @@
1
+ // GSD-2 — Guided smart entry complete-state behavior tests.
2
+
1
3
  import test from "node:test";
2
4
  import assert from "node:assert/strict";
3
- import { mkdtempSync, mkdirSync, rmSync, writeFileSync, readFileSync } from "node:fs";
5
+ import { mkdtempSync, mkdirSync, rmSync, writeFileSync } from "node:fs";
4
6
  import { join } from "node:path";
5
7
  import { tmpdir } from "node:os";
6
8
 
7
- const { deriveState } = await import("../state.js");
9
+ import { deriveState } from "../state.js";
10
+
11
+ function writeCompleteMilestone(base: string): void {
12
+ const milestoneDir = join(base, ".gsd", "milestones", "M001");
13
+ mkdirSync(milestoneDir, { recursive: true });
14
+ writeFileSync(
15
+ join(milestoneDir, "M001-ROADMAP.md"),
16
+ [
17
+ "# M001: Complete Milestone",
18
+ "",
19
+ "## Slices",
20
+ "- [x] **S01: Done slice** `risk:low` `depends:[]`",
21
+ " > Done.",
22
+ ].join("\n"),
23
+ );
24
+ writeFileSync(join(milestoneDir, "M001-SUMMARY.md"), "# M001 Summary\n\nComplete.");
25
+ }
8
26
 
9
27
  test("deriveState reports the last completed milestone when all milestone slices are done", async () => {
10
28
  const base = mkdtempSync(join(tmpdir(), "gsd-smart-entry-complete-"));
11
-
12
29
  try {
13
- const milestoneDir = join(base, ".gsd", "milestones", "M001");
14
- mkdirSync(milestoneDir, { recursive: true });
15
-
16
- writeFileSync(
17
- join(milestoneDir, "M001-ROADMAP.md"),
18
- [
19
- "# M001: Complete Milestone",
20
- "",
21
- "## Slices",
22
- "- [x] **S01: Done slice** `risk:low` `depends:[]`",
23
- " > Done.",
24
- ].join("\n"),
25
- );
26
-
27
- writeFileSync(
28
- join(milestoneDir, "M001-SUMMARY.md"),
29
- "# M001 Summary\n\nComplete.",
30
- );
31
-
30
+ writeCompleteMilestone(base);
32
31
  const state = await deriveState(base);
33
32
  assert.equal(state.phase, "complete");
34
33
  assert.equal(state.lastCompletedMilestone?.id, "M001");
@@ -36,78 +35,3 @@ test("deriveState reports the last completed milestone when all milestone slices
36
35
  rmSync(base, { recursive: true, force: true });
37
36
  }
38
37
  });
39
-
40
- test("guided-flow complete branch offers a chooser for next milestone or status", () => {
41
- const guidedFlowSource = readFileSync(join(import.meta.dirname, "..", "guided-flow.ts"), "utf-8");
42
- const branchIdx = guidedFlowSource.indexOf('state.phase === "complete"');
43
-
44
- assert.ok(branchIdx > -1, "guided-flow.ts should have a complete-phase smart-entry branch");
45
-
46
- const nextBranchIdx = guidedFlowSource.indexOf('state.phase === "needs-discussion"', branchIdx);
47
- const branchChunk = guidedFlowSource.slice(branchIdx, nextBranchIdx === -1 ? branchIdx + 1600 : nextBranchIdx);
48
-
49
- assert.match(branchChunk, /showNextAction\(/, "complete branch should present a chooser");
50
- assert.match(branchChunk, /id:\s*"quick_task"/, "complete branch should offer quick task before milestone planning");
51
- assert.match(branchChunk, /Do a small bounded task without opening a milestone/, "quick task action should explain that it avoids milestones");
52
- assert.match(branchChunk, /recommended:\s*true/, "quick task action should be the recommended complete-state action");
53
- assert.match(branchChunk, /findMilestoneIds\(basePath\)/, "complete branch should compute the next milestone id");
54
- assert.match(
55
- branchChunk,
56
- /nextMilestoneIdReserved\(milestoneIds,\s*uniqueMilestoneIds,\s*basePath\)/,
57
- "complete branch should derive the next milestone id",
58
- );
59
- assert.match(branchChunk, /dispatchWorkflow\(pi, await prepareAndBuildDiscussPrompt\(/, "complete branch should dispatch the prepared discuss prompt");
60
- });
61
-
62
- test("guided-flow quick task choices prompt for text and route through /gsd quick", () => {
63
- const guidedFlowSource = readFileSync(join(import.meta.dirname, "..", "guided-flow.ts"), "utf-8");
64
-
65
- assert.match(
66
- guidedFlowSource,
67
- /async function runQuickTaskChoice\([\s\S]*ctx\.ui\.input\("Quick task"[\s\S]*await import\("\.\/quick\.js"\)[\s\S]*await handleQuick\(task,\s*ctx,\s*pi\)/,
68
- "quick task chooser should prompt for task text and route through handleQuick",
69
- );
70
-
71
- const notifyOnlyPattern = /if \(choice === "quick_task"\) \{\s*ctx\.ui\.notify\("Run \/gsd quick <task>/;
72
- assert.doesNotMatch(
73
- guidedFlowSource,
74
- notifyOnlyPattern,
75
- "quick task chooser must not merely print instructions after selection",
76
- );
77
-
78
- const quickChoiceCalls = guidedFlowSource.match(/if \(choice === "quick_task"\) \{\s*await runQuickTaskChoice\(ctx,\s*pi\);/g) ?? [];
79
- assert.equal(quickChoiceCalls.length, 3, "all guided-flow quick task choices should dispatch the helper");
80
- });
81
-
82
- test("dispatcher routes multi-word freeform /gsd input through /gsd do", () => {
83
- const dispatcherSource = readFileSync(join(import.meta.dirname, "..", "commands", "dispatcher.ts"), "utf-8");
84
-
85
- assert.match(
86
- dispatcherSource,
87
- /if\s*\(trimmed\.includes\(" "\)\)\s*\{[\s\S]*handleDo\(trimmed,\s*ctx,\s*pi\)/,
88
- "dispatcher should treat multi-word unknown input as natural-language /gsd do work",
89
- );
90
- assert.match(
91
- dispatcherSource,
92
- /Unknown: \/gsd/,
93
- "single-token unknown commands should still report the normal unknown-command warning",
94
- );
95
- });
96
-
97
- test("guided-flow needs-discussion skip branch opens the project DB before reserving a new milestone", () => {
98
- const guidedFlowSource = readFileSync(join(import.meta.dirname, "..", "guided-flow.ts"), "utf-8");
99
- const laterDbOpenIdx = guidedFlowSource.indexOf("// Ensure DB is open before querying slices (#2560).");
100
- assert.ok(laterDbOpenIdx > -1, "guided-flow.ts should contain the post-draft DB-open guard");
101
-
102
- const branchPrefix = guidedFlowSource.slice(0, laterDbOpenIdx);
103
- const skipBranchIdx = branchPrefix.lastIndexOf('choice === "skip_milestone"');
104
- assert.ok(skipBranchIdx > -1, "needs-discussion skip branch should be present");
105
-
106
- const branchChunk = branchPrefix.slice(skipBranchIdx);
107
- const ensureIdx = branchChunk.indexOf("ensureDbOpen(basePath)");
108
- const reserveIdx = branchChunk.indexOf("nextMilestoneIdReserved");
109
-
110
- assert.ok(ensureIdx > -1, "skip branch should open the project DB");
111
- assert.ok(reserveIdx > -1, "skip branch should reserve the next milestone ID");
112
- assert.ok(ensureIdx < reserveIdx, "project DB must be opened before milestone ID reservation");
113
- });
@@ -1,124 +1,33 @@
1
- import { mkdtempSync, mkdirSync, rmSync, writeFileSync, readFileSync } from "node:fs";
1
+ // GSD-2 Guided smart entry draft-state behavior tests.
2
+
3
+ import test from "node:test";
4
+ import assert from "node:assert/strict";
5
+ import { mkdtempSync, mkdirSync, rmSync, writeFileSync } from "node:fs";
2
6
  import { join } from "node:path";
3
7
  import { tmpdir } from "node:os";
4
8
 
5
9
  import { deriveState } from "../state.js";
6
10
  import { resolveMilestoneFile } from "../paths.js";
7
- import { extractSourceRegion } from "./test-helpers.ts";
8
-
9
- let passed = 0;
10
- let failed = 0;
11
11
 
12
- function assert(condition: boolean, message: string): void {
13
- if (condition) {
14
- passed++;
15
- } else {
16
- failed++;
17
- console.error(` FAIL: ${message}`);
18
- }
12
+ function writeDraftOnlyMilestone(base: string): void {
13
+ const milestoneDir = join(base, ".gsd", "milestones", "M001");
14
+ mkdirSync(milestoneDir, { recursive: true });
15
+ writeFileSync(
16
+ join(milestoneDir, "M001-CONTEXT-DRAFT.md"),
17
+ "# M001: Test Milestone\n\n**Status:** Draft\n\nSeed material.\n",
18
+ );
19
19
  }
20
20
 
21
- // ─── Fixture: milestone with only CONTEXT-DRAFT.md ──────────────────────
22
-
23
- const tmpBase = mkdtempSync(join(tmpdir(), "gsd-smart-entry-draft-test-"));
24
- const gsd = join(tmpBase, ".gsd");
25
-
26
- mkdirSync(join(gsd, "milestones", "M001"), { recursive: true });
27
-
28
- const draftContent = `# M001: Test Milestone Context\n\n**Status:** Draft\n\nSeed material from a prior discussion.\n`;
29
- writeFileSync(
30
- join(gsd, "milestones", "M001", "M001-CONTEXT-DRAFT.md"),
31
- draftContent,
32
- );
33
-
34
- // ─── Test: deriveState returns 'needs-discussion' for draft-only milestone ───
35
-
36
- const state = await deriveState(tmpBase);
37
-
38
- assert(
39
- state.phase === "needs-discussion",
40
- `phase should be 'needs-discussion' for draft-only milestone, got: "${state.phase}"`,
41
- );
42
-
43
- assert(
44
- state.activeMilestone?.id === "M001",
45
- `active milestone should be M001, got: "${state.activeMilestone?.id}"`,
46
- );
47
-
48
- // ─── Test: resolveMilestoneFile resolves CONTEXT-DRAFT ─────────────────────
49
-
50
- const draftFile = resolveMilestoneFile(tmpBase, "M001", "CONTEXT-DRAFT");
51
-
52
- assert(
53
- draftFile !== null && draftFile !== undefined,
54
- `resolveMilestoneFile should resolve CONTEXT-DRAFT, got: ${draftFile}`,
55
- );
56
-
57
- assert(
58
- draftFile!.endsWith("M001-CONTEXT-DRAFT.md"),
59
- `resolved path should end with M001-CONTEXT-DRAFT.md, got: "${draftFile}"`,
60
- );
61
-
62
- // ─── Test: CONTEXT.md is NOT resolved (only draft exists) ──────────────────
63
-
64
- const contextFile = resolveMilestoneFile(tmpBase, "M001", "CONTEXT");
65
-
66
- assert(
67
- contextFile === null || contextFile === undefined,
68
- `resolveMilestoneFile should NOT resolve CONTEXT when only CONTEXT-DRAFT exists, got: "${contextFile}"`,
69
- );
70
-
71
- // ─── Static: guided-flow.ts has 'needs-discussion' branch ─────────────────
72
-
73
- const guidedFlowSource = readFileSync(
74
- join(import.meta.dirname, "..", "guided-flow.ts"),
75
- "utf-8",
76
- );
77
-
78
- assert(
79
- guidedFlowSource.includes('state.phase === "needs-discussion"'),
80
- "guided-flow.ts should have 'needs-discussion' phase check in showSmartEntry",
81
- );
82
-
83
- // Check the branch has draft-aware menu options
84
- const branchIdx = guidedFlowSource.indexOf('state.phase === "needs-discussion"');
85
- const branchChunk = extractSourceRegion(guidedFlowSource, 'state.phase === "needs-discussion"');
86
-
87
- assert(
88
- branchChunk.includes("discuss_draft"),
89
- "needs-discussion branch should have 'discuss_draft' option",
90
- );
91
-
92
- assert(
93
- branchChunk.includes("discuss_fresh"),
94
- "needs-discussion branch should have 'discuss_fresh' option",
95
- );
96
-
97
- assert(
98
- branchChunk.includes("skip_milestone"),
99
- "needs-discussion branch should have 'skip_milestone' option",
100
- );
101
-
102
- assert(
103
- branchChunk.includes("CONTEXT-DRAFT"),
104
- "needs-discussion branch should load CONTEXT-DRAFT via resolveMilestoneFile",
105
- );
106
-
107
- assert(
108
- branchChunk.includes("Draft Seed") || branchChunk.includes("draftContent"),
109
- "discuss_draft path should include draft content as seed in the dispatched prompt",
110
- );
111
-
112
- assert(
113
- branchChunk.includes("return"),
114
- "needs-discussion branch should return early (not fall through to generic no-roadmap menu)",
115
- );
116
-
117
- // ─── Cleanup ──────────────────────────────────────────────────────────────
118
-
119
- rmSync(tmpBase, { recursive: true, force: true });
120
-
121
- // ─── Results ──────────────────────────────────────────────────────────────
122
-
123
- console.log(`\nsmart-entry-draft: ${passed} passed, ${failed} failed`);
124
- if (failed > 0) process.exit(1);
21
+ test("deriveState returns needs-discussion for draft-only milestone", async () => {
22
+ const base = mkdtempSync(join(tmpdir(), "gsd-smart-entry-draft-"));
23
+ try {
24
+ writeDraftOnlyMilestone(base);
25
+ const state = await deriveState(base);
26
+ assert.equal(state.phase, "needs-discussion");
27
+ assert.equal(state.activeMilestone?.id, "M001");
28
+ assert.match(resolveMilestoneFile(base, "M001", "CONTEXT-DRAFT") ?? "", /M001-CONTEXT-DRAFT\.md$/);
29
+ assert.equal(resolveMilestoneFile(base, "M001", "CONTEXT"), null);
30
+ } finally {
31
+ rmSync(base, { recursive: true, force: true });
32
+ }
33
+ });