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,5 +1,4 @@
1
- import { test } from 'node:test';
2
- import assert from 'node:assert/strict';
1
+ import { createTestContext } from './test-helpers.ts';
3
2
  import * as fs from 'node:fs';
4
3
  import * as path from 'node:path';
5
4
  import * as os from 'node:os';
@@ -17,6 +16,7 @@ import {
17
16
  reconcileWorktreeDb,
18
17
  } from '../gsd-db.ts';
19
18
 
19
+ const { assertEq, assertTrue, report } = createTestContext();
20
20
 
21
21
  // ═══════════════════════════════════════════════════════════════════════════
22
22
  // Helpers
@@ -91,18 +91,18 @@ console.log('\n=== worktree-db: copyWorktreeDb ===');
91
91
  closeDatabase();
92
92
 
93
93
  const result = copyWorktreeDb(srcDb, destDb);
94
- assert.ok(result === true, 'copyWorktreeDb returns true on success');
95
- assert.ok(fs.existsSync(destDb), 'dest DB file exists after copy');
94
+ assertTrue(result === true, 'copyWorktreeDb returns true on success');
95
+ assertTrue(fs.existsSync(destDb), 'dest DB file exists after copy');
96
96
 
97
97
  // Open the copy and verify data is queryable
98
98
  openDatabase(destDb);
99
99
  const d = getDecisionById('D001');
100
- assert.ok(d !== null, 'decision queryable in copied DB');
101
- assert.deepStrictEqual(d?.choice, 'node:sqlite', 'decision data preserved in copy');
100
+ assertTrue(d !== null, 'decision queryable in copied DB');
101
+ assertEq(d?.choice, 'node:sqlite', 'decision data preserved in copy');
102
102
 
103
103
  const r = getRequirementById('R001');
104
- assert.ok(r !== null, 'requirement queryable in copied DB');
105
- assert.deepStrictEqual(r?.description, 'Must store decisions', 'requirement data preserved in copy');
104
+ assertTrue(r !== null, 'requirement queryable in copied DB');
105
+ assertEq(r?.description, 'Must store decisions', 'requirement data preserved in copy');
106
106
 
107
107
  cleanup(srcDir, destDir);
108
108
  }
@@ -123,9 +123,9 @@ console.log('\n=== worktree-db: copyWorktreeDb ===');
123
123
 
124
124
  copyWorktreeDb(srcDb, destDb);
125
125
 
126
- assert.ok(fs.existsSync(destDb), 'DB file copied');
127
- assert.ok(!fs.existsSync(destDb + '-wal'), 'WAL file NOT copied');
128
- assert.ok(!fs.existsSync(destDb + '-shm'), 'SHM file NOT copied');
126
+ assertTrue(fs.existsSync(destDb), 'DB file copied');
127
+ assertTrue(!fs.existsSync(destDb + '-wal'), 'WAL file NOT copied');
128
+ assertTrue(!fs.existsSync(destDb + '-shm'), 'SHM file NOT copied');
129
129
 
130
130
  cleanup(srcDir, destDir);
131
131
  }
@@ -134,7 +134,7 @@ console.log('\n=== worktree-db: copyWorktreeDb ===');
134
134
  {
135
135
  const destDir = tempDir();
136
136
  const result = copyWorktreeDb('/nonexistent/path/gsd.db', path.join(destDir, 'gsd.db'));
137
- assert.deepStrictEqual(result, false, 'returns false for missing source');
137
+ assertEq(result, false, 'returns false for missing source');
138
138
  cleanup(destDir);
139
139
  }
140
140
 
@@ -149,8 +149,8 @@ console.log('\n=== worktree-db: copyWorktreeDb ===');
149
149
  closeDatabase();
150
150
 
151
151
  const result = copyWorktreeDb(srcDb, deepDest);
152
- assert.ok(result === true, 'copyWorktreeDb succeeds with nested dest');
153
- assert.ok(fs.existsSync(deepDest), 'DB file created at deeply nested path');
152
+ assertTrue(result === true, 'copyWorktreeDb succeeds with nested dest');
153
+ assertTrue(fs.existsSync(deepDest), 'DB file created at deeply nested path');
154
154
 
155
155
  cleanup(srcDir, destDir);
156
156
  }
@@ -192,10 +192,10 @@ console.log('\n=== worktree-db: reconcileWorktreeDb ===');
192
192
  openDatabase(mainDb);
193
193
  const result = reconcileWorktreeDb(mainDb, wtDb);
194
194
 
195
- assert.ok(result.decisions > 0, 'decisions merged count > 0');
195
+ assertTrue(result.decisions > 0, 'decisions merged count > 0');
196
196
  const d2 = getDecisionById('D002');
