gsd-pi 2.18.0 → 2.20.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (289) hide show
  1. package/README.md +5 -1
  2. package/dist/cli.js +3 -3
  3. package/dist/onboarding.d.ts +3 -1
  4. package/dist/onboarding.js +77 -3
  5. package/dist/remote-questions-config.d.ts +1 -1
  6. package/dist/resources/extensions/google-search/index.ts +164 -47
  7. package/dist/resources/extensions/gsd/auto-dashboard.ts +14 -2
  8. package/dist/resources/extensions/gsd/auto-prompts.ts +148 -39
  9. package/dist/resources/extensions/gsd/auto-worktree.ts +93 -9
  10. package/dist/resources/extensions/gsd/auto.ts +690 -39
  11. package/dist/resources/extensions/gsd/captures.ts +384 -0
  12. package/dist/resources/extensions/gsd/commands.ts +654 -36
  13. package/dist/resources/extensions/gsd/complexity-classifier.ts +322 -0
  14. package/dist/resources/extensions/gsd/context-budget.ts +243 -0
  15. package/dist/resources/extensions/gsd/context-store.ts +195 -0
  16. package/dist/resources/extensions/gsd/dashboard-overlay.ts +51 -3
  17. package/dist/resources/extensions/gsd/db-writer.ts +341 -0
  18. package/dist/resources/extensions/gsd/debug-logger.ts +178 -0
  19. package/dist/resources/extensions/gsd/dispatch-guard.ts +0 -1
  20. package/dist/resources/extensions/gsd/docs/preferences-reference.md +54 -0
  21. package/dist/resources/extensions/gsd/doctor-proactive.ts +286 -0
  22. package/dist/resources/extensions/gsd/doctor.ts +283 -2
  23. package/dist/resources/extensions/gsd/export.ts +81 -2
  24. package/dist/resources/extensions/gsd/files.ts +39 -9
  25. package/dist/resources/extensions/gsd/git-service.ts +6 -0
  26. package/dist/resources/extensions/gsd/gsd-db.ts +752 -0
  27. package/dist/resources/extensions/gsd/guided-flow.ts +26 -1
  28. package/dist/resources/extensions/gsd/history.ts +0 -1
  29. package/dist/resources/extensions/gsd/index.ts +277 -1
  30. package/dist/resources/extensions/gsd/md-importer.ts +526 -0
  31. package/dist/resources/extensions/gsd/metrics.ts +84 -0
  32. package/dist/resources/extensions/gsd/model-cost-table.ts +65 -0
  33. package/dist/resources/extensions/gsd/model-router.ts +256 -0
  34. package/dist/resources/extensions/gsd/notifications.ts +0 -1
  35. package/dist/resources/extensions/gsd/post-unit-hooks.ts +72 -2
  36. package/dist/resources/extensions/gsd/preferences.ts +198 -150
  37. package/dist/resources/extensions/gsd/prompt-loader.ts +45 -9
  38. package/dist/resources/extensions/gsd/prompts/execute-task.md +3 -5
  39. package/dist/resources/extensions/gsd/prompts/heal-skill.md +45 -0
  40. package/dist/resources/extensions/gsd/prompts/plan-slice.md +5 -1
  41. package/dist/resources/extensions/gsd/prompts/quick-task.md +48 -0
  42. package/dist/resources/extensions/gsd/prompts/reassess-roadmap.md +6 -0
  43. package/dist/resources/extensions/gsd/prompts/replan-slice.md +8 -0
  44. package/dist/resources/extensions/gsd/prompts/system.md +2 -1
  45. package/dist/resources/extensions/gsd/prompts/triage-captures.md +62 -0
  46. package/dist/resources/extensions/gsd/quick.ts +156 -0
  47. package/dist/resources/extensions/gsd/skill-discovery.ts +5 -3
  48. package/dist/resources/extensions/gsd/skill-health.ts +417 -0
  49. package/dist/resources/extensions/gsd/skill-telemetry.ts +127 -0
  50. package/dist/resources/extensions/gsd/state.ts +30 -0
  51. package/dist/resources/extensions/gsd/templates/preferences.md +1 -0
  52. package/dist/resources/extensions/gsd/tests/captures.test.ts +438 -0
  53. package/dist/resources/extensions/gsd/tests/complexity-classifier.test.ts +181 -0
  54. package/dist/resources/extensions/gsd/tests/context-budget.test.ts +283 -0
  55. package/dist/resources/extensions/gsd/tests/context-compression.test.ts +1 -1
  56. package/dist/resources/extensions/gsd/tests/context-store.test.ts +462 -0
  57. package/dist/resources/extensions/gsd/tests/continue-here.test.ts +204 -0
  58. package/dist/resources/extensions/gsd/tests/dashboard-budget.test.ts +346 -0
  59. package/dist/resources/extensions/gsd/tests/db-writer.test.ts +602 -0
  60. package/dist/resources/extensions/gsd/tests/debug-logger.test.ts +185 -0
  61. package/dist/resources/extensions/gsd/tests/derive-state-db.test.ts +406 -0
  62. package/dist/resources/extensions/gsd/tests/dispatch-guard.test.ts +0 -1
  63. package/dist/resources/extensions/gsd/tests/dist-redirect.mjs +22 -0
  64. package/dist/resources/extensions/gsd/tests/doctor-proactive.test.ts +244 -0
  65. package/dist/resources/extensions/gsd/tests/doctor-runtime.test.ts +303 -0
  66. package/dist/resources/extensions/gsd/tests/feature-branch-lifecycle-integration.test.ts +434 -0
  67. package/dist/resources/extensions/gsd/tests/gsd-db.test.ts +353 -0
  68. package/dist/resources/extensions/gsd/tests/gsd-inspect.test.ts +125 -0
  69. package/dist/resources/extensions/gsd/tests/gsd-tools.test.ts +326 -0
  70. package/dist/resources/extensions/gsd/tests/integration-edge.test.ts +228 -0
  71. package/dist/resources/extensions/gsd/tests/integration-lifecycle.test.ts +277 -0
  72. package/dist/resources/extensions/gsd/tests/md-importer.test.ts +411 -0
  73. package/dist/resources/extensions/gsd/tests/metrics.test.ts +197 -0
  74. package/dist/resources/extensions/gsd/tests/milestone-transition-worktree.test.ts +144 -0
  75. package/dist/resources/extensions/gsd/tests/model-cost-table.test.ts +69 -0
  76. package/dist/resources/extensions/gsd/tests/model-isolation.test.ts +99 -0
  77. package/dist/resources/extensions/gsd/tests/model-router.test.ts +167 -0
  78. package/dist/resources/extensions/gsd/tests/parsers.test.ts +40 -0
  79. package/dist/resources/extensions/gsd/tests/post-unit-hooks.test.ts +41 -1
  80. package/dist/resources/extensions/gsd/tests/preferences-git.test.ts +0 -1
  81. package/dist/resources/extensions/gsd/tests/preferences-hooks.test.ts +0 -1
  82. package/dist/resources/extensions/gsd/tests/preferences-mode.test.ts +110 -0
  83. package/dist/resources/extensions/gsd/tests/preferences-models.test.ts +0 -1
  84. package/dist/resources/extensions/gsd/tests/prompt-budget-enforcement.test.ts +464 -0
  85. package/dist/resources/extensions/gsd/tests/prompt-db.test.ts +385 -0
  86. package/dist/resources/extensions/gsd/tests/remote-questions.test.ts +488 -1
  87. package/dist/resources/extensions/gsd/tests/resolve-ts-hooks.mjs +17 -29
  88. package/dist/resources/extensions/gsd/tests/resolve-ts.mjs +2 -8
  89. package/dist/resources/extensions/gsd/tests/routing-history.test.ts +215 -62
  90. package/dist/resources/extensions/gsd/tests/skill-lifecycle.test.ts +126 -0
  91. package/dist/resources/extensions/gsd/tests/stop-auto-remote.test.ts +31 -8
  92. package/dist/resources/extensions/gsd/tests/token-savings.test.ts +366 -0
  93. package/dist/resources/extensions/gsd/tests/triage-dispatch.test.ts +224 -0
  94. package/dist/resources/extensions/gsd/tests/triage-resolution.test.ts +215 -0
  95. package/dist/resources/extensions/gsd/tests/unit-runtime.test.ts +25 -1
  96. package/dist/resources/extensions/gsd/tests/visualizer-critical-path.test.ts +145 -0
  97. package/dist/resources/extensions/gsd/tests/visualizer-data.test.ts +290 -0
  98. package/dist/resources/extensions/gsd/tests/visualizer-overlay.test.ts +120 -0
  99. package/dist/resources/extensions/gsd/tests/visualizer-views.test.ts +478 -0
  100. package/dist/resources/extensions/gsd/tests/worktree-db-integration.test.ts +205 -0
  101. package/dist/resources/extensions/gsd/tests/worktree-db.test.ts +442 -0
  102. package/dist/resources/extensions/gsd/tests/worktree-post-create-hook.test.ts +165 -0
  103. package/dist/resources/extensions/gsd/triage-resolution.ts +200 -0
  104. package/dist/resources/extensions/gsd/triage-ui.ts +175 -0
  105. package/dist/resources/extensions/gsd/types.ts +29 -0
  106. package/dist/resources/extensions/gsd/undo.ts +0 -1
  107. package/dist/resources/extensions/gsd/unit-runtime.ts +5 -1
  108. package/dist/resources/extensions/gsd/visualizer-data.ts +505 -0
  109. package/dist/resources/extensions/gsd/visualizer-overlay.ts +337 -0
  110. package/dist/resources/extensions/gsd/visualizer-views.ts +755 -0
  111. package/dist/resources/extensions/gsd/worktree-command.ts +18 -0
  112. package/dist/resources/extensions/gsd/worktree-manager.ts +11 -4
  113. package/dist/resources/extensions/remote-questions/config.ts +4 -2
  114. package/dist/resources/extensions/remote-questions/discord-adapter.ts +35 -4
  115. package/dist/resources/extensions/remote-questions/format.ts +166 -14
  116. package/dist/resources/extensions/remote-questions/manager.ts +14 -4
  117. package/dist/resources/extensions/remote-questions/remote-command.ts +100 -4
  118. package/dist/resources/extensions/remote-questions/slack-adapter.ts +58 -2
  119. package/dist/resources/extensions/remote-questions/telegram-adapter.ts +161 -0
  120. package/dist/resources/extensions/remote-questions/types.ts +2 -1
  121. package/dist/resources/extensions/ttsr/ttsr-manager.ts +26 -0
  122. package/dist/resources/extensions/voice/index.ts +4 -3
  123. package/package.json +1 -1
  124. package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
  125. package/packages/pi-coding-agent/dist/core/agent-session.js +12 -1
  126. package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
  127. package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts.map +1 -1
  128. package/packages/pi-coding-agent/dist/core/extensions/loader.js +5 -0
  129. package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
  130. package/packages/pi-coding-agent/dist/core/lsp/client.d.ts +6 -0
  131. package/packages/pi-coding-agent/dist/core/lsp/client.d.ts.map +1 -1
  132. package/packages/pi-coding-agent/dist/core/lsp/client.js +25 -0
  133. package/packages/pi-coding-agent/dist/core/lsp/client.js.map +1 -1
  134. package/packages/pi-coding-agent/dist/core/lsp/index.d.ts +2 -0
  135. package/packages/pi-coding-agent/dist/core/lsp/index.d.ts.map +1 -1
  136. package/packages/pi-coding-agent/dist/core/lsp/index.js +106 -3
  137. package/packages/pi-coding-agent/dist/core/lsp/index.js.map +1 -1
  138. package/packages/pi-coding-agent/dist/core/lsp/lsp.md +6 -0
  139. package/packages/pi-coding-agent/dist/core/lsp/types.d.ts +35 -0
  140. package/packages/pi-coding-agent/dist/core/lsp/types.d.ts.map +1 -1
  141. package/packages/pi-coding-agent/dist/core/lsp/types.js +6 -0
  142. package/packages/pi-coding-agent/dist/core/lsp/types.js.map +1 -1
  143. package/packages/pi-coding-agent/dist/core/lsp/utils.d.ts +3 -1
  144. package/packages/pi-coding-agent/dist/core/lsp/utils.d.ts.map +1 -1
  145. package/packages/pi-coding-agent/dist/core/lsp/utils.js +45 -0
  146. package/packages/pi-coding-agent/dist/core/lsp/utils.js.map +1 -1
  147. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +6 -0
  148. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
  149. package/packages/pi-coding-agent/dist/core/settings-manager.js +43 -11
  150. package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
  151. package/packages/pi-coding-agent/dist/core/system-prompt.d.ts.map +1 -1
  152. package/packages/pi-coding-agent/dist/core/system-prompt.js +7 -1
  153. package/packages/pi-coding-agent/dist/core/system-prompt.js.map +1 -1
  154. package/packages/pi-coding-agent/dist/core/tools/edit.d.ts.map +1 -1
  155. package/packages/pi-coding-agent/dist/core/tools/edit.js +5 -0
  156. package/packages/pi-coding-agent/dist/core/tools/edit.js.map +1 -1
  157. package/packages/pi-coding-agent/dist/core/tools/index.d.ts +2 -0
  158. package/packages/pi-coding-agent/dist/core/tools/index.d.ts.map +1 -1
  159. package/packages/pi-coding-agent/dist/core/tools/write.d.ts.map +1 -1
  160. package/packages/pi-coding-agent/dist/core/tools/write.js +5 -0
  161. package/packages/pi-coding-agent/dist/core/tools/write.js.map +1 -1
  162. package/packages/pi-coding-agent/src/core/agent-session.ts +13 -1
  163. package/packages/pi-coding-agent/src/core/extensions/loader.ts +6 -0
  164. package/packages/pi-coding-agent/src/core/lsp/client.ts +26 -0
  165. package/packages/pi-coding-agent/src/core/lsp/index.ts +157 -2
  166. package/packages/pi-coding-agent/src/core/lsp/lsp.md +6 -0
  167. package/packages/pi-coding-agent/src/core/lsp/types.ts +53 -0
  168. package/packages/pi-coding-agent/src/core/lsp/utils.ts +56 -0
  169. package/packages/pi-coding-agent/src/core/settings-manager.ts +41 -11
  170. package/packages/pi-coding-agent/src/core/system-prompt.ts +7 -1
  171. package/packages/pi-coding-agent/src/core/tools/edit.ts +3 -0
  172. package/packages/pi-coding-agent/src/core/tools/write.ts +3 -0
  173. package/src/resources/extensions/google-search/index.ts +164 -47
  174. package/src/resources/extensions/gsd/auto-dashboard.ts +14 -2
  175. package/src/resources/extensions/gsd/auto-prompts.ts +148 -39
  176. package/src/resources/extensions/gsd/auto-worktree.ts +93 -9
  177. package/src/resources/extensions/gsd/auto.ts +690 -39
  178. package/src/resources/extensions/gsd/captures.ts +384 -0
  179. package/src/resources/extensions/gsd/commands.ts +654 -36
  180. package/src/resources/extensions/gsd/complexity-classifier.ts +322 -0
  181. package/src/resources/extensions/gsd/context-budget.ts +243 -0
  182. package/src/resources/extensions/gsd/context-store.ts +195 -0
  183. package/src/resources/extensions/gsd/dashboard-overlay.ts +51 -3
  184. package/src/resources/extensions/gsd/db-writer.ts +341 -0
  185. package/src/resources/extensions/gsd/debug-logger.ts +178 -0
  186. package/src/resources/extensions/gsd/dispatch-guard.ts +0 -1
  187. package/src/resources/extensions/gsd/docs/preferences-reference.md +54 -0
  188. package/src/resources/extensions/gsd/doctor-proactive.ts +286 -0
  189. package/src/resources/extensions/gsd/doctor.ts +283 -2
  190. package/src/resources/extensions/gsd/export.ts +81 -2
  191. package/src/resources/extensions/gsd/files.ts +39 -9
  192. package/src/resources/extensions/gsd/git-service.ts +6 -0
  193. package/src/resources/extensions/gsd/gsd-db.ts +752 -0
  194. package/src/resources/extensions/gsd/guided-flow.ts +26 -1
  195. package/src/resources/extensions/gsd/history.ts +0 -1
  196. package/src/resources/extensions/gsd/index.ts +277 -1
  197. package/src/resources/extensions/gsd/md-importer.ts +526 -0
  198. package/src/resources/extensions/gsd/metrics.ts +84 -0
  199. package/src/resources/extensions/gsd/model-cost-table.ts +65 -0
  200. package/src/resources/extensions/gsd/model-router.ts +256 -0
  201. package/src/resources/extensions/gsd/notifications.ts +0 -1
  202. package/src/resources/extensions/gsd/post-unit-hooks.ts +72 -2
  203. package/src/resources/extensions/gsd/preferences.ts +198 -150
  204. package/src/resources/extensions/gsd/prompt-loader.ts +45 -9
  205. package/src/resources/extensions/gsd/prompts/execute-task.md +3 -5
  206. package/src/resources/extensions/gsd/prompts/heal-skill.md +45 -0
  207. package/src/resources/extensions/gsd/prompts/plan-slice.md +5 -1
  208. package/src/resources/extensions/gsd/prompts/quick-task.md +48 -0
  209. package/src/resources/extensions/gsd/prompts/reassess-roadmap.md +6 -0
  210. package/src/resources/extensions/gsd/prompts/replan-slice.md +8 -0
  211. package/src/resources/extensions/gsd/prompts/system.md +2 -1
  212. package/src/resources/extensions/gsd/prompts/triage-captures.md +62 -0
  213. package/src/resources/extensions/gsd/quick.ts +156 -0
  214. package/src/resources/extensions/gsd/skill-discovery.ts +5 -3
  215. package/src/resources/extensions/gsd/skill-health.ts +417 -0
  216. package/src/resources/extensions/gsd/skill-telemetry.ts +127 -0
  217. package/src/resources/extensions/gsd/state.ts +30 -0
  218. package/src/resources/extensions/gsd/templates/preferences.md +1 -0
  219. package/src/resources/extensions/gsd/tests/captures.test.ts +438 -0
  220. package/src/resources/extensions/gsd/tests/complexity-classifier.test.ts +181 -0
  221. package/src/resources/extensions/gsd/tests/context-budget.test.ts +283 -0
  222. package/src/resources/extensions/gsd/tests/context-compression.test.ts +1 -1
  223. package/src/resources/extensions/gsd/tests/context-store.test.ts +462 -0
  224. package/src/resources/extensions/gsd/tests/continue-here.test.ts +204 -0
  225. package/src/resources/extensions/gsd/tests/dashboard-budget.test.ts +346 -0
  226. package/src/resources/extensions/gsd/tests/db-writer.test.ts +602 -0
  227. package/src/resources/extensions/gsd/tests/debug-logger.test.ts +185 -0
  228. package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +406 -0
  229. package/src/resources/extensions/gsd/tests/dispatch-guard.test.ts +0 -1
  230. package/src/resources/extensions/gsd/tests/dist-redirect.mjs +22 -0
  231. package/src/resources/extensions/gsd/tests/doctor-proactive.test.ts +244 -0
  232. package/src/resources/extensions/gsd/tests/doctor-runtime.test.ts +303 -0
  233. package/src/resources/extensions/gsd/tests/feature-branch-lifecycle-integration.test.ts +434 -0
  234. package/src/resources/extensions/gsd/tests/gsd-db.test.ts +353 -0
  235. package/src/resources/extensions/gsd/tests/gsd-inspect.test.ts +125 -0
  236. package/src/resources/extensions/gsd/tests/gsd-tools.test.ts +326 -0
  237. package/src/resources/extensions/gsd/tests/integration-edge.test.ts +228 -0
  238. package/src/resources/extensions/gsd/tests/integration-lifecycle.test.ts +277 -0
  239. package/src/resources/extensions/gsd/tests/md-importer.test.ts +411 -0
  240. package/src/resources/extensions/gsd/tests/metrics.test.ts +197 -0
  241. package/src/resources/extensions/gsd/tests/milestone-transition-worktree.test.ts +144 -0
  242. package/src/resources/extensions/gsd/tests/model-cost-table.test.ts +69 -0
  243. package/src/resources/extensions/gsd/tests/model-isolation.test.ts +99 -0
  244. package/src/resources/extensions/gsd/tests/model-router.test.ts +167 -0
  245. package/src/resources/extensions/gsd/tests/parsers.test.ts +40 -0
  246. package/src/resources/extensions/gsd/tests/post-unit-hooks.test.ts +41 -1
  247. package/src/resources/extensions/gsd/tests/preferences-git.test.ts +0 -1
  248. package/src/resources/extensions/gsd/tests/preferences-hooks.test.ts +0 -1
  249. package/src/resources/extensions/gsd/tests/preferences-mode.test.ts +110 -0
  250. package/src/resources/extensions/gsd/tests/preferences-models.test.ts +0 -1
  251. package/src/resources/extensions/gsd/tests/prompt-budget-enforcement.test.ts +464 -0
  252. package/src/resources/extensions/gsd/tests/prompt-db.test.ts +385 -0
  253. package/src/resources/extensions/gsd/tests/remote-questions.test.ts +488 -1
  254. package/src/resources/extensions/gsd/tests/resolve-ts-hooks.mjs +17 -29
  255. package/src/resources/extensions/gsd/tests/resolve-ts.mjs +2 -8
  256. package/src/resources/extensions/gsd/tests/routing-history.test.ts +215 -62
  257. package/src/resources/extensions/gsd/tests/skill-lifecycle.test.ts +126 -0
  258. package/src/resources/extensions/gsd/tests/stop-auto-remote.test.ts +31 -8
  259. package/src/resources/extensions/gsd/tests/token-savings.test.ts +366 -0
  260. package/src/resources/extensions/gsd/tests/triage-dispatch.test.ts +224 -0
  261. package/src/resources/extensions/gsd/tests/triage-resolution.test.ts +215 -0
  262. package/src/resources/extensions/gsd/tests/unit-runtime.test.ts +25 -1
  263. package/src/resources/extensions/gsd/tests/visualizer-critical-path.test.ts +145 -0
  264. package/src/resources/extensions/gsd/tests/visualizer-data.test.ts +290 -0
  265. package/src/resources/extensions/gsd/tests/visualizer-overlay.test.ts +120 -0
  266. package/src/resources/extensions/gsd/tests/visualizer-views.test.ts +478 -0
  267. package/src/resources/extensions/gsd/tests/worktree-db-integration.test.ts +205 -0
  268. package/src/resources/extensions/gsd/tests/worktree-db.test.ts +442 -0
  269. package/src/resources/extensions/gsd/tests/worktree-post-create-hook.test.ts +165 -0
  270. package/src/resources/extensions/gsd/triage-resolution.ts +200 -0
  271. package/src/resources/extensions/gsd/triage-ui.ts +175 -0
  272. package/src/resources/extensions/gsd/types.ts +29 -0
  273. package/src/resources/extensions/gsd/undo.ts +0 -1
  274. package/src/resources/extensions/gsd/unit-runtime.ts +5 -1
  275. package/src/resources/extensions/gsd/visualizer-data.ts +505 -0
  276. package/src/resources/extensions/gsd/visualizer-overlay.ts +337 -0
  277. package/src/resources/extensions/gsd/visualizer-views.ts +755 -0
  278. package/src/resources/extensions/gsd/worktree-command.ts +18 -0
  279. package/src/resources/extensions/gsd/worktree-manager.ts +11 -4
  280. package/src/resources/extensions/remote-questions/config.ts +4 -2
  281. package/src/resources/extensions/remote-questions/discord-adapter.ts +35 -4
  282. package/src/resources/extensions/remote-questions/format.ts +166 -14
  283. package/src/resources/extensions/remote-questions/manager.ts +14 -4
  284. package/src/resources/extensions/remote-questions/remote-command.ts +100 -4
  285. package/src/resources/extensions/remote-questions/slack-adapter.ts +58 -2
  286. package/src/resources/extensions/remote-questions/telegram-adapter.ts +161 -0
  287. package/src/resources/extensions/remote-questions/types.ts +2 -1
  288. package/src/resources/extensions/ttsr/ttsr-manager.ts +26 -0
  289. package/src/resources/extensions/voice/index.ts +4 -3
