gsd-pi 2.43.0-next.8 → 2.44.0-dev.0b97ffd

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 (399) hide show
  1. package/README.md +30 -12
  2. package/dist/cli.js +13 -1
  3. package/dist/help-text.js +24 -0
  4. package/dist/resources/extensions/gsd/auto-direct-dispatch.js +21 -8
  5. package/dist/resources/extensions/gsd/auto-prompts.js +130 -51
  6. package/dist/resources/extensions/gsd/auto-start.js +10 -0
  7. package/dist/resources/extensions/gsd/auto-worktree.js +16 -2
  8. package/dist/resources/extensions/gsd/commands/handlers/workflow.js +5 -0
  9. package/dist/resources/extensions/gsd/dispatch-guard.js +34 -10
  10. package/dist/resources/extensions/gsd/markdown-renderer.js +7 -5
  11. package/dist/resources/extensions/gsd/reactive-graph.js +13 -2
  12. package/dist/resources/extensions/gsd/skill-health.js +3 -1
  13. package/dist/resources/extensions/gsd/tools/plan-milestone.js +2 -11
  14. package/dist/resources/extensions/gsd/tools/plan-slice.js +2 -10
  15. package/dist/resources/extensions/gsd/visualizer-data.js +45 -13
  16. package/dist/resources/extensions/gsd/workspace-index.js +46 -15
  17. package/dist/web/standalone/.next/BUILD_ID +1 -1
  18. package/dist/web/standalone/.next/app-path-routes-manifest.json +18 -18
  19. package/dist/web/standalone/.next/build-manifest.json +3 -3
  20. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  21. package/dist/web/standalone/.next/required-server-files.json +4 -4
  22. package/dist/web/standalone/.next/server/app/_global-error/page.js +3 -3
  23. package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  24. package/dist/web/standalone/.next/server/app/_global-error.html +2 -2
  25. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  26. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  27. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  28. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  29. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  30. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  31. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  32. package/dist/web/standalone/.next/server/app/_not-found/page.js +2 -2
  33. package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  34. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  35. package/dist/web/standalone/.next/server/app/_not-found.rsc +3 -3
  36. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +3 -3
  37. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  38. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +3 -3
  39. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  40. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  41. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  42. package/dist/web/standalone/.next/server/app/api/boot/route.js +1 -1
  43. package/dist/web/standalone/.next/server/app/api/boot/route_client-reference-manifest.js +1 -1
  44. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js +1 -1
  45. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route_client-reference-manifest.js +1 -1
  46. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js +1 -1
  47. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route_client-reference-manifest.js +1 -1
  48. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js +2 -2
  49. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route_client-reference-manifest.js +1 -1
  50. package/dist/web/standalone/.next/server/app/api/browse-directories/route.js +1 -1
  51. package/dist/web/standalone/.next/server/app/api/browse-directories/route_client-reference-manifest.js +1 -1
  52. package/dist/web/standalone/.next/server/app/api/captures/route.js +1 -1
  53. package/dist/web/standalone/.next/server/app/api/captures/route_client-reference-manifest.js +1 -1
  54. package/dist/web/standalone/.next/server/app/api/cleanup/route.js +1 -1
  55. package/dist/web/standalone/.next/server/app/api/cleanup/route_client-reference-manifest.js +1 -1
  56. package/dist/web/standalone/.next/server/app/api/dev-mode/route.js +1 -1
  57. package/dist/web/standalone/.next/server/app/api/dev-mode/route_client-reference-manifest.js +1 -1
  58. package/dist/web/standalone/.next/server/app/api/doctor/route.js +1 -1
  59. package/dist/web/standalone/.next/server/app/api/doctor/route_client-reference-manifest.js +1 -1
  60. package/dist/web/standalone/.next/server/app/api/export-data/route.js +1 -1
  61. package/dist/web/standalone/.next/server/app/api/export-data/route_client-reference-manifest.js +1 -1
  62. package/dist/web/standalone/.next/server/app/api/files/route.js +1 -1
  63. package/dist/web/standalone/.next/server/app/api/files/route_client-reference-manifest.js +1 -1
  64. package/dist/web/standalone/.next/server/app/api/forensics/route.js +1 -1
  65. package/dist/web/standalone/.next/server/app/api/forensics/route_client-reference-manifest.js +1 -1
  66. package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
  67. package/dist/web/standalone/.next/server/app/api/git/route_client-reference-manifest.js +1 -1
  68. package/dist/web/standalone/.next/server/app/api/history/route.js +1 -1
  69. package/dist/web/standalone/.next/server/app/api/history/route_client-reference-manifest.js +1 -1
  70. package/dist/web/standalone/.next/server/app/api/hooks/route.js +1 -1
  71. package/dist/web/standalone/.next/server/app/api/hooks/route_client-reference-manifest.js +1 -1
  72. package/dist/web/standalone/.next/server/app/api/inspect/route.js +1 -1
  73. package/dist/web/standalone/.next/server/app/api/inspect/route_client-reference-manifest.js +1 -1
  74. package/dist/web/standalone/.next/server/app/api/knowledge/route.js +1 -1
  75. package/dist/web/standalone/.next/server/app/api/knowledge/route_client-reference-manifest.js +1 -1
  76. package/dist/web/standalone/.next/server/app/api/live-state/route.js +1 -1
  77. package/dist/web/standalone/.next/server/app/api/live-state/route_client-reference-manifest.js +1 -1
  78. package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
  79. package/dist/web/standalone/.next/server/app/api/onboarding/route_client-reference-manifest.js +1 -1
  80. package/dist/web/standalone/.next/server/app/api/preferences/route.js +1 -1
  81. package/dist/web/standalone/.next/server/app/api/preferences/route_client-reference-manifest.js +1 -1
  82. package/dist/web/standalone/.next/server/app/api/projects/route.js +1 -1
  83. package/dist/web/standalone/.next/server/app/api/projects/route_client-reference-manifest.js +1 -1
  84. package/dist/web/standalone/.next/server/app/api/recovery/route.js +1 -1
  85. package/dist/web/standalone/.next/server/app/api/recovery/route_client-reference-manifest.js +1 -1
  86. package/dist/web/standalone/.next/server/app/api/remote-questions/route.js +5 -5
  87. package/dist/web/standalone/.next/server/app/api/remote-questions/route_client-reference-manifest.js +1 -1
  88. package/dist/web/standalone/.next/server/app/api/session/browser/route.js +1 -1
  89. package/dist/web/standalone/.next/server/app/api/session/browser/route_client-reference-manifest.js +1 -1
  90. package/dist/web/standalone/.next/server/app/api/session/command/route.js +1 -1
  91. package/dist/web/standalone/.next/server/app/api/session/command/route_client-reference-manifest.js +1 -1
  92. package/dist/web/standalone/.next/server/app/api/session/events/route.js +2 -2
  93. package/dist/web/standalone/.next/server/app/api/session/events/route_client-reference-manifest.js +1 -1
  94. package/dist/web/standalone/.next/server/app/api/session/manage/route.js +1 -1
  95. package/dist/web/standalone/.next/server/app/api/session/manage/route_client-reference-manifest.js +1 -1
  96. package/dist/web/standalone/.next/server/app/api/settings-data/route.js +1 -1
  97. package/dist/web/standalone/.next/server/app/api/settings-data/route_client-reference-manifest.js +1 -1
  98. package/dist/web/standalone/.next/server/app/api/shutdown/route.js +1 -1
  99. package/dist/web/standalone/.next/server/app/api/shutdown/route_client-reference-manifest.js +1 -1
  100. package/dist/web/standalone/.next/server/app/api/skill-health/route.js +1 -1
  101. package/dist/web/standalone/.next/server/app/api/skill-health/route_client-reference-manifest.js +1 -1
  102. package/dist/web/standalone/.next/server/app/api/steer/route.js +1 -1
  103. package/dist/web/standalone/.next/server/app/api/steer/route_client-reference-manifest.js +1 -1
  104. package/dist/web/standalone/.next/server/app/api/switch-root/route.js +1 -1
  105. package/dist/web/standalone/.next/server/app/api/switch-root/route_client-reference-manifest.js +1 -1
  106. package/dist/web/standalone/.next/server/app/api/terminal/input/route.js +1 -1
  107. package/dist/web/standalone/.next/server/app/api/terminal/input/route_client-reference-manifest.js +1 -1
  108. package/dist/web/standalone/.next/server/app/api/terminal/resize/route.js +2 -2
  109. package/dist/web/standalone/.next/server/app/api/terminal/resize/route_client-reference-manifest.js +1 -1
  110. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js +2 -2
  111. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route_client-reference-manifest.js +1 -1
  112. package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js +4 -4
  113. package/dist/web/standalone/.next/server/app/api/terminal/stream/route_client-reference-manifest.js +1 -1
  114. package/dist/web/standalone/.next/server/app/api/terminal/upload/route.js +1 -1
  115. package/dist/web/standalone/.next/server/app/api/terminal/upload/route_client-reference-manifest.js +1 -1
  116. package/dist/web/standalone/.next/server/app/api/undo/route.js +1 -1
  117. package/dist/web/standalone/.next/server/app/api/undo/route_client-reference-manifest.js +1 -1
  118. package/dist/web/standalone/.next/server/app/api/update/route.js +1 -1
  119. package/dist/web/standalone/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
  120. package/dist/web/standalone/.next/server/app/api/visualizer/route.js +1 -1
  121. package/dist/web/standalone/.next/server/app/api/visualizer/route_client-reference-manifest.js +1 -1
  122. package/dist/web/standalone/.next/server/app/index.html +1 -1
  123. package/dist/web/standalone/.next/server/app/index.rsc +4 -4
  124. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  125. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +4 -4
  126. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  127. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +3 -3
  128. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  129. package/dist/web/standalone/.next/server/app/page.js +2 -2
  130. package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  131. package/dist/web/standalone/.next/server/app-paths-manifest.json +18 -18
  132. package/dist/web/standalone/.next/server/chunks/229.js +1 -1
  133. package/dist/web/standalone/.next/server/chunks/471.js +3 -3
  134. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  135. package/dist/web/standalone/.next/server/middleware.js +2 -2
  136. package/dist/web/standalone/.next/server/next-font-manifest.js +1 -1
  137. package/dist/web/standalone/.next/server/next-font-manifest.json +1 -1
  138. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  139. package/dist/web/standalone/.next/server/pages/500.html +2 -2
  140. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  141. package/dist/web/standalone/.next/static/chunks/app/_not-found/page-f2a7482d42a5614b.js +1 -0
  142. package/dist/web/standalone/.next/static/chunks/app/layout-a16c7a7ecdf0c2cf.js +1 -0
  143. package/dist/web/standalone/.next/static/chunks/app/page-b9367c5ae13b99c6.js +1 -0
  144. package/dist/web/standalone/.next/static/chunks/{main-app-2f2ee7b85712c2bd.js → main-app-fdab67f7802d7832.js} +1 -1
  145. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-459824ffb8c323dd.js +1 -0
  146. package/dist/web/standalone/node_modules/node-pty/build/Makefile +2 -2
  147. package/dist/web/standalone/node_modules/node-pty/build/Release/pty.node +0 -0
  148. package/dist/web/standalone/node_modules/node-pty/build/pty.target.mk +14 -14
  149. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api.target.mk +14 -14
  150. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_except.target.mk +14 -14
  151. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_maybe.target.mk +14 -14
  152. package/dist/web/standalone/server.js +1 -1
  153. package/package.json +4 -4
  154. package/packages/pi-coding-agent/dist/core/agent-session.d.ts +3 -3
  155. package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
  156. package/packages/pi-coding-agent/dist/core/agent-session.js +11 -34
  157. package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
  158. package/packages/pi-coding-agent/dist/core/auth-storage.test.js +6 -8
  159. package/packages/pi-coding-agent/dist/core/auth-storage.test.js.map +1 -1
  160. package/packages/pi-coding-agent/dist/core/compaction/branch-summarization.d.ts +2 -2
  161. package/packages/pi-coding-agent/dist/core/compaction/branch-summarization.d.ts.map +1 -1
  162. package/packages/pi-coding-agent/dist/core/compaction/branch-summarization.js.map +1 -1
  163. package/packages/pi-coding-agent/dist/core/compaction/compaction.d.ts +2 -2
  164. package/packages/pi-coding-agent/dist/core/compaction/compaction.d.ts.map +1 -1
  165. package/packages/pi-coding-agent/dist/core/compaction/compaction.js.map +1 -1
  166. package/packages/pi-coding-agent/dist/core/compaction-orchestrator.js +4 -4
  167. package/packages/pi-coding-agent/dist/core/compaction-orchestrator.js.map +1 -1
  168. package/packages/pi-coding-agent/dist/core/extensions/index.d.ts +1 -1
  169. package/packages/pi-coding-agent/dist/core/extensions/index.d.ts.map +1 -1
  170. package/packages/pi-coding-agent/dist/core/extensions/index.js.map +1 -1
  171. package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts.map +1 -1
  172. package/packages/pi-coding-agent/dist/core/extensions/loader.js +18 -0
  173. package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
  174. package/packages/pi-coding-agent/dist/core/extensions/runner.test.js +24 -26
  175. package/packages/pi-coding-agent/dist/core/extensions/runner.test.js.map +1 -1
  176. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts +37 -0
  177. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts.map +1 -1
  178. package/packages/pi-coding-agent/dist/core/extensions/types.js.map +1 -1
  179. package/packages/pi-coding-agent/dist/core/fallback-resolver.d.ts.map +1 -1
  180. package/packages/pi-coding-agent/dist/core/fallback-resolver.js +2 -3
  181. package/packages/pi-coding-agent/dist/core/fallback-resolver.js.map +1 -1
  182. package/packages/pi-coding-agent/dist/core/fallback-resolver.test.js +12 -2
  183. package/packages/pi-coding-agent/dist/core/fallback-resolver.test.js.map +1 -1
  184. package/packages/pi-coding-agent/dist/core/fs-utils.test.js +29 -48
  185. package/packages/pi-coding-agent/dist/core/fs-utils.test.js.map +1 -1
  186. package/packages/pi-coding-agent/dist/core/lifecycle-hooks.d.ts +38 -0
  187. package/packages/pi-coding-agent/dist/core/lifecycle-hooks.d.ts.map +1 -0
  188. package/packages/pi-coding-agent/dist/core/lifecycle-hooks.js +192 -0
  189. package/packages/pi-coding-agent/dist/core/lifecycle-hooks.js.map +1 -0
  190. package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.d.ts +2 -0
  191. package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.d.ts.map +1 -0
  192. package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.js +255 -0
  193. package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.js.map +1 -0
  194. package/packages/pi-coding-agent/dist/core/model-registry.d.ts +15 -0
  195. package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
  196. package/packages/pi-coding-agent/dist/core/model-registry.js +40 -3
  197. package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
  198. package/packages/pi-coding-agent/dist/core/package-commands.d.ts +25 -0
  199. package/packages/pi-coding-agent/dist/core/package-commands.d.ts.map +1 -0
  200. package/packages/pi-coding-agent/dist/core/package-commands.js +253 -0
  201. package/packages/pi-coding-agent/dist/core/package-commands.js.map +1 -0
  202. package/packages/pi-coding-agent/dist/core/package-commands.test.d.ts +2 -0
  203. package/packages/pi-coding-agent/dist/core/package-commands.test.d.ts.map +1 -0
  204. package/packages/pi-coding-agent/dist/core/package-commands.test.js +225 -0
  205. package/packages/pi-coding-agent/dist/core/package-commands.test.js.map +1 -0
  206. package/packages/pi-coding-agent/dist/core/resolve-config-value.test.js +34 -44
  207. package/packages/pi-coding-agent/dist/core/resolve-config-value.test.js.map +1 -1
  208. package/packages/pi-coding-agent/dist/core/sdk.d.ts.map +1 -1
  209. package/packages/pi-coding-agent/dist/core/sdk.js +4 -0
  210. package/packages/pi-coding-agent/dist/core/sdk.js.map +1 -1
  211. package/packages/pi-coding-agent/dist/core/session-manager.test.js +30 -34
  212. package/packages/pi-coding-agent/dist/core/session-manager.test.js.map +1 -1
  213. package/packages/pi-coding-agent/dist/core/tools/edit-diff.test.js +10 -12
  214. package/packages/pi-coding-agent/dist/core/tools/edit-diff.test.js.map +1 -1
  215. package/packages/pi-coding-agent/dist/index.d.ts +3 -1
  216. package/packages/pi-coding-agent/dist/index.d.ts.map +1 -1
  217. package/packages/pi-coding-agent/dist/index.js +1 -0
  218. package/packages/pi-coding-agent/dist/index.js.map +1 -1
  219. package/packages/pi-coding-agent/dist/main.d.ts.map +1 -1
  220. package/packages/pi-coding-agent/dist/main.js +11 -199
  221. package/packages/pi-coding-agent/dist/main.js.map +1 -1
  222. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.test.js +43 -47
  223. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.test.js.map +1 -1
  224. package/packages/pi-coding-agent/package.json +1 -1
  225. package/packages/pi-coding-agent/src/core/agent-session.ts +13 -37
  226. package/packages/pi-coding-agent/src/core/auth-storage.test.ts +7 -7
  227. package/packages/pi-coding-agent/src/core/compaction/branch-summarization.ts +2 -2
  228. package/packages/pi-coding-agent/src/core/compaction/compaction.ts +3 -3
  229. package/packages/pi-coding-agent/src/core/compaction-orchestrator.ts +4 -4
  230. package/packages/pi-coding-agent/src/core/extensions/index.ts +5 -0
  231. package/packages/pi-coding-agent/src/core/extensions/loader.ts +23 -0
  232. package/packages/pi-coding-agent/src/core/extensions/runner.test.ts +26 -26
  233. package/packages/pi-coding-agent/src/core/extensions/types.ts +44 -0
  234. package/packages/pi-coding-agent/src/core/fallback-resolver.test.ts +15 -2
  235. package/packages/pi-coding-agent/src/core/fallback-resolver.ts +2 -3
  236. package/packages/pi-coding-agent/src/core/fs-utils.test.ts +31 -43
  237. package/packages/pi-coding-agent/src/core/lifecycle-hooks.ts +274 -0
  238. package/packages/pi-coding-agent/src/core/model-registry-auth-mode.test.ts +288 -0
  239. package/packages/pi-coding-agent/src/core/model-registry.ts +39 -3
  240. package/packages/pi-coding-agent/src/core/package-commands.test.ts +240 -0
  241. package/packages/pi-coding-agent/src/core/package-commands.ts +310 -0
  242. package/packages/pi-coding-agent/src/core/resolve-config-value.test.ts +40 -45
  243. package/packages/pi-coding-agent/src/core/sdk.ts +4 -0
  244. package/packages/pi-coding-agent/src/core/session-manager.test.ts +33 -33
  245. package/packages/pi-coding-agent/src/core/tools/edit-diff.test.ts +17 -17
  246. package/packages/pi-coding-agent/src/index.ts +7 -0
  247. package/packages/pi-coding-agent/src/main.ts +11 -232
  248. package/packages/pi-coding-agent/src/resources/extensions/memory/storage.test.ts +74 -74
  249. package/pkg/package.json +1 -1
  250. package/src/resources/extensions/gsd/auto-direct-dispatch.ts +22 -7
  251. package/src/resources/extensions/gsd/auto-prompts.ts +109 -42
  252. package/src/resources/extensions/gsd/auto-start.ts +14 -0
  253. package/src/resources/extensions/gsd/auto-worktree.ts +16 -3
  254. package/src/resources/extensions/gsd/commands/handlers/workflow.ts +8 -0
  255. package/src/resources/extensions/gsd/dispatch-guard.ts +28 -10
  256. package/src/resources/extensions/gsd/markdown-renderer.ts +7 -5
  257. package/src/resources/extensions/gsd/reactive-graph.ts +12 -2
  258. package/src/resources/extensions/gsd/skill-health.ts +2 -1
  259. package/src/resources/extensions/gsd/tests/all-milestones-complete-merge.test.ts +99 -99
  260. package/src/resources/extensions/gsd/tests/auto-lock-creation.test.ts +14 -16
  261. package/src/resources/extensions/gsd/tests/auto-paused-session-validation.test.ts +43 -57
  262. package/src/resources/extensions/gsd/tests/auto-preflight.test.ts +11 -13
  263. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +465 -523
  264. package/src/resources/extensions/gsd/tests/auto-secrets-gate.test.ts +73 -75
  265. package/src/resources/extensions/gsd/tests/auto-start-needs-discussion.test.ts +34 -56
  266. package/src/resources/extensions/gsd/tests/auto-stash-merge.test.ts +3 -3
  267. package/src/resources/extensions/gsd/tests/auto-worktree-milestone-merge.test.ts +533 -656
  268. package/src/resources/extensions/gsd/tests/auto-worktree.test.ts +165 -143
  269. package/src/resources/extensions/gsd/tests/cache-staleness-regression.test.ts +29 -52
  270. package/src/resources/extensions/gsd/tests/captures.test.ts +148 -176
  271. package/src/resources/extensions/gsd/tests/claude-import-tui.test.ts +32 -33
  272. package/src/resources/extensions/gsd/tests/collect-from-manifest.test.ts +141 -143
  273. package/src/resources/extensions/gsd/tests/commands-inspect-open-db.test.ts +25 -25
  274. package/src/resources/extensions/gsd/tests/commands-logs.test.ts +81 -81
  275. package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +38 -59
  276. package/src/resources/extensions/gsd/tests/complete-slice.test.ts +228 -263
  277. package/src/resources/extensions/gsd/tests/complete-task.test.ts +250 -302
  278. package/src/resources/extensions/gsd/tests/context-store.test.ts +354 -367
  279. package/src/resources/extensions/gsd/tests/continue-here.test.ts +68 -72
  280. package/src/resources/extensions/gsd/tests/cost-projection.test.ts +92 -106
  281. package/src/resources/extensions/gsd/tests/crash-recovery.test.ts +27 -35
  282. package/src/resources/extensions/gsd/tests/dashboard-budget.test.ts +220 -237
  283. package/src/resources/extensions/gsd/tests/db-writer.test.ts +390 -420
  284. package/src/resources/extensions/gsd/tests/definition-loader.test.ts +76 -92
  285. package/src/resources/extensions/gsd/tests/derive-state-crossval.test.ts +68 -83
  286. package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +152 -183
  287. package/src/resources/extensions/gsd/tests/derive-state-deps.test.ts +78 -101
  288. package/src/resources/extensions/gsd/tests/derive-state.test.ts +192 -227
  289. package/src/resources/extensions/gsd/tests/detection.test.ts +232 -278
  290. package/src/resources/extensions/gsd/tests/dev-engine-wrapper.test.ts +30 -34
  291. package/src/resources/extensions/gsd/tests/dispatch-guard.test.ts +164 -180
  292. package/src/resources/extensions/gsd/tests/dispatch-missing-task-plans.test.ts +43 -49
  293. package/src/resources/extensions/gsd/tests/dispatch-uat-last-completed.test.ts +28 -32
  294. package/src/resources/extensions/gsd/tests/doctor-completion-deferral.test.ts +27 -29
  295. package/src/resources/extensions/gsd/tests/doctor-delimiter-fix.test.ts +34 -38
  296. package/src/resources/extensions/gsd/tests/doctor-enhancements.test.ts +54 -75
  297. package/src/resources/extensions/gsd/tests/doctor-environment-worktree.test.ts +21 -32
  298. package/src/resources/extensions/gsd/tests/doctor-environment.test.ts +72 -97
  299. package/src/resources/extensions/gsd/tests/doctor-fixlevel.test.ts +38 -44
  300. package/src/resources/extensions/gsd/tests/doctor-git.test.ts +104 -145
  301. package/src/resources/extensions/gsd/tests/doctor-proactive.test.ts +84 -106
  302. package/src/resources/extensions/gsd/tests/doctor-roadmap-summary-atomicity.test.ts +54 -60
  303. package/src/resources/extensions/gsd/tests/doctor-runtime.test.ts +72 -93
  304. package/src/resources/extensions/gsd/tests/doctor.test.ts +104 -134
  305. package/src/resources/extensions/gsd/tests/ensure-db-open.test.ts +123 -131
  306. package/src/resources/extensions/gsd/tests/exit-command.test.ts +20 -24
  307. package/src/resources/extensions/gsd/tests/feature-branch-lifecycle-integration.test.ts +48 -57
  308. package/src/resources/extensions/gsd/tests/files-loadfile-eisdir.test.ts +5 -7
  309. package/src/resources/extensions/gsd/tests/flag-file-db.test.ts +30 -42
  310. package/src/resources/extensions/gsd/tests/freeform-decisions.test.ts +198 -206
  311. package/src/resources/extensions/gsd/tests/git-locale.test.ts +13 -27
  312. package/src/resources/extensions/gsd/tests/git-service.test.ts +285 -388
  313. package/src/resources/extensions/gsd/tests/gitignore-tracked-gsd.test.ts +31 -39
  314. package/src/resources/extensions/gsd/tests/graph-operations.test.ts +63 -69
  315. package/src/resources/extensions/gsd/tests/gsd-db.test.ts +255 -264
  316. package/src/resources/extensions/gsd/tests/gsd-inspect.test.ts +108 -119
  317. package/src/resources/extensions/gsd/tests/gsd-recover.test.ts +81 -103
  318. package/src/resources/extensions/gsd/tests/gsd-tools.test.ts +229 -262
  319. package/src/resources/extensions/gsd/tests/headless-answers.test.ts +13 -13
  320. package/src/resources/extensions/gsd/tests/health-widget.test.ts +29 -37
  321. package/src/resources/extensions/gsd/tests/idle-recovery.test.ts +81 -102
  322. package/src/resources/extensions/gsd/tests/init-wizard.test.ts +16 -18
  323. package/src/resources/extensions/gsd/tests/integration-edge.test.ts +41 -46
  324. package/src/resources/extensions/gsd/tests/integration-lifecycle.test.ts +42 -53
  325. package/src/resources/extensions/gsd/tests/integration-mixed-milestones.test.ts +75 -91
  326. package/src/resources/extensions/gsd/tests/integration-proof.test.ts +18 -18
  327. package/src/resources/extensions/gsd/tests/markdown-renderer.test.ts +150 -194
  328. package/src/resources/extensions/gsd/tests/md-importer.test.ts +101 -125
  329. package/src/resources/extensions/gsd/tests/memory-extractor.test.ts +45 -54
  330. package/src/resources/extensions/gsd/tests/memory-store.test.ts +80 -93
  331. package/src/resources/extensions/gsd/tests/migrate-command.test.ts +57 -66
  332. package/src/resources/extensions/gsd/tests/migrate-hierarchy.test.ts +83 -93
  333. package/src/resources/extensions/gsd/tests/migrate-parser.test.ts +161 -170
  334. package/src/resources/extensions/gsd/tests/migrate-transformer.test.ts +125 -141
  335. package/src/resources/extensions/gsd/tests/migrate-validator-parsers.test.ts +107 -131
  336. package/src/resources/extensions/gsd/tests/migrate-writer-integration.test.ts +87 -96
  337. package/src/resources/extensions/gsd/tests/migrate-writer.test.ts +125 -164
  338. package/src/resources/extensions/gsd/tests/must-have-parser.test.ts +81 -94
  339. package/src/resources/extensions/gsd/tests/none-mode-gates.test.ts +35 -36
  340. package/src/resources/extensions/gsd/tests/overrides.test.ts +99 -106
  341. package/src/resources/extensions/gsd/tests/parallel-crash-recovery.test.ts +40 -47
  342. package/src/resources/extensions/gsd/tests/parallel-worker-monitoring.test.ts +25 -28
  343. package/src/resources/extensions/gsd/tests/parallel-workers-multi-milestone-e2e.test.ts +66 -83
  344. package/src/resources/extensions/gsd/tests/park-edge-cases.test.ts +54 -77
  345. package/src/resources/extensions/gsd/tests/park-milestone.test.ts +68 -115
  346. package/src/resources/extensions/gsd/tests/parsers.test.ts +546 -611
  347. package/src/resources/extensions/gsd/tests/paths.test.ts +72 -87
  348. package/src/resources/extensions/gsd/tests/post-unit-hooks.test.ts +77 -117
  349. package/src/resources/extensions/gsd/tests/prompt-db.test.ts +56 -56
  350. package/src/resources/extensions/gsd/tests/queue-draft-detection.test.ts +93 -119
  351. package/src/resources/extensions/gsd/tests/queue-order.test.ts +70 -82
  352. package/src/resources/extensions/gsd/tests/queue-reorder-e2e.test.ts +42 -55
  353. package/src/resources/extensions/gsd/tests/quick-auto-guard.test.ts +100 -0
  354. package/src/resources/extensions/gsd/tests/quick-branch-lifecycle.test.ts +45 -73
  355. package/src/resources/extensions/gsd/tests/reassess-prompt.test.ts +28 -38
  356. package/src/resources/extensions/gsd/tests/replan-slice.test.ts +73 -80
  357. package/src/resources/extensions/gsd/tests/repo-identity-worktree.test.ts +71 -74
  358. package/src/resources/extensions/gsd/tests/requirements.test.ts +70 -75
  359. package/src/resources/extensions/gsd/tests/retry-state-reset.test.ts +44 -66
  360. package/src/resources/extensions/gsd/tests/roadmap-parse-regression.test.ts +114 -181
  361. package/src/resources/extensions/gsd/tests/rule-registry.test.ts +63 -65
  362. package/src/resources/extensions/gsd/tests/run-uat.test.ts +66 -128
  363. package/src/resources/extensions/gsd/tests/session-lock-multipath.test.ts +18 -25
  364. package/src/resources/extensions/gsd/tests/session-lock-regression.test.ts +37 -44
  365. package/src/resources/extensions/gsd/tests/shared-wal.test.ts +19 -26
  366. package/src/resources/extensions/gsd/tests/sqlite-unavailable-gate.test.ts +63 -0
  367. package/src/resources/extensions/gsd/tests/stalled-tool-recovery.test.ts +6 -8
  368. package/src/resources/extensions/gsd/tests/symlink-numbered-variants.test.ts +22 -28
  369. package/src/resources/extensions/gsd/tests/token-savings.test.ts +54 -56
  370. package/src/resources/extensions/gsd/tests/tool-call-loop-guard.test.ts +23 -25
  371. package/src/resources/extensions/gsd/tests/tool-naming.test.ts +9 -11
  372. package/src/resources/extensions/gsd/tests/unique-milestone-ids.test.ts +66 -82
  373. package/src/resources/extensions/gsd/tests/unit-runtime.test.ts +46 -47
  374. package/src/resources/extensions/gsd/tests/visualizer-critical-path.test.ts +20 -22
  375. package/src/resources/extensions/gsd/tests/visualizer-data.test.ts +84 -86
  376. package/src/resources/extensions/gsd/tests/visualizer-overlay.test.ts +41 -43
  377. package/src/resources/extensions/gsd/tests/visualizer-views.test.ts +94 -96
  378. package/src/resources/extensions/gsd/tests/windows-path-normalization.test.ts +11 -13
  379. package/src/resources/extensions/gsd/tests/worker-registry.test.ts +27 -29
  380. package/src/resources/extensions/gsd/tests/workflow-templates.test.ts +50 -52
  381. package/src/resources/extensions/gsd/tests/worktree-bugfix.test.ts +10 -13
  382. package/src/resources/extensions/gsd/tests/worktree-db-integration.test.ts +14 -18
  383. package/src/resources/extensions/gsd/tests/worktree-db.test.ts +38 -39
  384. package/src/resources/extensions/gsd/tests/worktree-e2e.test.ts +17 -21
  385. package/src/resources/extensions/gsd/tests/worktree-health.test.ts +25 -30
  386. package/src/resources/extensions/gsd/tests/worktree-integration.test.ts +30 -37
  387. package/src/resources/extensions/gsd/tests/worktree-symlink-removal.test.ts +15 -22
  388. package/src/resources/extensions/gsd/tests/worktree-sync-milestones.test.ts +59 -66
  389. package/src/resources/extensions/gsd/tests/worktree.test.ts +44 -50
  390. package/src/resources/extensions/gsd/tools/plan-milestone.ts +1 -18
  391. package/src/resources/extensions/gsd/tools/plan-slice.ts +1 -15
  392. package/src/resources/extensions/gsd/visualizer-data.ts +46 -14
  393. package/src/resources/extensions/gsd/workspace-index.ts +49 -18
  394. package/dist/web/standalone/.next/static/chunks/app/_not-found/page-e07acdb7dd069836.js +0 -1
  395. package/dist/web/standalone/.next/static/chunks/app/layout-745c6ed5fea5fb06.js +0 -1
  396. package/dist/web/standalone/.next/static/chunks/app/page-801b53eff6e83579.js +0 -1
  397. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-e6255954dccfcf0a.js +0 -1
  398. /package/dist/web/standalone/.next/static/{drUWS0zys9uepCfCwecJv → alS4hoANx0TK4UVZY27da}/_buildManifest.js +0 -0
  399. /package/dist/web/standalone/.next/static/{drUWS0zys9uepCfCwecJv → alS4hoANx0TK4UVZY27da}/_ssgManifest.js +0 -0
