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,178 @@
1
+ // GSD Extension — Debug Logger
2
+ // Structured JSONL debug logging for diagnosing stuck/slow GSD sessions.
3
+ // Zero overhead when disabled — all public functions are no-ops.
4
+
5
+ import { appendFileSync, mkdirSync, readdirSync, unlinkSync } from 'node:fs';
6
+ import { join } from 'node:path';
7
+ import { gsdRoot } from './paths.js';
8
+
9
+ // ─── State ────────────────────────────────────────────────────────────────────
10
+
11
+ let _enabled = false;
12
+ let _logPath: string | null = null;
13
+ let _startTime = 0;
14
+
15
+ /** Rolling counters for the debug summary written on stop. */
16
+ const _counters = {
17
+ deriveStateCalls: 0,
18
+ deriveStateTotalMs: 0,
19
+ ttsrChecks: 0,
20
+ ttsrTotalMs: 0,
21
+ ttsrPeakBuffer: 0,
22
+ parseRoadmapCalls: 0,
23
+ parseRoadmapTotalMs: 0,
24
+ parsePlanCalls: 0,
25
+ parsePlanTotalMs: 0,
26
+ dispatches: 0,
27
+ renders: 0,
28
+ };
29
+
30
+ /** Max debug log files to keep. Older ones are pruned on enable. */
31
+ const MAX_DEBUG_LOGS = 5;
32
+
33
+ // ─── Public API ───────────────────────────────────────────────────────────────
34
+
35
+ /**
36
+ * Enable debug logging. Creates the log file and prunes old logs.
37
+ * Can be activated via `--debug` flag or `GSD_DEBUG=1` env var.
38
+ */
39
+ export function enableDebug(basePath: string): void {
40
+ const debugDir = join(gsdRoot(basePath), 'debug');
41
+ mkdirSync(debugDir, { recursive: true });
42
+
43
+ // Prune old debug logs
44
+ try {
45
+ const files = readdirSync(debugDir)
46
+ .filter(f => f.startsWith('debug-') && f.endsWith('.log'))
47
+ .sort();
48
+ while (files.length >= MAX_DEBUG_LOGS) {
49
+ const oldest = files.shift()!;
50
+ try { unlinkSync(join(debugDir, oldest)); } catch { /* ignore */ }
51
+ }
52
+ } catch { /* non-fatal */ }
53
+
54
+ const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
55
+ _logPath = join(debugDir, `debug-${timestamp}.log`);
56
+ _startTime = Date.now();
57
+ _enabled = true;
58
+
59
+ // Reset counters
60
+ for (const key of Object.keys(_counters) as (keyof typeof _counters)[]) {
61
+ _counters[key] = 0;
62
+ }
63
+ }
64
+
65
+ /** Disable debug logging and return the log file path (if any). */
66
+ export function disableDebug(): string | null {
67
+ const path = _logPath;
68
+ _enabled = false;
69
+ _logPath = null;
70
+ _startTime = 0;
71
+ return path;
72
+ }
73
+
74
+ /** Check if debug mode is active. */
75
+ export function isDebugEnabled(): boolean {
76
+ return _enabled;
77
+ }
78
+
79
+ /** Return the current log file path (or null). */
80
+ export function getDebugLogPath(): string | null {
81
+ return _logPath;
82
+ }
83
+
84
+ /**
85
+ * Log a structured debug event. No-op when debug is disabled.
86
+ *
87
+ * Each event is one JSON line: `{ ts, event, ...data }`
88
+ */
89
+ export function debugLog(event: string, data?: Record<string, unknown>): void {
90
+ if (!_enabled || !_logPath) return;
91
+
92
+ const entry = {
93
+ ts: new Date().toISOString(),
94
+ event,
95
+ ...data,
96
+ };
97
+
98
+ try {
99
+ appendFileSync(_logPath, JSON.stringify(entry) + '\n');
100
+ } catch {
101
+ // Silently ignore write failures — debug logging must never break GSD
102
+ }
103
+ }
104
+
105
+ /**
106
+ * Start a timer for a named operation. Returns a stop function that logs
107
+ * the elapsed time and optional result data.
108
+ *
109
+ * Usage:
110
+ * ```ts
111
+ * const stop = debugTime('derive-state');
112
+ * const result = await deriveState(base);
113
+ * stop({ phase: result.phase });
114
+ * ```
115
+ */
116
+ export function debugTime(event: string): (data?: Record<string, unknown>) => void {
117
+ if (!_enabled) return _noop;
118
+
119
+ const start = performance.now();
120
+ return (data?: Record<string, unknown>) => {
121
+ const elapsed_ms = Math.round((performance.now() - start) * 100) / 100;
122
+ debugLog(event, { elapsed_ms, ...data });
123
+ };
124
+ }
125
+
126
+ // ─── Counter Helpers ──────────────────────────────────────────────────────────
127
+
128
+ /** Increment a debug counter (used by instrumentation points). */
129
+ export function debugCount(counter: keyof typeof _counters, value = 1): void {
130
+ if (!_enabled) return;
131
+ _counters[counter] += value;
132
+ }
133
+
134
+ /** Record a peak value (only updates if new value is higher). */
135
+ export function debugPeak(counter: keyof typeof _counters, value: number): void {
136
+ if (!_enabled) return;
137
+ if (value > _counters[counter]) {
138
+ _counters[counter] = value;
139
+ }
140
+ }
141
+
142
+ /**
143
+ * Write the debug summary and disable logging. Call this when auto-mode stops.
144
+ * Returns the log file path for user notification.
145
+ */
146
+ export function writeDebugSummary(): string | null {
147
+ if (!_enabled || !_logPath) return null;
148
+
149
+ const totalElapsed_ms = Date.now() - _startTime;
150
+ const avgDeriveState_ms = _counters.deriveStateCalls > 0
151
+ ? Math.round((_counters.deriveStateTotalMs / _counters.deriveStateCalls) * 100) / 100
152
+ : 0;
153
+ const avgTtsrCheck_ms = _counters.ttsrChecks > 0
154
+ ? Math.round((_counters.ttsrTotalMs / _counters.ttsrChecks) * 100) / 100
155
+ : 0;
156
+
157
+ debugLog('debug-summary', {
158
+ totalElapsed_ms,
159
+ dispatches: _counters.dispatches,
160
+ deriveStateCalls: _counters.deriveStateCalls,
161
+ avgDeriveState_ms,
162
+ parseRoadmapCalls: _counters.parseRoadmapCalls,
163
+ avgParseRoadmap_ms: _counters.parseRoadmapCalls > 0
164
+ ? Math.round((_counters.parseRoadmapTotalMs / _counters.parseRoadmapCalls) * 100) / 100
165
+ : 0,
166
+ parsePlanCalls: _counters.parsePlanCalls,
167
+ ttsrChecks: _counters.ttsrChecks,
168
+ avgTtsrCheck_ms,
169
+ ttsrPeakBuffer: _counters.ttsrPeakBuffer,
170
+ renders: _counters.renders,
171
+ });
172
+
173
+ return disableDebug();
174
+ }
175
+
176
+ // ─── Internal ─────────────────────────────────────────────────────────────────
177
+
178
+ function _noop(_data?: Record<string, unknown>): void { /* no-op */ }
@@ -1,5 +1,4 @@
1
1
  // GSD Dispatch Guard — prevents out-of-order slice dispatch
