gsd-pi 2.43.0 → 2.44.0-dev.0b97ffd

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (693) hide show
  1. package/README.md +30 -12
  2. package/dist/cli.js +13 -1
  3. package/dist/help-text.js +24 -0
  4. package/dist/resources/extensions/bg-shell/overlay.js +3 -0
  5. package/dist/resources/extensions/github-sync/sync.js +2 -1
  6. package/dist/resources/extensions/gsd/auto/loop.js +0 -2
  7. package/dist/resources/extensions/gsd/auto/phases.js +7 -12
  8. package/dist/resources/extensions/gsd/auto-dashboard.js +19 -18
  9. package/dist/resources/extensions/gsd/auto-direct-dispatch.js +34 -19
  10. package/dist/resources/extensions/gsd/auto-dispatch.js +36 -21
  11. package/dist/resources/extensions/gsd/auto-post-unit.js +128 -14
  12. package/dist/resources/extensions/gsd/auto-prompts.js +202 -92
  13. package/dist/resources/extensions/gsd/auto-recovery.js +83 -135
  14. package/dist/resources/extensions/gsd/auto-start.js +10 -0
  15. package/dist/resources/extensions/gsd/auto-supervisor.js +14 -0
  16. package/dist/resources/extensions/gsd/auto-timeout-recovery.js +4 -7
  17. package/dist/resources/extensions/gsd/auto-verification.js +5 -10
  18. package/dist/resources/extensions/gsd/auto-worktree.js +123 -30
  19. package/dist/resources/extensions/gsd/auto.js +1 -4
  20. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +611 -0
  21. package/dist/resources/extensions/gsd/bootstrap/dynamic-tools.js +28 -3
  22. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +7 -0
  23. package/dist/resources/extensions/gsd/commands/catalog.js +3 -1
  24. package/dist/resources/extensions/gsd/commands/handlers/ops.js +15 -1
  25. package/dist/resources/extensions/gsd/commands/handlers/workflow.js +5 -0
  26. package/dist/resources/extensions/gsd/commands-handlers.js +1 -1
  27. package/dist/resources/extensions/gsd/commands-maintenance.js +78 -3
  28. package/dist/resources/extensions/gsd/dashboard-overlay.js +32 -31
  29. package/dist/resources/extensions/gsd/db-writer.js +95 -4
  30. package/dist/resources/extensions/gsd/dispatch-guard.js +35 -30
  31. package/dist/resources/extensions/gsd/doctor-checks.js +28 -11
  32. package/dist/resources/extensions/gsd/doctor-environment.js +28 -0
  33. package/dist/resources/extensions/gsd/doctor-types.js +0 -15
  34. package/dist/resources/extensions/gsd/doctor.js +46 -282
  35. package/dist/resources/extensions/gsd/file-watcher.js +5 -1
  36. package/dist/resources/extensions/gsd/files.js +14 -198
  37. package/dist/resources/extensions/gsd/git-service.js +4 -0
  38. package/dist/resources/extensions/gsd/gitignore.js +4 -0
  39. package/dist/resources/extensions/gsd/gsd-db.js +819 -197
  40. package/dist/resources/extensions/gsd/guided-flow.js +18 -8
  41. package/dist/resources/extensions/gsd/markdown-renderer.js +862 -0
  42. package/dist/resources/extensions/gsd/md-importer.js +182 -4
  43. package/dist/resources/extensions/gsd/native-git-bridge.js +10 -1
  44. package/dist/resources/extensions/gsd/parallel-eligibility.js +14 -19
  45. package/dist/resources/extensions/gsd/parallel-orchestrator.js +38 -0
  46. package/dist/resources/extensions/gsd/parsers-legacy.js +239 -0
  47. package/dist/resources/extensions/gsd/preferences-types.js +1 -0
  48. package/dist/resources/extensions/gsd/preferences-validation.js +9 -0
  49. package/dist/resources/extensions/gsd/preferences.js +1 -0
  50. package/dist/resources/extensions/gsd/prompts/complete-slice.md +22 -9
  51. package/dist/resources/extensions/gsd/prompts/discuss.md +2 -2
  52. package/dist/resources/extensions/gsd/prompts/execute-task.md +15 -5
  53. package/dist/resources/extensions/gsd/prompts/guided-complete-slice.md +1 -1
  54. package/dist/resources/extensions/gsd/prompts/guided-execute-task.md +1 -1
  55. package/dist/resources/extensions/gsd/prompts/guided-plan-milestone.md +1 -1
  56. package/dist/resources/extensions/gsd/prompts/plan-milestone.md +6 -10
  57. package/dist/resources/extensions/gsd/prompts/plan-slice.md +4 -7
  58. package/dist/resources/extensions/gsd/prompts/reactive-execute.md +3 -3
  59. package/dist/resources/extensions/gsd/prompts/reassess-roadmap.md +6 -7
  60. package/dist/resources/extensions/gsd/prompts/replan-slice.md +6 -6
  61. package/dist/resources/extensions/gsd/reactive-graph.js +33 -3
  62. package/dist/resources/extensions/gsd/skill-health.js +3 -1
  63. package/dist/resources/extensions/gsd/state.js +484 -30
  64. package/dist/resources/extensions/gsd/tools/complete-milestone.js +128 -0
  65. package/dist/resources/extensions/gsd/tools/complete-slice.js +244 -0
  66. package/dist/resources/extensions/gsd/tools/complete-task.js +204 -0
  67. package/dist/resources/extensions/gsd/tools/plan-milestone.js +205 -0
  68. package/dist/resources/extensions/gsd/tools/plan-slice.js +155 -0
  69. package/dist/resources/extensions/gsd/tools/plan-task.js +94 -0
  70. package/dist/resources/extensions/gsd/tools/reassess-roadmap.js +152 -0
  71. package/dist/resources/extensions/gsd/tools/replan-slice.js +146 -0
  72. package/dist/resources/extensions/gsd/triage-resolution.js +17 -1
  73. package/dist/resources/extensions/gsd/undo.js +197 -3
  74. package/dist/resources/extensions/gsd/visualizer-data.js +53 -16
  75. package/dist/resources/extensions/gsd/workspace-index.js +63 -39
  76. package/dist/web/standalone/.next/BUILD_ID +1 -1
  77. package/dist/web/standalone/.next/app-path-routes-manifest.json +18 -17
  78. package/dist/web/standalone/.next/build-manifest.json +4 -4
  79. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  80. package/dist/web/standalone/.next/react-loadable-manifest.json +1 -1
  81. package/dist/web/standalone/.next/required-server-files.json +4 -4
  82. package/dist/web/standalone/.next/routes-manifest.json +6 -0
  83. package/dist/web/standalone/.next/server/app/_global-error/page.js +3 -3
  84. package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  85. package/dist/web/standalone/.next/server/app/_global-error.html +2 -2
  86. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  87. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  88. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  89. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  90. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  91. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  92. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  93. package/dist/web/standalone/.next/server/app/_not-found/page.js +2 -2
  94. package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  95. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  96. package/dist/web/standalone/.next/server/app/_not-found.rsc +4 -4
  97. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +4 -4
  98. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  99. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +4 -4
  100. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  101. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  102. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  103. package/dist/web/standalone/.next/server/app/api/boot/route.js +1 -1
  104. package/dist/web/standalone/.next/server/app/api/boot/route_client-reference-manifest.js +1 -1
  105. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js +1 -1
  106. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route_client-reference-manifest.js +1 -1
  107. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js +1 -1
  108. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route_client-reference-manifest.js +1 -1
  109. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js +2 -2
  110. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route_client-reference-manifest.js +1 -1
  111. package/dist/web/standalone/.next/server/app/api/browse-directories/route.js +1 -1
  112. package/dist/web/standalone/.next/server/app/api/browse-directories/route_client-reference-manifest.js +1 -1
  113. package/dist/web/standalone/.next/server/app/api/captures/route.js +1 -1
  114. package/dist/web/standalone/.next/server/app/api/captures/route_client-reference-manifest.js +1 -1
  115. package/dist/web/standalone/.next/server/app/api/cleanup/route.js +1 -1
  116. package/dist/web/standalone/.next/server/app/api/cleanup/route_client-reference-manifest.js +1 -1
  117. package/dist/web/standalone/.next/server/app/api/dev-mode/route.js +1 -1
  118. package/dist/web/standalone/.next/server/app/api/dev-mode/route_client-reference-manifest.js +1 -1
  119. package/dist/web/standalone/.next/server/app/api/doctor/route.js +1 -1
  120. package/dist/web/standalone/.next/server/app/api/doctor/route_client-reference-manifest.js +1 -1
  121. package/dist/web/standalone/.next/server/app/api/export-data/route.js +1 -1
  122. package/dist/web/standalone/.next/server/app/api/export-data/route_client-reference-manifest.js +1 -1
  123. package/dist/web/standalone/.next/server/app/api/files/route.js +1 -1
  124. package/dist/web/standalone/.next/server/app/api/files/route_client-reference-manifest.js +1 -1
  125. package/dist/web/standalone/.next/server/app/api/forensics/route.js +1 -1
  126. package/dist/web/standalone/.next/server/app/api/forensics/route_client-reference-manifest.js +1 -1
  127. package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
  128. package/dist/web/standalone/.next/server/app/api/git/route_client-reference-manifest.js +1 -1
  129. package/dist/web/standalone/.next/server/app/api/history/route.js +1 -1
  130. package/dist/web/standalone/.next/server/app/api/history/route_client-reference-manifest.js +1 -1
  131. package/dist/web/standalone/.next/server/app/api/hooks/route.js +1 -1
  132. package/dist/web/standalone/.next/server/app/api/hooks/route_client-reference-manifest.js +1 -1
  133. package/dist/web/standalone/.next/server/app/api/inspect/route.js +1 -1
  134. package/dist/web/standalone/.next/server/app/api/inspect/route_client-reference-manifest.js +1 -1
  135. package/dist/web/standalone/.next/server/app/api/knowledge/route.js +1 -1
  136. package/dist/web/standalone/.next/server/app/api/knowledge/route_client-reference-manifest.js +1 -1
  137. package/dist/web/standalone/.next/server/app/api/live-state/route.js +1 -1
  138. package/dist/web/standalone/.next/server/app/api/live-state/route_client-reference-manifest.js +1 -1
  139. package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
  140. package/dist/web/standalone/.next/server/app/api/onboarding/route_client-reference-manifest.js +1 -1
  141. package/dist/web/standalone/.next/server/app/api/preferences/route.js +1 -1
  142. package/dist/web/standalone/.next/server/app/api/preferences/route_client-reference-manifest.js +1 -1
  143. package/dist/web/standalone/.next/server/app/api/projects/route.js +1 -1
  144. package/dist/web/standalone/.next/server/app/api/projects/route_client-reference-manifest.js +1 -1
  145. package/dist/web/standalone/.next/server/app/api/recovery/route.js +1 -1
  146. package/dist/web/standalone/.next/server/app/api/recovery/route_client-reference-manifest.js +1 -1
  147. package/dist/web/standalone/.next/server/app/api/remote-questions/route.js +5 -5
  148. package/dist/web/standalone/.next/server/app/api/remote-questions/route_client-reference-manifest.js +1 -1
  149. package/dist/web/standalone/.next/server/app/api/session/browser/route.js +1 -1
  150. package/dist/web/standalone/.next/server/app/api/session/browser/route_client-reference-manifest.js +1 -1
  151. package/dist/web/standalone/.next/server/app/api/session/command/route.js +1 -1
  152. package/dist/web/standalone/.next/server/app/api/session/command/route_client-reference-manifest.js +1 -1
  153. package/dist/web/standalone/.next/server/app/api/session/events/route.js +2 -2
  154. package/dist/web/standalone/.next/server/app/api/session/events/route_client-reference-manifest.js +1 -1
  155. package/dist/web/standalone/.next/server/app/api/session/manage/route.js +1 -1
  156. package/dist/web/standalone/.next/server/app/api/session/manage/route_client-reference-manifest.js +1 -1
  157. package/dist/web/standalone/.next/server/app/api/settings-data/route.js +1 -1
  158. package/dist/web/standalone/.next/server/app/api/settings-data/route_client-reference-manifest.js +1 -1
  159. package/dist/web/standalone/.next/server/app/api/shutdown/route.js +1 -1
  160. package/dist/web/standalone/.next/server/app/api/shutdown/route_client-reference-manifest.js +1 -1
  161. package/dist/web/standalone/.next/server/app/api/skill-health/route.js +1 -1
  162. package/dist/web/standalone/.next/server/app/api/skill-health/route_client-reference-manifest.js +1 -1
  163. package/dist/web/standalone/.next/server/app/api/steer/route.js +1 -1
  164. package/dist/web/standalone/.next/server/app/api/steer/route_client-reference-manifest.js +1 -1
  165. package/dist/web/standalone/.next/server/app/api/switch-root/route.js +1 -0
  166. package/dist/web/standalone/.next/server/app/api/switch-root/route.js.nft.json +1 -0
  167. package/dist/web/standalone/.next/server/app/api/switch-root/route_client-reference-manifest.js +1 -0
  168. package/dist/web/standalone/.next/server/app/api/terminal/input/route.js +1 -1
  169. package/dist/web/standalone/.next/server/app/api/terminal/input/route_client-reference-manifest.js +1 -1
  170. package/dist/web/standalone/.next/server/app/api/terminal/resize/route.js +2 -2
  171. package/dist/web/standalone/.next/server/app/api/terminal/resize/route_client-reference-manifest.js +1 -1
  172. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js +2 -2
  173. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route_client-reference-manifest.js +1 -1
  174. package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js +4 -4
  175. package/dist/web/standalone/.next/server/app/api/terminal/stream/route_client-reference-manifest.js +1 -1
  176. package/dist/web/standalone/.next/server/app/api/terminal/upload/route.js +1 -1
  177. package/dist/web/standalone/.next/server/app/api/terminal/upload/route_client-reference-manifest.js +1 -1
  178. package/dist/web/standalone/.next/server/app/api/undo/route.js +1 -1
  179. package/dist/web/standalone/.next/server/app/api/undo/route_client-reference-manifest.js +1 -1
  180. package/dist/web/standalone/.next/server/app/api/update/route.js +1 -1
  181. package/dist/web/standalone/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
  182. package/dist/web/standalone/.next/server/app/api/visualizer/route.js +1 -1
  183. package/dist/web/standalone/.next/server/app/api/visualizer/route_client-reference-manifest.js +1 -1
  184. package/dist/web/standalone/.next/server/app/index.html +1 -1
  185. package/dist/web/standalone/.next/server/app/index.rsc +5 -5
  186. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  187. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +5 -5
  188. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  189. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +4 -4
  190. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  191. package/dist/web/standalone/.next/server/app/page.js +2 -2
  192. package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  193. package/dist/web/standalone/.next/server/app-paths-manifest.json +18 -17
  194. package/dist/web/standalone/.next/server/chunks/229.js +3 -3
  195. package/dist/web/standalone/.next/server/chunks/471.js +3 -3
  196. package/dist/web/standalone/.next/server/functions-config-manifest.json +1 -0
  197. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  198. package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
  199. package/dist/web/standalone/.next/server/middleware.js +2 -2
  200. package/dist/web/standalone/.next/server/next-font-manifest.js +1 -1
  201. package/dist/web/standalone/.next/server/next-font-manifest.json +1 -1
  202. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  203. package/dist/web/standalone/.next/server/pages/500.html +2 -2
  204. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  205. package/dist/web/standalone/.next/static/alS4hoANx0TK4UVZY27da/_buildManifest.js +1 -0
  206. package/dist/web/standalone/.next/static/chunks/{4024.c195dc1fdd2adbea.js → 4024.0de81b543b28b9fe.js} +2 -2
  207. package/dist/web/standalone/.next/static/chunks/app/_global-error/{page-d07a2c023f1aef1e.js → page-d83ba70a25a85472.js} +1 -1
  208. package/dist/web/standalone/.next/static/chunks/app/_not-found/page-f2a7482d42a5614b.js +1 -0
  209. package/dist/web/standalone/.next/static/chunks/app/api/boot/{route-d07a2c023f1aef1e.js → route-d83ba70a25a85472.js} +1 -1
  210. package/dist/web/standalone/.next/static/chunks/app/api/bridge-terminal/input/{route-d07a2c023f1aef1e.js → route-d83ba70a25a85472.js} +1 -1
  211. package/dist/web/standalone/.next/static/chunks/app/api/bridge-terminal/resize/{route-d07a2c023f1aef1e.js → route-d83ba70a25a85472.js} +1 -1
  212. package/dist/web/standalone/.next/static/chunks/app/api/bridge-terminal/stream/route-d83ba70a25a85472.js +1 -0
  213. package/dist/web/standalone/.next/static/chunks/app/api/browse-directories/route-d83ba70a25a85472.js +1 -0
  214. package/dist/web/standalone/.next/static/chunks/app/api/captures/route-d83ba70a25a85472.js +1 -0
  215. package/dist/web/standalone/.next/static/chunks/app/api/cleanup/route-d83ba70a25a85472.js +1 -0
  216. package/dist/web/standalone/.next/static/chunks/app/api/dev-mode/route-d83ba70a25a85472.js +1 -0
  217. package/dist/web/standalone/.next/static/chunks/app/api/doctor/route-d83ba70a25a85472.js +1 -0
  218. package/dist/web/standalone/.next/static/chunks/app/api/export-data/route-d83ba70a25a85472.js +1 -0
  219. package/dist/web/standalone/.next/static/chunks/app/api/files/route-d83ba70a25a85472.js +1 -0
  220. package/dist/web/standalone/.next/static/chunks/app/api/forensics/route-d83ba70a25a85472.js +1 -0
  221. package/dist/web/standalone/.next/static/chunks/app/api/git/route-d83ba70a25a85472.js +1 -0
  222. package/dist/web/standalone/.next/static/chunks/app/api/history/route-d83ba70a25a85472.js +1 -0
  223. package/dist/web/standalone/.next/static/chunks/app/api/hooks/route-d83ba70a25a85472.js +1 -0
  224. package/dist/web/standalone/.next/static/chunks/app/api/inspect/route-d83ba70a25a85472.js +1 -0
  225. package/dist/web/standalone/.next/static/chunks/app/api/knowledge/route-d83ba70a25a85472.js +1 -0
  226. package/dist/web/standalone/.next/static/chunks/app/api/live-state/route-d83ba70a25a85472.js +1 -0
  227. package/dist/web/standalone/.next/static/chunks/app/api/onboarding/route-d83ba70a25a85472.js +1 -0
  228. package/dist/web/standalone/.next/static/chunks/app/api/preferences/route-d83ba70a25a85472.js +1 -0
  229. package/dist/web/standalone/.next/static/chunks/app/api/projects/route-d83ba70a25a85472.js +1 -0
  230. package/dist/web/standalone/.next/static/chunks/app/api/recovery/route-d83ba70a25a85472.js +1 -0
  231. package/dist/web/standalone/.next/static/chunks/app/api/remote-questions/route-d83ba70a25a85472.js +1 -0
  232. package/dist/web/standalone/.next/static/chunks/app/api/session/browser/route-d83ba70a25a85472.js +1 -0
  233. package/dist/web/standalone/.next/static/chunks/app/api/session/command/route-d83ba70a25a85472.js +1 -0
  234. package/dist/web/standalone/.next/static/chunks/app/api/session/events/route-d83ba70a25a85472.js +1 -0
  235. package/dist/web/standalone/.next/static/chunks/app/api/session/manage/route-d83ba70a25a85472.js +1 -0
  236. package/dist/web/standalone/.next/static/chunks/app/api/settings-data/route-d83ba70a25a85472.js +1 -0
  237. package/dist/web/standalone/.next/static/chunks/app/api/shutdown/route-d83ba70a25a85472.js +1 -0
  238. package/dist/web/standalone/.next/static/chunks/app/api/skill-health/route-d83ba70a25a85472.js +1 -0
  239. package/dist/web/standalone/.next/static/chunks/app/api/steer/route-d83ba70a25a85472.js +1 -0
  240. package/dist/web/standalone/.next/static/chunks/app/api/switch-root/route-d83ba70a25a85472.js +1 -0
  241. package/dist/web/standalone/.next/static/chunks/app/api/terminal/input/route-d83ba70a25a85472.js +1 -0
  242. package/dist/web/standalone/.next/static/chunks/app/api/terminal/resize/route-d83ba70a25a85472.js +1 -0
  243. package/dist/web/standalone/.next/static/chunks/app/api/terminal/sessions/route-d83ba70a25a85472.js +1 -0
  244. package/dist/web/standalone/.next/static/chunks/app/api/terminal/stream/route-d83ba70a25a85472.js +1 -0
  245. package/dist/web/standalone/.next/static/chunks/app/api/terminal/upload/route-d83ba70a25a85472.js +1 -0
  246. package/dist/web/standalone/.next/static/chunks/app/api/undo/route-d83ba70a25a85472.js +1 -0
  247. package/dist/web/standalone/.next/static/chunks/app/api/update/route-d83ba70a25a85472.js +1 -0
  248. package/dist/web/standalone/.next/static/chunks/app/api/visualizer/route-d83ba70a25a85472.js +1 -0
  249. package/dist/web/standalone/.next/static/chunks/app/layout-a16c7a7ecdf0c2cf.js +1 -0
  250. package/dist/web/standalone/.next/static/chunks/app/page-b9367c5ae13b99c6.js +1 -0
  251. package/dist/web/standalone/.next/static/chunks/{main-app-2f2ee7b85712c2bd.js → main-app-fdab67f7802d7832.js} +1 -1
  252. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/app-error-d83ba70a25a85472.js +1 -0
  253. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/forbidden-d83ba70a25a85472.js +1 -0
  254. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-459824ffb8c323dd.js +1 -0
  255. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/not-found-d83ba70a25a85472.js +1 -0
  256. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/unauthorized-d83ba70a25a85472.js +1 -0
  257. package/dist/web/standalone/.next/static/chunks/{webpack-fa307370fcf9fb2c.js → webpack-9014b5adb127a98a.js} +1 -1
  258. package/dist/web/standalone/.next/static/css/8a727f372cf53002.css +1 -0
  259. package/dist/web/standalone/node_modules/node-pty/build/Makefile +2 -2
  260. package/dist/web/standalone/node_modules/node-pty/build/Release/pty.node +0 -0
  261. package/dist/web/standalone/node_modules/node-pty/build/pty.target.mk +14 -14
  262. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api.target.mk +14 -14
  263. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_except.target.mk +14 -14
  264. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_maybe.target.mk +14 -14
  265. package/dist/web/standalone/server.js +1 -1
  266. package/package.json +4 -4
  267. package/packages/pi-ai/dist/models.custom.d.ts +173 -0
  268. package/packages/pi-ai/dist/models.custom.d.ts.map +1 -0
  269. package/packages/pi-ai/dist/models.custom.js +170 -0
  270. package/packages/pi-ai/dist/models.custom.js.map +1 -0
  271. package/packages/pi-ai/dist/models.d.ts.map +1 -1
  272. package/packages/pi-ai/dist/models.js +16 -1
  273. package/packages/pi-ai/dist/models.js.map +1 -1
  274. package/packages/pi-ai/dist/models.test.d.ts +2 -0
  275. package/packages/pi-ai/dist/models.test.d.ts.map +1 -0
  276. package/packages/pi-ai/dist/models.test.js +67 -0
  277. package/packages/pi-ai/dist/models.test.js.map +1 -0
  278. package/packages/pi-ai/src/models.custom.ts +172 -0
  279. package/packages/pi-ai/src/models.test.ts +85 -0
  280. package/packages/pi-ai/src/models.ts +17 -1
  281. package/packages/pi-coding-agent/dist/core/agent-session.d.ts +10 -3
  282. package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
  283. package/packages/pi-coding-agent/dist/core/agent-session.js +21 -34
  284. package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
  285. package/packages/pi-coding-agent/dist/core/auth-storage.test.js +6 -8
  286. package/packages/pi-coding-agent/dist/core/auth-storage.test.js.map +1 -1
  287. package/packages/pi-coding-agent/dist/core/compaction/branch-summarization.d.ts +2 -2
  288. package/packages/pi-coding-agent/dist/core/compaction/branch-summarization.d.ts.map +1 -1
  289. package/packages/pi-coding-agent/dist/core/compaction/branch-summarization.js.map +1 -1
  290. package/packages/pi-coding-agent/dist/core/compaction/compaction.d.ts +2 -2
  291. package/packages/pi-coding-agent/dist/core/compaction/compaction.d.ts.map +1 -1
  292. package/packages/pi-coding-agent/dist/core/compaction/compaction.js.map +1 -1
  293. package/packages/pi-coding-agent/dist/core/compaction-orchestrator.js +4 -4
  294. package/packages/pi-coding-agent/dist/core/compaction-orchestrator.js.map +1 -1
  295. package/packages/pi-coding-agent/dist/core/extensions/index.d.ts +1 -1
  296. package/packages/pi-coding-agent/dist/core/extensions/index.d.ts.map +1 -1
  297. package/packages/pi-coding-agent/dist/core/extensions/index.js.map +1 -1
  298. package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts +6 -0
  299. package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts.map +1 -1
  300. package/packages/pi-coding-agent/dist/core/extensions/loader.js +80 -0
  301. package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
  302. package/packages/pi-coding-agent/dist/core/extensions/loader.test.js +63 -0
  303. package/packages/pi-coding-agent/dist/core/extensions/loader.test.js.map +1 -1
  304. package/packages/pi-coding-agent/dist/core/extensions/runner.test.js +24 -26
  305. package/packages/pi-coding-agent/dist/core/extensions/runner.test.js.map +1 -1
  306. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts +37 -0
  307. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts.map +1 -1
  308. package/packages/pi-coding-agent/dist/core/extensions/types.js.map +1 -1
  309. package/packages/pi-coding-agent/dist/core/fallback-resolver.d.ts.map +1 -1
  310. package/packages/pi-coding-agent/dist/core/fallback-resolver.js +2 -3
  311. package/packages/pi-coding-agent/dist/core/fallback-resolver.js.map +1 -1
  312. package/packages/pi-coding-agent/dist/core/fallback-resolver.test.js +12 -2
  313. package/packages/pi-coding-agent/dist/core/fallback-resolver.test.js.map +1 -1
  314. package/packages/pi-coding-agent/dist/core/fs-utils.test.js +29 -48
  315. package/packages/pi-coding-agent/dist/core/fs-utils.test.js.map +1 -1
  316. package/packages/pi-coding-agent/dist/core/lifecycle-hooks.d.ts +38 -0
  317. package/packages/pi-coding-agent/dist/core/lifecycle-hooks.d.ts.map +1 -0
  318. package/packages/pi-coding-agent/dist/core/lifecycle-hooks.js +192 -0
  319. package/packages/pi-coding-agent/dist/core/lifecycle-hooks.js.map +1 -0
  320. package/packages/pi-coding-agent/dist/core/lsp/client.d.ts +5 -0
  321. package/packages/pi-coding-agent/dist/core/lsp/client.d.ts.map +1 -1
  322. package/packages/pi-coding-agent/dist/core/lsp/client.js +69 -21
  323. package/packages/pi-coding-agent/dist/core/lsp/client.js.map +1 -1
  324. package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.d.ts +2 -0
  325. package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.d.ts.map +1 -0
  326. package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.js +255 -0
  327. package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.js.map +1 -0
  328. package/packages/pi-coding-agent/dist/core/model-registry.d.ts +15 -0
  329. package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
  330. package/packages/pi-coding-agent/dist/core/model-registry.js +40 -3
  331. package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
  332. package/packages/pi-coding-agent/dist/core/package-commands.d.ts +25 -0
  333. package/packages/pi-coding-agent/dist/core/package-commands.d.ts.map +1 -0
  334. package/packages/pi-coding-agent/dist/core/package-commands.js +253 -0
  335. package/packages/pi-coding-agent/dist/core/package-commands.js.map +1 -0
  336. package/packages/pi-coding-agent/dist/core/package-commands.test.d.ts +2 -0
  337. package/packages/pi-coding-agent/dist/core/package-commands.test.d.ts.map +1 -0
  338. package/packages/pi-coding-agent/dist/core/package-commands.test.js +225 -0
  339. package/packages/pi-coding-agent/dist/core/package-commands.test.js.map +1 -0
  340. package/packages/pi-coding-agent/dist/core/resolve-config-value.test.js +34 -44
  341. package/packages/pi-coding-agent/dist/core/resolve-config-value.test.js.map +1 -1
  342. package/packages/pi-coding-agent/dist/core/sdk.d.ts.map +1 -1
  343. package/packages/pi-coding-agent/dist/core/sdk.js +4 -0
  344. package/packages/pi-coding-agent/dist/core/sdk.js.map +1 -1
  345. package/packages/pi-coding-agent/dist/core/session-manager.test.js +30 -34
  346. package/packages/pi-coding-agent/dist/core/session-manager.test.js.map +1 -1
  347. package/packages/pi-coding-agent/dist/core/tools/edit-diff.test.js +10 -12
  348. package/packages/pi-coding-agent/dist/core/tools/edit-diff.test.js.map +1 -1
  349. package/packages/pi-coding-agent/dist/index.d.ts +3 -1
  350. package/packages/pi-coding-agent/dist/index.d.ts.map +1 -1
  351. package/packages/pi-coding-agent/dist/index.js +1 -0
  352. package/packages/pi-coding-agent/dist/index.js.map +1 -1
  353. package/packages/pi-coding-agent/dist/main.d.ts.map +1 -1
  354. package/packages/pi-coding-agent/dist/main.js +11 -199
  355. package/packages/pi-coding-agent/dist/main.js.map +1 -1
  356. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.d.ts +6 -0
  357. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.d.ts.map +1 -1
  358. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js +21 -0
  359. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js.map +1 -1
  360. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.d.ts +1 -1
  361. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  362. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.js +8 -15
  363. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.js.map +1 -1
  364. package/packages/pi-coding-agent/dist/modes/print-mode.d.ts.map +1 -1
  365. package/packages/pi-coding-agent/dist/modes/print-mode.js +45 -34
  366. package/packages/pi-coding-agent/dist/modes/print-mode.js.map +1 -1
  367. package/packages/pi-coding-agent/dist/modes/rpc/rpc-client.d.ts +1 -0
  368. package/packages/pi-coding-agent/dist/modes/rpc/rpc-client.d.ts.map +1 -1
  369. package/packages/pi-coding-agent/dist/modes/rpc/rpc-client.js +7 -2
  370. package/packages/pi-coding-agent/dist/modes/rpc/rpc-client.js.map +1 -1
  371. package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  372. package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.js +2 -1
  373. package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.js.map +1 -1
  374. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.test.js +43 -47
  375. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.test.js.map +1 -1
  376. package/packages/pi-coding-agent/package.json +1 -1
  377. package/packages/pi-coding-agent/src/core/agent-session.ts +26 -37
  378. package/packages/pi-coding-agent/src/core/auth-storage.test.ts +7 -7
  379. package/packages/pi-coding-agent/src/core/compaction/branch-summarization.ts +2 -2
  380. package/packages/pi-coding-agent/src/core/compaction/compaction.ts +3 -3
  381. package/packages/pi-coding-agent/src/core/compaction-orchestrator.ts +4 -4
  382. package/packages/pi-coding-agent/src/core/extensions/index.ts +5 -0
  383. package/packages/pi-coding-agent/src/core/extensions/loader.test.ts +96 -0
  384. package/packages/pi-coding-agent/src/core/extensions/loader.ts +89 -0
  385. package/packages/pi-coding-agent/src/core/extensions/runner.test.ts +26 -26
  386. package/packages/pi-coding-agent/src/core/extensions/types.ts +44 -0
  387. package/packages/pi-coding-agent/src/core/fallback-resolver.test.ts +15 -2
  388. package/packages/pi-coding-agent/src/core/fallback-resolver.ts +2 -3
  389. package/packages/pi-coding-agent/src/core/fs-utils.test.ts +31 -43
  390. package/packages/pi-coding-agent/src/core/lifecycle-hooks.ts +274 -0
  391. package/packages/pi-coding-agent/src/core/lsp/client.ts +83 -21
  392. package/packages/pi-coding-agent/src/core/model-registry-auth-mode.test.ts +288 -0
  393. package/packages/pi-coding-agent/src/core/model-registry.ts +39 -3
  394. package/packages/pi-coding-agent/src/core/package-commands.test.ts +240 -0
  395. package/packages/pi-coding-agent/src/core/package-commands.ts +310 -0
  396. package/packages/pi-coding-agent/src/core/resolve-config-value.test.ts +40 -45
  397. package/packages/pi-coding-agent/src/core/sdk.ts +4 -0
  398. package/packages/pi-coding-agent/src/core/session-manager.test.ts +33 -33
  399. package/packages/pi-coding-agent/src/core/tools/edit-diff.test.ts +17 -17
  400. package/packages/pi-coding-agent/src/index.ts +7 -0
  401. package/packages/pi-coding-agent/src/main.ts +11 -232
  402. package/packages/pi-coding-agent/src/modes/interactive/components/footer.ts +20 -0
  403. package/packages/pi-coding-agent/src/modes/interactive/theme/theme.ts +9 -16
  404. package/packages/pi-coding-agent/src/modes/print-mode.ts +42 -32
  405. package/packages/pi-coding-agent/src/modes/rpc/rpc-client.ts +8 -2
  406. package/packages/pi-coding-agent/src/modes/rpc/rpc-mode.ts +2 -1
  407. package/packages/pi-coding-agent/src/resources/extensions/memory/storage.test.ts +74 -74
  408. package/pkg/dist/modes/interactive/theme/theme.d.ts +1 -1
  409. package/pkg/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  410. package/pkg/dist/modes/interactive/theme/theme.js +8 -15
  411. package/pkg/dist/modes/interactive/theme/theme.js.map +1 -1
  412. package/pkg/package.json +1 -1
  413. package/src/resources/extensions/bg-shell/overlay.ts +4 -0
  414. package/src/resources/extensions/github-sync/sync.ts +2 -1
  415. package/src/resources/extensions/gsd/auto/loop-deps.ts +0 -8
  416. package/src/resources/extensions/gsd/auto/loop.ts +0 -2
  417. package/src/resources/extensions/gsd/auto/phases.ts +7 -20
  418. package/src/resources/extensions/gsd/auto/types.ts +0 -1
  419. package/src/resources/extensions/gsd/auto-dashboard.ts +20 -16
  420. package/src/resources/extensions/gsd/auto-direct-dispatch.ts +34 -19
  421. package/src/resources/extensions/gsd/auto-dispatch.ts +38 -21
  422. package/src/resources/extensions/gsd/auto-post-unit.ts +150 -15
  423. package/src/resources/extensions/gsd/auto-prompts.ts +186 -103
  424. package/src/resources/extensions/gsd/auto-recovery.ts +77 -142
  425. package/src/resources/extensions/gsd/auto-start.ts +14 -0
  426. package/src/resources/extensions/gsd/auto-supervisor.ts +14 -0
  427. package/src/resources/extensions/gsd/auto-timeout-recovery.ts +6 -7
  428. package/src/resources/extensions/gsd/auto-verification.ts +4 -9
  429. package/src/resources/extensions/gsd/auto-worktree.ts +126 -30
  430. package/src/resources/extensions/gsd/auto.ts +0 -9
  431. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +675 -4
  432. package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +31 -3
  433. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +7 -0
  434. package/src/resources/extensions/gsd/commands/catalog.ts +3 -1
  435. package/src/resources/extensions/gsd/commands/handlers/ops.ts +15 -1
  436. package/src/resources/extensions/gsd/commands/handlers/workflow.ts +8 -0
  437. package/src/resources/extensions/gsd/commands-handlers.ts +1 -1
  438. package/src/resources/extensions/gsd/commands-maintenance.ts +86 -3
  439. package/src/resources/extensions/gsd/dashboard-overlay.ts +17 -13
  440. package/src/resources/extensions/gsd/db-writer.ts +105 -4
  441. package/src/resources/extensions/gsd/dispatch-guard.ts +32 -30
  442. package/src/resources/extensions/gsd/doctor-checks.ts +25 -11
  443. package/src/resources/extensions/gsd/doctor-environment.ts +31 -0
  444. package/src/resources/extensions/gsd/doctor-types.ts +0 -23
  445. package/src/resources/extensions/gsd/doctor.ts +45 -295
  446. package/src/resources/extensions/gsd/file-watcher.ts +4 -1
  447. package/src/resources/extensions/gsd/files.ts +16 -220
  448. package/src/resources/extensions/gsd/git-service.ts +4 -0
  449. package/src/resources/extensions/gsd/gitignore.ts +4 -0
  450. package/src/resources/extensions/gsd/gsd-db.ts +1157 -370
  451. package/src/resources/extensions/gsd/guided-flow.ts +20 -8
  452. package/src/resources/extensions/gsd/markdown-renderer.ts +1098 -0
  453. package/src/resources/extensions/gsd/md-importer.ts +211 -2
  454. package/src/resources/extensions/gsd/native-git-bridge.ts +12 -1
  455. package/src/resources/extensions/gsd/parallel-eligibility.ts +14 -18
  456. package/src/resources/extensions/gsd/parallel-orchestrator.ts +43 -0
  457. package/src/resources/extensions/gsd/parsers-legacy.ts +271 -0
  458. package/src/resources/extensions/gsd/preferences-types.ts +3 -0
  459. package/src/resources/extensions/gsd/preferences-validation.ts +9 -0
  460. package/src/resources/extensions/gsd/preferences.ts +1 -0
  461. package/src/resources/extensions/gsd/prompts/complete-slice.md +22 -9
  462. package/src/resources/extensions/gsd/prompts/discuss.md +2 -2
  463. package/src/resources/extensions/gsd/prompts/execute-task.md +15 -5
  464. package/src/resources/extensions/gsd/prompts/guided-complete-slice.md +1 -1
  465. package/src/resources/extensions/gsd/prompts/guided-execute-task.md +1 -1
  466. package/src/resources/extensions/gsd/prompts/guided-plan-milestone.md +1 -1
  467. package/src/resources/extensions/gsd/prompts/plan-milestone.md +6 -10
  468. package/src/resources/extensions/gsd/prompts/plan-slice.md +4 -7
  469. package/src/resources/extensions/gsd/prompts/reactive-execute.md +3 -3
  470. package/src/resources/extensions/gsd/prompts/reassess-roadmap.md +6 -7
  471. package/src/resources/extensions/gsd/prompts/replan-slice.md +6 -6
  472. package/src/resources/extensions/gsd/reactive-graph.ts +33 -3
  473. package/src/resources/extensions/gsd/skill-health.ts +2 -1
  474. package/src/resources/extensions/gsd/state.ts +547 -29
  475. package/src/resources/extensions/gsd/tests/all-milestones-complete-merge.test.ts +99 -99
  476. package/src/resources/extensions/gsd/tests/atomic-task-closeout.test.ts +8 -120
  477. package/src/resources/extensions/gsd/tests/auto-lock-creation.test.ts +14 -16
  478. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +20 -11
  479. package/src/resources/extensions/gsd/tests/auto-paused-session-validation.test.ts +43 -57
  480. package/src/resources/extensions/gsd/tests/auto-preflight.test.ts +11 -13
  481. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +600 -513
  482. package/src/resources/extensions/gsd/tests/auto-secrets-gate.test.ts +73 -75
  483. package/src/resources/extensions/gsd/tests/auto-start-needs-discussion.test.ts +34 -56
  484. package/src/resources/extensions/gsd/tests/auto-stash-merge.test.ts +121 -0
  485. package/src/resources/extensions/gsd/tests/auto-worktree-milestone-merge.test.ts +540 -668
  486. package/src/resources/extensions/gsd/tests/auto-worktree.test.ts +165 -143
  487. package/src/resources/extensions/gsd/tests/cache-staleness-regression.test.ts +29 -52
  488. package/src/resources/extensions/gsd/tests/captures.test.ts +148 -176
  489. package/src/resources/extensions/gsd/tests/claude-import-tui.test.ts +32 -33
  490. package/src/resources/extensions/gsd/tests/collect-from-manifest.test.ts +141 -143
  491. package/src/resources/extensions/gsd/tests/commands-inspect-open-db.test.ts +25 -25
  492. package/src/resources/extensions/gsd/tests/commands-logs.test.ts +81 -81
  493. package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +39 -60
  494. package/src/resources/extensions/gsd/tests/complete-slice.test.ts +375 -0
  495. package/src/resources/extensions/gsd/tests/complete-task.test.ts +387 -0
  496. package/src/resources/extensions/gsd/tests/context-store.test.ts +354 -367
  497. package/src/resources/extensions/gsd/tests/continue-here.test.ts +68 -72
  498. package/src/resources/extensions/gsd/tests/cost-projection.test.ts +92 -106
  499. package/src/resources/extensions/gsd/tests/crash-recovery.test.ts +27 -35
  500. package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +0 -2
  501. package/src/resources/extensions/gsd/tests/dashboard-budget.test.ts +220 -237
  502. package/src/resources/extensions/gsd/tests/db-writer.test.ts +390 -420
  503. package/src/resources/extensions/gsd/tests/definition-loader.test.ts +76 -92
  504. package/src/resources/extensions/gsd/tests/derive-state-crossval.test.ts +512 -0
  505. package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +644 -84
  506. package/src/resources/extensions/gsd/tests/derive-state-deps.test.ts +78 -101
  507. package/src/resources/extensions/gsd/tests/derive-state.test.ts +192 -227
  508. package/src/resources/extensions/gsd/tests/detection.test.ts +232 -278
  509. package/src/resources/extensions/gsd/tests/dev-engine-wrapper.test.ts +30 -34
  510. package/src/resources/extensions/gsd/tests/dispatch-guard.test.ts +192 -161
  511. package/src/resources/extensions/gsd/tests/dispatch-missing-task-plans.test.ts +43 -49
  512. package/src/resources/extensions/gsd/tests/dispatch-uat-last-completed.test.ts +28 -32
  513. package/src/resources/extensions/gsd/tests/doctor-completion-deferral.test.ts +30 -90
  514. package/src/resources/extensions/gsd/tests/doctor-delimiter-fix.test.ts +34 -38
  515. package/src/resources/extensions/gsd/tests/doctor-enhancements.test.ts +57 -80
  516. package/src/resources/extensions/gsd/tests/doctor-environment-worktree.test.ts +164 -0
  517. package/src/resources/extensions/gsd/tests/doctor-environment.test.ts +72 -97
  518. package/src/resources/extensions/gsd/tests/doctor-fixlevel.test.ts +55 -153
  519. package/src/resources/extensions/gsd/tests/doctor-git.test.ts +104 -145
  520. package/src/resources/extensions/gsd/tests/doctor-proactive.test.ts +84 -106
  521. package/src/resources/extensions/gsd/tests/doctor-roadmap-summary-atomicity.test.ts +53 -97
  522. package/src/resources/extensions/gsd/tests/doctor-runtime.test.ts +72 -93
  523. package/src/resources/extensions/gsd/tests/doctor.test.ts +109 -149
  524. package/src/resources/extensions/gsd/tests/ensure-db-open.test.ts +123 -131
  525. package/src/resources/extensions/gsd/tests/exit-command.test.ts +20 -24
  526. package/src/resources/extensions/gsd/tests/feature-branch-lifecycle-integration.test.ts +48 -57
  527. package/src/resources/extensions/gsd/tests/files-loadfile-eisdir.test.ts +5 -7
  528. package/src/resources/extensions/gsd/tests/flag-file-db.test.ts +278 -0
  529. package/src/resources/extensions/gsd/tests/freeform-decisions.test.ts +232 -0
  530. package/src/resources/extensions/gsd/tests/git-locale.test.ts +13 -27
  531. package/src/resources/extensions/gsd/tests/git-service.test.ts +291 -390
  532. package/src/resources/extensions/gsd/tests/gitignore-tracked-gsd.test.ts +31 -39
  533. package/src/resources/extensions/gsd/tests/graph-operations.test.ts +63 -69
  534. package/src/resources/extensions/gsd/tests/gsd-db.test.ts +255 -264
  535. package/src/resources/extensions/gsd/tests/gsd-inspect.test.ts +108 -119
  536. package/src/resources/extensions/gsd/tests/gsd-recover.test.ts +440 -0
  537. package/src/resources/extensions/gsd/tests/gsd-tools.test.ts +229 -262
  538. package/src/resources/extensions/gsd/tests/headless-answers.test.ts +13 -13
  539. package/src/resources/extensions/gsd/tests/health-widget.test.ts +29 -37
  540. package/src/resources/extensions/gsd/tests/idle-recovery.test.ts +81 -270
  541. package/src/resources/extensions/gsd/tests/init-wizard.test.ts +16 -18
  542. package/src/resources/extensions/gsd/tests/integration-edge.test.ts +41 -46
  543. package/src/resources/extensions/gsd/tests/integration-lifecycle.test.ts +42 -53
  544. package/src/resources/extensions/gsd/tests/integration-mixed-milestones.test.ts +75 -91
  545. package/src/resources/extensions/gsd/tests/integration-proof.test.ts +643 -0
  546. package/src/resources/extensions/gsd/tests/journal-integration.test.ts +0 -3
  547. package/src/resources/extensions/gsd/tests/markdown-renderer.test.ts +1161 -0
  548. package/src/resources/extensions/gsd/tests/md-importer.test.ts +101 -125
  549. package/src/resources/extensions/gsd/tests/memory-extractor.test.ts +45 -54
  550. package/src/resources/extensions/gsd/tests/memory-store.test.ts +81 -94
  551. package/src/resources/extensions/gsd/tests/migrate-command.test.ts +57 -66
  552. package/src/resources/extensions/gsd/tests/migrate-hierarchy.test.ts +429 -0
  553. package/src/resources/extensions/gsd/tests/migrate-parser.test.ts +161 -170
  554. package/src/resources/extensions/gsd/tests/migrate-transformer.test.ts +125 -141
  555. package/src/resources/extensions/gsd/tests/migrate-validator-parsers.test.ts +107 -131
  556. package/src/resources/extensions/gsd/tests/migrate-writer-integration.test.ts +89 -97
  557. package/src/resources/extensions/gsd/tests/migrate-writer.test.ts +127 -164
  558. package/src/resources/extensions/gsd/tests/must-have-parser.test.ts +81 -94
  559. package/src/resources/extensions/gsd/tests/none-mode-gates.test.ts +35 -36
  560. package/src/resources/extensions/gsd/tests/overrides.test.ts +99 -106
  561. package/src/resources/extensions/gsd/tests/parallel-crash-recovery.test.ts +40 -47
  562. package/src/resources/extensions/gsd/tests/parallel-worker-monitoring.test.ts +25 -28
  563. package/src/resources/extensions/gsd/tests/parallel-workers-multi-milestone-e2e.test.ts +66 -83
  564. package/src/resources/extensions/gsd/tests/park-edge-cases.test.ts +54 -77
  565. package/src/resources/extensions/gsd/tests/park-milestone.test.ts +68 -115
  566. package/src/resources/extensions/gsd/tests/parsers.test.ts +548 -612
  567. package/src/resources/extensions/gsd/tests/paths.test.ts +72 -87
  568. package/src/resources/extensions/gsd/tests/plan-milestone.test.ts +176 -113
  569. package/src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +7 -0
  570. package/src/resources/extensions/gsd/tests/plan-slice.test.ts +179 -0
  571. package/src/resources/extensions/gsd/tests/plan-task.test.ts +145 -0
  572. package/src/resources/extensions/gsd/tests/planning-crossval.test.ts +305 -0
  573. package/src/resources/extensions/gsd/tests/post-unit-hooks.test.ts +77 -117
  574. package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +139 -0
  575. package/src/resources/extensions/gsd/tests/prompt-db.test.ts +56 -56
  576. package/src/resources/extensions/gsd/tests/queue-draft-detection.test.ts +93 -119
  577. package/src/resources/extensions/gsd/tests/queue-order.test.ts +70 -82
  578. package/src/resources/extensions/gsd/tests/queue-reorder-e2e.test.ts +42 -55
  579. package/src/resources/extensions/gsd/tests/quick-auto-guard.test.ts +100 -0
  580. package/src/resources/extensions/gsd/tests/quick-branch-lifecycle.test.ts +45 -73
  581. package/src/resources/extensions/gsd/tests/reassess-handler.test.ts +325 -0
  582. package/src/resources/extensions/gsd/tests/reassess-prompt.test.ts +28 -38
  583. package/src/resources/extensions/gsd/tests/replan-handler.test.ts +410 -0
  584. package/src/resources/extensions/gsd/tests/replan-slice.test.ts +73 -80
  585. package/src/resources/extensions/gsd/tests/repo-identity-worktree.test.ts +71 -74
  586. package/src/resources/extensions/gsd/tests/requirements.test.ts +70 -75
  587. package/src/resources/extensions/gsd/tests/retry-state-reset.test.ts +44 -66
  588. package/src/resources/extensions/gsd/tests/roadmap-parse-regression.test.ts +114 -181
  589. package/src/resources/extensions/gsd/tests/roadmap-slices.test.ts +1 -1
  590. package/src/resources/extensions/gsd/tests/rogue-file-detection.test.ts +296 -0
  591. package/src/resources/extensions/gsd/tests/rule-registry.test.ts +63 -65
  592. package/src/resources/extensions/gsd/tests/run-uat.test.ts +66 -128
  593. package/src/resources/extensions/gsd/tests/schema-v9-sequence.test.ts +176 -0
  594. package/src/resources/extensions/gsd/tests/session-lock-multipath.test.ts +18 -25
  595. package/src/resources/extensions/gsd/tests/session-lock-regression.test.ts +37 -44
  596. package/src/resources/extensions/gsd/tests/shared-wal.test.ts +209 -0
  597. package/src/resources/extensions/gsd/tests/sqlite-unavailable-gate.test.ts +63 -0
  598. package/src/resources/extensions/gsd/tests/stalled-tool-recovery.test.ts +6 -8
  599. package/src/resources/extensions/gsd/tests/symlink-numbered-variants.test.ts +22 -28
  600. package/src/resources/extensions/gsd/tests/token-cost-display.test.ts +118 -0
  601. package/src/resources/extensions/gsd/tests/token-savings.test.ts +54 -56
  602. package/src/resources/extensions/gsd/tests/tool-call-loop-guard.test.ts +23 -25
  603. package/src/resources/extensions/gsd/tests/tool-naming.test.ts +19 -13
  604. package/src/resources/extensions/gsd/tests/undo.test.ts +321 -1
  605. package/src/resources/extensions/gsd/tests/unique-milestone-ids.test.ts +66 -82
  606. package/src/resources/extensions/gsd/tests/unit-runtime.test.ts +46 -47
  607. package/src/resources/extensions/gsd/tests/validate-milestone.test.ts +1 -1
  608. package/src/resources/extensions/gsd/tests/verification-evidence.test.ts +0 -142
  609. package/src/resources/extensions/gsd/tests/visualizer-critical-path.test.ts +20 -22
  610. package/src/resources/extensions/gsd/tests/visualizer-data.test.ts +84 -86
  611. package/src/resources/extensions/gsd/tests/visualizer-overlay.test.ts +41 -43
  612. package/src/resources/extensions/gsd/tests/visualizer-views.test.ts +94 -96
  613. package/src/resources/extensions/gsd/tests/windows-path-normalization.test.ts +11 -13
  614. package/src/resources/extensions/gsd/tests/worker-registry.test.ts +27 -29
  615. package/src/resources/extensions/gsd/tests/workflow-templates.test.ts +50 -52
  616. package/src/resources/extensions/gsd/tests/worktree-bugfix.test.ts +10 -13
  617. package/src/resources/extensions/gsd/tests/worktree-db-integration.test.ts +14 -18
  618. package/src/resources/extensions/gsd/tests/worktree-db.test.ts +38 -39
  619. package/src/resources/extensions/gsd/tests/worktree-e2e.test.ts +17 -21
  620. package/src/resources/extensions/gsd/tests/worktree-health-dispatch.test.ts +12 -5
  621. package/src/resources/extensions/gsd/tests/worktree-health.test.ts +25 -30
  622. package/src/resources/extensions/gsd/tests/worktree-integration.test.ts +30 -37
  623. package/src/resources/extensions/gsd/tests/worktree-symlink-removal.test.ts +15 -22
  624. package/src/resources/extensions/gsd/tests/worktree-sync-milestones.test.ts +59 -66
  625. package/src/resources/extensions/gsd/tests/worktree.test.ts +44 -50
  626. package/src/resources/extensions/gsd/tools/complete-milestone.ts +176 -0
  627. package/src/resources/extensions/gsd/tools/complete-slice.ts +300 -0
  628. package/src/resources/extensions/gsd/tools/complete-task.ts +245 -0
  629. package/src/resources/extensions/gsd/tools/plan-milestone.ts +249 -0
  630. package/src/resources/extensions/gsd/tools/plan-slice.ts +194 -0
  631. package/src/resources/extensions/gsd/tools/plan-task.ts +116 -0
  632. package/src/resources/extensions/gsd/tools/reassess-roadmap.ts +203 -0
  633. package/src/resources/extensions/gsd/tools/replan-slice.ts +192 -0
  634. package/src/resources/extensions/gsd/triage-resolution.ts +20 -1
  635. package/src/resources/extensions/gsd/types.ts +50 -0
  636. package/src/resources/extensions/gsd/undo.ts +247 -3
  637. package/src/resources/extensions/gsd/visualizer-data.ts +54 -17
  638. package/src/resources/extensions/gsd/workspace-index.ts +64 -46
  639. package/dist/resources/extensions/gsd/auto-observability.js +0 -56
  640. package/dist/resources/extensions/gsd/observability-validator.js +0 -422
  641. package/dist/resources/extensions/gsd/roadmap-mutations.js +0 -110
  642. package/dist/web/standalone/.next/static/VvclDCW6TAWjEyLU-EYL1/_buildManifest.js +0 -1
  643. package/dist/web/standalone/.next/static/chunks/app/_not-found/page-e07acdb7dd069836.js +0 -1
  644. package/dist/web/standalone/.next/static/chunks/app/api/bridge-terminal/stream/route-d07a2c023f1aef1e.js +0 -1
  645. package/dist/web/standalone/.next/static/chunks/app/api/browse-directories/route-d07a2c023f1aef1e.js +0 -1
  646. package/dist/web/standalone/.next/static/chunks/app/api/captures/route-d07a2c023f1aef1e.js +0 -1
  647. package/dist/web/standalone/.next/static/chunks/app/api/cleanup/route-d07a2c023f1aef1e.js +0 -1
  648. package/dist/web/standalone/.next/static/chunks/app/api/dev-mode/route-d07a2c023f1aef1e.js +0 -1
  649. package/dist/web/standalone/.next/static/chunks/app/api/doctor/route-d07a2c023f1aef1e.js +0 -1
  650. package/dist/web/standalone/.next/static/chunks/app/api/export-data/route-d07a2c023f1aef1e.js +0 -1
  651. package/dist/web/standalone/.next/static/chunks/app/api/files/route-d07a2c023f1aef1e.js +0 -1
  652. package/dist/web/standalone/.next/static/chunks/app/api/forensics/route-d07a2c023f1aef1e.js +0 -1
  653. package/dist/web/standalone/.next/static/chunks/app/api/git/route-d07a2c023f1aef1e.js +0 -1
  654. package/dist/web/standalone/.next/static/chunks/app/api/history/route-d07a2c023f1aef1e.js +0 -1
  655. package/dist/web/standalone/.next/static/chunks/app/api/hooks/route-d07a2c023f1aef1e.js +0 -1
  656. package/dist/web/standalone/.next/static/chunks/app/api/inspect/route-d07a2c023f1aef1e.js +0 -1
  657. package/dist/web/standalone/.next/static/chunks/app/api/knowledge/route-d07a2c023f1aef1e.js +0 -1
  658. package/dist/web/standalone/.next/static/chunks/app/api/live-state/route-d07a2c023f1aef1e.js +0 -1
  659. package/dist/web/standalone/.next/static/chunks/app/api/onboarding/route-d07a2c023f1aef1e.js +0 -1
  660. package/dist/web/standalone/.next/static/chunks/app/api/preferences/route-d07a2c023f1aef1e.js +0 -1
  661. package/dist/web/standalone/.next/static/chunks/app/api/projects/route-d07a2c023f1aef1e.js +0 -1
  662. package/dist/web/standalone/.next/static/chunks/app/api/recovery/route-d07a2c023f1aef1e.js +0 -1
  663. package/dist/web/standalone/.next/static/chunks/app/api/remote-questions/route-d07a2c023f1aef1e.js +0 -1
  664. package/dist/web/standalone/.next/static/chunks/app/api/session/browser/route-d07a2c023f1aef1e.js +0 -1
  665. package/dist/web/standalone/.next/static/chunks/app/api/session/command/route-d07a2c023f1aef1e.js +0 -1
  666. package/dist/web/standalone/.next/static/chunks/app/api/session/events/route-d07a2c023f1aef1e.js +0 -1
  667. package/dist/web/standalone/.next/static/chunks/app/api/session/manage/route-d07a2c023f1aef1e.js +0 -1
  668. package/dist/web/standalone/.next/static/chunks/app/api/settings-data/route-d07a2c023f1aef1e.js +0 -1
  669. package/dist/web/standalone/.next/static/chunks/app/api/shutdown/route-d07a2c023f1aef1e.js +0 -1
  670. package/dist/web/standalone/.next/static/chunks/app/api/skill-health/route-d07a2c023f1aef1e.js +0 -1
  671. package/dist/web/standalone/.next/static/chunks/app/api/steer/route-d07a2c023f1aef1e.js +0 -1
  672. package/dist/web/standalone/.next/static/chunks/app/api/terminal/input/route-d07a2c023f1aef1e.js +0 -1
  673. package/dist/web/standalone/.next/static/chunks/app/api/terminal/resize/route-d07a2c023f1aef1e.js +0 -1
  674. package/dist/web/standalone/.next/static/chunks/app/api/terminal/sessions/route-d07a2c023f1aef1e.js +0 -1
  675. package/dist/web/standalone/.next/static/chunks/app/api/terminal/stream/route-d07a2c023f1aef1e.js +0 -1
  676. package/dist/web/standalone/.next/static/chunks/app/api/terminal/upload/route-d07a2c023f1aef1e.js +0 -1
  677. package/dist/web/standalone/.next/static/chunks/app/api/undo/route-d07a2c023f1aef1e.js +0 -1
  678. package/dist/web/standalone/.next/static/chunks/app/api/update/route-d07a2c023f1aef1e.js +0 -1
  679. package/dist/web/standalone/.next/static/chunks/app/api/visualizer/route-d07a2c023f1aef1e.js +0 -1
  680. package/dist/web/standalone/.next/static/chunks/app/layout-745c6ed5fea5fb06.js +0 -1
  681. package/dist/web/standalone/.next/static/chunks/app/page-801b53eff6e83579.js +0 -1
  682. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/app-error-d07a2c023f1aef1e.js +0 -1
  683. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/forbidden-d07a2c023f1aef1e.js +0 -1
  684. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-e6255954dccfcf0a.js +0 -1
  685. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/not-found-d07a2c023f1aef1e.js +0 -1
  686. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/unauthorized-d07a2c023f1aef1e.js +0 -1
  687. package/dist/web/standalone/.next/static/css/123c0bb039697968.css +0 -1
  688. package/src/resources/extensions/gsd/auto-observability.ts +0 -74
  689. package/src/resources/extensions/gsd/observability-validator.ts +0 -456
  690. package/src/resources/extensions/gsd/roadmap-mutations.ts +0 -134
  691. package/src/resources/extensions/gsd/tests/doctor-task-done-missing-summary-slice-loop.test.ts +0 -174
  692. package/src/resources/extensions/gsd/tests/plan-quality-validator.test.ts +0 -474
  693. /package/dist/web/standalone/.next/static/{VvclDCW6TAWjEyLU-EYL1 → alS4hoANx0TK4UVZY27da}/_ssgManifest.js +0 -0
