gsd-pi 2.44.0-dev.848dd4c → 2.44.0

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 (298) hide show
  1. package/README.md +12 -30
  2. package/dist/resources/extensions/gsd/auto-start.js +0 -10
  3. package/dist/resources/extensions/gsd/commands/handlers/workflow.js +0 -5
  4. package/dist/web/standalone/.next/BUILD_ID +1 -1
  5. package/dist/web/standalone/.next/app-path-routes-manifest.json +14 -14
  6. package/dist/web/standalone/.next/build-manifest.json +3 -3
  7. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  8. package/dist/web/standalone/.next/required-server-files.json +3 -3
  9. package/dist/web/standalone/.next/server/app/_global-error/page.js +3 -3
  10. package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  11. package/dist/web/standalone/.next/server/app/_global-error.html +2 -2
  12. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  13. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  14. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  15. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  16. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  17. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  18. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  19. package/dist/web/standalone/.next/server/app/_not-found/page.js +2 -2
  20. package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  21. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  22. package/dist/web/standalone/.next/server/app/_not-found.rsc +3 -3
  23. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +3 -3
  24. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  25. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +3 -3
  26. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  27. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  28. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  29. package/dist/web/standalone/.next/server/app/api/boot/route.js +1 -1
  30. package/dist/web/standalone/.next/server/app/api/boot/route_client-reference-manifest.js +1 -1
  31. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js +1 -1
  32. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route_client-reference-manifest.js +1 -1
  33. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js +1 -1
  34. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route_client-reference-manifest.js +1 -1
  35. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js +2 -2
  36. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route_client-reference-manifest.js +1 -1
  37. package/dist/web/standalone/.next/server/app/api/browse-directories/route.js +1 -1
  38. package/dist/web/standalone/.next/server/app/api/browse-directories/route_client-reference-manifest.js +1 -1
  39. package/dist/web/standalone/.next/server/app/api/captures/route.js +1 -1
  40. package/dist/web/standalone/.next/server/app/api/captures/route_client-reference-manifest.js +1 -1
  41. package/dist/web/standalone/.next/server/app/api/cleanup/route.js +1 -1
  42. package/dist/web/standalone/.next/server/app/api/cleanup/route_client-reference-manifest.js +1 -1
  43. package/dist/web/standalone/.next/server/app/api/dev-mode/route.js +1 -1
  44. package/dist/web/standalone/.next/server/app/api/dev-mode/route_client-reference-manifest.js +1 -1
  45. package/dist/web/standalone/.next/server/app/api/doctor/route.js +1 -1
  46. package/dist/web/standalone/.next/server/app/api/doctor/route_client-reference-manifest.js +1 -1
  47. package/dist/web/standalone/.next/server/app/api/export-data/route.js +1 -1
  48. package/dist/web/standalone/.next/server/app/api/export-data/route_client-reference-manifest.js +1 -1
  49. package/dist/web/standalone/.next/server/app/api/files/route.js +1 -1
  50. package/dist/web/standalone/.next/server/app/api/files/route_client-reference-manifest.js +1 -1
  51. package/dist/web/standalone/.next/server/app/api/forensics/route.js +1 -1
  52. package/dist/web/standalone/.next/server/app/api/forensics/route_client-reference-manifest.js +1 -1
  53. package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
  54. package/dist/web/standalone/.next/server/app/api/git/route_client-reference-manifest.js +1 -1
  55. package/dist/web/standalone/.next/server/app/api/history/route.js +1 -1
  56. package/dist/web/standalone/.next/server/app/api/history/route_client-reference-manifest.js +1 -1
  57. package/dist/web/standalone/.next/server/app/api/hooks/route.js +1 -1
  58. package/dist/web/standalone/.next/server/app/api/hooks/route_client-reference-manifest.js +1 -1
  59. package/dist/web/standalone/.next/server/app/api/inspect/route.js +1 -1
  60. package/dist/web/standalone/.next/server/app/api/inspect/route_client-reference-manifest.js +1 -1
  61. package/dist/web/standalone/.next/server/app/api/knowledge/route.js +1 -1
  62. package/dist/web/standalone/.next/server/app/api/knowledge/route_client-reference-manifest.js +1 -1
  63. package/dist/web/standalone/.next/server/app/api/live-state/route.js +1 -1
  64. package/dist/web/standalone/.next/server/app/api/live-state/route_client-reference-manifest.js +1 -1
  65. package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
  66. package/dist/web/standalone/.next/server/app/api/onboarding/route_client-reference-manifest.js +1 -1
  67. package/dist/web/standalone/.next/server/app/api/preferences/route.js +1 -1
  68. package/dist/web/standalone/.next/server/app/api/preferences/route_client-reference-manifest.js +1 -1
  69. package/dist/web/standalone/.next/server/app/api/projects/route.js +1 -1
  70. package/dist/web/standalone/.next/server/app/api/projects/route_client-reference-manifest.js +1 -1
  71. package/dist/web/standalone/.next/server/app/api/recovery/route.js +1 -1
  72. package/dist/web/standalone/.next/server/app/api/recovery/route_client-reference-manifest.js +1 -1
  73. package/dist/web/standalone/.next/server/app/api/remote-questions/route.js +5 -5
  74. package/dist/web/standalone/.next/server/app/api/remote-questions/route_client-reference-manifest.js +1 -1
  75. package/dist/web/standalone/.next/server/app/api/session/browser/route.js +1 -1
  76. package/dist/web/standalone/.next/server/app/api/session/browser/route_client-reference-manifest.js +1 -1
  77. package/dist/web/standalone/.next/server/app/api/session/command/route.js +1 -1
  78. package/dist/web/standalone/.next/server/app/api/session/command/route_client-reference-manifest.js +1 -1
  79. package/dist/web/standalone/.next/server/app/api/session/events/route.js +2 -2
  80. package/dist/web/standalone/.next/server/app/api/session/events/route_client-reference-manifest.js +1 -1
  81. package/dist/web/standalone/.next/server/app/api/session/manage/route.js +1 -1
  82. package/dist/web/standalone/.next/server/app/api/session/manage/route_client-reference-manifest.js +1 -1
  83. package/dist/web/standalone/.next/server/app/api/settings-data/route.js +1 -1
  84. package/dist/web/standalone/.next/server/app/api/settings-data/route_client-reference-manifest.js +1 -1
  85. package/dist/web/standalone/.next/server/app/api/shutdown/route.js +1 -1
  86. package/dist/web/standalone/.next/server/app/api/shutdown/route_client-reference-manifest.js +1 -1
  87. package/dist/web/standalone/.next/server/app/api/skill-health/route.js +1 -1
  88. package/dist/web/standalone/.next/server/app/api/skill-health/route_client-reference-manifest.js +1 -1
  89. package/dist/web/standalone/.next/server/app/api/steer/route.js +1 -1
  90. package/dist/web/standalone/.next/server/app/api/steer/route_client-reference-manifest.js +1 -1
  91. package/dist/web/standalone/.next/server/app/api/switch-root/route.js +1 -1
  92. package/dist/web/standalone/.next/server/app/api/switch-root/route_client-reference-manifest.js +1 -1
  93. package/dist/web/standalone/.next/server/app/api/terminal/input/route.js +2 -2
  94. package/dist/web/standalone/.next/server/app/api/terminal/input/route_client-reference-manifest.js +1 -1
  95. package/dist/web/standalone/.next/server/app/api/terminal/resize/route.js +2 -2
  96. package/dist/web/standalone/.next/server/app/api/terminal/resize/route_client-reference-manifest.js +1 -1
  97. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js +2 -2
  98. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route_client-reference-manifest.js +1 -1
  99. package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js +4 -4
  100. package/dist/web/standalone/.next/server/app/api/terminal/stream/route_client-reference-manifest.js +1 -1
  101. package/dist/web/standalone/.next/server/app/api/terminal/upload/route.js +1 -1
  102. package/dist/web/standalone/.next/server/app/api/terminal/upload/route_client-reference-manifest.js +1 -1
  103. package/dist/web/standalone/.next/server/app/api/undo/route.js +1 -1
  104. package/dist/web/standalone/.next/server/app/api/undo/route_client-reference-manifest.js +1 -1
  105. package/dist/web/standalone/.next/server/app/api/update/route.js +1 -1
  106. package/dist/web/standalone/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
  107. package/dist/web/standalone/.next/server/app/api/visualizer/route.js +1 -1
  108. package/dist/web/standalone/.next/server/app/api/visualizer/route_client-reference-manifest.js +1 -1
  109. package/dist/web/standalone/.next/server/app/index.html +1 -1
  110. package/dist/web/standalone/.next/server/app/index.rsc +4 -4
  111. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  112. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +4 -4
  113. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  114. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +3 -3
  115. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  116. package/dist/web/standalone/.next/server/app/page.js +2 -2
  117. package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  118. package/dist/web/standalone/.next/server/app-paths-manifest.json +14 -14
  119. package/dist/web/standalone/.next/server/chunks/229.js +1 -1
  120. package/dist/web/standalone/.next/server/chunks/471.js +3 -3
  121. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  122. package/dist/web/standalone/.next/server/middleware.js +2 -2
  123. package/dist/web/standalone/.next/server/next-font-manifest.js +1 -1
  124. package/dist/web/standalone/.next/server/next-font-manifest.json +1 -1
  125. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  126. package/dist/web/standalone/.next/server/pages/500.html +2 -2
  127. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  128. package/dist/web/standalone/.next/static/chunks/app/_not-found/{page-f2a7482d42a5614b.js → page-2f24283c162b6ab3.js} +1 -1
  129. package/dist/web/standalone/.next/static/chunks/app/{layout-a16c7a7ecdf0c2cf.js → layout-9ecfd95f343793f0.js} +1 -1
  130. package/dist/web/standalone/.next/static/chunks/app/page-7e9530a7122506c5.js +1 -0
  131. package/dist/web/standalone/.next/static/chunks/main-app-d3d4c336195465f9.js +1 -0
  132. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-ab5a8926e07ec673.js +1 -0
  133. package/dist/web/standalone/node_modules/node-pty/build/Makefile +2 -2
  134. package/dist/web/standalone/node_modules/node-pty/build/Release/pty.node +0 -0
  135. package/dist/web/standalone/node_modules/node-pty/build/pty.target.mk +14 -14
  136. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api.target.mk +14 -14
  137. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_except.target.mk +14 -14
  138. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_maybe.target.mk +14 -14
  139. package/dist/web/standalone/server.js +1 -1
  140. package/package.json +1 -1
  141. package/packages/pi-coding-agent/dist/core/auth-storage.test.js +8 -6
  142. package/packages/pi-coding-agent/dist/core/auth-storage.test.js.map +1 -1
  143. package/packages/pi-coding-agent/dist/core/extensions/runner.test.js +26 -24
  144. package/packages/pi-coding-agent/dist/core/extensions/runner.test.js.map +1 -1
  145. package/packages/pi-coding-agent/dist/core/fs-utils.test.js +48 -29
  146. package/packages/pi-coding-agent/dist/core/fs-utils.test.js.map +1 -1
  147. package/packages/pi-coding-agent/dist/core/resolve-config-value.test.js +44 -34
  148. package/packages/pi-coding-agent/dist/core/resolve-config-value.test.js.map +1 -1
  149. package/packages/pi-coding-agent/dist/core/session-manager.test.js +34 -30
  150. package/packages/pi-coding-agent/dist/core/session-manager.test.js.map +1 -1
  151. package/packages/pi-coding-agent/dist/core/tools/edit-diff.test.js +12 -10
  152. package/packages/pi-coding-agent/dist/core/tools/edit-diff.test.js.map +1 -1
  153. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.test.js +47 -43
  154. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.test.js.map +1 -1
  155. package/packages/pi-coding-agent/src/core/auth-storage.test.ts +7 -7
  156. package/packages/pi-coding-agent/src/core/extensions/runner.test.ts +26 -26
  157. package/packages/pi-coding-agent/src/core/fs-utils.test.ts +43 -31
  158. package/packages/pi-coding-agent/src/core/resolve-config-value.test.ts +45 -40
  159. package/packages/pi-coding-agent/src/core/session-manager.test.ts +33 -33
  160. package/packages/pi-coding-agent/src/core/tools/edit-diff.test.ts +17 -17
  161. package/packages/pi-coding-agent/src/resources/extensions/memory/storage.test.ts +74 -74
  162. package/src/resources/extensions/gsd/auto-start.ts +0 -14
  163. package/src/resources/extensions/gsd/commands/handlers/workflow.ts +0 -8
  164. package/src/resources/extensions/gsd/tests/all-milestones-complete-merge.test.ts +99 -99
  165. package/src/resources/extensions/gsd/tests/auto-lock-creation.test.ts +16 -14
  166. package/src/resources/extensions/gsd/tests/auto-paused-session-validation.test.ts +57 -43
  167. package/src/resources/extensions/gsd/tests/auto-preflight.test.ts +13 -11
  168. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +523 -465
  169. package/src/resources/extensions/gsd/tests/auto-secrets-gate.test.ts +75 -73
  170. package/src/resources/extensions/gsd/tests/auto-start-needs-discussion.test.ts +56 -34
  171. package/src/resources/extensions/gsd/tests/auto-worktree-milestone-merge.test.ts +656 -533
  172. package/src/resources/extensions/gsd/tests/auto-worktree.test.ts +143 -165
  173. package/src/resources/extensions/gsd/tests/cache-staleness-regression.test.ts +52 -29
  174. package/src/resources/extensions/gsd/tests/captures.test.ts +176 -148
  175. package/src/resources/extensions/gsd/tests/claude-import-tui.test.ts +33 -32
  176. package/src/resources/extensions/gsd/tests/collect-from-manifest.test.ts +143 -141
  177. package/src/resources/extensions/gsd/tests/commands-inspect-open-db.test.ts +25 -25
  178. package/src/resources/extensions/gsd/tests/commands-logs.test.ts +81 -81
  179. package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +59 -38
  180. package/src/resources/extensions/gsd/tests/complete-slice.test.ts +263 -228
  181. package/src/resources/extensions/gsd/tests/complete-task.test.ts +302 -250
  182. package/src/resources/extensions/gsd/tests/context-store.test.ts +367 -354
  183. package/src/resources/extensions/gsd/tests/continue-here.test.ts +72 -68
  184. package/src/resources/extensions/gsd/tests/cost-projection.test.ts +106 -92
  185. package/src/resources/extensions/gsd/tests/crash-recovery.test.ts +35 -27
  186. package/src/resources/extensions/gsd/tests/dashboard-budget.test.ts +237 -220
  187. package/src/resources/extensions/gsd/tests/db-writer.test.ts +420 -390
  188. package/src/resources/extensions/gsd/tests/definition-loader.test.ts +92 -76
  189. package/src/resources/extensions/gsd/tests/derive-state-crossval.test.ts +83 -68
  190. package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +183 -152
  191. package/src/resources/extensions/gsd/tests/derive-state-deps.test.ts +101 -78
  192. package/src/resources/extensions/gsd/tests/derive-state.test.ts +227 -192
  193. package/src/resources/extensions/gsd/tests/detection.test.ts +278 -232
  194. package/src/resources/extensions/gsd/tests/dev-engine-wrapper.test.ts +34 -30
  195. package/src/resources/extensions/gsd/tests/dispatch-guard.test.ts +180 -164
  196. package/src/resources/extensions/gsd/tests/dispatch-missing-task-plans.test.ts +49 -43
  197. package/src/resources/extensions/gsd/tests/dispatch-uat-last-completed.test.ts +32 -28
  198. package/src/resources/extensions/gsd/tests/doctor-completion-deferral.test.ts +29 -27
  199. package/src/resources/extensions/gsd/tests/doctor-delimiter-fix.test.ts +38 -34
  200. package/src/resources/extensions/gsd/tests/doctor-enhancements.test.ts +75 -54
  201. package/src/resources/extensions/gsd/tests/doctor-environment-worktree.test.ts +32 -21
  202. package/src/resources/extensions/gsd/tests/doctor-environment.test.ts +97 -72
  203. package/src/resources/extensions/gsd/tests/doctor-fixlevel.test.ts +44 -38
  204. package/src/resources/extensions/gsd/tests/doctor-git.test.ts +145 -104
  205. package/src/resources/extensions/gsd/tests/doctor-proactive.test.ts +106 -84
  206. package/src/resources/extensions/gsd/tests/doctor-roadmap-summary-atomicity.test.ts +60 -54
  207. package/src/resources/extensions/gsd/tests/doctor-runtime.test.ts +93 -72
  208. package/src/resources/extensions/gsd/tests/doctor.test.ts +134 -104
  209. package/src/resources/extensions/gsd/tests/ensure-db-open.test.ts +131 -123
  210. package/src/resources/extensions/gsd/tests/exit-command.test.ts +24 -20
  211. package/src/resources/extensions/gsd/tests/feature-branch-lifecycle-integration.test.ts +57 -48
  212. package/src/resources/extensions/gsd/tests/files-loadfile-eisdir.test.ts +7 -5
  213. package/src/resources/extensions/gsd/tests/flag-file-db.test.ts +42 -30
  214. package/src/resources/extensions/gsd/tests/freeform-decisions.test.ts +206 -198
  215. package/src/resources/extensions/gsd/tests/git-locale.test.ts +27 -13
  216. package/src/resources/extensions/gsd/tests/git-service.test.ts +388 -285
  217. package/src/resources/extensions/gsd/tests/gitignore-tracked-gsd.test.ts +39 -31
  218. package/src/resources/extensions/gsd/tests/graph-operations.test.ts +69 -63
  219. package/src/resources/extensions/gsd/tests/gsd-db.test.ts +264 -255
  220. package/src/resources/extensions/gsd/tests/gsd-inspect.test.ts +119 -108
  221. package/src/resources/extensions/gsd/tests/gsd-recover.test.ts +103 -81
  222. package/src/resources/extensions/gsd/tests/gsd-tools.test.ts +262 -229
  223. package/src/resources/extensions/gsd/tests/headless-answers.test.ts +13 -13
  224. package/src/resources/extensions/gsd/tests/health-widget.test.ts +37 -29
  225. package/src/resources/extensions/gsd/tests/idle-recovery.test.ts +102 -81
  226. package/src/resources/extensions/gsd/tests/init-wizard.test.ts +18 -16
  227. package/src/resources/extensions/gsd/tests/integration-edge.test.ts +46 -41
  228. package/src/resources/extensions/gsd/tests/integration-lifecycle.test.ts +53 -42
  229. package/src/resources/extensions/gsd/tests/integration-mixed-milestones.test.ts +91 -75
  230. package/src/resources/extensions/gsd/tests/integration-proof.test.ts +18 -18
  231. package/src/resources/extensions/gsd/tests/markdown-renderer.test.ts +194 -150
  232. package/src/resources/extensions/gsd/tests/md-importer.test.ts +125 -101
  233. package/src/resources/extensions/gsd/tests/memory-extractor.test.ts +54 -45
  234. package/src/resources/extensions/gsd/tests/memory-store.test.ts +93 -80
  235. package/src/resources/extensions/gsd/tests/migrate-command.test.ts +66 -57
  236. package/src/resources/extensions/gsd/tests/migrate-hierarchy.test.ts +93 -83
  237. package/src/resources/extensions/gsd/tests/migrate-parser.test.ts +170 -161
  238. package/src/resources/extensions/gsd/tests/migrate-transformer.test.ts +141 -125
  239. package/src/resources/extensions/gsd/tests/migrate-validator-parsers.test.ts +131 -107
  240. package/src/resources/extensions/gsd/tests/migrate-writer-integration.test.ts +96 -87
  241. package/src/resources/extensions/gsd/tests/migrate-writer.test.ts +164 -125
  242. package/src/resources/extensions/gsd/tests/must-have-parser.test.ts +94 -81
  243. package/src/resources/extensions/gsd/tests/none-mode-gates.test.ts +36 -35
  244. package/src/resources/extensions/gsd/tests/overrides.test.ts +106 -99
  245. package/src/resources/extensions/gsd/tests/parallel-crash-recovery.test.ts +47 -40
  246. package/src/resources/extensions/gsd/tests/parallel-worker-monitoring.test.ts +28 -25
  247. package/src/resources/extensions/gsd/tests/parallel-workers-multi-milestone-e2e.test.ts +83 -66
  248. package/src/resources/extensions/gsd/tests/park-edge-cases.test.ts +77 -54
  249. package/src/resources/extensions/gsd/tests/park-milestone.test.ts +115 -68
  250. package/src/resources/extensions/gsd/tests/parsers.test.ts +611 -546
  251. package/src/resources/extensions/gsd/tests/paths.test.ts +87 -72
  252. package/src/resources/extensions/gsd/tests/post-unit-hooks.test.ts +117 -77
  253. package/src/resources/extensions/gsd/tests/prompt-db.test.ts +56 -56
  254. package/src/resources/extensions/gsd/tests/queue-draft-detection.test.ts +119 -93
  255. package/src/resources/extensions/gsd/tests/queue-order.test.ts +82 -70
  256. package/src/resources/extensions/gsd/tests/queue-reorder-e2e.test.ts +55 -42
  257. package/src/resources/extensions/gsd/tests/quick-branch-lifecycle.test.ts +73 -45
  258. package/src/resources/extensions/gsd/tests/reassess-prompt.test.ts +38 -28
  259. package/src/resources/extensions/gsd/tests/replan-slice.test.ts +80 -73
  260. package/src/resources/extensions/gsd/tests/repo-identity-worktree.test.ts +74 -71
  261. package/src/resources/extensions/gsd/tests/requirements.test.ts +75 -70
  262. package/src/resources/extensions/gsd/tests/retry-state-reset.test.ts +66 -44
  263. package/src/resources/extensions/gsd/tests/roadmap-parse-regression.test.ts +181 -114
  264. package/src/resources/extensions/gsd/tests/rule-registry.test.ts +65 -63
  265. package/src/resources/extensions/gsd/tests/run-uat.test.ts +128 -66
  266. package/src/resources/extensions/gsd/tests/session-lock-multipath.test.ts +25 -18
  267. package/src/resources/extensions/gsd/tests/session-lock-regression.test.ts +44 -37
  268. package/src/resources/extensions/gsd/tests/shared-wal.test.ts +26 -19
  269. package/src/resources/extensions/gsd/tests/stalled-tool-recovery.test.ts +8 -6
  270. package/src/resources/extensions/gsd/tests/symlink-numbered-variants.test.ts +28 -22
  271. package/src/resources/extensions/gsd/tests/token-savings.test.ts +56 -54
  272. package/src/resources/extensions/gsd/tests/tool-call-loop-guard.test.ts +25 -23
  273. package/src/resources/extensions/gsd/tests/tool-naming.test.ts +11 -9
  274. package/src/resources/extensions/gsd/tests/unique-milestone-ids.test.ts +82 -66
  275. package/src/resources/extensions/gsd/tests/unit-runtime.test.ts +47 -46
  276. package/src/resources/extensions/gsd/tests/visualizer-critical-path.test.ts +22 -20
  277. package/src/resources/extensions/gsd/tests/visualizer-data.test.ts +86 -84
  278. package/src/resources/extensions/gsd/tests/visualizer-overlay.test.ts +43 -41
  279. package/src/resources/extensions/gsd/tests/visualizer-views.test.ts +96 -94
  280. package/src/resources/extensions/gsd/tests/windows-path-normalization.test.ts +13 -11
  281. package/src/resources/extensions/gsd/tests/worker-registry.test.ts +29 -27
  282. package/src/resources/extensions/gsd/tests/workflow-templates.test.ts +52 -50
  283. package/src/resources/extensions/gsd/tests/worktree-bugfix.test.ts +13 -10
  284. package/src/resources/extensions/gsd/tests/worktree-db-integration.test.ts +18 -14
  285. package/src/resources/extensions/gsd/tests/worktree-db.test.ts +39 -38
  286. package/src/resources/extensions/gsd/tests/worktree-e2e.test.ts +21 -17
  287. package/src/resources/extensions/gsd/tests/worktree-health.test.ts +30 -25
  288. package/src/resources/extensions/gsd/tests/worktree-integration.test.ts +37 -30
  289. package/src/resources/extensions/gsd/tests/worktree-symlink-removal.test.ts +22 -15
  290. package/src/resources/extensions/gsd/tests/worktree-sync-milestones.test.ts +66 -59
  291. package/src/resources/extensions/gsd/tests/worktree.test.ts +50 -44
  292. package/dist/web/standalone/.next/static/chunks/app/page-b9367c5ae13b99c6.js +0 -1
  293. package/dist/web/standalone/.next/static/chunks/main-app-fdab67f7802d7832.js +0 -1
  294. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-459824ffb8c323dd.js +0 -1
  295. package/src/resources/extensions/gsd/tests/quick-auto-guard.test.ts +0 -100
  296. package/src/resources/extensions/gsd/tests/sqlite-unavailable-gate.test.ts +0 -63
  297. /package/dist/web/standalone/.next/static/{-zps1Q9mQmioAKLcQiCr8 → mgkxN0mGP6gSUmGPEzbk_}/_buildManifest.js +0 -0
  298. /package/dist/web/standalone/.next/static/{-zps1Q9mQmioAKLcQiCr8 → mgkxN0mGP6gSUmGPEzbk_}/_ssgManifest.js +0 -0