2
- // Copyright (c) 2026 Jeremy McSpadden <jeremy@fluxlabs.net>
3
2
 
4
3
  import { readFileSync } from "node:fs";
5
4
  import { readdirSync } from "node:fs";
@@ -72,6 +72,20 @@ Setting `prefer_skills: []` does **not** disable skill discovery — it just mea
72
72
 
73
73
  - `version`: schema version. Start at `1`.
74
74
 
75
+ - `mode`: workflow mode — `"solo"` or `"team"`. Sets sensible defaults for git and project settings based on your workflow. Mode defaults are the lowest priority layer — any explicit preference overrides them. Omit to configure everything manually.
76
+
77
+ | Setting | `solo` | `team` |
78
+ |---|---|---|
79
+ | `git.auto_push` | `true` | `false` |
80
+ | `git.push_branches` | `false` | `true` |
81
+ | `git.pre_merge_check` | `false` | `true` |
82
+ | `git.merge_strategy` | `"squash"` | `"squash"` |
83
+ | `git.isolation` | `"worktree"` | `"worktree"` |
84
+ | `git.commit_docs` | `true` | `true` |
85
+ | `unique_milestone_ids` | `false` | `true` |
86
+
87
+ Quick setup: `/gsd mode` (global) or `/gsd mode project` (project-level).
88
+
75
89
  - `always_use_skills`: skills GSD should use whenever they are relevant.