@@ -13,11 +13,12 @@
13
13
  * - Cost projection with budget ceiling awareness
14
14
  */
15
15
 
16
+ import { describe, test } from 'node:test';
17
+ import assert from 'node:assert/strict';
16
18
  import { mkdtempSync, mkdirSync, rmSync, writeFileSync, readFileSync } from 'node:fs';
17
19
  import { join } from 'node:path';
18
20
  import { tmpdir } from 'node:os';
19
21
 
20
- import { createTestContext } from './test-helpers.ts';
21
22
  import {
22
23
  registerWorker,
23
24
  updateWorker,
@@ -43,8 +44,6 @@ import {
43
44
  predictRemainingCost,
44
45
  } from '../metrics.ts';
45
46
 
46
- const { assertEq, assertTrue, assertMatch, report } = createTestContext();
47
-
48
47
  // ─── Fixture helpers ──────────────────────────────────────────────────────────
49
48
 
50
49
  function createFixtureBase(): string {
@@ -83,9 +82,9 @@ function cleanup(base: string): void {
83
82
 
84
83
  // ─── E2E: Parallel workers across M001 and M002 ──────────────────────────────
85
84
 
86
- console.log("\n=== E2E: Parallel workers across milestones ===");
87
85
 
88
- {
86
+ describe('parallel-workers-multi-milestone-e2e', () => {
87
+ test('E2E: Parallel workers across milestones', () => {
89
88
  resetWorkerRegistry();
90
89
  const base = createFixtureBase();
91
90
 
@@ -99,52 +98,49 @@ console.log("\n=== E2E: Parallel workers across milestones ===");
99
98
  const w2 = registerWorker("researcher", "Research M001 APIs", 1, 3, batch1Id);
100
99
  const w3 = registerWorker("worker", "Implement M001 feature", 2, 3, batch1Id);
101
100
 
102
- assertEq(getActiveWorkers().length, 3, "M001: 3 parallel workers registered");
103
- assertTrue(hasActiveWorkers(), "M001: has active workers");
101
+ assert.deepStrictEqual(getActiveWorkers().length, 3, "M001: 3 parallel workers registered");
102
+ assert.ok(hasActiveWorkers(), "M001: has active workers");
104
103
 
105
104
  const batches1 = getWorkerBatches();
106
- assertEq(batches1.size, 1, "M001: single batch");
107
- assertEq(batches1.get(batch1Id)!.length, 3, "M001: batch has 3 workers");
105
+ assert.deepStrictEqual(batches1.size, 1, "M001: single batch");
106
+ assert.deepStrictEqual(batches1.get(batch1Id)!.length, 3, "M001: batch has 3 workers");
108
107
 
109
108
  // Complete M001 workers
110
109
  updateWorker(w1, "completed");
111
110
  updateWorker(w2, "completed");
112
111
  updateWorker(w3, "completed");
113
- assertTrue(!hasActiveWorkers(), "M001: no active workers after completion");
112
+ assert.ok(!hasActiveWorkers(), "M001: no active workers after completion");
114
113
 
115
114
  // Simulate M002 parallel workers (batch 2) — overlapping with M001 cleanup
116
115
  const batch2Id = "batch-m002";
117
116
  const w4 = registerWorker("scout", "Explore M002 codebase", 0, 2, batch2Id);
118
117
  const w5 = registerWorker("worker", "Implement M002 feature", 1, 2, batch2Id);
119
118
 
120
- assertTrue(hasActiveWorkers(), "M002: has active workers");
119
+ assert.ok(hasActiveWorkers(), "M002: has active workers");
121
120
  const batches2 = getWorkerBatches();
122
121
  // M001 workers may still be in cleanup window (5s timeout), M002 workers are active
123
- assertTrue(batches2.has(batch2Id), "M002: batch exists");
124
- assertEq(batches2.get(batch2Id)!.length, 2, "M002: batch has 2 workers");
122
+ assert.ok(batches2.has(batch2Id), "M002: batch exists");
123
+ assert.deepStrictEqual(batches2.get(batch2Id)!.length, 2, "M002: batch has 2 workers");
125
124
 
126
125
  // One worker fails in M002
127
126
  updateWorker(w4, "completed");
128
127
  updateWorker(w5, "failed");
129
- assertTrue(!hasActiveWorkers(), "M002: no active workers after all finish");
128
+ assert.ok(!hasActiveWorkers(), "M002: no active workers after all finish");
130
129
 
131
130
  // Verify worker statuses reflect correctly
132
131
  const allWorkers = getActiveWorkers();
133
132
  const m002Workers = allWorkers.filter(w => w.batchId === batch2Id);
134
133
  if (m002Workers.length > 0) {
135
134
  const failedWorker = m002Workers.find(w => w.status === "failed");
136
- assertTrue(failedWorker !== undefined, "M002: failed worker tracked");
137
- assertEq(failedWorker?.agent, "worker", "M002: failed worker is 'worker'");
135
+ assert.ok(failedWorker !== undefined, "M002: failed worker tracked");
136
+ assert.deepStrictEqual(failedWorker?.agent, "worker", "M002: failed worker is 'worker'");
138
137
  }
139
138
 
140
139
  cleanup(base);
141
- }
140
+ });
142
141
 
143
142
  // ─── E2E: Metrics accumulation across milestones ──────────────────────────────
144
-
145
- console.log("\n=== E2E: Metrics across milestones ===");
146
-
147
- {
143
+ test('E2E: Metrics across milestones', () => {
148
144
  const base = createFixtureBase();
149
145
 
150
146
  // Build a ledger spanning two milestones
@@ -175,90 +171,84 @@ console.log("\n=== E2E: Metrics across milestones ===");
175
171
 
176
172
  // Verify totals
177
173
  const totals = getProjectTotals(loaded.units);
178
- assertEq(totals.units, 13, "metrics: 13 total units across M001+M002");
174
+ assert.deepStrictEqual(totals.units, 13, "metrics: 13 total units across M001+M002");
179
175
  const totalCost = loaded.units.reduce((sum, u) => sum + u.cost, 0);
180
- assertTrue(Math.abs(totals.cost - totalCost) < 0.001, "metrics: total cost matches sum");
176
+ assert.ok(Math.abs(totals.cost - totalCost) < 0.001, "metrics: total cost matches sum");
181
177
 
182
178
  // Verify phase aggregation
183
179
  const phases = aggregateByPhase(loaded.units);
184
180
  const research = phases.find(p => p.phase === "research");
185
- assertTrue(research !== undefined, "metrics: research phase exists");
186
- assertEq(research!.units, 2, "metrics: 2 research units (M001 + M002)");
181
+ assert.ok(research !== undefined, "metrics: research phase exists");
182
+ assert.deepStrictEqual(research!.units, 2, "metrics: 2 research units (M001 + M002)");
187
183
 
188
184
  const execution = phases.find(p => p.phase === "execution");
189
- assertTrue(execution !== undefined, "metrics: execution phase exists");
190
- assertEq(execution!.units, 4, "metrics: 4 execution units across both milestones");
185
+ assert.ok(execution !== undefined, "metrics: execution phase exists");
186
+ assert.deepStrictEqual(execution!.units, 4, "metrics: 4 execution units across both milestones");
191
187
 
192
188
  // Verify slice aggregation
193
189
  const slices = aggregateBySlice(loaded.units);
194
- assertTrue(slices.length >= 4, "metrics: at least 4 slice aggregates (M001/S01, M001/S02, M002/S01, milestone-level)");
190
+ assert.ok(slices.length >= 4, "metrics: at least 4 slice aggregates (M001/S01, M001/S02, M002/S01, milestone-level)");
195
191
 
196
192
  const m001s01 = slices.find(s => s.sliceId === "M001/S01");
197
- assertTrue(m001s01 !== undefined, "metrics: M001/S01 slice aggregate exists");
193
+ assert.ok(m001s01 !== undefined, "metrics: M001/S01 slice aggregate exists");
198
194
  // M001/S01 has: plan-slice + T01 + T02 + complete-slice = 4 units
199
- assertEq(m001s01!.units, 4, "metrics: M001/S01 has 4 units");
195
+ assert.deepStrictEqual(m001s01!.units, 4, "metrics: M001/S01 has 4 units");
200
196
 
201
197
  // Cost projection
202
198
  const projLines = formatCostProjection(slices, 3, 2.0);
203
- assertTrue(projLines.length >= 1, "metrics: cost projection generated");
204
- assertMatch(projLines[0], /Projected remaining/, "metrics: projection line text");
199
+ assert.ok(projLines.length >= 1, "metrics: cost projection generated");
200
+ assert.match(projLines[0], /Projected remaining/, "metrics: projection line text");
205
201
 
206
202
  cleanup(base);
207
- }
203
+ });
208
204
 
209
205
  // ─── E2E: Budget alert progression through all thresholds ─────────────────────
210
-
211
- console.log("\n=== E2E: Budget alert progression 0→75→80→90→100 ===");
212
-
213
- {
206
+ test('E2E: Budget alert progression 0→75→80→90→100', () => {
214
207
  // Simulate spending progression against a $10 budget ceiling
215
208
  const ceiling = 10.0;
216
209
 
217
210
  // Start: 50% spent
218
211
  let lastLevel = getBudgetAlertLevel(5.0 / ceiling);
219
- assertEq(lastLevel, 0, "budget: 50% → level 0");
220
- assertEq(getNewBudgetAlertLevel(0, 5.0 / ceiling), null, "budget: no alert at 50%");
212
+ assert.deepStrictEqual(lastLevel, 0, "budget: 50% → level 0");
213
+ assert.deepStrictEqual(getNewBudgetAlertLevel(0, 5.0 / ceiling), null, "budget: no alert at 50%");
221
214
 
222
215
  // Spend to 75%
223
216
  let newLevel = getNewBudgetAlertLevel(lastLevel, 7.5 / ceiling);
224
- assertEq(newLevel, 75, "budget: alert fires at 75%");
217
+ assert.deepStrictEqual(newLevel, 75, "budget: alert fires at 75%");
225
218
  lastLevel = newLevel!;
226
219
 
227
220
  // Spend to 78% — no alert (between 75 and 80)
228
- assertEq(getNewBudgetAlertLevel(lastLevel, 7.8 / ceiling), null, "budget: no alert at 78%");
221
+ assert.deepStrictEqual(getNewBudgetAlertLevel(lastLevel, 7.8 / ceiling), null, "budget: no alert at 78%");
229
222
 
230
223
  // Spend to 80% — 80% approach alert
231
224
  newLevel = getNewBudgetAlertLevel(lastLevel, 8.0 / ceiling);
232
- assertEq(newLevel, 80, "budget: approach alert fires at 80%");
225
+ assert.deepStrictEqual(newLevel, 80, "budget: approach alert fires at 80%");
233
226
  lastLevel = newLevel!;
234
227
 
235
228
  // Spend to 85% — no alert (still at 80 level)
236
- assertEq(getNewBudgetAlertLevel(lastLevel, 8.5 / ceiling), null, "budget: no alert at 85%");
229
+ assert.deepStrictEqual(getNewBudgetAlertLevel(lastLevel, 8.5 / ceiling), null, "budget: no alert at 85%");
237
230
 
238
231
  // Spend to 90%
239
232
  newLevel = getNewBudgetAlertLevel(lastLevel, 9.0 / ceiling);
240
- assertEq(newLevel, 90, "budget: alert fires at 90%");
233
+ assert.deepStrictEqual(newLevel, 90, "budget: alert fires at 90%");
241
234
  lastLevel = newLevel!;
242
235
 
243
236
  // Spend to 100%
244
237
  newLevel = getNewBudgetAlertLevel(lastLevel, 10.0 / ceiling);
245
- assertEq(newLevel, 100, "budget: alert fires at 100%");
238
+ assert.deepStrictEqual(newLevel, 100, "budget: alert fires at 100%");
246
239
  lastLevel = newLevel!;
247
240
 
248
241
  // Over budget — no re-emission
249
- assertEq(getNewBudgetAlertLevel(lastLevel, 12.0 / ceiling), null, "budget: no re-alert over 100%");
242
+ assert.deepStrictEqual(getNewBudgetAlertLevel(lastLevel, 12.0 / ceiling), null, "budget: no re-alert over 100%");
250
243
 
251
244
  // Enforcement at 80% — still "none" (enforcement only at 100%)
252
- assertEq(getBudgetEnforcementAction("pause", 0.80), "none", "budget: no enforcement at 80%");
253
- assertEq(getBudgetEnforcementAction("halt", 0.80), "none", "budget: no enforcement at 80%");
254
- assertEq(getBudgetEnforcementAction("warn", 0.80), "none", "budget: no enforcement at 80%");
255
- }
245
+ assert.deepStrictEqual(getBudgetEnforcementAction("pause", 0.80), "none", "budget: no enforcement at 80%");
246
+ assert.deepStrictEqual(getBudgetEnforcementAction("halt", 0.80), "none", "budget: no enforcement at 80%");
247
+ assert.deepStrictEqual(getBudgetEnforcementAction("warn", 0.80), "none", "budget: no enforcement at 80%");
248
+ });
256
249
 
257
250
  // ─── E2E: Budget prediction with multi-milestone cost data ────────────────────
258
-
259
- console.log("\n=== E2E: Budget prediction across milestones ===");
260
-
261
- {
251
+ test('E2E: Budget prediction across milestones', () => {
262
252
  const units: UnitMetrics[] = [
263
253
  makeUnit({ type: "execute-task", id: "M001/S01/T01", cost: 0.10 }),
264
254
  makeUnit({ type: "execute-task", id: "M001/S01/T02", cost: 0.15 }),
@@ -268,30 +258,27 @@ console.log("\n=== E2E: Budget prediction across milestones ===");
268
258
  ];
269
259
 
270
260
  const avgCosts = getAverageCostPerUnitType(units);
271
- assertTrue(avgCosts.has("execute-task"), "prediction: has execute-task average");
272
- assertTrue(avgCosts.has("plan-slice"), "prediction: has plan-slice average");
261
+ assert.ok(avgCosts.has("execute-task"), "prediction: has execute-task average");
262
+ assert.ok(avgCosts.has("plan-slice"), "prediction: has plan-slice average");
273
263
 
274
264
  // Average execute-task cost: (0.10 + 0.15 + 0.20) / 3 = 0.15
275
265
  const execAvg = avgCosts.get("execute-task")!;
276
- assertTrue(Math.abs(execAvg - 0.15) < 0.001, `prediction: execute-task avg is $0.15 (got ${execAvg})`);
266
+ assert.ok(Math.abs(execAvg - 0.15) < 0.001, `prediction: execute-task avg is $0.15 (got ${execAvg})`);
277
267
 
278
268
  // Average plan-slice cost: (0.05 + 0.08) / 2 = 0.065
279
269
  const planAvg = avgCosts.get("plan-slice")!;
280
- assertTrue(Math.abs(planAvg - 0.065) < 0.001, `prediction: plan-slice avg is $0.065 (got ${planAvg})`);
270
+ assert.ok(Math.abs(planAvg - 0.065) < 0.001, `prediction: plan-slice avg is $0.065 (got ${planAvg})`);
281
271
 
282
272
  // Predict remaining cost for 3 more execute-tasks and 1 plan-slice
283
273
  const remaining = predictRemainingCost(avgCosts, [
284
274
  "execute-task", "execute-task", "execute-task", "plan-slice",
285
275
  ]);
286
276
  // Expected: 3 * 0.15 + 1 * 0.065 = 0.515
287
- assertTrue(Math.abs(remaining - 0.515) < 0.001, `prediction: remaining cost ~$0.515 (got ${remaining})`);
288
- }
277
+ assert.ok(Math.abs(remaining - 0.515) < 0.001, `prediction: remaining cost ~$0.515 (got ${remaining})`);
278
+ });
289
279
 
290
280
  // ─── E2E: Parallel workers + budget alerts combined scenario ──────────────────
291
-
292
- console.log("\n=== E2E: Combined parallel workers + budget monitoring ===");
293
-
294
- {
281
+ test('E2E: Combined parallel workers + budget monitoring', () => {
295
282
  resetWorkerRegistry();
296
283
 
297
284
  // Simulate a scenario: 3 parallel workers running while budget is at 78%
@@ -303,34 +290,31 @@ console.log("\n=== E2E: Combined parallel workers + budget monitoring ===");
303
290
  // Budget is at 78% — no alert yet (between 75 and 80)
304
291
  const ceiling = 10.0;
305
292
  let lastLevel: ReturnType<typeof getBudgetAlertLevel> = 75; // already got 75% alert
306
- assertEq(getNewBudgetAlertLevel(lastLevel, 7.8 / ceiling), null, "combined: no alert at 78% with workers running");
307
- assertTrue(hasActiveWorkers(), "combined: workers running during budget check");
293
+ assert.deepStrictEqual(getNewBudgetAlertLevel(lastLevel, 7.8 / ceiling), null, "combined: no alert at 78% with workers running");
294
+ assert.ok(hasActiveWorkers(), "combined: workers running during budget check");
308
295
 
309
296
  // First worker completes, cost rises to 80%
310
297
  updateWorker(w1, "completed");
311
298
  const level80 = getNewBudgetAlertLevel(lastLevel, 8.0 / ceiling);
312
- assertEq(level80, 80, "combined: 80% approach alert fires after worker completes");
299
+ assert.deepStrictEqual(level80, 80, "combined: 80% approach alert fires after worker completes");
313
300
  lastLevel = level80!;
314
301
 
315
302
  // Second worker completes, cost rises to 88%
316
303
  updateWorker(w2, "completed");
317
- assertEq(getNewBudgetAlertLevel(lastLevel, 8.8 / ceiling), null, "combined: no alert at 88%");
304
+ assert.deepStrictEqual(getNewBudgetAlertLevel(lastLevel, 8.8 / ceiling), null, "combined: no alert at 88%");
318
305
 
319
306
  // Third worker completes, cost reaches 90%
320
307
  updateWorker(w3, "completed");
321
308
  const level90 = getNewBudgetAlertLevel(lastLevel, 9.0 / ceiling);
322
- assertEq(level90, 90, "combined: 90% alert fires after all workers complete");
309
+ assert.deepStrictEqual(level90, 90, "combined: 90% alert fires after all workers complete");
323
310
 
324
- assertTrue(!hasActiveWorkers(), "combined: no active workers at end");
311
+ assert.ok(!hasActiveWorkers(), "combined: no active workers at end");
325
312
 
326
313
  resetWorkerRegistry();
327
- }
314
+ });
328
315
 
329
316
  // ─── E2E: formatCostProjection with budget ceiling warnings ───────────────────
330
-
331
- console.log("\n=== E2E: Cost projection ceiling warnings ===");
332
-
333
- {
317
+ test('E2E: Cost projection ceiling warnings', () => {
334
318
  const slices = [
335
319
  { sliceId: "M001/S01", units: 4, tokens: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 }, cost: 3.0, duration: 10000 },
336
320
  { sliceId: "M001/S02", units: 3, tokens: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 }, cost: 4.0, duration: 8000 },
@@ -339,16 +323,15 @@ console.log("\n=== E2E: Cost projection ceiling warnings ===");
339
323
 
340
324
  // With ceiling NOT yet reached
341
325
  const proj1 = formatCostProjection(slices, 2, 20.0);
342
- assertTrue(proj1.length >= 1, "projection: has projection line");
343
- assertMatch(proj1[0], /Projected remaining/, "projection: shows projection");
344
- assertTrue(proj1.length === 1, "projection: no ceiling warning when under budget");
326
+ assert.ok(proj1.length >= 1, "projection: has projection line");
327
+ assert.match(proj1[0], /Projected remaining/, "projection: shows projection");
328
+ assert.ok(proj1.length === 1, "projection: no ceiling warning when under budget");
345
329
 
346
330
  // With ceiling reached (spent 12.0 >= ceiling 10.0)
347
331
  const proj2 = formatCostProjection(slices, 2, 10.0);
348
- assertTrue(proj2.length >= 2, "projection: has ceiling warning when over budget");
349
- assertMatch(proj2[1], /ceiling/, "projection: ceiling warning text");
350
- }
332
+ assert.ok(proj2.length >= 2, "projection: has ceiling warning when over budget");
333
+ assert.match(proj2[1], /ceiling/, "projection: ceiling warning text");
334
+ });
351
335
 
352
336
  // ─── Summary ──────────────────────────────────────────────────────────────────
353
-
354
- report();
337
+ });
@@ -12,6 +12,8 @@
12
12
  * 8. Discard milestone that has depends_on on others
13
13
  */
14
14
 
15
+ import { describe, test } from 'node:test';
16
+ import assert from 'node:assert/strict';
15
17
  import { mkdtempSync, mkdirSync, rmSync, writeFileSync, readFileSync } from 'node:fs';
16
18
  import { join } from 'node:path';
17
19
  import { tmpdir } from 'node:os';
@@ -20,16 +22,6 @@ import { deriveState, invalidateStateCache } from '../state.ts';
20
22
  import { clearPathCache } from '../paths.ts';
21
23
  import { parkMilestone, unparkMilestone, discardMilestone } from '../milestone-actions.ts';
22
24
 
23
- let passed = 0;
24
- let failed = 0;
25
-
26
- function assert(condition: boolean, message: string): void {
27
- if (condition) { passed++; } else { failed++; console.error(` FAIL: ${message}`); }
28
- }
29
- function assertEq<T>(actual: T, expected: T, message: string): void {
30
- if (JSON.stringify(actual) === JSON.stringify(expected)) { passed++; }
31
- else { failed++; console.error(` FAIL: ${message} — expected ${JSON.stringify(expected)}, got ${JSON.stringify(actual)}`); }
32
- }
33
25
 
34
26
  function createFixture(): string {
35
27
  const b = mkdtempSync(join(tmpdir(), 'gsd-edge-'));
@@ -61,11 +53,10 @@ function createM(b: string, mid: string, opts?: { roadmap?: boolean; summary?: b
61
53
  function clear(): void { clearPathCache(); invalidateStateCache(); }
62
54
  function cleanup(b: string): void { rmSync(b, { recursive: true, force: true }); }
63
55
 
64
- async function main(): Promise<void> {
65
-
66
56
  // ─── EDGE 1: Discard breaks depends_on → downstream is BLOCKED ────────
67
- console.log('\n=== EDGE 1: Discard breaks depends_on chain ===');
68
- {
57
+
58
+ describe('park-edge-cases', () => {
59
+ test('EDGE 1: Discard breaks depends_on chain', async () => {
69
60
  const b = createFixture();
70
61
  try {
71
62
  createM(b, 'M001', { roadmap: true, summary: true }); // complete
@@ -78,17 +69,16 @@ async function main(): Promise<void> {
78
69
 
79
70
  // M003 depends on M002 which no longer exists.
80
71
  // M002 is not in completeMilestoneIds → dep is unmet → M003 stays pending
81
- assertEq(s.registry.find(e => e.id === 'M003')?.status, 'pending', 'M003 stays pending after dep discarded');
82
- assertEq(s.phase, 'blocked', 'system is blocked (unmet dep on deleted milestone)');
83
- assert(s.blockers.length > 0, 'blockers list is not empty');
72
+ assert.deepStrictEqual(s.registry.find(e => e.id === 'M003')?.status, 'pending', 'M003 stays pending after dep discarded');
73
+ assert.deepStrictEqual(s.phase, 'blocked', 'system is blocked (unmet dep on deleted milestone)');
74
+ assert.ok(s.blockers.length > 0, 'blockers list is not empty');
84
75
  } finally {
85
76
  cleanup(b);
86
77
  }
87
- }
78
+ });
88
79
 
89
80
  // ─── EDGE 2: Park blocks depends_on chain ────────────────────────────
90
- console.log('\n=== EDGE 2: Park blocks depends_on chain ===');
91
- {
81
+ test('EDGE 2: Park blocks depends_on chain', async () => {
92
82
  const b = createFixture();
93
83
  try {
94
84
  createM(b, 'M001', { roadmap: true, summary: true });
@@ -98,17 +88,16 @@ async function main(): Promise<void> {
98
88
 
99
89
  parkMilestone(b, 'M002', 'testing');
100
90
  const s = await deriveState(b);
101
- assertEq(s.registry.find(e => e.id === 'M003')?.status, 'pending', 'M003 pending when M002 parked');
91
+ assert.deepStrictEqual(s.registry.find(e => e.id === 'M003')?.status, 'pending', 'M003 pending when M002 parked');
102
92
  // System should be blocked since M003 deps unmet and M002 is parked
103
- assert(s.activeMilestone === null, 'no active milestone (M002 parked, M003 dep-blocked)');
93
+ assert.ok(s.activeMilestone === null, 'no active milestone (M002 parked, M003 dep-blocked)');
104
94
  } finally {
105
95
  cleanup(b);
106
96
  }
107
- }
97
+ });
108
98
 
109
99
  // ─── EDGE 3: Discard active, next (no deps) activates ────────────────
110
- console.log('\n=== EDGE 3: Discard active → next activates ===');
111
- {
100
+ test('EDGE 3: Discard active → next activates', async () => {
112
101
  const b = createFixture();
113
102
  try {
114
103
  createM(b, 'M001', { roadmap: true });
@@ -117,16 +106,15 @@ async function main(): Promise<void> {
117
106
 
118
107
  discardMilestone(b, 'M001');
119
108
  const s = await deriveState(b);
120
- assertEq(s.activeMilestone?.id, 'M002', 'M002 becomes active');
121
- assert(s.phase !== 'blocked', 'not blocked');
109
+ assert.deepStrictEqual(s.activeMilestone?.id, 'M002', 'M002 becomes active');
110
+ assert.ok(s.phase !== 'blocked', 'not blocked');
122
111
  } finally {
123
112
  cleanup(b);
124
113
  }
125
- }
114
+ });
126
115
 
127
116
  // ─── EDGE 4: Park all + discard all → clean pre-planning ─────────────
128
- console.log('\n=== EDGE 4: Park all → discard all → clean state ===');
129
- {
117
+ test('EDGE 4: Park all → discard all → clean state', async () => {
130
118
  const b = createFixture();
131
119
  try {
132
120
  createM(b, 'M001', { roadmap: true });
@@ -138,30 +126,28 @@ async function main(): Promise<void> {
138
126
  discardMilestone(b, 'M001');
139
127
  discardMilestone(b, 'M002');
140
128
  const s = await deriveState(b);
141
- assertEq(s.activeMilestone, null, 'no active milestone');
142
- assertEq(s.phase, 'pre-planning', 'phase is pre-planning');
143
- assertEq(s.registry.length, 0, 'empty registry');
144
- assert(s.nextAction.includes('No milestones'), 'nextAction mentions no milestones');
129
+ assert.deepStrictEqual(s.activeMilestone, null, 'no active milestone');
130
+ assert.deepStrictEqual(s.phase, 'pre-planning', 'phase is pre-planning');
131
+ assert.deepStrictEqual(s.registry.length, 0, 'empty registry');
132
+ assert.ok(s.nextAction.includes('No milestones'), 'nextAction mentions no milestones');
145
133
  } finally {
146
134
  cleanup(b);
147
135
  }
148
- }
136
+ });
149
137
 
150
138
  // ─── EDGE 5: Discard non-existent → graceful false ───────────────────
151
- console.log('\n=== EDGE 5: Discard non-existent ===');
152
- {
139
+ test('EDGE 5: Discard non-existent', () => {
153
140
  const b = createFixture();
154
141
  try {
155
142
  const result = discardMilestone(b, 'M999');
156
- assert(!result, 'returns false for non-existent');
143
+ assert.ok(!result, 'returns false for non-existent');
157
144
  } finally {
158
145
  cleanup(b);
159
146
  }
160
- }
147
+ });
161
148
 
162
149
  // ─── EDGE 6: Queue order survives discards ───────────────────────────
163
- console.log('\n=== EDGE 6: Queue order after discard ===');
164
- {
150
+ test('EDGE 6: Queue order after discard', async () => {
165
151
  const b = createFixture();
166
152
  try {
167
153
  createM(b, 'M001', { roadmap: true });
@@ -176,24 +162,23 @@ async function main(): Promise<void> {
176
162
 
177
163
  // With custom queue order, M003 should be active first
178
164
  let s = await deriveState(b);
179
- assertEq(s.activeMilestone?.id, 'M003', 'M003 active (custom queue order)');
165
+ assert.deepStrictEqual(s.activeMilestone?.id, 'M003', 'M003 active (custom queue order)');
180
166
 
181
167
  // Discard M003 → M001 should be next per queue order
182
168
  discardMilestone(b, 'M003');
183
169
  s = await deriveState(b);
184
- assertEq(s.activeMilestone?.id, 'M001', 'M001 active after M003 discarded');
170
+ assert.deepStrictEqual(s.activeMilestone?.id, 'M001', 'M001 active after M003 discarded');
185
171
 
186
172
  // Verify queue order file was updated
187
173
  const order = JSON.parse(readFileSync(join(b, '.gsd', 'QUEUE-ORDER.json'), 'utf-8'));
188
- assert(!order.order.includes('M003'), 'M003 removed from QUEUE-ORDER.json');
174
+ assert.ok(!order.order.includes('M003'), 'M003 removed from QUEUE-ORDER.json');
189
175
  } finally {
190
176
  cleanup(b);
191
177
  }
192
- }
178
+ });
193
179
 
194
180
  // ─── EDGE 7: Discard milestone that has deps on others ───────────────
195
- console.log('\n=== EDGE 7: Discard a milestone that depends on others ===');
196
- {
181
+ test('EDGE 7: Discard a milestone that depends on others', async () => {
197
182
  const b = createFixture();
198
183
  try {
199
184
  createM(b, 'M001', { roadmap: true });
@@ -203,23 +188,22 @@ async function main(): Promise<void> {
203
188
 
204
189
  // M002 depends on M001, so M001 is active, M002 is pending
205
190
  let s = await deriveState(b);
206
- assertEq(s.activeMilestone?.id, 'M001', 'M001 is active');
207
- assertEq(s.registry.find(e => e.id === 'M002')?.status, 'pending', 'M002 pending (dep on M001)');
191
+ assert.deepStrictEqual(s.activeMilestone?.id, 'M001', 'M001 is active');
192
+ assert.deepStrictEqual(s.registry.find(e => e.id === 'M002')?.status, 'pending', 'M002 pending (dep on M001)');
208
193
 
209
194
  // Discard M002 (the one WITH deps) — should be fine, M003 becomes pending
210
195
  discardMilestone(b, 'M002');
211
196
  s = await deriveState(b);
212
- assertEq(s.activeMilestone?.id, 'M001', 'M001 still active');
213
- assert(!s.registry.some(e => e.id === 'M002'), 'M002 gone from registry');
214
- assertEq(s.registry.find(e => e.id === 'M003')?.status, 'pending', 'M003 is pending (after M001)');
197
+ assert.deepStrictEqual(s.activeMilestone?.id, 'M001', 'M001 still active');
198
+ assert.ok(!s.registry.some(e => e.id === 'M002'), 'M002 gone from registry');
199
+ assert.deepStrictEqual(s.registry.find(e => e.id === 'M003')?.status, 'pending', 'M003 is pending (after M001)');
215
200
  } finally {
216
201
  cleanup(b);
217
202
  }
218
- }
203
+ });
219
204
 
220
205
  // ─── EDGE 8: Park → Discard → state transitions ─────────────────────
221
- console.log('\n=== EDGE 8: Park then discard same milestone ===');
222
- {
206
+ test('EDGE 8: Park then discard same milestone', async () => {
223
207
  const b = createFixture();
224
208
  try {
225
209
  createM(b, 'M001', { roadmap: true });
@@ -228,22 +212,21 @@ async function main(): Promise<void> {
228
212
 
229
213
  parkMilestone(b, 'M001', 'temp');
230
214
  let s = await deriveState(b);
231
- assertEq(s.activeMilestone?.id, 'M002', 'M002 active while M001 parked');
215
+ assert.deepStrictEqual(s.activeMilestone?.id, 'M002', 'M002 active while M001 parked');
232
216
 
233
217
  // Now discard the parked milestone
234
218
  discardMilestone(b, 'M001');
235
219
  s = await deriveState(b);
236
- assertEq(s.activeMilestone?.id, 'M002', 'M002 still active');
237
- assert(!s.registry.some(e => e.id === 'M001'), 'M001 gone completely');
238
- assertEq(s.registry.length, 1, 'only M002 in registry');
220
+ assert.deepStrictEqual(s.activeMilestone?.id, 'M002', 'M002 still active');
221
+ assert.ok(!s.registry.some(e => e.id === 'M001'), 'M001 gone completely');
222
+ assert.deepStrictEqual(s.registry.length, 1, 'only M002 in registry');
239
223
  } finally {
240
224
  cleanup(b);
241
225
  }
242
- }
226
+ });
243
227
 
244
228
  // ─── EDGE 9: Complete + parked + pending coexist ─────────────────────
245
- console.log('\n=== EDGE 9: Mixed states — complete + parked + active ===');
246
- {
229
+ test('EDGE 9: Mixed states — complete + parked + active', async () => {
247
230
  const b = createFixture();
248
231
  try {
249
232
  createM(b, 'M001', { roadmap: true, summary: true }); // complete
@@ -254,23 +237,17 @@ async function main(): Promise<void> {
254
237
 
255
238
  parkMilestone(b, 'M002', 'parked');
256
239
  const s = await deriveState(b);
257
- assertEq(s.registry.find(e => e.id === 'M001')?.status, 'complete', 'M001 complete');
258
- assertEq(s.registry.find(e => e.id === 'M002')?.status, 'parked', 'M002 parked');
259
- assertEq(s.registry.find(e => e.id === 'M003')?.status, 'active', 'M003 active');
260
- assertEq(s.registry.find(e => e.id === 'M004')?.status, 'pending', 'M004 pending');
261
- assertEq(s.activeMilestone?.id, 'M003', 'M003 is the active milestone');
262
- assertEq(s.progress?.milestones.done, 1, '1 done');
263
- assertEq(s.progress?.milestones.total, 4, '4 total');
240
+ assert.deepStrictEqual(s.registry.find(e => e.id === 'M001')?.status, 'complete', 'M001 complete');
241
+ assert.deepStrictEqual(s.registry.find(e => e.id === 'M002')?.status, 'parked', 'M002 parked');
242
+ assert.deepStrictEqual(s.registry.find(e => e.id === 'M003')?.status, 'active', 'M003 active');
243
+ assert.deepStrictEqual(s.registry.find(e => e.id === 'M004')?.status, 'pending', 'M004 pending');
244
+ assert.deepStrictEqual(s.activeMilestone?.id, 'M003', 'M003 is the active milestone');
245
+ assert.deepStrictEqual(s.progress?.milestones.done, 1, '1 done');
246
+ assert.deepStrictEqual(s.progress?.milestones.total, 4, '4 total');
264
247
  } finally {
265
248
  cleanup(b);
266
249
  }
267
- }
250
+ });
268
251
 
269
- // ═══════════════════════════════════════════════════════════════════════
270
- console.log(`\n${'='.repeat(50)}`);
271
- console.log(`Results: ${passed} passed, ${failed} failed`);
272
- if (failed > 0) process.exit(1);
273
- else console.log('All edge cases passed!');
274
- }
252
+ });
275
253
 
276
- main().catch(e => { console.error(e); process.exit(1); });