@@ -1,14 +1,15 @@
1
1
  // GSD Extension - Override Tests
2
2
  // Tests for parseOverrides, appendOverride, loadActiveOverrides, formatOverridesSection, resolveAllOverrides
3
3
 
4
- import { describe, test, afterEach } from 'node:test';
5
- import assert from 'node:assert/strict';
6
4
  import { mkdtempSync, mkdirSync, readFileSync, writeFileSync, rmSync } from "node:fs";
7
5
  import { join } from "node:path";
8
6
  import { tmpdir } from "node:os";
7
+ import { createTestContext } from './test-helpers.ts';
9
8
  import { parseOverrides, appendOverride, loadActiveOverrides, formatOverridesSection, resolveAllOverrides } from '../files.ts';
10
9
  import type { Override } from '../files.ts';
11
10
 
11
+ const { assertEq, assertTrue, assertMatch, assertNoMatch, report } = createTestContext();
12
+
12
13
  const tempDirs: string[] = [];
13
14
 
14
15
  function makeTempDir(prefix: string): string {
@@ -25,100 +26,106 @@ function cleanup(): void {
25
26
  tempDirs.length = 0;
26
27
  }
27
28
 
28
- describe('overrides', () => {
29
- afterEach(() => cleanup());
30
-
31
- test('parseOverrides: empty content', () => {
32
- const result = parseOverrides(""); assert.deepStrictEqual(result.length, 0, "empty content returns no overrides");
33
- });
34
-
35
- test('parseOverrides: single active override', () => {
36
- const content = `# GSD Overrides\n\nUser-issued overrides that supersede plan document content.\n\n---\n\n## Override: 2026-03-14T10:00:00.000Z\n\n**Change:** Use Postgres instead of SQLite\n**Scope:** active\n**Applied-at:** M001/S02/T03\n\n---\n`;
37
- const result = parseOverrides(content);
38
- assert.deepStrictEqual(result.length, 1, "parses one override");
39
- assert.deepStrictEqual(result[0].timestamp, "2026-03-14T10:00:00.000Z", "correct timestamp");
40
- assert.deepStrictEqual(result[0].change, "Use Postgres instead of SQLite", "correct change");
41
- assert.deepStrictEqual(result[0].scope, "active", "correct scope");
42
- assert.deepStrictEqual(result[0].appliedAt, "M001/S02/T03", "correct appliedAt");
43
- });
44
-
45
- test('parseOverrides: multiple overrides, mixed scopes', () => {
46
- const content = `# GSD Overrides\n\n---\n\n## Override: 2026-03-14T10:00:00.000Z\n\n**Change:** Use Postgres instead of SQLite\n**Scope:** resolved\n**Applied-at:** M001/S02/T03\n\n---\n\n## Override: 2026-03-14T11:00:00.000Z\n\n**Change:** Use JWT instead of session cookies\n**Scope:** active\n**Applied-at:** M001/S03/T01\n\n---\n`;
47
- const result = parseOverrides(content);
48
- assert.deepStrictEqual(result.length, 2, "parses two overrides");
49
- assert.deepStrictEqual(result[0].scope, "resolved", "first is resolved");
50
- assert.deepStrictEqual(result[1].scope, "active", "second is active");
51
- assert.deepStrictEqual(result[1].change, "Use JWT instead of session cookies", "second change text");
52
- });
53
-
54
- test('appendOverride: creates new file', async () => {
55
- const tmp = makeTempDir("append-new");
56
- await appendOverride(tmp, "Use Postgres", "M001/S01/T01");
57
- const content = readFileSync(join(tmp, ".gsd", "OVERRIDES.md"), "utf-8");
58
- assert.ok(content.includes("# GSD Overrides"), "has header");
59
- assert.ok(content.includes("**Change:** Use Postgres"), "has change");
60
- assert.ok(content.includes("**Scope:** active"), "has active scope");
61
- assert.ok(content.includes("**Applied-at:** M001/S01/T01"), "has appliedAt");
62
- });
63
-
64
- test('appendOverride: appends to existing file', async () => {
65
- const tmp = makeTempDir("append-existing");
66
- await appendOverride(tmp, "First override", "M001/S01/T01");
67
- await appendOverride(tmp, "Second override", "M001/S02/T02");
68
- const content = readFileSync(join(tmp, ".gsd", "OVERRIDES.md"), "utf-8");
69
- assert.ok(content.includes("**Change:** First override"), "has first override");
70
- assert.ok(content.includes("**Change:** Second override"), "has second override");
71
- const parsed = parseOverrides(content);
72
- assert.deepStrictEqual(parsed.length, 2, "two overrides in file");
73
- });
74
-
75
- test('loadActiveOverrides: no file', async () => {
76
- const tmp = makeTempDir("load-no-file");
77
- const result = await loadActiveOverrides(tmp);
78
- assert.deepStrictEqual(result.length, 0, "returns empty when no file");
79
- });
80
-
81
- test('loadActiveOverrides: filters to active only', async () => {
82
- const tmp = makeTempDir("load-filter");
83
- const content = `# GSD Overrides\n\n---\n\n## Override: 2026-03-14T10:00:00.000Z\n\n**Change:** Resolved change\n**Scope:** resolved\n**Applied-at:** M001/S01/T01\n\n---\n\n## Override: 2026-03-14T11:00:00.000Z\n\n**Change:** Active change\n**Scope:** active\n**Applied-at:** M001/S02/T01\n\n---\n`;
84
- writeFileSync(join(tmp, ".gsd", "OVERRIDES.md"), content, "utf-8");
85
- const result = await loadActiveOverrides(tmp);
86
- assert.deepStrictEqual(result.length, 1, "only one active override");
87
- assert.deepStrictEqual(result[0].change, "Active change", "correct active change");
88
- });
89
-
90
- test('formatOverridesSection: empty array', () => {
91
- const result = formatOverridesSection([]); assert.deepStrictEqual(result, "", "empty overrides returns empty string");
92
- });
93
-
94
- test('formatOverridesSection: formats section', () => {
95
- const overrides: Override[] = [
96
- { timestamp: "2026-03-14T10:00:00.000Z", change: "Use Postgres", scope: "active", appliedAt: "M001/S01/T01" },
97
- ];
98
- const result = formatOverridesSection(overrides);
99
- assert.ok(result.includes("## Active Overrides (supersede plan content)"), "has header");
100
- assert.ok(result.includes("**Use Postgres**"), "has change text");
101
- assert.ok(result.includes("supersede any conflicting content"), "has instruction");
102
- });
103
-
104
- test('resolveAllOverrides: marks all as resolved', async () => {
105
- const tmp = makeTempDir("resolve-all");
106
- await appendOverride(tmp, "First", "M001/S01/T01");
107
- await appendOverride(tmp, "Second", "M001/S02/T01");
108
- let active = await loadActiveOverrides(tmp);
109
- assert.deepStrictEqual(active.length, 2, "two active before resolve");
110
- await resolveAllOverrides(tmp);
111
- active = await loadActiveOverrides(tmp);
112
- assert.deepStrictEqual(active.length, 0, "no active after resolve");
113
- const content = readFileSync(join(tmp, ".gsd", "OVERRIDES.md"), "utf-8");
114
- const allOverrides = parseOverrides(content);
115
- assert.deepStrictEqual(allOverrides.length, 2, "still two overrides total");
116
- assert.ok(allOverrides.every(o => o.scope === "resolved"), "all resolved");
117
- });
118
-
119
- test('resolveAllOverrides: no file no error', async () => {
120
- const tmp = makeTempDir("resolve-no-file");
121
- await resolveAllOverrides(tmp);
122
- assert.ok(true, "resolveAllOverrides with no file does not throw");
123
- });
124
- });
29
+ console.log('\n=== parseOverrides: empty content ===');
30
+ { const result = parseOverrides(""); assertEq(result.length, 0, "empty content returns no overrides"); }
31
+
32
+ console.log('\n=== parseOverrides: single active override ===');
33
+ {
34
+ const content = `# GSD Overrides\n\nUser-issued overrides that supersede plan document content.\n\n---\n\n## Override: 2026-03-14T10:00:00.000Z\n\n**Change:** Use Postgres instead of SQLite\n**Scope:** active\n**Applied-at:** M001/S02/T03\n\n---\n`;
35
+ const result = parseOverrides(content);
36
+ assertEq(result.length, 1, "parses one override");
37
+ assertEq(result[0].timestamp, "2026-03-14T10:00:00.000Z", "correct timestamp");
38
+ assertEq(result[0].change, "Use Postgres instead of SQLite", "correct change");
39
+ assertEq(result[0].scope, "active", "correct scope");
40
+ assertEq(result[0].appliedAt, "M001/S02/T03", "correct appliedAt");
41
+ }
42
+
43
+ console.log('\n=== parseOverrides: multiple overrides, mixed scopes ===');
44
+ {
45
+ const content = `# GSD Overrides\n\n---\n\n## Override: 2026-03-14T10:00:00.000Z\n\n**Change:** Use Postgres instead of SQLite\n**Scope:** resolved\n**Applied-at:** M001/S02/T03\n\n---\n\n## Override: 2026-03-14T11:00:00.000Z\n\n**Change:** Use JWT instead of session cookies\n**Scope:** active\n**Applied-at:** M001/S03/T01\n\n---\n`;
46
+ const result = parseOverrides(content);
47
+ assertEq(result.length, 2, "parses two overrides");
48
+ assertEq(result[0].scope, "resolved", "first is resolved");
49
+ assertEq(result[1].scope, "active", "second is active");
50
+ assertEq(result[1].change, "Use JWT instead of session cookies", "second change text");
51
+ }
52
+
53
+ console.log('\n=== appendOverride: creates new file ===');
54
+ {
55
+ const tmp = makeTempDir("append-new");
56
+ await appendOverride(tmp, "Use Postgres", "M001/S01/T01");
57
+ const content = readFileSync(join(tmp, ".gsd", "OVERRIDES.md"), "utf-8");
58
+ assertTrue(content.includes("# GSD Overrides"), "has header");
59
+ assertTrue(content.includes("**Change:** Use Postgres"), "has change");
60
+ assertTrue(content.includes("**Scope:** active"), "has active scope");
61
+ assertTrue(content.includes("**Applied-at:** M001/S01/T01"), "has appliedAt");
62
+ }
63
+
64
+ console.log('\n=== appendOverride: appends to existing file ===');
65
+ {
66
+ const tmp = makeTempDir("append-existing");
67
+ await appendOverride(tmp, "First override", "M001/S01/T01");
68
+ await appendOverride(tmp, "Second override", "M001/S02/T02");
69
+ const content = readFileSync(join(tmp, ".gsd", "OVERRIDES.md"), "utf-8");
70
+ assertTrue(content.includes("**Change:** First override"), "has first override");
71
+ assertTrue(content.includes("**Change:** Second override"), "has second override");
72
+ const parsed = parseOverrides(content);
73
+ assertEq(parsed.length, 2, "two overrides in file");
74
+ }
75
+
76
+ console.log('\n=== loadActiveOverrides: no file ===');
77
+ {
78
+ const tmp = makeTempDir("load-no-file");
79
+ const result = await loadActiveOverrides(tmp);
80
+ assertEq(result.length, 0, "returns empty when no file");
81
+ }
82
+
83
+ console.log('\n=== loadActiveOverrides: filters to active only ===');
84
+ {
85
+ const tmp = makeTempDir("load-filter");
86
+ const content = `# GSD Overrides\n\n---\n\n## Override: 2026-03-14T10:00:00.000Z\n\n**Change:** Resolved change\n**Scope:** resolved\n**Applied-at:** M001/S01/T01\n\n---\n\n## Override: 2026-03-14T11:00:00.000Z\n\n**Change:** Active change\n**Scope:** active\n**Applied-at:** M001/S02/T01\n\n---\n`;
87
+ writeFileSync(join(tmp, ".gsd", "OVERRIDES.md"), content, "utf-8");
88
+ const result = await loadActiveOverrides(tmp);
89
+ assertEq(result.length, 1, "only one active override");
90
+ assertEq(result[0].change, "Active change", "correct active change");
91
+ }
92
+
93
+ console.log('\n=== formatOverridesSection: empty array ===');
94
+ { const result = formatOverridesSection([]); assertEq(result, "", "empty overrides returns empty string"); }
95
+
96
+ console.log('\n=== formatOverridesSection: formats section ===');
97
+ {
98
+ const overrides: Override[] = [
99
+ { timestamp: "2026-03-14T10:00:00.000Z", change: "Use Postgres", scope: "active", appliedAt: "M001/S01/T01" },
100
+ ];
101
+ const result = formatOverridesSection(overrides);
102
+ assertTrue(result.includes("## Active Overrides (supersede plan content)"), "has header");
103
+ assertTrue(result.includes("**Use Postgres**"), "has change text");
104
+ assertTrue(result.includes("supersede any conflicting content"), "has instruction");
105
+ }
106
+
107
+ console.log('\n=== resolveAllOverrides: marks all as resolved ===');
108
+ {
109
+ const tmp = makeTempDir("resolve-all");
110
+ await appendOverride(tmp, "First", "M001/S01/T01");
111
+ await appendOverride(tmp, "Second", "M001/S02/T01");
112
+ let active = await loadActiveOverrides(tmp);
113
+ assertEq(active.length, 2, "two active before resolve");
114
+ await resolveAllOverrides(tmp);
115
+ active = await loadActiveOverrides(tmp);
116
+ assertEq(active.length, 0, "no active after resolve");
117
+ const content = readFileSync(join(tmp, ".gsd", "OVERRIDES.md"), "utf-8");
118
+ const allOverrides = parseOverrides(content);
119
+ assertEq(allOverrides.length, 2, "still two overrides total");
120
+ assertTrue(allOverrides.every(o => o.scope === "resolved"), "all resolved");
121
+ }
122
+
123
+ console.log('\n=== resolveAllOverrides: no file no error ===');
124
+ {
125
+ const tmp = makeTempDir("resolve-no-file");
126
+ await resolveAllOverrides(tmp);
127
+ assertTrue(true, "resolveAllOverrides with no file does not throw");
128
+ }
129
+
130
+ cleanup();
131
+ report();
@@ -5,8 +5,6 @@
5
5
  * restored after a coordinator crash, with PID liveness filtering.
6
6
  */
7
7
 
8
- import { describe, test } from 'node:test';
9
- import assert from 'node:assert/strict';
10
8
  import {
11
9
  mkdtempSync,
12
10
  mkdirSync,
@@ -26,6 +24,10 @@ import {
26
24
  type PersistedState,
27
25
  } from "../parallel-orchestrator.ts";
28
26
  import { writeSessionStatus, readAllSessionStatuses, removeSessionStatus } from "../session-status-io.ts";
27
+ import { createTestContext } from './test-helpers.ts';
28
+
29
+ const { assertEq, assertTrue, report } = createTestContext();
30
+
29
31
  // ─── Helpers ──────────────────────────────────────────────────────────────────
30
32
 
31
33
  function makeTempDir(): string {
@@ -55,9 +57,8 @@ function makePersistedState(overrides: Partial<PersistedState> = {}): PersistedS
55
57
 
56
58
  // ─── Tests ────────────────────────────────────────────────────────────────────
57
59
 
58
-
59
- describe('parallel-crash-recovery', () => {
60
- test('Test 1: persistState writes valid JSON', () => {
60
+ // Test 1: persistState writes valid JSON
61
+ {
61
62
  const basePath = makeTempDir();
62
63
  try {
63
64
  // We can't call persistState directly without internal state set up,
@@ -81,27 +82,29 @@ test('Test 1: persistState writes valid JSON', () => {
81
82
 
82
83
  const raw = readFileSync(stateFilePath(basePath), "utf-8");
83
84
  const parsed = JSON.parse(raw) as PersistedState;
84
- assert.deepStrictEqual(parsed.active, true, "persistState: active field preserved");
85
- assert.deepStrictEqual(parsed.workers.length, 1, "persistState: worker count preserved");
86
- assert.deepStrictEqual(parsed.workers[0].milestoneId, "M001", "persistState: milestoneId preserved");
87
- assert.deepStrictEqual(parsed.workers[0].cost, 0.15, "persistState: cost preserved");
88
- assert.deepStrictEqual(parsed.totalCost, 0.15, "persistState: totalCost preserved");
85
+ assertEq(parsed.active, true, "persistState: active field preserved");
86
+ assertEq(parsed.workers.length, 1, "persistState: worker count preserved");
87
+ assertEq(parsed.workers[0].milestoneId, "M001", "persistState: milestoneId preserved");
88
+ assertEq(parsed.workers[0].cost, 0.15, "persistState: cost preserved");
89
+ assertEq(parsed.totalCost, 0.15, "persistState: totalCost preserved");
89
90
  } finally {
90
91
  rmSync(basePath, { recursive: true, force: true });
91
92
  }
92
- });
93
+ }
93
94
 
94
- test('Test 2: restoreState returns null for missing file', () => {
95
+ // Test 2: restoreState returns null for missing file
96
+ {
95
97
  const basePath = makeTempDir();
96
98
  try {
97
99
  const result = restoreState(basePath);
98
- assert.deepStrictEqual(result, null, "restoreState: returns null when no state file");
100
+ assertEq(result, null, "restoreState: returns null when no state file");
99
101
  } finally {
100
102
  rmSync(basePath, { recursive: true, force: true });
101
103
  }
102
- });
104
+ }
103
105
 
104
- test('Test 3: restoreState filters dead PIDs', () => {
106
+ // Test 3: restoreState filters dead PIDs
107
+ {
105
108
  const basePath = makeTempDir();
106
109
  try {
107
110
  // PID 99999999 is almost certainly not alive
@@ -133,14 +136,15 @@ test('Test 3: restoreState filters dead PIDs', () => {
133
136
 
134
137
  const result = restoreState(basePath);
135
138
  // Both PIDs are dead, so result should be null and file should be cleaned up
136
- assert.deepStrictEqual(result, null, "restoreState: returns null when all PIDs dead");
137
- assert.ok(!existsSync(stateFilePath(basePath)), "restoreState: cleans up state file when all dead");
139
+ assertEq(result, null, "restoreState: returns null when all PIDs dead");
140
+ assertTrue(!existsSync(stateFilePath(basePath)), "restoreState: cleans up state file when all dead");
138
141
  } finally {
139
142
  rmSync(basePath, { recursive: true, force: true });
140
143
  }
141
- });
144
+ }
142
145
 
143
- test('Test 4: restoreState keeps alive PIDs', () => {
146
+ // Test 4: restoreState keeps alive PIDs
147
+ {
144
148
  const basePath = makeTempDir();
145
149
  try {
146
150
  // Use current process PID (definitely alive)
@@ -172,17 +176,18 @@ test('Test 4: restoreState keeps alive PIDs', () => {
172
176
  writeStateFile(basePath, state);
173
177
 
174
178
  const result = restoreState(basePath);
175
- assert.ok(result !== null, "restoreState: returns state when alive PID exists");
176
- assert.deepStrictEqual(result!.workers.length, 1, "restoreState: filters out dead PID");
177
- assert.deepStrictEqual(result!.workers[0].milestoneId, "M001", "restoreState: keeps alive worker");
178
- assert.deepStrictEqual(result!.workers[0].pid, process.pid, "restoreState: preserves PID");
179
- assert.deepStrictEqual(result!.workers[0].completedUnits, 5, "restoreState: preserves progress");
179
+ assertTrue(result !== null, "restoreState: returns state when alive PID exists");
180
+ assertEq(result!.workers.length, 1, "restoreState: filters out dead PID");
181
+ assertEq(result!.workers[0].milestoneId, "M001", "restoreState: keeps alive worker");
182
+ assertEq(result!.workers[0].pid, process.pid, "restoreState: preserves PID");
183
+ assertEq(result!.workers[0].completedUnits, 5, "restoreState: preserves progress");
180
184
  } finally {
181
185
  rmSync(basePath, { recursive: true, force: true });
182
186
  }
183
- });
187
+ }
184
188
 
185
- test('Test 5: restoreState skips stopped/error workers even with alive PIDs', () => {
189
+ // Test 5: restoreState skips stopped/error workers even with alive PIDs
190
+ {
186
191
  const basePath = makeTempDir();
187
192
  try {
188
193
  const state = makePersistedState({
@@ -202,13 +207,14 @@ test('Test 5: restoreState skips stopped/error workers even with alive PIDs', ()
202
207
  writeStateFile(basePath, state);
203
208
 
204
209
  const result = restoreState(basePath);
205
- assert.deepStrictEqual(result, null, "restoreState: skips stopped workers");
210
+ assertEq(result, null, "restoreState: skips stopped workers");
206
211
  } finally {
207
212
  rmSync(basePath, { recursive: true, force: true });
208
213
  }
209
- });
214
+ }
210
215
 
211
- test('Test 6: orphan detection finds stale sessions', () => {
216
+ // Test 6: orphan detection finds stale sessions
217
+ {
212
218
  const basePath = makeTempDir();
213
219
  try {
214
220
  // Write a session status with a dead PID
@@ -240,7 +246,7 @@ test('Test 6: orphan detection finds stale sessions', () => {
240
246
 
241
247
  // Read all sessions — both should exist initially
242
248
  const before = readAllSessionStatuses(basePath);
243
- assert.deepStrictEqual(before.length, 2, "orphan: both sessions exist before detection");
249
+ assertEq(before.length, 2, "orphan: both sessions exist before detection");
244
250
 
245
251
  // Now simulate orphan detection logic (same as prepareParallelStart)
246
252
  const sessions = readAllSessionStatuses(basePath);
@@ -259,33 +265,34 @@ test('Test 6: orphan detection finds stale sessions', () => {
259
265
  }
260
266
  }
261
267
 
262
- assert.ok(orphans.length === 2, "orphan: detected both sessions");
268
+ assertTrue(orphans.length === 2, "orphan: detected both sessions");
263
269
  const deadOrphan = orphans.find(o => o.milestoneId === "M001");
264
- assert.ok(deadOrphan !== undefined && !deadOrphan.alive, "orphan: M001 detected as dead");
270
+ assertTrue(deadOrphan !== undefined && !deadOrphan.alive, "orphan: M001 detected as dead");
265
271
  const aliveOrphan = orphans.find(o => o.milestoneId === "M002");
266
- assert.ok(aliveOrphan !== undefined && aliveOrphan.alive, "orphan: M002 detected as alive");
272
+ assertTrue(aliveOrphan !== undefined && aliveOrphan.alive, "orphan: M002 detected as alive");
267
273
 
268
274
  // Dead session should be cleaned up
269
275
  const after = readAllSessionStatuses(basePath);
270
- assert.deepStrictEqual(after.length, 1, "orphan: dead session cleaned up");
271
- assert.deepStrictEqual(after[0].milestoneId, "M002", "orphan: alive session remains");
276
+ assertEq(after.length, 1, "orphan: dead session cleaned up");
277
+ assertEq(after[0].milestoneId, "M002", "orphan: alive session remains");
272
278
  } finally {
273
279
  rmSync(basePath, { recursive: true, force: true });
274
280
  }
275
- });
281
+ }
276
282
 
277
- test('Test 7: restoreState handles corrupt JSON gracefully', () => {
283
+ // Test 7: restoreState handles corrupt JSON gracefully
284
+ {
278
285
  const basePath = makeTempDir();
279
286
  try {
280
287
  writeFileSync(stateFilePath(basePath), "{ not valid json !!!", "utf-8");
281
288
  const result = restoreState(basePath);
282
- assert.deepStrictEqual(result, null, "restoreState: returns null for corrupt JSON");
289
+ assertEq(result, null, "restoreState: returns null for corrupt JSON");
283
290
  } finally {
284
291
  rmSync(basePath, { recursive: true, force: true });
285
292
  }
286
- });
293
+ }
287
294
 
288
295
  // Clean up module state
289
296
  resetOrchestrator();
290
297
 
291
- });
298
+ report();
@@ -10,11 +10,12 @@
10
10
  * 6. completedUnits counter increments on assistant message_end
11
11
  */
12
12
 
13
- import assert from 'node:assert/strict';
14
13
  import { describe, it, after } from "node:test";
15
14
  import { mkdtempSync, rmSync, writeFileSync, mkdirSync } from "node:fs";
16
15
  import { join } from "node:path";
17
16
  import { tmpdir } from "node:os";
17
+ import { createTestContext } from "./test-helpers.ts";
18
+
18
19
  // We test processWorkerLine indirectly via the module's exported state.
19
20
  // To test the internal function, we use the exported accessors.
20
21
  import {
@@ -26,6 +27,8 @@ import {
26
27
  refreshWorkerStatuses,
27
28
  } from "../parallel-orchestrator.ts";
28
29
 
30
+ const { assertEq, assertTrue, report } = createTestContext();
31
+
29
32
  // ─── Helpers ──────────────────────────────────────────────────────────────
30
33
 
31
34
  /** Create a minimal message_end NDJSON line with cost data. */
@@ -49,7 +52,7 @@ function makeMessageEndLine(cost: number, role = "assistant"): string {
49
52
  describe("parallel-worker-monitoring", () => {
50
53
  after(() => {
51
54
  resetOrchestrator();
52
-
55
+ report();
53
56
  });
54
57
 
55
58
  // Note: processWorkerLine is not exported, so we test the observable effects
@@ -58,39 +61,39 @@ describe("parallel-worker-monitoring", () => {
58
61
 
59
62
  it("isBudgetExceeded returns false when no state exists", () => {
60
63
  resetOrchestrator();
61
- assert.ok(!isBudgetExceeded(), "no state = not exceeded");
64
+ assertTrue(!isBudgetExceeded(), "no state = not exceeded");
62
65
  });
63
66
 
64
67
  it("isBudgetExceeded returns false when no ceiling configured", () => {
65
68
  resetOrchestrator();
66
69
  // Can't directly set state without startParallel, so test the accessor
67
- assert.ok(!isBudgetExceeded(), "no ceiling = not exceeded");
70
+ assertTrue(!isBudgetExceeded(), "no ceiling = not exceeded");
68
71
  });
69
72
 
70
73
  it("getAggregateCost returns 0 when no state exists", () => {
71
74
  resetOrchestrator();
72
- assert.deepStrictEqual(getAggregateCost(), 0, "no state = zero cost");
75
+ assertEq(getAggregateCost(), 0, "no state = zero cost");
73
76
  });
74
77
 
75
78
  it("isParallelActive returns false after reset", () => {
76
79
  resetOrchestrator();
77
- assert.ok(!isParallelActive(), "reset = not active");
80
+ assertTrue(!isParallelActive(), "reset = not active");
78
81
  });
79
82
 
80
83
  it("getWorkerStatuses returns empty array when no state", () => {
81
84
  resetOrchestrator();
82
- assert.deepStrictEqual(getWorkerStatuses().length, 0, "no state = empty workers");
85
+ assertEq(getWorkerStatuses().length, 0, "no state = empty workers");
83
86
  });
84
87
 
85
88
  it("NDJSON message_end format matches expected structure", () => {
86
89
  // Verify the NDJSON line format we expect from workers
87
90
  const line = makeMessageEndLine(0.05);
88
91
  const parsed = JSON.parse(line);
89
- assert.deepStrictEqual(parsed.type, "message_end", "type is message_end");
90
- assert.deepStrictEqual(parsed.message.role, "assistant", "role is assistant");
91
- assert.deepStrictEqual(parsed.message.usage.cost.total, 0.05, "cost.total is 0.05");
92
- assert.ok(typeof parsed.message.usage.input === "number", "input is number");
93
- assert.ok(typeof parsed.message.usage.output === "number", "output is number");
92
+ assertEq(parsed.type, "message_end", "type is message_end");
93
+ assertEq(parsed.message.role, "assistant", "role is assistant");
94
+ assertEq(parsed.message.usage.cost.total, 0.05, "cost.total is 0.05");
95
+ assertTrue(typeof parsed.message.usage.input === "number", "input is number");
96
+ assertTrue(typeof parsed.message.usage.output === "number", "output is number");
94
97
  });
95
98
 
96
99
  it("malformed JSON does not throw (tested via parse safety)", () => {
@@ -108,7 +111,7 @@ describe("parallel-worker-monitoring", () => {
108
111
  JSON.parse(line);
109
112
  } catch {
110
113
  // Expected — processWorkerLine catches this silently
111
- assert.ok(true, `malformed line "${line.slice(0, 20)}" handled`);
114
+ assertTrue(true, `malformed line "${line.slice(0, 20)}" handled`);
112
115
  }
113
116
  }
114
117
  });
@@ -119,25 +122,25 @@ describe("parallel-worker-monitoring", () => {
119
122
  let total = 0;
120
123
  for (const c of costs) total += c;
121
124
  // Floating point: round to 2 decimal places for comparison
122
- assert.deepStrictEqual(Math.round(total * 100) / 100, 0.28, "cost sum is correct");
125
+ assertEq(Math.round(total * 100) / 100, 0.28, "cost sum is correct");
123
126
  });
124
127
 
125
128
  it("budget ceiling comparison works with typical values", () => {
126
129
  // Test the ceiling check pattern
127
130
  const ceiling = 5.0;
128
- assert.ok(0 < ceiling, "0 is under ceiling");
129
- assert.ok(4.99 < ceiling, "4.99 is under ceiling");
130
- assert.ok(!(5.0 < ceiling), "5.0 is at ceiling");
131
- assert.ok(!(5.01 < ceiling), "5.01 is over ceiling");
131
+ assertTrue(0 < ceiling, "0 is under ceiling");
132
+ assertTrue(4.99 < ceiling, "4.99 is under ceiling");
133
+ assertTrue(!(5.0 < ceiling), "5.0 is at ceiling");
134
+ assertTrue(!(5.01 < ceiling), "5.01 is over ceiling");
132
135
  });
133
136
 
134
137
  it("worker spawn args include --mode json", () => {
135
138
  // Verify the spawn command includes JSON mode for NDJSON output.
136
139
  // We can't easily test the actual spawn, but we verify the args pattern.
137
140
  const expectedArgs = ["--mode", "json", "--print", "/gsd auto"];
138
- assert.ok(expectedArgs.includes("--mode"), "args include --mode");
139
- assert.ok(expectedArgs.includes("json"), "args include json");
140
- assert.ok(expectedArgs.indexOf("--mode") < expectedArgs.indexOf("json"),
141
+ assertTrue(expectedArgs.includes("--mode"), "args include --mode");
142
+ assertTrue(expectedArgs.includes("json"), "args include json");
143
+ assertTrue(expectedArgs.indexOf("--mode") < expectedArgs.indexOf("json"),
141
144
  "--mode comes before json");
142
145
  });
143
146
 
@@ -165,8 +168,8 @@ describe("parallel-worker-monitoring", () => {
165
168
  }, null, 2));
166
169
  refreshWorkerStatuses(base, { restoreIfNeeded: true });
167
170
  const workers = getWorkerStatuses();
168
- assert.deepStrictEqual(workers.length, 1, "restored one worker");
169
- assert.deepStrictEqual(workers[0].milestoneId, "M001", "worker restored from persisted state");
171
+ assertEq(workers.length, 1, "restored one worker");
172
+ assertEq(workers[0].milestoneId, "M001", "worker restored from persisted state");
170
173
  } finally {
171
174
  resetOrchestrator();
172
175
  rmSync(base, { recursive: true, force: true });
@@ -190,8 +193,8 @@ describe("parallel-worker-monitoring", () => {
190
193
  }, null, 2));
191
194
  refreshWorkerStatuses(base, { restoreIfNeeded: true });
192
195
  const workers = getWorkerStatuses();
193
- assert.deepStrictEqual(workers[0].state, "running", "live session status restored");
194
- assert.deepStrictEqual(workers[0].completedUnits, 3, "completed units restored from status file");
196
+ assertEq(workers[0].state, "running", "live session status restored");
197
+ assertEq(workers[0].completedUnits, 3, "completed units restored from status file");
195
198
  } finally {
196
199
  resetOrchestrator();
197
200
  rmSync(base, { recursive: true, force: true });