76
90
 
77
91
  - `prefer_skills`: soft defaults GSD should prefer when relevant.
@@ -111,6 +125,7 @@ Setting `prefer_skills: []` does **not** disable skill discovery — it just mea
111
125
  - `merge_strategy`: `"squash"` or `"merge"` — controls how worktree branches are merged back. `"squash"` combines all commits into one; `"merge"` preserves individual commits. Default: `"squash"`.
112
126
  - `isolation`: `"worktree"` or `"branch"` — controls auto-mode git isolation strategy. `"worktree"` creates a milestone worktree for isolated work; `"branch"` works directly in the project root (useful for submodule-heavy repos). Default: `"worktree"`.
113
127
  - `commit_docs`: boolean — when `false`, prevents GSD from committing `.gsd/` planning artifacts to git. The `.gsd/` folder is added to `.gitignore` and kept local-only. Useful for teams where only some members use GSD, or when company policy requires a clean repository. Default: `true`.
128
+ - `worktree_post_create`: string — script to run after a worktree is created (both auto-mode and manual `/worktree`). Receives `SOURCE_DIR` and `WORKTREE_DIR` as environment variables. Can be absolute or relative to project root. Runs with 30-second timeout. Failure is non-fatal (logged as warning). Default: none.
114
129
 
115
130
  - `unique_milestone_ids`: boolean — when `true`, generates milestone IDs in `M{seq}-{rand6}` format (e.g. `M001-eh88as`) instead of plain sequential `M001`. Prevents ID collisions in team workflows where multiple contributors create milestones concurrently. Both formats coexist — existing `M001`-style milestones remain valid. Default: `false`.
116
131
 
@@ -189,6 +204,45 @@ Setting `prefer_skills: []` does **not** disable skill discovery — it just mea
189
204
 
190
205
  ---
191
206
 
207
+ ## Workflow Mode Examples
208
+
209
+ **Solo developer — auto-push, simple IDs:**
210
+
211
+ ```yaml
212
+ ---
213
+ version: 1
214
+ mode: solo
215
+ ---
216
+ ```
217
+
218
+ Equivalent to setting `git.auto_push: true`, `git.push_branches: false`, `git.pre_merge_check: false`, `git.merge_strategy: squash`, `git.isolation: worktree`, `git.commit_docs: true`, `unique_milestone_ids: false`.
219
+
220
+ **Team — unique IDs, push branches, pre-merge checks:**
221
+
222
+ ```yaml
223
+ ---
224
+ version: 1
225
+ mode: team
226
+ ---
227
+ ```
228
+
229
+ Equivalent to setting `git.auto_push: false`, `git.push_branches: true`, `git.pre_merge_check: true`, `git.merge_strategy: squash`, `git.isolation: worktree`, `git.commit_docs: true`, `unique_milestone_ids: true`.
230
+
231
+ **Mode with overrides — team mode but with auto-push:**
232
+
233
+ ```yaml
234
+ ---
235
+ version: 1
236
+ mode: team
237
+ git:
238
+ auto_push: true
239
+ ---
240
+ ```
241
+
242
+ Gets all team defaults except `auto_push`, which is explicitly overridden to `true`. Any explicit setting always wins over the mode default.
243
+
244
+ ---
245
+
192
246
  ## Minimal Example