197
- assert.ok(d2 !== null, 'D002 from worktree now in main');
198
- assert.deepStrictEqual(d2?.choice, 'WAL', 'D002 data correct after merge');
197
+ assertTrue(d2 !== null, 'D002 from worktree now in main');
198
+ assertEq(d2?.choice, 'WAL', 'D002 data correct after merge');
199
199
 
200
200
  cleanup(mainDir, wtDir);
201
201
  }
@@ -231,10 +231,10 @@ console.log('\n=== worktree-db: reconcileWorktreeDb ===');
231
231
  openDatabase(mainDb);
232
232
  const result = reconcileWorktreeDb(mainDb, wtDb);
233
233
 
234
- assert.ok(result.requirements > 0, 'requirements merged count > 0');
234
+ assertTrue(result.requirements > 0, 'requirements merged count > 0');
235
235
  const r2 = getRequirementById('R002');
236
- assert.ok(r2 !== null, 'R002 from worktree now in main');
237
- assert.deepStrictEqual(r2?.description, 'Must be fast', 'R002 data correct after merge');
236
+ assertTrue(r2 !== null, 'R002 from worktree now in main');
237
+ assertEq(r2?.description, 'Must be fast', 'R002 data correct after merge');
238
238
 
239
239
  cleanup(mainDir, wtDir);
240
240
  }
@@ -264,11 +264,11 @@ console.log('\n=== worktree-db: reconcileWorktreeDb ===');
264
264
  openDatabase(mainDb);
265
265
  const result = reconcileWorktreeDb(mainDb, wtDb);
266
266
 
267
- assert.ok(result.artifacts > 0, 'artifacts merged count > 0');
267
+ assertTrue(result.artifacts > 0, 'artifacts merged count > 0');
268
268
  const adapter = _getAdapter()!;
269
269
  const row = adapter.prepare('SELECT * FROM artifacts WHERE path = ?').get('docs/api.md');
270
- assert.ok(row !== null, 'artifact from worktree now in main');
271
- assert.deepStrictEqual(row?.['artifact_type'], 'reference', 'artifact data correct after merge');
270
+ assertTrue(row !== null, 'artifact from worktree now in main');
271
+ assertEq(row?.['artifact_type'], 'reference', 'artifact data correct after merge');
272
272
 
273
273
  cleanup(mainDir, wtDir);
274
274
  }
@@ -305,15 +305,15 @@ console.log('\n=== worktree-db: reconcileWorktreeDb ===');
305
305
  openDatabase(mainDb);
306
306
  const result = reconcileWorktreeDb(mainDb, wtDb);
307
307
 
308
- assert.ok(result.conflicts.length > 0, 'conflicts detected');
309
- assert.ok(
308
+ assertTrue(result.conflicts.length > 0, 'conflicts detected');
309
+ assertTrue(
310
310
  result.conflicts.some(c => c.includes('D001')),
311
311
  'conflict mentions D001',
312
312
  );
313
313
 
314
314
  // Worktree-wins: D001 should now have worktree's value
315
315
  const d1 = getDecisionById('D001');
316
- assert.deepStrictEqual(d1?.choice, 'sql.js', 'worktree wins on conflict (INSERT OR REPLACE)');
316
+ assertEq(d1?.choice, 'sql.js', 'worktree wins on conflict (INSERT OR REPLACE)');
317
317
 
318
318
  cleanup(mainDir, wtDir);
319
319
  }
@@ -326,10 +326,10 @@ console.log('\n=== worktree-db: reconcileWorktreeDb ===');
326
326
  seedMainDb(mainDb);
327
327
 
328
328
  const result = reconcileWorktreeDb(mainDb, '/nonexistent/worktree.db');
329
- assert.deepStrictEqual(result.decisions, 0, 'no decisions merged for missing worktree DB');
330
- assert.deepStrictEqual(result.requirements, 0, 'no requirements merged for missing worktree DB');
331
- assert.deepStrictEqual(result.artifacts, 0, 'no artifacts merged for missing worktree DB');
332
- assert.deepStrictEqual(result.conflicts.length, 0, 'no conflicts for missing worktree DB');
329
+ assertEq(result.decisions, 0, 'no decisions merged for missing worktree DB');
330
+ assertEq(result.requirements, 0, 'no requirements merged for missing worktree DB');
331
+ assertEq(result.artifacts, 0, 'no artifacts merged for missing worktree DB');
332
+ assertEq(result.conflicts.length, 0, 'no conflicts for missing worktree DB');
333
333
 
334
334
  cleanup(mainDir);
335
335
  }
@@ -366,9 +366,9 @@ console.log('\n=== worktree-db: reconcileWorktreeDb ===');
366
366
 