@@ -0,0 +1,120 @@
1
+ // Tests for GSD visualizer overlay.
2
+ // Verifies filter mode, tab switching, and export key handling.
3
+
4
+ import { readFileSync } from "node:fs";
5
+ import { join, dirname } from "node:path";
6
+ import { fileURLToPath } from "node:url";
7
+ import { createTestContext } from "./test-helpers.ts";
8
+
9
+ const __dirname = dirname(fileURLToPath(import.meta.url));
10
+ const { assertTrue, assertEq, report } = createTestContext();
11
+
12
+ const overlaySrc = readFileSync(join(__dirname, "..", "visualizer-overlay.ts"), "utf-8");
13
+
14
+ console.log("\n=== Overlay: Tab Configuration ===");
15
+
16
+ assertTrue(
17
+ overlaySrc.includes("TAB_COUNT = 7"),
18
+ "TAB_COUNT is 7",
19
+ );
20
+
21
+ assertTrue(
22
+ overlaySrc.includes('"1 Progress"'),
23
+ "has Progress tab label",
24
+ );
25
+
26
+ assertTrue(
27
+ overlaySrc.includes('"5 Agent"'),
28
+ "has Agent tab label",
29
+ );
30
+
31
+ assertTrue(
32
+ overlaySrc.includes('"6 Changes"'),
33
+ "has Changes tab label",
34
+ );
35
+
36
+ assertTrue(
37
+ overlaySrc.includes('"7 Export"'),
38
+ "has Export tab label",
39
+ );
40
+
41
+ console.log("\n=== Overlay: Filter Mode ===");
42
+
43
+ assertTrue(
44
+ overlaySrc.includes('filterMode = false'),
45
+ "filterMode initialized to false",
46
+ );
47
+
48
+ assertTrue(
49
+ overlaySrc.includes('filterText = ""'),
50
+ "filterText initialized to empty string",
51
+ );
52
+
53
+ assertTrue(
54
+ overlaySrc.includes('filterField:'),
55
+ "has filterField state",
56
+ );
57
+
58
+ // Filter mode entry via "/"
59
+ assertTrue(
60
+ overlaySrc.includes('data === "/"') || overlaySrc.includes("data === '/'"),
61
+ "/ key enters filter mode",
62
+ );
63
+
64
+ // Filter field cycling via "f"
65
+ assertTrue(
66
+ overlaySrc.includes('data === "f"') || overlaySrc.includes("data === 'f'"),
67
+ "f key cycles filter field",
68
+ );
69
+
70
+ console.log("\n=== Overlay: Tab Switching ===");
71
+
72
+ // Supports 1-7 keys
73
+ assertTrue(
74
+ overlaySrc.includes('"1234567"'),
75
+ "supports keys 1-7 for tab switching",
76
+ );
77
+
78
+ // Tab wraps with TAB_COUNT
79
+ assertTrue(
80
+ overlaySrc.includes("% TAB_COUNT"),
81
+ "tab key wraps around TAB_COUNT",
82
+ );
83
+
84
+ console.log("\n=== Overlay: Export Key Interception ===");
85
+
86
+ assertTrue(
87
+ overlaySrc.includes("activeTab === 6"),
88
+ "export key handling checks for tab 7 (index 6)",
89
+ );
90
+
91
+ assertTrue(
92
+ overlaySrc.includes('handleExportKey'),
93
+ "has handleExportKey method",
94
+ );
95
+
96
+ assertTrue(
97
+ overlaySrc.includes('"m"') && overlaySrc.includes('"j"') && overlaySrc.includes('"s"'),
98
+ "handles m, j, s keys for export",
99
+ );
100
+
101
+ console.log("\n=== Overlay: Footer ===");
102
+
103
+ assertTrue(
104
+ overlaySrc.includes("Tab/1-7"),
105
+ "footer hint shows 1-7 tab range",
106
+ );
107
+
108
+ assertTrue(
109
+ overlaySrc.includes("/ filter"),
110
+ "footer hint mentions filter",
111
+ );
112
+
113
+ console.log("\n=== Overlay: Scroll Offsets ===");
114
+
115
+ assertTrue(
116
+ overlaySrc.includes(`new Array(TAB_COUNT).fill(0)`),
117
+ "scroll offsets sized to TAB_COUNT",
118
+ );
119
+
120
+ report();
@@ -0,0 +1,478 @@
1
+ // Tests for GSD visualizer view renderers.
2
+ // Tests the pure view functions with mock data — no file I/O.
3
+
4
+ import {
5
+ renderProgressView,
6
+ renderDepsView,
7
+ renderMetricsView,
8
+ renderTimelineView,
9
+ renderAgentView,
10
+ renderChangelogView,
11
+ renderExportView,
12
+ } from "../visualizer-views.js";
13
+ import type { VisualizerData } from "../visualizer-data.js";
14
+ import { createTestContext } from "./test-helpers.ts";
15
+
16
+ const { assertEq, assertTrue, report } = createTestContext();
17
+
18
+ // ─── Mock theme ─────────────────────────────────────────────────────────────
19
+
20
+ const mockTheme = {
21
+ fg: (_color: string, text: string) => text,
22
+ bold: (text: string) => text,
23
+ } as any;
24
+
25
+ // ─── Test data factories ────────────────────────────────────────────────────
26
+
27
+ function makeVisualizerData(overrides: Partial<VisualizerData> = {}): VisualizerData {
28
+ return {
29
+ milestones: [],
30
+ phase: "executing",
31
+ totals: null,
32
+ byPhase: [],
33
+ bySlice: [],
34
+ byModel: [],
35
+ units: [],
36
+ criticalPath: {
37
+ milestonePath: [],
38
+ slicePath: [],
39
+ milestoneSlack: new Map(),
40
+ sliceSlack: new Map(),
41
+ },
42
+ remainingSliceCount: 0,
43
+ agentActivity: null,
44
+ changelog: { entries: [] },
45
+ ...overrides,
46
+ };
47
+ }
48
+
49
+ // ─── renderProgressView ─────────────────────────────────────────────────────
50
+
51
+ console.log("\n=== renderProgressView ===");
52
+
53
+ {
54
+ const data = makeVisualizerData({
55
+ milestones: [
56
+ {
57
+ id: "M001",
58
+ title: "First Milestone",
59
+ status: "active",
60
+ dependsOn: [],
61
+ slices: [
62
+ {
63
+ id: "S01",
64
+ title: "Core Types",
65
+ done: true,
66
+ active: false,
67
+ risk: "low",
68
+ depends: [],
69
+ tasks: [],
70
+ },
71
+ {
72
+ id: "S02",
73
+ title: "State Engine",
74
+ done: false,
75
+ active: true,
76
+ risk: "high",
77
+ depends: ["S01"],
78
+ tasks: [
79
+ { id: "T01", title: "Dispatch Loop", done: false, active: true },
80
+ { id: "T02", title: "Session Mgmt", done: true, active: false },
81
+ ],
82
+ },
83
+ {
84
+ id: "S03",
85
+ title: "Dashboard",
86
+ done: false,
87
+ active: false,
88
+ risk: "medium",
89
+ depends: ["S02"],
90
+ tasks: [],
91
+ },
92
+ ],
93
+ },
94
+ {
95
+ id: "M002",
96
+ title: "Plugin Arch",
97
+ status: "pending",
98
+ dependsOn: ["M001"],
99
+ slices: [],
100
+ },
101
+ ],
102
+ });
103
+
104
+ const lines = renderProgressView(data, mockTheme, 80);
105
+ assertTrue(lines.length > 0, "progress view produces output");
106
+ assertTrue(lines.some(l => l.includes("M001")), "shows milestone M001");
107
+ assertTrue(lines.some(l => l.includes("S01")), "shows slice S01");
108
+ assertTrue(lines.some(l => l.includes("T01")), "shows task T01 for active slice");
109
+ assertTrue(lines.some(l => l.includes("M002")), "shows milestone M002");
110
+ assertTrue(lines.some(l => l.includes("depends on M001")), "shows dependency note");
111
+ }
112
+
113
+ {
114
+ const data = makeVisualizerData({ milestones: [] });
115
+ const lines = renderProgressView(data, mockTheme, 80);
116
+ assertEq(lines.length, 0, "empty milestones produce no lines");
117
+ }
118
+
119
+ // ─── Risk Heatmap ───────────────────────────────────────────────────────────
120
+
121
+ console.log("\n=== Risk Heatmap ===");
122
+
123
+ {
124
+ const data = makeVisualizerData({
125
+ milestones: [
126
+ {
127
+ id: "M001",
128
+ title: "First",
129
+ status: "active",
130
+ dependsOn: [],
131
+ slices: [
132
+ { id: "S01", title: "A", done: true, active: false, risk: "low", depends: [], tasks: [] },
133
+ { id: "S02", title: "B", done: false, active: true, risk: "high", depends: [], tasks: [] },
134
+ { id: "S03", title: "C", done: false, active: false, risk: "medium", depends: [], tasks: [] },
135
+ { id: "S04", title: "D", done: false, active: false, risk: "high", depends: [], tasks: [] },
136
+ ],
137
+ },
138
+ ],
139
+ });
140
+
141
+ const lines = renderProgressView(data, mockTheme, 80);
142
+ assertTrue(lines.some(l => l.includes("Risk Heatmap")), "heatmap header present");
143
+ assertTrue(lines.some(l => l.includes("██")), "heatmap has colored blocks");
144
+ assertTrue(lines.some(l => l.includes("low") && l.includes("med") && l.includes("high")), "heatmap legend present");
145
+ assertTrue(lines.some(l => l.includes("1 low, 1 med, 2 high")), "risk summary counts");
146
+ assertTrue(lines.some(l => l.includes("1 high-risk not started")), "high-risk not started warning");
147
+ }
148
+
149
+ // ─── Search/Filter ──────────────────────────────────────────────────────────
150
+
151
+ console.log("\n=== Search/Filter ===");
152
+
153
+ {
154
+ const data = makeVisualizerData({
155
+ milestones: [
156
+ {
157
+ id: "M001",
158
+ title: "Auth",
159
+ status: "active",
160
+ dependsOn: [],
161
+ slices: [
162
+ { id: "S01", title: "JWT", done: false, active: false, risk: "low", depends: [], tasks: [] },
163
+ { id: "S02", title: "OAuth", done: false, active: false, risk: "high", depends: [], tasks: [] },
164
+ ],
165
+ },
166
+ {
167
+ id: "M002",
168
+ title: "Dashboard",
169
+ status: "pending",
170
+ dependsOn: ["M001"],
171
+ slices: [],
172
+ },
173
+ ],
174
+ });
175
+
176
+ // Filter by keyword "auth"
177
+ const filtered = renderProgressView(data, mockTheme, 80, { text: "auth", field: "all" });
178
+ assertTrue(filtered.some(l => l.includes("M001")), "filter shows matching milestone");
179
+ assertTrue(filtered.some(l => l.includes("Filter (all): auth")), "filter indicator present");
180
+
181
+ // Filter by risk "high"
182
+ const riskFiltered = renderProgressView(data, mockTheme, 80, { text: "high", field: "risk" });
183
+ assertTrue(riskFiltered.some(l => l.includes("M001")), "risk filter shows milestone with high-risk slice");
184
+ }
185
+
186
+ // ─── renderDepsView ─────────────────────────────────────────────────────────
187
+
188
+ console.log("\n=== renderDepsView ===");
189
+
190
+ {
191
+ const data = makeVisualizerData({
192
+ milestones: [
193
+ {
194
+ id: "M001",
195
+ title: "First",
196
+ status: "active",
197
+ dependsOn: [],
198
+ slices: [
199
+ { id: "S01", title: "A", done: false, active: true, risk: "low", depends: [], tasks: [] },
200
+ { id: "S02", title: "B", done: false, active: false, risk: "low", depends: ["S01"], tasks: [] },
201
+ ],
202
+ },
203
+ {
204
+ id: "M002",
205
+ title: "Second",
206
+ status: "pending",
207
+ dependsOn: ["M001"],
208
+ slices: [],
209
+ },
210
+ ],
211
+ criticalPath: {
212
+ milestonePath: ["M001", "M002"],
213
+ slicePath: ["S01", "S02"],
214
+ milestoneSlack: new Map([["M001", 0], ["M002", 0]]),
215
+ sliceSlack: new Map([["S01", 0], ["S02", 0]]),
216
+ },
217
+ });
218
+
219
+ const lines = renderDepsView(data, mockTheme, 80);
220
+ assertTrue(lines.length > 0, "deps view produces output");
221
+ assertTrue(lines.some(l => l.includes("M001") && l.includes("M002")), "shows milestone dep edge");
222
+ assertTrue(lines.some(l => l.includes("S01") && l.includes("S02")), "shows slice dep edge");
223
+ assertTrue(lines.some(l => l.includes("Critical Path")), "shows critical path section");
224
+ assertTrue(lines.some(l => l.includes("[CRITICAL]")), "shows CRITICAL badge");
225
+ }
226
+
227
+ {
228
+ const data = makeVisualizerData({
229
+ milestones: [
230
+ { id: "M001", title: "Only", status: "active", dependsOn: [], slices: [] },
231
+ ],
232
+ });
233
+
234
+ const lines = renderDepsView(data, mockTheme, 80);
235
+ assertTrue(lines.some(l => l.includes("No milestone dependencies")), "shows no-deps message");
236
+ }
237
+
238
+ // ─── renderMetricsView ──────────────────────────────────────────────────────
239
+
240
+ console.log("\n=== renderMetricsView ===");
241
+
242
+ {
243
+ const data = makeVisualizerData({
244
+ totals: {
245
+ units: 5,
246
+ tokens: { input: 1000, output: 500, cacheRead: 200, cacheWrite: 100, total: 1800 },
247
+ cost: 2.50,
248
+ duration: 60000,
249
+ toolCalls: 15,
250
+ assistantMessages: 10,
251
+ userMessages: 5,
252
+ totalTruncationSections: 0,
253
+ continueHereFiredCount: 0,
254
+ },
255
+ byPhase: [
256
+ {
257
+ phase: "execution",
258
+ units: 3,
259
+ tokens: { input: 600, output: 300, cacheRead: 100, cacheWrite: 50, total: 1050 },
260
+ cost: 1.50,
261
+ duration: 40000,
262
+ },
263
+ {
264
+ phase: "planning",
265
+ units: 2,
266
+ tokens: { input: 400, output: 200, cacheRead: 100, cacheWrite: 50, total: 750 },
267
+ cost: 1.00,
268
+ duration: 20000,
269
+ },
270
+ ],
271
+ byModel: [
272
+ {
273
+ model: "claude-opus-4-6",
274
+ units: 5,
275
+ tokens: { input: 1000, output: 500, cacheRead: 200, cacheWrite: 100, total: 1800 },
276
+ cost: 2.50,
277
+ },
278
+ ],
279
+ bySlice: [
280
+ { sliceId: "M001/S01", units: 3, tokens: { input: 600, output: 300, cacheRead: 100, cacheWrite: 50, total: 1050 }, cost: 1.50, duration: 40000 },
281
+ { sliceId: "M001/S02", units: 2, tokens: { input: 400, output: 200, cacheRead: 100, cacheWrite: 50, total: 750 }, cost: 1.00, duration: 20000 },
282
+ ],
283
+ remainingSliceCount: 3,
284
+ });
285
+
286
+ const lines = renderMetricsView(data, mockTheme, 80);
287
+ assertTrue(lines.length > 0, "metrics view produces output");
288
+ assertTrue(lines.some(l => l.includes("$2.50")), "shows total cost");
289
+ assertTrue(lines.some(l => l.includes("execution")), "shows phase name");
290
+ assertTrue(lines.some(l => l.includes("claude-opus-4-6")), "shows model name");
291
+ assertTrue(lines.some(l => l.includes("Projections")), "shows projections section");
292
+ assertTrue(lines.some(l => l.includes("Avg cost/slice")), "shows avg cost per slice");
293
+ assertTrue(lines.some(l => l.includes("Projected remaining")), "shows projected remaining");
294
+ assertTrue(lines.some(l => l.includes("Burn rate")), "shows burn rate");
295
+ assertTrue(lines.some(l => l.includes("Cost trend")), "shows sparkline");
296
+ }
297
+
298
+ {
299
+ const data = makeVisualizerData({ totals: null });
300
+ const lines = renderMetricsView(data, mockTheme, 80);
301
+ assertTrue(lines.some(l => l.includes("No metrics data")), "shows no-data message");
302
+ }
303
+
304
+ // ─── renderTimelineView ─────────────────────────────────────────────────────
305
+
306
+ console.log("\n=== renderTimelineView ===");
307
+
308
+ {
309
+ const now = Date.now();
310
+ const data = makeVisualizerData({
311
+ units: [
312
+ {
313
+ type: "execute-task",
314
+ id: "M001/S01/T01",
315
+ model: "claude-opus-4-6",
316
+ startedAt: now - 120000,
317
+ finishedAt: now - 60000,
318
+ tokens: { input: 500, output: 200, cacheRead: 100, cacheWrite: 50, total: 850 },
319
+ cost: 0.42,
320
+ toolCalls: 5,
321
+ assistantMessages: 3,
322
+ userMessages: 1,
323
+ },
324
+ {
325
+ type: "plan-slice",
326
+ id: "M001/S02",
327
+ model: "claude-opus-4-6",
328
+ startedAt: now - 60000,
329
+ finishedAt: now - 30000,
330
+ tokens: { input: 300, output: 150, cacheRead: 50, cacheWrite: 25, total: 525 },
331
+ cost: 0.18,
332
+ toolCalls: 2,
333
+ assistantMessages: 2,
334
+ userMessages: 1,
335
+ },
336
+ ],
337
+ });
338
+
339
+ // Wide terminal — Gantt view
340
+ const ganttLines = renderTimelineView(data, mockTheme, 120);
341
+ assertTrue(ganttLines.length >= 2, "gantt view produces lines for each unit");
342
+
343
+ // Narrow terminal — list view
344
+ const listLines = renderTimelineView(data, mockTheme, 80);
345
+ assertTrue(listLines.length >= 2, "list view produces lines for each unit");
346
+ assertTrue(listLines.some(l => l.includes("execute-task")), "shows unit type");
347
+ assertTrue(listLines.some(l => l.includes("M001/S01/T01")), "shows unit id");
348
+ assertTrue(listLines.some(l => l.includes("$0.42")), "shows unit cost");
349
+ }
350
+
351
+ {
352
+ const data = makeVisualizerData({ units: [] });
353
+ const lines = renderTimelineView(data, mockTheme, 80);
354
+ assertTrue(lines.some(l => l.includes("No execution history")), "shows empty message");
355
+ }
356
+
357
+ // ─── renderAgentView ────────────────────────────────────────────────────────
358
+
359
+ console.log("\n=== renderAgentView ===");
360
+
361
+ {
362
+ const now = Date.now();
363
+ const data = makeVisualizerData({
364
+ agentActivity: {
365
+ currentUnit: { type: "execute-task", id: "M001/S02/T03", startedAt: now - 60000 },
366
+ elapsed: 60000,
367
+ completedUnits: 8,
368
+ totalSlices: 15,
369
+ completionRate: 2.4,
370
+ active: true,
371
+ sessionCost: 1.23,
372
+ sessionTokens: 45200,
373
+ },
374
+ units: [
375
+ {
376
+ type: "execute-task", id: "M001/S01/T01", model: "claude-opus-4-6",
377
+ startedAt: now - 300000, finishedAt: now - 240000,
378
+ tokens: { input: 500, output: 200, cacheRead: 100, cacheWrite: 50, total: 850 },
379
+ cost: 0.12, toolCalls: 5, assistantMessages: 3, userMessages: 1,
380
+ },
381
+ ],
382
+ });
383
+
384
+ const lines = renderAgentView(data, mockTheme, 80);
385
+ assertTrue(lines.length > 0, "agent view produces output");
386
+ assertTrue(lines.some(l => l.includes("ACTIVE")), "shows active status");
387
+ assertTrue(lines.some(l => l.includes("M001/S02/T03")), "shows current unit");
388
+ assertTrue(lines.some(l => l.includes("8/15")), "shows progress fraction");
389
+ assertTrue(lines.some(l => l.includes("2.4 units/hr")), "shows completion rate");
390
+ assertTrue(lines.some(l => l.includes("$1.23")), "shows session cost");
391
+ }
392
+
393
+ {
394
+ const data = makeVisualizerData({ agentActivity: null });
395
+ const lines = renderAgentView(data, mockTheme, 80);
396
+ assertTrue(lines.some(l => l.includes("No agent activity")), "shows no-activity message");
397
+ }
398
+
399
+ {
400
+ const data = makeVisualizerData({
401
+ agentActivity: {
402
+ currentUnit: null,
403
+ elapsed: 0,
404
+ completedUnits: 5,
405
+ totalSlices: 10,
406
+ completionRate: 1.5,
407
+ active: false,
408
+ sessionCost: 0.50,
409
+ sessionTokens: 20000,
410
+ },
411
+ });
412
+
413
+ const lines = renderAgentView(data, mockTheme, 80);
414
+ assertTrue(lines.some(l => l.includes("IDLE")), "shows idle status");
415
+ assertTrue(lines.some(l => l.includes("Not in auto mode")), "shows not-in-auto message");
416
+ }
417
+
418
+ // ─── renderChangelogView ────────────────────────────────────────────────────
419
+
420
+ console.log("\n=== renderChangelogView ===");
421
+
422
+ {
423
+ const data = makeVisualizerData({
424
+ changelog: {
425
+ entries: [
426
+ {
427
+ milestoneId: "M001",
428
+ sliceId: "S01",
429
+ title: "Core Authentication Setup",
430
+ oneLiner: "Added JWT-based auth with refresh token rotation",
431
+ filesModified: [
432
+ { path: "src/auth/jwt.ts", description: "JWT token generation and validation" },
433
+ { path: "src/auth/middleware.ts", description: "Express middleware for auth checks" },
434
+ ],
435
+ completedAt: "2026-03-15T14:30:00Z",
436
+ },
437
+ ],
438
+ },
439
+ });
440
+
441
+ const lines = renderChangelogView(data, mockTheme, 80);
442
+ assertTrue(lines.length > 0, "changelog view produces output");
443
+ assertTrue(lines.some(l => l.includes("M001/S01")), "shows slice reference");
444
+ assertTrue(lines.some(l => l.includes("Core Authentication Setup")), "shows entry title");
445
+ assertTrue(lines.some(l => l.includes("JWT-based auth")), "shows one-liner");
446
+ assertTrue(lines.some(l => l.includes("src/auth/jwt.ts")), "shows modified file");
447
+ assertTrue(lines.some(l => l.includes("2026-03-15")), "shows completed date");
448
+ }
449
+
450
+ {
451
+ const data = makeVisualizerData({ changelog: { entries: [] } });
452
+ const lines = renderChangelogView(data, mockTheme, 80);
453
+ assertTrue(lines.some(l => l.includes("No completed slices")), "shows empty state");
454
+ }
455
+
456
+ // ─── renderExportView ───────────────────────────────────────────────────────
457
+
458
+ console.log("\n=== renderExportView ===");
459
+
460
+ {
461
+ const data = makeVisualizerData();
462
+ const lines = renderExportView(data, mockTheme, 80);
463
+ assertTrue(lines.some(l => l.includes("Export Options")), "shows export header");
464
+ assertTrue(lines.some(l => l.includes("[m]")), "shows markdown option");
465
+ assertTrue(lines.some(l => l.includes("[j]")), "shows json option");
466
+ assertTrue(lines.some(l => l.includes("[s]")), "shows snapshot option");
467
+ }
468
+
469
+ {
470
+ const data = makeVisualizerData();
471
+ const lines = renderExportView(data, mockTheme, 80, "/tmp/export-2026.md");
472
+ assertTrue(lines.some(l => l.includes("Last export:")), "shows last export path");
473
+ assertTrue(lines.some(l => l.includes("/tmp/export-2026.md")), "shows specific export path");
474
+ }
475
+
476
+ // ─── Report ─────────────────────────────────────────────────────────────────
477
+
478
+ report();