193
247
 
194
248
  The cleanest preferences file only specifies what you actually want:
@@ -0,0 +1,286 @@
1
+ /**
2
+ * GSD Doctor — Proactive Healing Layer
3
+ *
4
+ * Three mechanisms for automatic health monitoring during auto-mode:
5
+ *
6
+ * 1. Pre-dispatch health gate: lightweight check before each unit dispatch.
7
+ * Returns blocking issues that should pause auto-mode rather than
8
+ * dispatching into a broken state.
9
+ *
10
+ * 2. Health score tracking: tracks issue counts over time to detect
11
+ * degradation trends. If health is declining, surfaces a warning.
12
+ *
13
+ * 3. Auto-heal escalation: if deterministic fix can't resolve issues
14
+ * after N units, escalates to LLM-assisted heal dispatch.
15
+ */
16
+
17
+ import { existsSync, readFileSync } from "node:fs";
18
+ import { join } from "node:path";
19
+ import { gsdRoot, resolveGsdRootFile } from "./paths.js";
20
+ import { readCrashLock, isLockProcessAlive, clearLock } from "./crash-recovery.js";
21
+ import { abortAndReset } from "./git-self-heal.js";
22
+
23
+ // ── Health Score Tracking ──────────────────────────────────────────────────
24
+
25
+ export interface HealthSnapshot {
26
+ timestamp: number;
27
+ errors: number;
28
+ warnings: number;
29
+ fixesApplied: number;
30
+ unitIndex: number; // which unit dispatch triggered this snapshot
31
+ }
32
+
33
+ /** In-memory health history for the current auto-mode session. */
34
+ let healthHistory: HealthSnapshot[] = [];
35
+
36
+ /** Count of consecutive units with unresolved errors. */
37
+ let consecutiveErrorUnits = 0;
38
+
39
+ /** Unit index counter for health tracking. */
40
+ let healthUnitIndex = 0;
41
+
42
+ /**
43
+ * Record a health snapshot after a doctor run.
44
+ * Called from the post-unit hook in auto.ts.
45
+ */
46
+ export function recordHealthSnapshot(errors: number, warnings: number, fixesApplied: number): void {
47
+ healthUnitIndex++;
48
+ healthHistory.push({
49
+ timestamp: Date.now(),
50
+ errors,
51
+ warnings,
52
+ fixesApplied,
53
+ unitIndex: healthUnitIndex,
54
+ });
55
+
56
+ // Keep only the last 50 snapshots to bound memory
57
+ if (healthHistory.length > 50) {
58
+ healthHistory = healthHistory.slice(-50);
59
+ }
60
+
61
+ if (errors > 0) {
62
+ consecutiveErrorUnits++;
63
+ } else {
64
+ consecutiveErrorUnits = 0;
65
+ }
66
+ }
67
+
68
+ /**
69
+ * Get the current health trend.
70
+ * Returns "improving", "stable", "degrading", or "unknown" (not enough data).
71
+ */
72
+ export function getHealthTrend(): "improving" | "stable" | "degrading" | "unknown" {
73
+ if (healthHistory.length < 3) return "unknown";
74
+
75
+ const recent = healthHistory.slice(-5);
76
+ const older = healthHistory.slice(-10, -5);
77
+
78
+ if (older.length === 0) return "unknown";
79
+
80
+ const recentAvg = recent.reduce((sum, s) => sum + s.errors + s.warnings, 0) / recent.length;
81
+ const olderAvg = older.reduce((sum, s) => sum + s.errors + s.warnings, 0) / older.length;
82
+
83
+ const delta = recentAvg - olderAvg;
84
+ if (delta > 1) return "degrading";
85
+ if (delta < -1) return "improving";
86
+ return "stable";
87
+ }
88
+
89
+ /**
90
+ * Get the number of consecutive units with unresolved errors.
91
+ */
92
+ export function getConsecutiveErrorUnits(): number {
93
+ return consecutiveErrorUnits;
94
+ }
95
+
96
+ /**
97
+ * Get health history for display (e.g., dashboard overlay).
98
+ */
99
+ export function getHealthHistory(): readonly HealthSnapshot[] {
100
+ return healthHistory;
101
+ }
102
+
103
+ /**
104
+ * Reset health tracking state. Called on auto-mode start/stop.
105
+ */
106
+ export function resetHealthTracking(): void {
107
+ healthHistory = [];
108
+ consecutiveErrorUnits = 0;
109
+ healthUnitIndex = 0;
110
+ }
111
+
112
+ // ── Pre-Dispatch Health Gate ───────────────────────────────────────────────
113
+
114
+ export interface PreDispatchHealthResult {
115
+ /** Whether the dispatch should proceed. */
116
+ proceed: boolean;
117
+ /** If blocked, the reason to show the user. */
118
+ reason?: string;
119
+ /** Issues found (for logging). */
120
+ issues: string[];
121
+ /** Whether fix was applied. */
122
+ fixesApplied: string[];
123
+ }
124
+
125
+ /**
126
+ * Lightweight pre-dispatch health check. Runs fast checks that should
127
+ * block dispatch if they fail — avoids dispatching into a broken state.
128
+ *
129
+ * This is NOT a full doctor run — it only checks critical, fast-to-evaluate
130
+ * conditions that would cause the next unit to fail or corrupt state.
131
+ *
132
+ * Returns { proceed: true } if dispatch should continue.
133
+ */
134
+ export function preDispatchHealthGate(basePath: string): PreDispatchHealthResult {
135
+ const issues: string[] = [];
136
+ const fixesApplied: string[] = [];
137
+
138
+ // ── Stale crash lock blocks dispatch ──
139
+ // If a stale lock exists, the crash recovery path should handle it,
140
+ // not a new dispatch. This prevents double-dispatch after crashes.
141
+ try {
142
+ const lock = readCrashLock(basePath);
143
+ if (lock && !isLockProcessAlive(lock)) {
144
+ // Auto-clear it since we're about to dispatch anyway
145
+ clearLock(basePath);
146
+ fixesApplied.push("cleared stale auto.lock before dispatch");
147
+ }
148
+ } catch {
149
+ // Non-fatal
150
+ }
151
+
152
+ // ── Corrupt merge/rebase state blocks dispatch ──
153
+ // Dispatching a unit with MERGE_HEAD present will cause git operations to fail.
154
+ try {
155
+ const gitDir = join(basePath, ".git");
156
+ if (existsSync(gitDir)) {
157
+ const blockers = ["MERGE_HEAD", "rebase-apply", "rebase-merge"].filter(
158
+ f => existsSync(join(gitDir, f)),
159
+ );
160
+ if (blockers.length > 0) {
161
+ // Try to auto-heal
162
+ try {
163
+ const result = abortAndReset(basePath);
164
+ fixesApplied.push(`pre-dispatch: cleaned merge state (${result.cleaned.join(", ")})`);
165
+ } catch {
166
+ issues.push(`Corrupt git state: ${blockers.join(", ")}. Run /gsd doctor fix.`);
167
+ }
168
+ }
169
+ }
170
+ } catch {
171
+ // Non-fatal
172
+ }
173
+
174
+ // ── STATE.md existence check ──
175
+ // If STATE.md is missing, deriveState will still work but the LLM
176
+ // may get confused. Rebuild it silently.
177
+ try {
178
+ const stateFile = resolveGsdRootFile(basePath, "STATE");
179
+ const milestonesDir = join(gsdRoot(basePath), "milestones");
180
+ if (existsSync(milestonesDir) && !existsSync(stateFile)) {
181
+ issues.push("STATE.md missing — will rebuild after this unit");
182
+ // Don't block dispatch — rebuilding happens in post-hook
183
+ }
184
+ } catch {
185
+ // Non-fatal
186
+ }
187
+
188
+ // If we had critical issues that couldn't be auto-healed, block dispatch
189
+ if (issues.length > 0) {
190
+ return {
191
+ proceed: false,
192
+ reason: `Pre-dispatch health check failed:\n${issues.map(i => ` - ${i}`).join("\n")}\nRun /gsd doctor fix to resolve.`,
193
+ issues,
194
+ fixesApplied,
195
+ };
196
+ }
197
+
198
+ return { proceed: true, issues, fixesApplied };
199
+ }
200
+
201
+ // ── Auto-Heal Escalation ──────────────────────────────────────────────────
202
+
203
+ /** Threshold: escalate to LLM heal after this many consecutive error units. */
204
+ const ESCALATION_THRESHOLD = 5;
205
+
206
+ /** Whether an escalation has already been triggered this session (prevent spam). */
207
+ let escalationTriggered = false;
208
+
209
+ /**
210
+ * Check whether auto-heal should escalate from deterministic fix to
211
+ * LLM-assisted heal. Called after each post-unit doctor run.
212
+ *
213
+ * Returns the structured issue text for LLM dispatch, or null if
214
+ * escalation is not needed.
215
+ */
216
+ export function checkHealEscalation(
217
+ errors: number,
218
+ unresolvedIssues: Array<{ code: string; message: string; unitId: string }>,
219
+ ): { shouldEscalate: boolean; reason: string; issues: typeof unresolvedIssues } {
220
+ if (escalationTriggered) {
221
+ return { shouldEscalate: false, reason: "already escalated this session", issues: [] };
222
+ }
223
+
224
+ if (consecutiveErrorUnits < ESCALATION_THRESHOLD) {
225
+ return {
226
+ shouldEscalate: false,
227
+ reason: `${consecutiveErrorUnits}/${ESCALATION_THRESHOLD} consecutive error units`,
228
+ issues: [],
229
+ };
230
+ }
231
+
232
+ if (errors === 0) {
233
+ return { shouldEscalate: false, reason: "no errors to escalate", issues: [] };
234
+ }
235
+
236
+ const trend = getHealthTrend();
237
+ if (trend === "improving") {
238
+ return { shouldEscalate: false, reason: "health is improving — deferring escalation", issues: [] };
239
+ }
240
+
241
+ escalationTriggered = true;
242
+ return {
243
+ shouldEscalate: true,
244
+ reason: `${consecutiveErrorUnits} consecutive units with unresolved errors (trend: ${trend})`,
245
+ issues: unresolvedIssues,
246
+ };
247
+ }
248
+
249
+ /**
250
+ * Reset escalation state. Called on auto-mode start/stop.
251
+ */
252
+ export function resetEscalation(): void {
253
+ escalationTriggered = false;
254
+ }
255
+
256
+ /**
257
+ * Format a health summary for display in the auto-mode dashboard.
258
+ */
259
+ export function formatHealthSummary(): string {
260
+ if (healthHistory.length === 0) return "No health data yet.";
261
+
262
+ const latest = healthHistory[healthHistory.length - 1]!;
263
+ const trend = getHealthTrend();
264
+ const trendIcon = trend === "improving" ? "+" : trend === "degrading" ? "-" : "=";
265
+ const totalFixes = healthHistory.reduce((sum, s) => sum + s.fixesApplied, 0);
266
+
267
+ const parts = [
268
+ `Health: ${latest.errors}E/${latest.warnings}W`,
269
+ `trend:${trendIcon}`,
270
+ `fixes:${totalFixes}`,
271
+ ];
272
+
273
+ if (consecutiveErrorUnits > 0) {
274
+ parts.push(`streak:${consecutiveErrorUnits}/${ESCALATION_THRESHOLD}`);
275
+ }
276
+
277
+ return parts.join(" | ");
278
+ }
279
+
280
+ /**
281
+ * Reset all proactive healing state. Called on auto-mode start/stop.
282
+ */
283
+ export function resetProactiveHealing(): void {
284
+ resetHealthTracking();
285
+ resetEscalation();
286
+ }