367
367
  openDatabase(mainDb);
368
368
  const result = reconcileWorktreeDb(mainDb, wtDb);
369
- assert.ok(result.decisions > 0, 'reconciliation works with spaces in path');
369
+ assertTrue(result.decisions > 0, 'reconciliation works with spaces in path');
370
370
  const d3 = getDecisionById('D003');
371
- assert.ok(d3 !== null, 'D003 merged from worktree with spaces in path');
371
+ assertTrue(d3 !== null, 'D003 merged from worktree with spaces in path');
372
372
 
373
373
  cleanup(baseDir);
374
374
  }
@@ -388,7 +388,7 @@ console.log('\n=== worktree-db: reconcileWorktreeDb ===');
388
388
  reconcileWorktreeDb(mainDb, wtDb);
389
389
 
390
390
  // Verify main DB is still fully usable after DETACH
391
- assert.ok(isDbAvailable(), 'DB still available after reconciliation');
391
+ assertTrue(isDbAvailable(), 'DB still available after reconciliation');
392
392
 
393
393
  insertDecision({
394
394
  id: 'D099',
@@ -403,8 +403,8 @@ console.log('\n=== worktree-db: reconcileWorktreeDb ===');
403
403
  });
404
404
 
405
405
  const d99 = getDecisionById('D099');
406
- assert.ok(d99 !== null, 'can insert and query after reconciliation');
407
- assert.deepStrictEqual(d99?.choice, 'works', 'post-reconcile data correct');
406
+ assertTrue(d99 !== null, 'can insert and query after reconciliation');
407
+ assertEq(d99?.choice, 'works', 'post-reconcile data correct');
408
408
 
409
409
  // Verify no "wt" database still attached
410
410
  const adapter = _getAdapter()!;
@@ -415,7 +415,7 @@ console.log('\n=== worktree-db: reconcileWorktreeDb ===');
415
415
  } catch {
416
416
  // Expected — wt should be detached
417
417
  }
418
- assert.ok(!wtAccessible, 'wt database is detached after reconciliation');
418
+ assertTrue(!wtAccessible, 'wt database is detached after reconciliation');
419
419
 
420
420
  cleanup(mainDir, wtDir);
421
421
  }
@@ -436,10 +436,11 @@ console.log('\n=== worktree-db: reconcileWorktreeDb ===');
436
436
  const result = reconcileWorktreeDb(mainDb, wtDb);
437
437
 
438
438
  // Should still report counts for the existing rows (INSERT OR REPLACE touches them)
439
- assert.ok(result.conflicts.length === 0, 'no conflicts when DBs are identical');
440
- assert.ok(isDbAvailable(), 'DB usable after no-change reconciliation');
439
+ assertTrue(result.conflicts.length === 0, 'no conflicts when DBs are identical');
440
+ assertTrue(isDbAvailable(), 'DB usable after no-change reconciliation');
441
441
 
442
442
  cleanup(mainDir, wtDir);
443
443
  }
444
444
 
445
445
  // ─── Final Report ──────────────────────────────────────────────────────────