@@ -23,15 +23,15 @@ import { tmpdir } from "node:os";
23
23
  import { execSync } from "node:child_process";
24
24
 
25
25
  import { ensureGsdSymlink, externalGsdRoot } from "../repo-identity.ts";
26
- import { createTestContext } from "./test-helpers.ts";
26
+ import { describe, test } from 'node:test';
27
+ import assert from 'node:assert/strict';
27
28
 
28
- const { assertEq, assertTrue, report } = createTestContext();
29
29
 
30
30
  function run(command: string, cwd: string): string {
31
31
  return execSync(command, { cwd, stdio: ["ignore", "pipe", "pipe"], encoding: "utf-8" }).trim();
32
32
  }
33
33
 
34
- async function main(): Promise<void> {
34
+ describe('symlink-numbered-variants', async () => {
35
35
  const base = realpathSync(mkdtempSync(join(tmpdir(), "gsd-symlink-variants-")));
36
36
  const stateDir = realpathSync(mkdtempSync(join(tmpdir(), "gsd-state-variants-")));
37
37
 
@@ -58,14 +58,14 @@ async function main(): Promise<void> {
58
58
  mkdirSync(join(base, ".gsd 4"), { recursive: true });
59
59
 
60
60
  const result = ensureGsdSymlink(base);
61
- assertEq(result, externalPath, "ensureGsdSymlink returns external path");
62
- assertTrue(existsSync(join(base, ".gsd")), ".gsd exists after ensureGsdSymlink");
63
- assertTrue(lstatSync(join(base, ".gsd")).isSymbolicLink(), ".gsd is a symlink");
61
+ assert.deepStrictEqual(result, externalPath, "ensureGsdSymlink returns external path");
62
+ assert.ok(existsSync(join(base, ".gsd")), ".gsd exists after ensureGsdSymlink");
63
+ assert.ok(lstatSync(join(base, ".gsd")).isSymbolicLink(), ".gsd is a symlink");
64
64
 
65
65
  // The numbered variants must have been removed
66
- assertTrue(!existsSync(join(base, ".gsd 2")), '".gsd 2" directory was cleaned up');
67
- assertTrue(!existsSync(join(base, ".gsd 3")), '".gsd 3" directory was cleaned up');
68
- assertTrue(!existsSync(join(base, ".gsd 4")), '".gsd 4" directory was cleaned up');
66
+ assert.ok(!existsSync(join(base, ".gsd 2")), '".gsd 2" directory was cleaned up');
67
+ assert.ok(!existsSync(join(base, ".gsd 3")), '".gsd 3" directory was cleaned up');
68
+ assert.ok(!existsSync(join(base, ".gsd 4")), '".gsd 4" directory was cleaned up');
69
69
  }
70
70
 
71
71
  // ── Test: numbered variant symlinks are cleaned up ─────────────────
@@ -82,12 +82,12 @@ async function main(): Promise<void> {
82
82
  symlinkSync(staleTarget, join(base, ".gsd 3"), "junction");
83
83
 
84
84
  const result = ensureGsdSymlink(base);
85
- assertEq(result, externalPath, "ensureGsdSymlink returns external path when variants exist");
86
- assertTrue(existsSync(join(base, ".gsd")), ".gsd exists");
87
- assertTrue(lstatSync(join(base, ".gsd")).isSymbolicLink(), ".gsd is a symlink");
85
+ assert.deepStrictEqual(result, externalPath, "ensureGsdSymlink returns external path when variants exist");
86
+ assert.ok(existsSync(join(base, ".gsd")), ".gsd exists");
87
+ assert.ok(lstatSync(join(base, ".gsd")).isSymbolicLink(), ".gsd is a symlink");
88
88
 
89
- assertTrue(!existsSync(join(base, ".gsd 2")), '".gsd 2" symlink variant was cleaned up');
90
- assertTrue(!existsSync(join(base, ".gsd 3")), '".gsd 3" symlink variant was cleaned up');
89
+ assert.ok(!existsSync(join(base, ".gsd 2")), '".gsd 2" symlink variant was cleaned up');
90
+ assert.ok(!existsSync(join(base, ".gsd 3")), '".gsd 3" symlink variant was cleaned up');
91
91
  }
92
92
 
93
93
  // ── Test: real .gsd directory blocks symlink, but variants still cleaned ──
@@ -104,12 +104,12 @@ async function main(): Promise<void> {
104
104
 
105
105
  const result = ensureGsdSymlink(base);
106
106
  // When .gsd is a real directory, ensureGsdSymlink preserves it
107
- assertEq(result, join(base, ".gsd"), "real .gsd directory preserved");
108
- assertTrue(lstatSync(join(base, ".gsd")).isDirectory(), ".gsd remains a directory");
107
+ assert.deepStrictEqual(result, join(base, ".gsd"), "real .gsd directory preserved");
108
+ assert.ok(lstatSync(join(base, ".gsd")).isDirectory(), ".gsd remains a directory");
109
109
 
110
110
  // But the numbered variants should still be cleaned up
111
- assertTrue(!existsSync(join(base, ".gsd 2")), '".gsd 2" cleaned even when .gsd is a directory');
112
- assertTrue(!existsSync(join(base, ".gsd 3")), '".gsd 3" cleaned even when .gsd is a directory');
111
+ assert.ok(!existsSync(join(base, ".gsd 2")), '".gsd 2" cleaned even when .gsd is a directory');
112
+ assert.ok(!existsSync(join(base, ".gsd 3")), '".gsd 3" cleaned even when .gsd is a directory');
113
113
  }
114
114
 
115
115
  // ── Test: only numeric-suffixed variants are removed ───────────────
@@ -127,10 +127,10 @@ async function main(): Promise<void> {
127
127
 
128
128
  ensureGsdSymlink(base);
129
129
 
130
- assertTrue(existsSync(join(base, ".gsd-backup")), ".gsd-backup is NOT removed");
131
- assertTrue(existsSync(join(base, ".gsd_old")), ".gsd_old is NOT removed");
132
- assertTrue(!existsSync(join(base, ".gsd 2")), '".gsd 2" removed');
133
- assertTrue(!existsSync(join(base, ".gsd 10")), '".gsd 10" removed');
130
+ assert.ok(existsSync(join(base, ".gsd-backup")), ".gsd-backup is NOT removed");
131
+ assert.ok(existsSync(join(base, ".gsd_old")), ".gsd_old is NOT removed");
132
+ assert.ok(!existsSync(join(base, ".gsd 2")), '".gsd 2" removed');
133
+ assert.ok(!existsSync(join(base, ".gsd 10")), '".gsd 10" removed');
134
134
 
135
135
  // Cleanup non-variant dirs
136
136
  rmSync(join(base, ".gsd-backup"), { recursive: true, force: true });
@@ -141,11 +141,5 @@ async function main(): Promise<void> {
141
141
  delete process.env.GSD_STATE_DIR;
142
142
  try { rmSync(base, { recursive: true, force: true }); } catch { /* ignore */ }
143
143
  try { rmSync(stateDir, { recursive: true, force: true }); } catch { /* ignore */ }
144
- report();
145
144
  }
146
- }
147
-
148
- main().catch((error) => {
149
- console.error(error);
150
- process.exit(1);
151
145
  });
@@ -0,0 +1,118 @@
1
+ /**
2
+ * Tests for the show_token_cost preference (#1515).
3
+ *
4
+ * Covers:
5
+ * - Preference recognition and validation
6
+ * - Cost formatting accuracy (inline re-implementation for test isolation)
7
+ * - Disabled-by-default behavior
8
+ * - Preference parsing from markdown frontmatter
9
+ */
10
+
11
+ import test from "node:test";
12
+ import assert from "node:assert/strict";
13
+ import {
14
+ validatePreferences,
15
+ parsePreferencesMarkdown,
16
+ } from "../preferences.ts";
17
+ import { KNOWN_PREFERENCE_KEYS } from "../preferences-types.ts";
18
+
19
+ // Re-implement formatPromptCost here for test isolation (avoids pi-coding-agent build dep).
20
+ // The canonical implementation lives in footer.ts.
21
+ function formatPromptCost(cost: number): string {
22
+ if (cost < 0.001) return `$${cost.toFixed(4)}`;
23
+ if (cost < 0.01) return `$${cost.toFixed(3)}`;
24
+ if (cost < 1) return `$${cost.toFixed(3)}`;
25
+ return `$${cost.toFixed(2)}`;
26
+ }
27
+
28
+ // ── Preference recognition ──────────────────────────────────────────────────
29
+
30
+ test("show_token_cost is a known preference key", () => {
31
+ assert.ok(KNOWN_PREFERENCE_KEYS.has("show_token_cost"));
32
+ });
33
+
34
+ test("show_token_cost: true validates without errors", () => {
35
+ const { errors, preferences } = validatePreferences({ show_token_cost: true });
36
+ assert.equal(errors.length, 0);
37
+ assert.equal(preferences.show_token_cost, true);
38
+ });
39
+
40
+ test("show_token_cost: false validates without errors", () => {
41
+ const { errors, preferences } = validatePreferences({ show_token_cost: false });
42
+ assert.equal(errors.length, 0);
43
+ assert.equal(preferences.show_token_cost, false);
44
+ });
45
+
46
+ test("show_token_cost: non-boolean produces validation error", () => {
47
+ const { errors } = validatePreferences({ show_token_cost: "yes" as any });
48
+ assert.ok(errors.length > 0);
49
+ assert.ok(errors[0].includes("show_token_cost"));
50
+ assert.ok(errors[0].includes("boolean"));
51
+ });
52
+
53
+ test("show_token_cost does not produce unknown-key warning", () => {
54
+ const { warnings } = validatePreferences({ show_token_cost: true });
55
+ const unknownWarnings = warnings.filter(w => w.includes("show_token_cost"));
56
+ assert.equal(unknownWarnings.length, 0);
57
+ });
58
+
59
+ // ── Disabled by default ─────────────────────────────────────────────────────
60
+
61
+ test("show_token_cost defaults to undefined (disabled) when not set", () => {
62
+ const { preferences } = validatePreferences({});
63
+ assert.equal(preferences.show_token_cost, undefined);
64
+ });
65
+
66
+ test("empty preferences.md does not enable show_token_cost", () => {
67
+ const prefs = parsePreferencesMarkdown("---\nversion: 1\n---\n");
68
+ assert.ok(prefs);
69
+ assert.equal(prefs.show_token_cost, undefined);
70
+ });
71
+
72
+ test("preferences.md with show_token_cost: true enables the preference", () => {
73
+ const prefs = parsePreferencesMarkdown("---\nshow_token_cost: true\n---\n");
74
+ assert.ok(prefs);
75
+ assert.equal(prefs.show_token_cost, true);
76
+ });
77
+
78
+ // ── Cost formatting ─────────────────────────────────────────────────────────
79
+
80
+ test("formatPromptCost formats sub-cent amounts with 4 decimals", () => {
81
+ assert.equal(formatPromptCost(0.0003), "$0.0003");
82
+ assert.equal(formatPromptCost(0.0009), "$0.0009");
83
+ });
84
+
85
+ test("formatPromptCost formats cent-range amounts with 3 decimals", () => {
86
+ assert.equal(formatPromptCost(0.003), "$0.003");
87
+ assert.equal(formatPromptCost(0.012), "$0.012");
88
+ assert.equal(formatPromptCost(0.1), "$0.100");
89
+ });
90
+
91
+ test("formatPromptCost formats dollar-range amounts with 2 decimals", () => {
92
+ assert.equal(formatPromptCost(1.5), "$1.50");
93
+ assert.equal(formatPromptCost(12.345), "$12.35");
94
+ });
95
+
96
+ test("formatPromptCost handles zero", () => {
97
+ assert.equal(formatPromptCost(0), "$0.0000");
98
+ });
99
+
100
+ // ── Cost calculation correctness ────────────────────────────────────────────
101
+
102
+ test("cost calculation formula matches Model cost structure", () => {
103
+ // Simulates: usage.input * model.cost.input / 1_000_000 + usage.output * model.cost.output / 1_000_000
104
+ // Model.cost fields are $/million tokens
105
+ const modelCost = { input: 15, output: 75, cacheRead: 1.5, cacheWrite: 18.75 }; // claude-opus-4 pricing
106
+ const usage = { input: 2000, output: 500, cacheRead: 10000, cacheWrite: 1000 };
107
+
108
+ const cost =
109
+ (usage.input * modelCost.input / 1_000_000) +
110
+ (usage.output * modelCost.output / 1_000_000) +
111
+ (usage.cacheRead * modelCost.cacheRead / 1_000_000) +
112
+ (usage.cacheWrite * modelCost.cacheWrite / 1_000_000);
113
+
114
+ // 2000*15/1M + 500*75/1M + 10000*1.5/1M + 1000*18.75/1M
115
+ // = 0.03 + 0.0375 + 0.015 + 0.01875 = 0.10125
116
+ assert.ok(Math.abs(cost - 0.10125) < 0.0001, `Expected ~$0.10125 but got $${cost}`);
117
+ assert.equal(formatPromptCost(cost), "$0.101");
118
+ });
@@ -18,9 +18,9 @@ import {
18
18
  formatDecisionsForPrompt,
19
19
  formatRequirementsForPrompt,
20
20
  } from '../context-store.ts';
21
- import { createTestContext } from './test-helpers.ts';
21
+ import { test } from 'node:test';
22
+ import assert from 'node:assert/strict';
22
23
 
23
- const { assertEq, assertTrue, assertMatch, assertNoMatch, report } = createTestContext();
24
24
 
25
25
  // ─── Fixture Generators ────────────────────────────────────────────────────
26
26
 
@@ -154,8 +154,8 @@ console.log('\n=== token-savings: plan-slice prompt ≥30% character savings ===
154
154
  openDatabase(':memory:');
155
155
  const result = migrateFromMarkdown(base);
156
156
 
157
- assertTrue(result.decisions === DECISIONS_COUNT, `imported ${result.decisions} decisions, expected ${DECISIONS_COUNT}`);
158
- assertTrue(result.requirements === REQUIREMENTS_COUNT, `imported ${result.requirements} requirements, expected ${REQUIREMENTS_COUNT}`);
157
+ assert.ok(result.decisions === DECISIONS_COUNT, `imported ${result.decisions} decisions, expected ${DECISIONS_COUNT}`);
158
+ assert.ok(result.requirements === REQUIREMENTS_COUNT, `imported ${result.requirements} requirements, expected ${REQUIREMENTS_COUNT}`);
159
159
 
160
160
  // ── DB-scoped content for plan-slice (M001 decisions + S01 requirements) ──
161
161
  const scopedDecisions = queryDecisions({ milestoneId: 'M001' });
@@ -174,31 +174,31 @@ console.log('\n=== token-savings: plan-slice prompt ≥30% character savings ===
174
174
  const savingsPercent = ((fullTotal - dbTotal) / fullTotal) * 100;
175
175
  console.log(` Plan-slice savings: ${savingsPercent.toFixed(1)}% (DB: ${dbTotal} chars, full: ${fullTotal} chars)`);
176
176
 
177
- assertTrue(dbTotal > 0, 'DB-scoped content is non-empty');
178
- assertTrue(dbDecisionsContent.length > 0, 'DB-scoped decisions content is non-empty');
179
- assertTrue(dbRequirementsContent.length > 0, 'DB-scoped requirements content is non-empty');
180
- assertTrue(savingsPercent >= 30, `plan-slice savings ≥30% (actual: ${savingsPercent.toFixed(1)}%)`);
181
- assertTrue(dbTotal < fullTotal * 0.70, `DB total (${dbTotal}) < 70% of full total (${fullTotal})`);
177
+ assert.ok(dbTotal > 0, 'DB-scoped content is non-empty');
178
+ assert.ok(dbDecisionsContent.length > 0, 'DB-scoped decisions content is non-empty');
179
+ assert.ok(dbRequirementsContent.length > 0, 'DB-scoped requirements content is non-empty');
180
+ assert.ok(savingsPercent >= 30, `plan-slice savings ≥30% (actual: ${savingsPercent.toFixed(1)}%)`);
181
+ assert.ok(dbTotal < fullTotal * 0.70, `DB total (${dbTotal}) < 70% of full total (${fullTotal})`);
182
182
 
183
183
  // ── Verify correct scoping: decisions ──
184
184
  // M001 decisions: those with when_context containing 'M001' — indices 1,4,7,10,13,16,19,22
185
185
  // (24 decisions round-robin across M001/M002/M003 → 8 for M001)
186
- assertTrue(scopedDecisions.length === 8, `M001 decisions: expected 8, got ${scopedDecisions.length}`);
186
+ assert.ok(scopedDecisions.length === 8, `M001 decisions: expected 8, got ${scopedDecisions.length}`);
187
187
  for (const d of scopedDecisions) {
188
- assertTrue(d.when_context.includes('M001'), `decision ${d.id} should have M001 in when_context, got "${d.when_context}"`);
188
+ assert.ok(d.when_context.includes('M001'), `decision ${d.id} should have M001 in when_context, got "${d.when_context}"`);
189
189
  }
190
190
 
191
191
  // Verify NO decisions from other milestones leak in
192
192
  for (const d of scopedDecisions) {
193
- assertNoMatch(d.when_context, /M002|M003/, `decision ${d.id} should not contain M002 or M003`);
193
+ assert.doesNotMatch(d.when_context, /M002|M003/, `decision ${d.id} should not contain M002 or M003`);
194
194
  }
195
195
 
196
196
  // ── Verify correct scoping: requirements ──
197
197
  // S01 requirements: those assigned to S01 as primary_owner
198
198
  // S01 appears in positions 1,6,11,16,21 (5 assignments cycling, 21 reqs → indices 0,5,10,15,20)
199
- assertTrue(scopedRequirements.length > 0, 'S01 requirements non-empty');
199
+ assert.ok(scopedRequirements.length > 0, 'S01 requirements non-empty');
200
200
  for (const r of scopedRequirements) {
201
- assertTrue(
201
+ assert.ok(
202
202
  r.primary_owner.includes('S01') || r.supporting_slices.includes('S01'),
203
203
  `requirement ${r.id} should be owned by or support S01`,
204
204
  );
@@ -206,13 +206,13 @@ console.log('\n=== token-savings: plan-slice prompt ≥30% character savings ===
206
206
 
207
207
  // Verify specific expected IDs are present
208
208
  const scopedDecisionIds = scopedDecisions.map(d => d.id);
209
- assertTrue(scopedDecisionIds.includes('D001'), 'M001 scoped decisions includes D001');
210
- assertTrue(scopedDecisionIds.includes('D004'), 'M001 scoped decisions includes D004');
211
- assertTrue(!scopedDecisionIds.includes('D002'), 'M001 scoped decisions excludes D002 (M002)');
212
- assertTrue(!scopedDecisionIds.includes('D003'), 'M001 scoped decisions excludes D003 (M003)');
209
+ assert.ok(scopedDecisionIds.includes('D001'), 'M001 scoped decisions includes D001');
210
+ assert.ok(scopedDecisionIds.includes('D004'), 'M001 scoped decisions includes D004');
211
+ assert.ok(!scopedDecisionIds.includes('D002'), 'M001 scoped decisions excludes D002 (M002)');
212
+ assert.ok(!scopedDecisionIds.includes('D003'), 'M001 scoped decisions excludes D003 (M003)');
213
213
 
214
214
  const scopedReqIds = scopedRequirements.map(r => r.id);
215
- assertTrue(scopedReqIds.includes('R001'), 'S01 scoped requirements includes R001');
215
+ assert.ok(scopedReqIds.includes('R001'), 'S01 scoped requirements includes R001');
216
216
 
217
217
  closeDatabase();
218
218
  rmSync(base, { recursive: true, force: true });
@@ -246,9 +246,9 @@ console.log('\n=== token-savings: research-milestone prompt shows meaningful sav
246
246
  const decisionsSavings = ((fullDecisionsContent.length - dbDecisionsContent.length) / fullDecisionsContent.length) * 100;
247
247
  console.log(` Decisions savings (M001): ${decisionsSavings.toFixed(1)}% (DB: ${dbDecisionsContent.length}, full: ${fullDecisionsContent.length})`);
248
248
 
249
- assertTrue(decisionsSavings > 0, `decisions savings > 0% (actual: ${decisionsSavings.toFixed(1)}%)`);
250
- assertTrue(scopedDecisions.length === 8, `M001 decisions: 8 of 24 total`);
251
- assertTrue(allRequirements.length === REQUIREMENTS_COUNT, `all requirements returned: ${allRequirements.length}`);
249
+ assert.ok(decisionsSavings > 0, `decisions savings > 0% (actual: ${decisionsSavings.toFixed(1)}%)`);
250
+ assert.ok(scopedDecisions.length === 8, `M001 decisions: 8 of 24 total`);
251
+ assert.ok(allRequirements.length === REQUIREMENTS_COUNT, `all requirements returned: ${allRequirements.length}`);
252
252
 
253
253
  // Requirements: DB-formatted vs raw markdown — formatted output may differ in size
254
254
  // but decisions savings alone should make the composite meaningful
@@ -259,8 +259,8 @@ console.log('\n=== token-savings: research-milestone prompt shows meaningful sav
259
259
 
260
260
  // With 8/24 decisions = 66% reduction in decisions, even if requirements are equal,
261
261
  // the composite should show meaningful savings
262
- assertTrue(compositeSavings > 10, `research-milestone shows >10% composite savings (actual: ${compositeSavings.toFixed(1)}%)`);
263
- assertTrue(decisionsSavings >= 30, `decisions-only savings ≥30% for M001 scope (actual: ${decisionsSavings.toFixed(1)}%)`);
262
+ assert.ok(compositeSavings > 10, `research-milestone shows >10% composite savings (actual: ${compositeSavings.toFixed(1)}%)`);
263
+ assert.ok(decisionsSavings >= 30, `decisions-only savings ≥30% for M001 scope (actual: ${decisionsSavings.toFixed(1)}%)`);
264
264
 
265
265
  closeDatabase();
266
266
  rmSync(base, { recursive: true, force: true });
@@ -283,17 +283,17 @@ console.log('\n=== token-savings: quality — correct scoping, no cross-contamin
283
283
 
284
284
  // ── M002-scoped decisions should not contain M001/M003 items ──
285
285
  const m002Decisions = queryDecisions({ milestoneId: 'M002' });
286
- assertTrue(m002Decisions.length === 8, `M002 decisions: expected 8, got ${m002Decisions.length}`);
286
+ assert.ok(m002Decisions.length === 8, `M002 decisions: expected 8, got ${m002Decisions.length}`);
287
287
  for (const d of m002Decisions) {
288
- assertTrue(d.when_context.includes('M002'), `M002 decision ${d.id} has M002 in when_context`);
289
- assertNoMatch(d.when_context, /M001|M003/, `M002 decision ${d.id} should not contain M001/M003`);
288
+ assert.ok(d.when_context.includes('M002'), `M002 decision ${d.id} has M002 in when_context`);
289
+ assert.doesNotMatch(d.when_context, /M001|M003/, `M002 decision ${d.id} should not contain M001/M003`);
290
290
  }
291
291
 
292
292
  // ── S04-scoped requirements should only include S04-related items ──
293
293
  const s04Requirements = queryRequirements({ sliceId: 'S04' });
294
- assertTrue(s04Requirements.length > 0, 'S04 requirements non-empty');
294
+ assert.ok(s04Requirements.length > 0, 'S04 requirements non-empty');
295
295
  for (const r of s04Requirements) {
296
- assertTrue(
296
+ assert.ok(
297
297
  r.primary_owner.includes('S04') || r.supporting_slices.includes('S04'),
298
298
  `S04 requirement ${r.id} should be owned by or support S04`,
299
299
  );
@@ -301,13 +301,13 @@ console.log('\n=== token-savings: quality — correct scoping, no cross-contamin
301
301
 
302
302
  // ── Verify formatted output is well-formed and non-empty ──
303
303
  const formattedDecisions = formatDecisionsForPrompt(m002Decisions);
304
- assertTrue(formattedDecisions.length > 0, 'formatted M002 decisions is non-empty');
305
- assertMatch(formattedDecisions, /\| D/, 'formatted decisions contains decision rows');
306
- assertMatch(formattedDecisions, /\| # \|/, 'formatted decisions has table header');
304
+ assert.ok(formattedDecisions.length > 0, 'formatted M002 decisions is non-empty');
305
+ assert.match(formattedDecisions, /\| D/, 'formatted decisions contains decision rows');
306
+ assert.match(formattedDecisions, /\| # \|/, 'formatted decisions has table header');
307
307
 
308
308
  const formattedReqs = formatRequirementsForPrompt(s04Requirements);
309
- assertTrue(formattedReqs.length > 0, 'formatted S04 requirements is non-empty');
310
- assertMatch(formattedReqs, /### R\d+/, 'formatted requirements has requirement headings');
309
+ assert.ok(formattedReqs.length > 0, 'formatted S04 requirements is non-empty');
310
+ assert.match(formattedReqs, /### R\d+/, 'formatted requirements has requirement headings');
311
311
 
312
312
  // ── Verify all milestones have decisions and counts add up ──
313
313
  const m001Count = queryDecisions({ milestoneId: 'M001' }).length;
@@ -315,11 +315,11 @@ console.log('\n=== token-savings: quality — correct scoping, no cross-contamin
315
315
  const m003Count = queryDecisions({ milestoneId: 'M003' }).length;
316
316
  const allCount = queryDecisions().length;
317
317
 
318
- assertTrue(m001Count === 8, `M001: 8 decisions (got ${m001Count})`);
319
- assertTrue(m002Count === 8, `M002: 8 decisions (got ${m002Count})`);
320
- assertTrue(m003Count === 8, `M003: 8 decisions (got ${m003Count})`);
321
- assertTrue(allCount === DECISIONS_COUNT, `all: ${DECISIONS_COUNT} decisions (got ${allCount})`);
322
- assertTrue(m001Count + m002Count + m003Count === allCount, 'milestone decision counts sum to total');
318
+ assert.ok(m001Count === 8, `M001: 8 decisions (got ${m001Count})`);
319
+ assert.ok(m002Count === 8, `M002: 8 decisions (got ${m002Count})`);
320
+ assert.ok(m003Count === 8, `M003: 8 decisions (got ${m003Count})`);
321
+ assert.ok(allCount === DECISIONS_COUNT, `all: ${DECISIONS_COUNT} decisions (got ${allCount})`);
322
+ assert.ok(m001Count + m002Count + m003Count === allCount, 'milestone decision counts sum to total');
323
323
 
324
324
  // ── Verify all slices have requirements ──
325
325
  const s01Reqs = queryRequirements({ sliceId: 'S01' });
@@ -328,11 +328,11 @@ console.log('\n=== token-savings: quality — correct scoping, no cross-contamin
328
328
  const s04Reqs = queryRequirements({ sliceId: 'S04' });
329
329
  const s05Reqs = queryRequirements({ sliceId: 'S05' });
330
330
 
331
- assertTrue(s01Reqs.length > 0, 'S01 has requirements');
332
- assertTrue(s02Reqs.length > 0, 'S02 has requirements');
333
- assertTrue(s03Reqs.length > 0, 'S03 has requirements');
334
- assertTrue(s04Reqs.length > 0, 'S04 has requirements');
335
- assertTrue(s05Reqs.length > 0, 'S05 has requirements');
331
+ assert.ok(s01Reqs.length > 0, 'S01 has requirements');
332
+ assert.ok(s02Reqs.length > 0, 'S02 has requirements');
333
+ assert.ok(s03Reqs.length > 0, 'S03 has requirements');
334
+ assert.ok(s04Reqs.length > 0, 'S04 has requirements');
335
+ assert.ok(s05Reqs.length > 0, 'S05 has requirements');
336
336
 
337
337
  closeDatabase();
338
338
  rmSync(base, { recursive: true, force: true });
@@ -345,22 +345,20 @@ console.log('\n=== token-savings: quality — correct scoping, no cross-contamin
345
345
  console.log('\n=== token-savings: fixture data realism ===');
346
346
  {
347
347
  // Verify fixture generators produce sufficient volume
348
- assertTrue(DECISIONS_COUNT >= 20, `decisions count ≥ 20 (actual: ${DECISIONS_COUNT})`);
349
- assertTrue(REQUIREMENTS_COUNT >= 20, `requirements count ≥ 20 (actual: ${REQUIREMENTS_COUNT})`);
350
- assertTrue(MILESTONES.length >= 3, `milestones ≥ 3 (actual: ${MILESTONES.length})`);
351
- assertTrue(SLICE_ASSIGNMENTS.length >= 5, `slice assignments ≥ 5 (actual: ${SLICE_ASSIGNMENTS.length})`);
348
+ assert.ok(DECISIONS_COUNT >= 20, `decisions count ≥ 20 (actual: ${DECISIONS_COUNT})`);
349
+ assert.ok(REQUIREMENTS_COUNT >= 20, `requirements count ≥ 20 (actual: ${REQUIREMENTS_COUNT})`);
350
+ assert.ok(MILESTONES.length >= 3, `milestones ≥ 3 (actual: ${MILESTONES.length})`);
351
+ assert.ok(SLICE_ASSIGNMENTS.length >= 5, `slice assignments ≥ 5 (actual: ${SLICE_ASSIGNMENTS.length})`);
352
352
 
353
353
  // Verify markdown content is substantial
354
- assertTrue(decisionsMarkdown.length > 1000, `decisions markdown > 1000 chars (actual: ${decisionsMarkdown.length})`);
355
- assertTrue(requirementsMarkdown.length > 1000, `requirements markdown > 1000 chars (actual: ${requirementsMarkdown.length})`);
354
+ assert.ok(decisionsMarkdown.length > 1000, `decisions markdown > 1000 chars (actual: ${decisionsMarkdown.length})`);
355
+ assert.ok(requirementsMarkdown.length > 1000, `requirements markdown > 1000 chars (actual: ${requirementsMarkdown.length})`);
356
356
 
357
357
  // Verify content structure
358
- assertMatch(decisionsMarkdown, /\| D001 \|/, 'decisions markdown has D001');
359
- assertMatch(decisionsMarkdown, /\| D024 \|/, 'decisions markdown has D024');
360
- assertMatch(requirementsMarkdown, /### R001/, 'requirements markdown has R001');
361
- assertMatch(requirementsMarkdown, /### R021/, 'requirements markdown has R021');
358
+ assert.match(decisionsMarkdown, /\| D001 \|/, 'decisions markdown has D001');
359
+ assert.match(decisionsMarkdown, /\| D024 \|/, 'decisions markdown has D024');
360
+ assert.match(requirementsMarkdown, /### R001/, 'requirements markdown has R001');
361
+ assert.match(requirementsMarkdown, /### R021/, 'requirements markdown has R021');
362
362
  }
363
363
 
364
364
  // ─── Report ────────────────────────────────────────────────────────────────
365
-
366
- report();
@@ -3,7 +3,8 @@
3
3
  // Verifies that identical consecutive tool calls are detected and blocked
4
4
  // after exceeding the threshold, and that the guard resets properly.
5
5
 
6
- import { createTestContext } from './test-helpers.ts';
6
+ import { test } from 'node:test';
7
+ import assert from 'node:assert/strict';
7
8
  import {
8
9
  checkToolCallLoop,
9
10
  resetToolCallLoopGuard,
@@ -11,7 +12,6 @@ import {
11
12
  getToolCallLoopCount,
12
13
  } from '../bootstrap/tool-call-loop-guard.ts';
13
14
 
14
- const { assertEq, assertTrue, report } = createTestContext();
15
15
 
16
16
  // ═══════════════════════════════════════════════════════════════════════════
17
17
  // Allows first N calls, blocks after threshold
@@ -25,15 +25,15 @@ console.log('\n── Loop guard: blocks after threshold ──');
25
25
  // First 4 identical calls should be allowed (threshold is 4)
26
26
  for (let i = 1; i <= 4; i++) {
27
27
  const result = checkToolCallLoop('web_search', { query: 'same query' });
28
- assertTrue(result.block === false, `Call ${i} should be allowed`);
29
- assertEq(result.count, i, `Count should be ${i} after call ${i}`);
28
+ assert.ok(result.block === false, `Call ${i} should be allowed`);
29
+ assert.deepStrictEqual(result.count, i, `Count should be ${i} after call ${i}`);
30
30
  }
31
31
 
32
32
  // 5th identical call should be blocked
33
33
  const blocked = checkToolCallLoop('web_search', { query: 'same query' });
34
- assertTrue(blocked.block === true, '5th identical call should be blocked');
35
- assertTrue(blocked.reason!.includes('web_search'), 'Reason should mention tool name');
36
- assertTrue(blocked.reason!.includes('5'), 'Reason should mention count');
34
+ assert.ok(blocked.block === true, '5th identical call should be blocked');
35
+ assert.ok(blocked.reason!.includes('web_search'), 'Reason should mention tool name');
36
+ assert.ok(blocked.reason!.includes('5'), 'Reason should mention count');
37
37
  }
38
38
 
39
39
  // ═══════════════════════════════════════════════════════════════════════════
@@ -48,17 +48,17 @@ console.log('\n── Loop guard: different calls reset streak ──');
48
48
  checkToolCallLoop('web_search', { query: 'query A' });
49
49
  checkToolCallLoop('web_search', { query: 'query A' });
50
50
  checkToolCallLoop('web_search', { query: 'query A' });
51
- assertEq(getToolCallLoopCount(), 3, 'Count should be 3 after 3 identical calls');
51
+ assert.deepStrictEqual(getToolCallLoopCount(), 3, 'Count should be 3 after 3 identical calls');
52
52
 
53
53
  // A different call resets the streak
54
54
  const different = checkToolCallLoop('bash', { command: 'ls' });
55
- assertTrue(different.block === false, 'Different tool call should be allowed');
56
- assertEq(getToolCallLoopCount(), 1, 'Count should reset to 1 after different call');
55
+ assert.ok(different.block === false, 'Different tool call should be allowed');
56
+ assert.deepStrictEqual(getToolCallLoopCount(), 1, 'Count should reset to 1 after different call');
57
57
 
58
58
  // Same tool but different args also resets
59
59
  checkToolCallLoop('web_search', { query: 'query A' });
60
60
  checkToolCallLoop('web_search', { query: 'query B' }); // different args
61
- assertEq(getToolCallLoopCount(), 1, 'Different args should reset count');
61
+ assert.deepStrictEqual(getToolCallLoopCount(), 1, 'Different args should reset count');
62
62
  }
63
63
 
64
64
  // ═══════════════════════════════════════════════════════════════════════════
@@ -72,15 +72,15 @@ console.log('\n── Loop guard: reset clears state ──');
72
72
  checkToolCallLoop('web_search', { query: 'q' });
73
73
  checkToolCallLoop('web_search', { query: 'q' });
74
74
  checkToolCallLoop('web_search', { query: 'q' });
75
- assertEq(getToolCallLoopCount(), 3, 'Count should be 3 before reset');
75
+ assert.deepStrictEqual(getToolCallLoopCount(), 3, 'Count should be 3 before reset');
76
76
 
77
77
  resetToolCallLoopGuard();
78
- assertEq(getToolCallLoopCount(), 0, 'Count should be 0 after reset');
78
+ assert.deepStrictEqual(getToolCallLoopCount(), 0, 'Count should be 0 after reset');
79
79
 
80
80
  // After reset, the same call starts fresh
81
81
  const result = checkToolCallLoop('web_search', { query: 'q' });
82
- assertTrue(result.block === false, 'Call after reset should be allowed');
83
- assertEq(getToolCallLoopCount(), 1, 'Count should be 1 after first call post-reset');
82
+ assert.ok(result.block === false, 'Call after reset should be allowed');
83
+ assert.deepStrictEqual(getToolCallLoopCount(), 1, 'Count should be 1 after first call post-reset');
84
84
  }
85
85
 
86
86
  // ═══════════════════════════════════════════════════════════════════════════
@@ -94,13 +94,13 @@ console.log('\n── Loop guard: disable allows everything ──');
94
94
 
95
95
  for (let i = 0; i < 10; i++) {
96
96
  const result = checkToolCallLoop('web_search', { query: 'same' });
97
- assertTrue(result.block === false, `Call ${i + 1} should be allowed when disabled`);
97
+ assert.ok(result.block === false, `Call ${i + 1} should be allowed when disabled`);
98
98
  }
99
99
 
100
100
  // Re-enable via reset
101
101
  resetToolCallLoopGuard();
102
102
  checkToolCallLoop('web_search', { query: 'q' });
103
- assertEq(getToolCallLoopCount(), 1, 'Guard should be active again after reset');
103
+ assert.deepStrictEqual(getToolCallLoopCount(), 1, 'Guard should be active again after reset');
104
104
  }
105
105
 
106
106
  // ═══════════════════════════════════════════════════════════════════════════
@@ -114,8 +114,8 @@ console.log('\n── Loop guard: arg order is normalized ──');
114
114
 
115
115
  checkToolCallLoop('web_search', { query: 'test', limit: 5 });
116
116
  const result = checkToolCallLoop('web_search', { limit: 5, query: 'test' }); // same args, different order
117
- assertTrue(result.block === false, 'Same args in different order should count as consecutive');
118
- assertEq(getToolCallLoopCount(), 2, 'Should detect as same call regardless of key order');
117
+ assert.ok(result.block === false, 'Same args in different order should count as consecutive');
118
+ assert.deepStrictEqual(getToolCallLoopCount(), 2, 'Should detect as same call regardless of key order');
119
119
  }
120
120
 
121
121
  // ═══════════════════════════════════════════════════════════════════════════
@@ -132,8 +132,8 @@ console.log('\n── Loop guard: nested args are not stripped ──');
132
132
  const result = checkToolCallLoop('ask_user_questions', {
133
133
  questions: [{ id: `q${i}`, question: `Question ${i}?` }],
134
134
  });
135
- assertTrue(result.block === false, `Nested call ${i} with unique content should be allowed`);
136
- assertEq(getToolCallLoopCount(), 1, `Each unique nested call should reset count to 1`);
135
+ assert.ok(result.block === false, `Nested call ${i} with unique content should be allowed`);
136
+ assert.deepStrictEqual(getToolCallLoopCount(), 1, `Each unique nested call should reset count to 1`);
137
137
  }
138
138
 
139
139
  // Truly identical nested calls should still be detected
@@ -146,7 +146,7 @@ console.log('\n── Loop guard: nested args are not stripped ──');
146
146
  const blocked = checkToolCallLoop('ask_user_questions', {
147
147
  questions: [{ id: 'same', question: 'Same?' }],
148
148
  });
149
- assertTrue(blocked.block === true, 'Identical nested calls should still be blocked');
149
+ assert.ok(blocked.block === true, 'Identical nested calls should still be blocked');
150
150
  }
151
151
 
152
152
  // ═══════════════════════════════════════════════════════════════════════════
@@ -160,9 +160,7 @@ console.log('\n── Loop guard: nested key order is normalized ──');
160
160
 
161
161
  checkToolCallLoop('tool', { outer: { b: 2, a: 1 } });
162
162
  const result = checkToolCallLoop('tool', { outer: { a: 1, b: 2 } });
163
- assertEq(getToolCallLoopCount(), 2, 'Same nested args in different key order should match');
163
+ assert.deepStrictEqual(getToolCallLoopCount(), 2, 'Same nested args in different key order should match');
164
164
  }
165
165
 
166
166
  // ═══════════════════════════════════════════════════════════════════════════
167
-
168
- report();