446
+ report();
@@ -22,9 +22,9 @@ import {
22
22
  import { getSliceBranchName } from "../worktree.ts";
23
23
  import { abortAndReset } from "../git-self-heal.ts";
24
24
  import { runGSDDoctor } from "../doctor.ts";
25
- import { describe, test } from 'node:test';
26
- import assert from 'node:assert/strict';
25
+ import { createTestContext } from "./test-helpers.ts";
27
26
 
27
+ const { assertEq, assertTrue, assertMatch, report } = createTestContext();
28
28
 
29
29
  // ---- Helpers ----
30
30
 
@@ -80,7 +80,7 @@ function addSliceToMilestone(
80
80
  run(`git merge --no-ff ${sliceBranch} -m "merge ${sliceId}"`, wtPath);
81
81
  }
82
82
 
83
- describe('worktree-e2e', async () => {
83
+ async function main(): Promise<void> {
84
84
  const savedCwd = process.cwd();
85
85
  const tempDirs: string[] = [];
86
86
 
@@ -100,7 +100,7 @@ describe('worktree-e2e', async () => {
100
100
  // Create worktree for M001
101
101
  const wtPath = createAutoWorktree(repo, "M001");
102
102
  tempDirs.push(wtPath);
103
- assert.ok(existsSync(wtPath), "worktree directory created");
103
+ assertTrue(existsSync(wtPath), "worktree directory created");
104
104
 
105
105
  // Add two slices with commits
106
106
  addSliceToMilestone(repo, wtPath, "M001", "S01", "Add auth", [
@@ -124,19 +124,19 @@ describe('worktree-e2e', async () => {
124
124
  // Assert exactly one new commit on main
125
125
  const mainLogAfter = run("git log --oneline main", repo);
126
126
  const commitCountAfter = mainLogAfter.split("\n").length;
127
- assert.deepStrictEqual(commitCountAfter, commitCountBefore + 1, "exactly one new commit on main");
127
+ assertEq(commitCountAfter, commitCountBefore + 1, "exactly one new commit on main");
128
128
 
129
129
  // Commit message contains both slice titles
130
130
  const lastCommitMsg = run("git log -1 --format=%B main", repo);
131
- assert.match(lastCommitMsg, /Add auth/, "commit message contains S01 title");
132
- assert.match(lastCommitMsg, /Add dashboard/, "commit message contains S02 title");
131
+ assertMatch(lastCommitMsg, /Add auth/, "commit message contains S01 title");
132
+ assertMatch(lastCommitMsg, /Add dashboard/, "commit message contains S02 title");
133
133
 
134
134
  // Worktree directory removed
135
- assert.ok(!existsSync(wtPath), "worktree directory removed after merge");
135
+ assertTrue(!existsSync(wtPath), "worktree directory removed after merge");
136
136
 
137
137
  // Milestone branch deleted
138
138
  const branches = run("git branch", repo);
139
- assert.ok(!branches.includes("milestone/M001"), "milestone branch deleted");
139
+ assertTrue(!branches.includes("milestone/M001"), "milestone branch deleted");
140
140
  }
141
141
 
142
142
  // ================================================================
@@ -159,11 +159,11 @@ describe('worktree-e2e', async () => {
159
159
 
160
160
  // Trigger merge conflict
161
161
  try { run("git merge feature", repo); } catch { /* expected */ }
162
- assert.ok(existsSync(join(repo, ".git", "MERGE_HEAD")), "MERGE_HEAD exists before abort");
162
+ assertTrue(existsSync(join(repo, ".git", "MERGE_HEAD")), "MERGE_HEAD exists before abort");
163
163
 
164
164
  const abortResult = abortAndReset(repo);
165
- assert.ok(!existsSync(join(repo, ".git", "MERGE_HEAD")), "MERGE_HEAD removed after abort");
166
- assert.ok(abortResult.cleaned.length > 0, "abortAndReset reports cleaned items");
165
+ assertTrue(!existsSync(join(repo, ".git", "MERGE_HEAD")), "MERGE_HEAD removed after abort");
166
+ assertTrue(abortResult.cleaned.length > 0, "abortAndReset reports cleaned items");
167
167
  }
168
168
 
169
169
  // ================================================================
@@ -211,19 +211,19 @@ _None_
211
211
  // Detect
212
212
  const detect = await runGSDDoctor(repo, { isolationMode: "worktree" });
213
213
  const orphanIssues = detect.issues.filter(i => i.code === "orphaned_auto_worktree");
214
- assert.ok(orphanIssues.length > 0, "doctor detects orphaned worktree");
215
- assert.deepStrictEqual(orphanIssues[0]?.unitId, "M001", "orphaned worktree unitId is M001");
214
+ assertTrue(orphanIssues.length > 0, "doctor detects orphaned worktree");
215
+ assertEq(orphanIssues[0]?.unitId, "M001", "orphaned worktree unitId is M001");
216
216
 
217
217
  // Fix
218
218
  const fixed = await runGSDDoctor(repo, { fix: true, isolationMode: "worktree" });
219
- assert.ok(
219
+ assertTrue(
220
220
  fixed.fixesApplied.some(f => f.includes("removed orphaned worktree")),
221
221
  "doctor fix removes orphaned worktree",
222
222
  );
223
223
 
224
224
  // Verify gone
225
225
  const wtList = run("git worktree list", repo);
226
- assert.ok(!wtList.includes("milestone/M001"), "worktree gone after doctor fix");
226
+ assertTrue(!wtList.includes("milestone/M001"), "worktree gone after doctor fix");
227
227
  }
228
228
  } else {
229
229
  console.log("\n=== Doctor: orphaned worktree detection (skipped on Windows) ===");
@@ -234,4 +234,8 @@ _None_
234
234
  try { rmSync(d, { recursive: true, force: true }); } catch { /* ignore */ }
235
235
  }
236
236
  }
237
- });
237
+
238
+ report();
239
+ }
240
+
241
+ main();
@@ -12,9 +12,9 @@ import { execSync } from "node:child_process";
12
12
 
13
13
  import { getWorktreeHealth, formatWorktreeStatusLine } from "../worktree-health.ts";
14
14
  import { listWorktrees } from "../worktree-manager.ts";
15
- import { describe, test } from 'node:test';
16
- import assert from 'node:assert/strict';
15
+ import { createTestContext } from "./test-helpers.ts";
17
16
 
17
+ const { assertEq, assertTrue, report } = createTestContext();
18
18
 
19
19
  function run(cmd: string, cwd: string): string {
20
20
  return execSync(cmd, { cwd, stdio: ["ignore", "pipe", "pipe"], encoding: "utf-8" }).trim();
@@ -32,10 +32,11 @@ function createBaseRepo(): string {
32
32
  return dir;
33
33
  }
34
34
 
35
- describe('worktree-health', async () => {
35
+ async function main(): Promise<void> {
36
36
  // Skip all tests on Windows — git worktree path resolution issues
37
37
  if (process.platform === "win32") {
38
38
  console.log("(all worktree-health tests skipped on Windows)");
39
+ report();
39
40
  return;
40
41
  }
41
42
 
@@ -58,16 +59,16 @@ describe('worktree-health', async () => {
58
59
 
59
60
  const worktrees = listWorktrees(dir);
60
61
  const wt = worktrees.find(w => w.name === "done-feature");
61
- assert.ok(!!wt, "worktree found");
62
+ assertTrue(!!wt, "worktree found");
62
63
 
63
64
  const health = getWorktreeHealth(dir, wt!);
64
- assert.ok(health.mergedIntoMain, "branch detected as merged");
65
- assert.ok(!health.dirty, "not dirty");
66
- assert.ok(health.safeToRemove, "safe to remove");
65
+ assertTrue(health.mergedIntoMain, "branch detected as merged");
66
+ assertTrue(!health.dirty, "not dirty");
67
+ assertTrue(health.safeToRemove, "safe to remove");
67
68
 
68
69
  const line = formatWorktreeStatusLine(health);
69
- assert.ok(line.includes("merged"), "status line mentions merged");
70
- assert.ok(line.includes("safe to remove"), "status line mentions safe to remove");
70
+ assertTrue(line.includes("merged"), "status line mentions merged");
71
+ assertTrue(line.includes("safe to remove"), "status line mentions safe to remove");
71
72
  }
72
73
 
73
74
  // ─── Test: unmerged worktree with dirty files ──────────────────────
@@ -88,13 +89,13 @@ describe('worktree-health', async () => {
88
89
 
89
90
  const worktrees = listWorktrees(dir);
90
91
  const wt = worktrees.find(w => w.name === "dirty-wip");
91
- assert.ok(!!wt, "worktree found");
92
+ assertTrue(!!wt, "worktree found");
92
93
 
93
94
  const health = getWorktreeHealth(dir, wt!);
94
- assert.ok(!health.mergedIntoMain, "not merged");
95
- assert.ok(health.dirty, "dirty detected");
96
- assert.ok(health.dirtyFileCount > 0, "dirty file count > 0");
97
- assert.ok(!health.safeToRemove, "not safe to remove");
95
+ assertTrue(!health.mergedIntoMain, "not merged");
96
+ assertTrue(health.dirty, "dirty detected");
97
+ assertTrue(health.dirtyFileCount > 0, "dirty file count > 0");
98
+ assertTrue(!health.safeToRemove, "not safe to remove");
98
99
  }
99
100
 
100
101
  // ─── Test: unmerged worktree with unpushed commits ─────────────────
@@ -112,12 +113,12 @@ describe('worktree-health', async () => {
112
113
 
113
114
  const worktrees = listWorktrees(dir);
114
115
  const wt = worktrees.find(w => w.name === "unpushed");
115
- assert.ok(!!wt, "worktree found");
116
+ assertTrue(!!wt, "worktree found");
116
117
 
117
118
  const health = getWorktreeHealth(dir, wt!);
118
- assert.ok(!health.mergedIntoMain, "not merged");
119
- assert.ok(health.unpushedCommits > 0, "unpushed commits detected");
120
- assert.ok(!health.safeToRemove, "not safe to remove");
119
+ assertTrue(!health.mergedIntoMain, "not merged");
120
+ assertTrue(health.unpushedCommits > 0, "unpushed commits detected");
121
+ assertTrue(!health.safeToRemove, "not safe to remove");
121
122
  }
122
123
 
123
124
  // ─── Test: stale detection with short threshold ────────────────────
@@ -136,17 +137,17 @@ describe('worktree-health', async () => {
136
137
 
137
138
  const worktrees = listWorktrees(dir);
138
139
  const wt = worktrees.find(w => w.name === "stale-test");
139
- assert.ok(!!wt, "worktree found");
140
+ assertTrue(!!wt, "worktree found");
140
141
 
141
142
  // With staleDays=0, any worktree should be stale (commit was just now, but threshold is 0)
142
143
  // Actually, a just-created worktree has lastCommitAgeDays ~0 which is >= 0
143
144
  const health = getWorktreeHealth(dir, wt!, 0);
144
- assert.ok(health.stale, "stale with 0-day threshold");
145
- assert.ok(health.lastCommitAgeDays >= 0, "last commit age is non-negative");
145
+ assertTrue(health.stale, "stale with 0-day threshold");
146
+ assertTrue(health.lastCommitAgeDays >= 0, "last commit age is non-negative");
146
147
 
147
148
  // With staleDays=9999, should NOT be stale
148
149
  const healthNotStale = getWorktreeHealth(dir, wt!, 9999);
149
- assert.ok(!healthNotStale.stale, "not stale with high threshold");
150
+ assertTrue(!healthNotStale.stale, "not stale with high threshold");
150
151
  }
151
152
 
152
153
  // ─── Test: formatWorktreeStatusLine for clean active worktree ──────
@@ -165,12 +166,12 @@ describe('worktree-health', async () => {
165
166
 
166
167
  const worktrees = listWorktrees(dir);
167
168
  const wt = worktrees.find(w => w.name === "clean-active");
168
- assert.ok(!!wt, "worktree found");
169
+ assertTrue(!!wt, "worktree found");
169
170
 
170
171
  const health = getWorktreeHealth(dir, wt!, 9999); // high threshold so not stale
171
172
  const line = formatWorktreeStatusLine(health);
172
173
  // Should show last commit age since it's not merged and not stale
173
- assert.ok(line.includes("last commit"), "shows last commit age for active worktree");
174
+ assertTrue(line.includes("last commit"), "shows last commit age for active worktree");
174
175
  }
175
176
 
176
177
  } finally {
@@ -178,4 +179,8 @@ describe('worktree-health', async () => {
178
179
  try { rmSync(dir, { recursive: true, force: true }); } catch { /* ignore */ }
179
180
  }
180
181
  }
181
- });
182
+
183
+ report();
184
+ }
185
+
186
+ main();
@@ -29,9 +29,9 @@ import {
29
29
  } from "../worktree.ts";
30
30
 
31
31
  import { deriveState } from "../state.ts";
32
- import { describe, test } from 'node:test';
33
- import assert from 'node:assert/strict';
32
+ import { createTestContext } from './test-helpers.ts';
34
33
 
34
+ const { assertEq, assertTrue, report } = createTestContext();
35
35
  function run(command: string, cwd: string): string {
36
36
  return execSync(command, { cwd, stdio: ["ignore", "pipe", "pipe"], encoding: "utf-8" }).trim();
37
37
  }
@@ -73,42 +73,42 @@ writeFileSync(
73
73
  run("git add .", base);
74
74
  run('git commit -m "chore: init"', base);
75
75
 
76
- describe('worktree-integration', async () => {
76
+ async function main(): Promise<void> {
77
77
  // ── Verify main tree baseline ──────────────────────────────────────────────
78
78
 
79
79
  console.log("\n=== Main tree baseline ===");
80
- assert.deepStrictEqual(getMainBranch(base), "main", "main tree getMainBranch returns main");
81
- assert.deepStrictEqual(detectWorktreeName(base), null, "main tree not detected as worktree");
80
+ assertEq(getMainBranch(base), "main", "main tree getMainBranch returns main");
81
+ assertEq(detectWorktreeName(base), null, "main tree not detected as worktree");
82
82
 
83
83
  // ── Create worktree and verify detection ───────────────────────────────────
84
84
 
85
85
  console.log("\n=== Create worktree ===");
86
86
  const wt = createWorktree(base, "alpha");
87
- assert.ok(existsSync(wt.path), "worktree created on disk");
88
- assert.deepStrictEqual(wt.branch, "worktree/alpha", "worktree branch name");
87
+ assertTrue(existsSync(wt.path), "worktree created on disk");
88
+ assertEq(wt.branch, "worktree/alpha", "worktree branch name");
89
89
 
90
90
  console.log("\n=== Worktree detection ===");
91
- assert.deepStrictEqual(detectWorktreeName(wt.path), "alpha", "detectWorktreeName inside worktree");
92
- assert.deepStrictEqual(getMainBranch(wt.path), "worktree/alpha", "getMainBranch returns worktree branch inside worktree");
91
+ assertEq(detectWorktreeName(wt.path), "alpha", "detectWorktreeName inside worktree");
92
+ assertEq(getMainBranch(wt.path), "worktree/alpha", "getMainBranch returns worktree branch inside worktree");
93
93
 
94
94
  // ── Verify current branch inside worktree ──────────────────────────────────
95
95
 
96
96
  console.log("\n=== Worktree initial branch ===");
97
- assert.deepStrictEqual(getCurrentBranch(wt.path), "worktree/alpha", "worktree starts on its own branch");
97
+ assertEq(getCurrentBranch(wt.path), "worktree/alpha", "worktree starts on its own branch");
98
98
 
99
99
  // ── Verify branch name helper ──────────────────────────────────────────────
100
100
 
101
101
  console.log("\n=== getSliceBranchName with worktree ===");
102
- assert.deepStrictEqual(getSliceBranchName("M001", "S01", "alpha"), "gsd/alpha/M001/S01", "explicit worktree param");
103
- assert.deepStrictEqual(getSliceBranchName("M001", "S01"), "gsd/M001/S01", "no worktree param = plain branch");
102
+ assertEq(getSliceBranchName("M001", "S01", "alpha"), "gsd/alpha/M001/S01", "explicit worktree param");
103
+ assertEq(getSliceBranchName("M001", "S01"), "gsd/M001/S01", "no worktree param = plain branch");
104
104
 
105
105
  // ── Slice branch creation and detection inside worktree ────────────────────
106
106
 
107
107
  console.log("\n=== Slice branch in worktree ===");
108
108
  const sliceBranch = getSliceBranchName("M001", "S01", "alpha");
109
109
  run(`git checkout -b ${sliceBranch}`, wt.path);
110
- assert.deepStrictEqual(getCurrentBranch(wt.path), "gsd/alpha/M001/S01", "worktree-namespaced slice branch");
111
- assert.ok(SLICE_BRANCH_RE.test(getCurrentBranch(wt.path)), "slice branch regex matches namespaced branch");
110
+ assertEq(getCurrentBranch(wt.path), "gsd/alpha/M001/S01", "worktree-namespaced slice branch");
111
+ assertTrue(SLICE_BRANCH_RE.test(getCurrentBranch(wt.path)), "slice branch regex matches namespaced branch");
112
112
 
113
113
  // ── Do work on slice branch, then merge to worktree branch ─────────────────
114
114
 
@@ -119,23 +119,23 @@ describe('worktree-integration', async () => {
119
119
 
120
120
  // Checkout worktree base branch and merge slice branch
121
121
  run("git checkout worktree/alpha", wt.path);
122
- assert.deepStrictEqual(getCurrentBranch(wt.path), "worktree/alpha", "back on worktree branch");
122
+ assertEq(getCurrentBranch(wt.path), "worktree/alpha", "back on worktree branch");
123
123
 
124
124
  run(`git merge --no-ff ${sliceBranch} -m "feat(M001/S01): First"`, wt.path);
125
125
  run(`git branch -d ${sliceBranch}`, wt.path);
126
- assert.deepStrictEqual(getCurrentBranch(wt.path), "worktree/alpha", "still on worktree branch after merge");
127
- assert.ok(readFileSync(join(wt.path, "feature.txt"), "utf-8").includes("new feature"), "merge brought feature to worktree branch");
126
+ assertEq(getCurrentBranch(wt.path), "worktree/alpha", "still on worktree branch after merge");
127
+ assertTrue(readFileSync(join(wt.path, "feature.txt"), "utf-8").includes("new feature"), "merge brought feature to worktree branch");
128
128
 
129
129
  // Verify slice branch is gone
130
130
  const branches = run("git branch", base);
131
- assert.ok(!branches.includes("gsd/alpha/M001/S01"), "slice branch cleaned up");
131
+ assertTrue(!branches.includes("gsd/alpha/M001/S01"), "slice branch cleaned up");
132
132
 
133
133
  // ── Second slice in same worktree ──────────────────────────────────────────
134
134
 
135
135
  console.log("\n=== Second slice in worktree ===");
136
136
  const sliceBranch2 = getSliceBranchName("M001", "S02", "alpha");
137
137
  run(`git checkout -b ${sliceBranch2}`, wt.path);
138
- assert.deepStrictEqual(getCurrentBranch(wt.path), "gsd/alpha/M001/S02", "on S02 namespaced branch");
138
+ assertEq(getCurrentBranch(wt.path), "gsd/alpha/M001/S02", "on S02 namespaced branch");
139
139
 
140
140
  writeFileSync(join(wt.path, "feature2.txt"), "second feature\n", "utf-8");
141
141
  run("git add .", wt.path);
@@ -144,28 +144,28 @@ describe('worktree-integration', async () => {
144
144
  run("git checkout worktree/alpha", wt.path);
145
145
  run(`git merge --no-ff ${sliceBranch2} -m "feat(M001/S02): Second"`, wt.path);
146
146
  run(`git branch -d ${sliceBranch2}`, wt.path);
147
- assert.deepStrictEqual(getCurrentBranch(wt.path), "worktree/alpha", "back on worktree branch");
147
+ assertEq(getCurrentBranch(wt.path), "worktree/alpha", "back on worktree branch");
148
148
 
149
149
  // ── Parallel worktrees don't conflict ──────────────────────────────────────
150
150
 
151
151
  console.log("\n=== Parallel worktrees ===");
152
152
  const wt2 = createWorktree(base, "beta");
153
- assert.deepStrictEqual(getMainBranch(wt2.path), "worktree/beta", "second worktree has its own base branch");
153
+ assertEq(getMainBranch(wt2.path), "worktree/beta", "second worktree has its own base branch");
154
154
 
155
155
  // Both worktrees can create S01 branches without conflict
156
156
  const betaBranch = getSliceBranchName("M001", "S01", "beta");
157
157
  run(`git checkout -b ${betaBranch}`, wt2.path);
158
- assert.deepStrictEqual(getCurrentBranch(wt2.path), "gsd/beta/M001/S01", "beta has its own namespaced branch");
158
+ assertEq(getCurrentBranch(wt2.path), "gsd/beta/M001/S01", "beta has its own namespaced branch");
159
159
 
160
160
  // Alpha worktree can re-create S01 too (it was already merged+deleted earlier)
161
161
  const alphaReBranch = getSliceBranchName("M001", "S01", "alpha");
162
162
  run(`git checkout -b ${alphaReBranch}`, wt.path);
163
- assert.deepStrictEqual(getCurrentBranch(wt.path), "gsd/alpha/M001/S01", "alpha re-created S01");
163
+ assertEq(getCurrentBranch(wt.path), "gsd/alpha/M001/S01", "alpha re-created S01");
164
164
 
165
165
  // Both exist simultaneously
166
166
  const allBranches = run("git branch", base);
167
- assert.ok(allBranches.includes("gsd/alpha/M001/S01"), "alpha S01 branch exists");
168
- assert.ok(allBranches.includes("gsd/beta/M001/S01"), "beta S01 branch exists");
167
+ assertTrue(allBranches.includes("gsd/alpha/M001/S01"), "alpha S01 branch exists");
168
+ assertTrue(allBranches.includes("gsd/beta/M001/S01"), "beta S01 branch exists");
169
169
 
170
170
  // ── State derivation in worktree ───────────────────────────────────────────
171
171
 
@@ -173,8 +173,8 @@ describe('worktree-integration', async () => {
173
173
  // Switch alpha back to its base so deriveState sees milestone files
174
174
  run("git checkout worktree/alpha", wt.path);
175
175
  const state = await deriveState(wt.path);
176
- assert.ok(state.activeMilestone !== null, "worktree has active milestone");
177
- assert.deepStrictEqual(state.activeMilestone?.id, "M001", "correct milestone");
176
+ assertTrue(state.activeMilestone !== null, "worktree has active milestone");
177
+ assertEq(state.activeMilestone?.id, "M001", "correct milestone");
178
178
 
179
179
  // ── autoCommitCurrentBranch in worktree ────────────────────────────────────
180
180
 
@@ -183,8 +183,8 @@ describe('worktree-integration', async () => {
183
183
  run(`git checkout ${betaBranch}`, wt2.path);
184
184
  writeFileSync(join(wt2.path, "dirty.txt"), "uncommitted\n", "utf-8");
185
185
  const commitMsg = autoCommitCurrentBranch(wt2.path, "execute-task", "M001/S01/T01");
186
- assert.ok(commitMsg !== null, "auto-commit works in worktree");
187
- assert.deepStrictEqual(run("git status --short", wt2.path), "", "worktree clean after auto-commit");
186
+ assertTrue(commitMsg !== null, "auto-commit works in worktree");
187
+ assertEq(run("git status --short", wt2.path), "", "worktree clean after auto-commit");
188
188
 
189
189
  // ── Cleanup ────────────────────────────────────────────────────────────────
190
190
 
@@ -194,7 +194,14 @@ describe('worktree-integration', async () => {
194
194
  run("git checkout worktree/beta", wt2.path);
195
195
  removeWorktree(base, "alpha", { deleteBranch: true });
196
196
  removeWorktree(base, "beta", { deleteBranch: true });
197
- assert.deepStrictEqual(listWorktrees(base).length, 0, "all worktrees removed");
197
+ assertEq(listWorktrees(base).length, 0, "all worktrees removed");
198
198
 
199
199
  rmSync(base, { recursive: true, force: true });
200
+
201
+ report();
202
+ }
203
+
204
+ main().catch((error) => {
205
+ console.error(error);
206
+ process.exit(1);
200
207
  });