gsd-pi 2.38.0-dev.eeb3520 → 2.39.0-dev.20aba06

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 (346) hide show
  1. package/README.md +15 -11
  2. package/dist/app-paths.js +1 -1
  3. package/dist/cli.js +9 -0
  4. package/dist/extension-discovery.d.ts +5 -3
  5. package/dist/extension-discovery.js +14 -9
  6. package/dist/extension-registry.js +2 -2
  7. package/dist/remote-questions-config.js +2 -2
  8. package/dist/resource-loader.js +100 -3
  9. package/dist/resources/extensions/async-jobs/index.js +10 -0
  10. package/dist/resources/extensions/browser-tools/index.js +3 -1
  11. package/dist/resources/extensions/browser-tools/package.json +3 -1
  12. package/dist/resources/extensions/browser-tools/tools/verify.js +97 -0
  13. package/dist/resources/extensions/cmux/index.js +55 -1
  14. package/dist/resources/extensions/context7/package.json +1 -1
  15. package/dist/resources/extensions/get-secrets-from-user.js +5 -24
  16. package/dist/resources/extensions/github-sync/cli.js +284 -0
  17. package/dist/resources/extensions/github-sync/index.js +73 -0
  18. package/dist/resources/extensions/github-sync/mapping.js +67 -0
  19. package/dist/resources/extensions/github-sync/sync.js +424 -0
  20. package/dist/resources/extensions/github-sync/templates.js +118 -0
  21. package/dist/resources/extensions/github-sync/types.js +7 -0
  22. package/dist/resources/extensions/google-search/package.json +3 -1
  23. package/dist/resources/extensions/gsd/auto/session.js +6 -23
  24. package/dist/resources/extensions/gsd/auto-dashboard.js +7 -0
  25. package/dist/resources/extensions/gsd/auto-dispatch.js +8 -9
  26. package/dist/resources/extensions/gsd/auto-loop.js +923 -787
  27. package/dist/resources/extensions/gsd/auto-post-unit.js +107 -70
  28. package/dist/resources/extensions/gsd/auto-prompts.js +205 -51
  29. package/dist/resources/extensions/gsd/auto-start.js +19 -3
  30. package/dist/resources/extensions/gsd/auto-worktree-sync.js +13 -5
  31. package/dist/resources/extensions/gsd/auto-worktree.js +3 -3
  32. package/dist/resources/extensions/gsd/auto.js +149 -100
  33. package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +126 -0
  34. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +233 -0
  35. package/dist/resources/extensions/gsd/bootstrap/dynamic-tools.js +59 -0
  36. package/dist/resources/extensions/gsd/bootstrap/register-extension.js +38 -0
  37. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +156 -0
  38. package/dist/resources/extensions/gsd/bootstrap/register-shortcuts.js +46 -0
  39. package/dist/resources/extensions/gsd/bootstrap/system-context.js +300 -0
  40. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +38 -0
  41. package/dist/resources/extensions/gsd/captures.js +9 -1
  42. package/dist/resources/extensions/gsd/commands/catalog.js +278 -0
  43. package/dist/resources/extensions/gsd/commands/context.js +84 -0
  44. package/dist/resources/extensions/gsd/commands/dispatcher.js +21 -0
  45. package/dist/resources/extensions/gsd/commands/handlers/auto.js +72 -0
  46. package/dist/resources/extensions/gsd/commands/handlers/core.js +246 -0
  47. package/dist/resources/extensions/gsd/commands/handlers/ops.js +166 -0
  48. package/dist/resources/extensions/gsd/commands/handlers/parallel.js +94 -0
  49. package/dist/resources/extensions/gsd/commands/handlers/workflow.js +102 -0
  50. package/dist/resources/extensions/gsd/commands/index.js +11 -0
  51. package/dist/resources/extensions/gsd/commands-extensions.js +3 -2
  52. package/dist/resources/extensions/gsd/commands-handlers.js +17 -4
  53. package/dist/resources/extensions/gsd/commands-prefs-wizard.js +1 -1
  54. package/dist/resources/extensions/gsd/commands.js +8 -1169
  55. package/dist/resources/extensions/gsd/context-budget.js +2 -10
  56. package/dist/resources/extensions/gsd/dashboard-overlay.js +9 -0
  57. package/dist/resources/extensions/gsd/detection.js +1 -2
  58. package/dist/resources/extensions/gsd/docs/preferences-reference.md +0 -2
  59. package/dist/resources/extensions/gsd/doctor-checks.js +82 -0
  60. package/dist/resources/extensions/gsd/doctor-environment.js +78 -0
  61. package/dist/resources/extensions/gsd/doctor-format.js +15 -0
  62. package/dist/resources/extensions/gsd/doctor-proactive.js +80 -10
  63. package/dist/resources/extensions/gsd/doctor-providers.js +30 -11
  64. package/dist/resources/extensions/gsd/doctor.js +234 -12
  65. package/dist/resources/extensions/gsd/env-utils.js +29 -0
  66. package/dist/resources/extensions/gsd/exit-command.js +2 -1
  67. package/dist/resources/extensions/gsd/export-html.js +46 -0
  68. package/dist/resources/extensions/gsd/export.js +1 -1
  69. package/dist/resources/extensions/gsd/files.js +48 -9
  70. package/dist/resources/extensions/gsd/forensics.js +1 -1
  71. package/dist/resources/extensions/gsd/git-service.js +30 -12
  72. package/dist/resources/extensions/gsd/gitignore.js +16 -3
  73. package/dist/resources/extensions/gsd/guided-flow.js +149 -38
  74. package/dist/resources/extensions/gsd/health-widget-core.js +32 -70
  75. package/dist/resources/extensions/gsd/health-widget.js +4 -87
  76. package/dist/resources/extensions/gsd/index.js +4 -1111
  77. package/dist/resources/extensions/gsd/migrate/parsers.js +1 -1
  78. package/dist/resources/extensions/gsd/migrate-external.js +18 -1
  79. package/dist/resources/extensions/gsd/native-git-bridge.js +37 -0
  80. package/dist/resources/extensions/gsd/package.json +1 -1
  81. package/dist/resources/extensions/gsd/paths.js +3 -0
  82. package/dist/resources/extensions/gsd/preferences-models.js +0 -12
  83. package/dist/resources/extensions/gsd/preferences-types.js +1 -1
  84. package/dist/resources/extensions/gsd/preferences-validation.js +59 -11
  85. package/dist/resources/extensions/gsd/preferences.js +22 -11
  86. package/dist/resources/extensions/gsd/progress-score.js +20 -1
  87. package/dist/resources/extensions/gsd/prompt-loader.js +6 -2
  88. package/dist/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
  89. package/dist/resources/extensions/gsd/prompts/complete-slice.md +1 -1
  90. package/dist/resources/extensions/gsd/prompts/discuss.md +11 -14
  91. package/dist/resources/extensions/gsd/prompts/execute-task.md +5 -3
  92. package/dist/resources/extensions/gsd/prompts/forensics.md +121 -46
  93. package/dist/resources/extensions/gsd/prompts/guided-complete-slice.md +1 -1
  94. package/dist/resources/extensions/gsd/prompts/guided-discuss-milestone.md +11 -12
  95. package/dist/resources/extensions/gsd/prompts/guided-discuss-slice.md +8 -10
  96. package/dist/resources/extensions/gsd/prompts/guided-execute-task.md +1 -1
  97. package/dist/resources/extensions/gsd/prompts/guided-plan-milestone.md +1 -1
  98. package/dist/resources/extensions/gsd/prompts/guided-plan-slice.md +1 -1
  99. package/dist/resources/extensions/gsd/prompts/guided-research-slice.md +1 -1
  100. package/dist/resources/extensions/gsd/prompts/guided-resume-task.md +1 -1
  101. package/dist/resources/extensions/gsd/prompts/plan-milestone.md +1 -1
  102. package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  103. package/dist/resources/extensions/gsd/prompts/queue.md +4 -8
  104. package/dist/resources/extensions/gsd/prompts/reactive-execute.md +11 -8
  105. package/dist/resources/extensions/gsd/prompts/reassess-roadmap.md +1 -1
  106. package/dist/resources/extensions/gsd/prompts/research-milestone.md +1 -1
  107. package/dist/resources/extensions/gsd/prompts/research-slice.md +1 -1
  108. package/dist/resources/extensions/gsd/prompts/run-uat.md +28 -11
  109. package/dist/resources/extensions/gsd/prompts/workflow-start.md +2 -2
  110. package/dist/resources/extensions/gsd/repo-identity.js +21 -4
  111. package/dist/resources/extensions/gsd/resource-version.js +2 -1
  112. package/dist/resources/extensions/gsd/roadmap-mutations.js +24 -0
  113. package/dist/resources/extensions/gsd/state.js +42 -23
  114. package/dist/resources/extensions/gsd/templates/runtime.md +21 -0
  115. package/dist/resources/extensions/gsd/templates/task-plan.md +3 -0
  116. package/dist/resources/extensions/gsd/visualizer-data.js +27 -2
  117. package/dist/resources/extensions/gsd/visualizer-views.js +52 -0
  118. package/dist/resources/extensions/gsd/worktree.js +35 -16
  119. package/dist/resources/extensions/mcp-client/index.js +14 -1
  120. package/dist/resources/extensions/remote-questions/status.js +4 -1
  121. package/dist/resources/extensions/remote-questions/store.js +4 -1
  122. package/dist/resources/extensions/search-the-web/provider.js +2 -1
  123. package/dist/resources/extensions/shared/frontmatter.js +1 -1
  124. package/dist/resources/extensions/subagent/index.js +12 -3
  125. package/dist/resources/extensions/subagent/isolation.js +2 -1
  126. package/dist/resources/extensions/ttsr/rule-loader.js +2 -1
  127. package/dist/resources/extensions/universal-config/package.json +1 -1
  128. package/dist/welcome-screen.d.ts +13 -0
  129. package/dist/welcome-screen.js +97 -0
  130. package/package.json +1 -1
  131. package/packages/pi-ai/dist/utils/oauth/anthropic.js +2 -2
  132. package/packages/pi-ai/dist/utils/oauth/anthropic.js.map +1 -1
  133. package/packages/pi-ai/src/utils/oauth/anthropic.ts +2 -2
  134. package/packages/pi-coding-agent/dist/core/agent-session.d.ts +12 -0
  135. package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
  136. package/packages/pi-coding-agent/dist/core/agent-session.js +107 -24
  137. package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
  138. package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts.map +1 -1
  139. package/packages/pi-coding-agent/dist/core/extensions/loader.js +205 -7
  140. package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
  141. package/packages/pi-coding-agent/dist/core/package-manager.d.ts.map +1 -1
  142. package/packages/pi-coding-agent/dist/core/package-manager.js +8 -4
  143. package/packages/pi-coding-agent/dist/core/package-manager.js.map +1 -1
  144. package/packages/pi-coding-agent/dist/core/skill-tool.test.d.ts +2 -0
  145. package/packages/pi-coding-agent/dist/core/skill-tool.test.d.ts.map +1 -0
  146. package/packages/pi-coding-agent/dist/core/skill-tool.test.js +70 -0
  147. package/packages/pi-coding-agent/dist/core/skill-tool.test.js.map +1 -0
  148. package/packages/pi-coding-agent/dist/core/skills.d.ts +1 -0
  149. package/packages/pi-coding-agent/dist/core/skills.d.ts.map +1 -1
  150. package/packages/pi-coding-agent/dist/core/skills.js +8 -2
  151. package/packages/pi-coding-agent/dist/core/skills.js.map +1 -1
  152. package/packages/pi-coding-agent/dist/index.d.ts +1 -1
  153. package/packages/pi-coding-agent/dist/index.d.ts.map +1 -1
  154. package/packages/pi-coding-agent/dist/index.js +1 -1
  155. package/packages/pi-coding-agent/dist/index.js.map +1 -1
  156. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts +17 -0
  157. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -0
  158. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +244 -0
  159. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -0
  160. package/packages/pi-coding-agent/dist/modes/interactive/controllers/extension-ui-controller.d.ts +3 -0
  161. package/packages/pi-coding-agent/dist/modes/interactive/controllers/extension-ui-controller.d.ts.map +1 -0
  162. package/packages/pi-coding-agent/dist/modes/interactive/controllers/extension-ui-controller.js +58 -0
  163. package/packages/pi-coding-agent/dist/modes/interactive/controllers/extension-ui-controller.js.map +1 -0
  164. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.d.ts +12 -0
  165. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.d.ts.map +1 -0
  166. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js +54 -0
  167. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js.map +1 -0
  168. package/packages/pi-coding-agent/dist/modes/interactive/controllers/model-controller.d.ts +6 -0
  169. package/packages/pi-coding-agent/dist/modes/interactive/controllers/model-controller.d.ts.map +1 -0
  170. package/packages/pi-coding-agent/dist/modes/interactive/controllers/model-controller.js +63 -0
  171. package/packages/pi-coding-agent/dist/modes/interactive/controllers/model-controller.js.map +1 -0
  172. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts +38 -0
  173. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts.map +1 -0
  174. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.js +2 -0
  175. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.js.map +1 -0
  176. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts +1 -1
  177. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  178. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +15 -457
  179. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  180. package/packages/pi-coding-agent/package.json +1 -1
  181. package/packages/pi-coding-agent/src/core/agent-session.ts +122 -23
  182. package/packages/pi-coding-agent/src/core/extensions/loader.ts +223 -7
  183. package/packages/pi-coding-agent/src/core/package-manager.ts +8 -4
  184. package/packages/pi-coding-agent/src/core/skill-tool.test.ts +89 -0
  185. package/packages/pi-coding-agent/src/core/skills.ts +11 -2
  186. package/packages/pi-coding-agent/src/index.ts +1 -0
  187. package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +302 -0
  188. package/packages/pi-coding-agent/src/modes/interactive/controllers/extension-ui-controller.ts +59 -0
  189. package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.ts +68 -0
  190. package/packages/pi-coding-agent/src/modes/interactive/controllers/model-controller.ts +71 -0
  191. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode-state.ts +37 -0
  192. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +18 -510
  193. package/pkg/package.json +1 -1
  194. package/src/resources/extensions/async-jobs/index.ts +11 -0
  195. package/src/resources/extensions/browser-tools/index.ts +3 -0
  196. package/src/resources/extensions/browser-tools/tools/verify.ts +117 -0
  197. package/src/resources/extensions/cmux/index.ts +57 -1
  198. package/src/resources/extensions/get-secrets-from-user.ts +5 -24
  199. package/src/resources/extensions/github-sync/cli.ts +364 -0
  200. package/src/resources/extensions/github-sync/index.ts +93 -0
  201. package/src/resources/extensions/github-sync/mapping.ts +81 -0
  202. package/src/resources/extensions/github-sync/sync.ts +556 -0
  203. package/src/resources/extensions/github-sync/templates.ts +183 -0
  204. package/src/resources/extensions/github-sync/tests/cli.test.ts +20 -0
  205. package/src/resources/extensions/github-sync/tests/commit-linking.test.ts +39 -0
  206. package/src/resources/extensions/github-sync/tests/mapping.test.ts +104 -0
  207. package/src/resources/extensions/github-sync/tests/templates.test.ts +110 -0
  208. package/src/resources/extensions/github-sync/types.ts +47 -0
  209. package/src/resources/extensions/gsd/auto/session.ts +7 -25
  210. package/src/resources/extensions/gsd/auto-dashboard.ts +10 -0
  211. package/src/resources/extensions/gsd/auto-dispatch.ts +7 -9
  212. package/src/resources/extensions/gsd/auto-loop.ts +1285 -1138
  213. package/src/resources/extensions/gsd/auto-post-unit.ts +90 -46
  214. package/src/resources/extensions/gsd/auto-prompts.ts +250 -53
  215. package/src/resources/extensions/gsd/auto-start.ts +24 -3
  216. package/src/resources/extensions/gsd/auto-worktree-sync.ts +15 -4
  217. package/src/resources/extensions/gsd/auto-worktree.ts +3 -3
  218. package/src/resources/extensions/gsd/auto.ts +152 -111
  219. package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +142 -0
  220. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +238 -0
  221. package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +90 -0
  222. package/src/resources/extensions/gsd/bootstrap/register-extension.ts +46 -0
  223. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +167 -0
  224. package/src/resources/extensions/gsd/bootstrap/register-shortcuts.ts +55 -0
  225. package/src/resources/extensions/gsd/bootstrap/system-context.ts +340 -0
  226. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +51 -0
  227. package/src/resources/extensions/gsd/captures.ts +10 -1
  228. package/src/resources/extensions/gsd/commands/catalog.ts +301 -0
  229. package/src/resources/extensions/gsd/commands/context.ts +101 -0
  230. package/src/resources/extensions/gsd/commands/dispatcher.ts +32 -0
  231. package/src/resources/extensions/gsd/commands/handlers/auto.ts +74 -0
  232. package/src/resources/extensions/gsd/commands/handlers/core.ts +274 -0
  233. package/src/resources/extensions/gsd/commands/handlers/ops.ts +169 -0
  234. package/src/resources/extensions/gsd/commands/handlers/parallel.ts +118 -0
  235. package/src/resources/extensions/gsd/commands/handlers/workflow.ts +109 -0
  236. package/src/resources/extensions/gsd/commands/index.ts +14 -0
  237. package/src/resources/extensions/gsd/commands-extensions.ts +4 -2
  238. package/src/resources/extensions/gsd/commands-handlers.ts +18 -3
  239. package/src/resources/extensions/gsd/commands-prefs-wizard.ts +1 -1
  240. package/src/resources/extensions/gsd/commands.ts +10 -1307
  241. package/src/resources/extensions/gsd/context-budget.ts +2 -12
  242. package/src/resources/extensions/gsd/dashboard-overlay.ts +10 -0
  243. package/src/resources/extensions/gsd/detection.ts +2 -2
  244. package/src/resources/extensions/gsd/docs/preferences-reference.md +0 -2
  245. package/src/resources/extensions/gsd/doctor-checks.ts +75 -0
  246. package/src/resources/extensions/gsd/doctor-environment.ts +82 -1
  247. package/src/resources/extensions/gsd/doctor-format.ts +20 -0
  248. package/src/resources/extensions/gsd/doctor-proactive.ts +106 -10
  249. package/src/resources/extensions/gsd/doctor-providers.ts +30 -9
  250. package/src/resources/extensions/gsd/doctor-types.ts +16 -1
  251. package/src/resources/extensions/gsd/doctor.ts +243 -14
  252. package/src/resources/extensions/gsd/env-utils.ts +31 -0
  253. package/src/resources/extensions/gsd/exit-command.ts +2 -2
  254. package/src/resources/extensions/gsd/export-html.ts +51 -0
  255. package/src/resources/extensions/gsd/export.ts +1 -1
  256. package/src/resources/extensions/gsd/files.ts +51 -11
  257. package/src/resources/extensions/gsd/forensics.ts +1 -1
  258. package/src/resources/extensions/gsd/git-service.ts +44 -10
  259. package/src/resources/extensions/gsd/gitignore.ts +17 -3
  260. package/src/resources/extensions/gsd/guided-flow.ts +177 -44
  261. package/src/resources/extensions/gsd/health-widget-core.ts +28 -80
  262. package/src/resources/extensions/gsd/health-widget.ts +4 -89
  263. package/src/resources/extensions/gsd/index.ts +12 -1307
  264. package/src/resources/extensions/gsd/migrate/parsers.ts +1 -1
  265. package/src/resources/extensions/gsd/migrate-external.ts +18 -1
  266. package/src/resources/extensions/gsd/native-git-bridge.ts +37 -0
  267. package/src/resources/extensions/gsd/paths.ts +4 -0
  268. package/src/resources/extensions/gsd/preferences-models.ts +0 -12
  269. package/src/resources/extensions/gsd/preferences-types.ts +4 -4
  270. package/src/resources/extensions/gsd/preferences-validation.ts +51 -11
  271. package/src/resources/extensions/gsd/preferences.ts +25 -11
  272. package/src/resources/extensions/gsd/progress-score.ts +23 -0
  273. package/src/resources/extensions/gsd/prompt-loader.ts +7 -2
  274. package/src/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
  275. package/src/resources/extensions/gsd/prompts/complete-slice.md +1 -1
  276. package/src/resources/extensions/gsd/prompts/discuss.md +11 -14
  277. package/src/resources/extensions/gsd/prompts/execute-task.md +5 -3
  278. package/src/resources/extensions/gsd/prompts/forensics.md +121 -46
  279. package/src/resources/extensions/gsd/prompts/guided-complete-slice.md +1 -1
  280. package/src/resources/extensions/gsd/prompts/guided-discuss-milestone.md +11 -12
  281. package/src/resources/extensions/gsd/prompts/guided-discuss-slice.md +8 -10
  282. package/src/resources/extensions/gsd/prompts/guided-execute-task.md +1 -1
  283. package/src/resources/extensions/gsd/prompts/guided-plan-milestone.md +1 -1
  284. package/src/resources/extensions/gsd/prompts/guided-plan-slice.md +1 -1
  285. package/src/resources/extensions/gsd/prompts/guided-research-slice.md +1 -1
  286. package/src/resources/extensions/gsd/prompts/guided-resume-task.md +1 -1
  287. package/src/resources/extensions/gsd/prompts/plan-milestone.md +1 -1
  288. package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  289. package/src/resources/extensions/gsd/prompts/queue.md +4 -8
  290. package/src/resources/extensions/gsd/prompts/reactive-execute.md +11 -8
  291. package/src/resources/extensions/gsd/prompts/reassess-roadmap.md +1 -1
  292. package/src/resources/extensions/gsd/prompts/research-milestone.md +1 -1
  293. package/src/resources/extensions/gsd/prompts/research-slice.md +1 -1
  294. package/src/resources/extensions/gsd/prompts/run-uat.md +28 -11
  295. package/src/resources/extensions/gsd/prompts/workflow-start.md +2 -2
  296. package/src/resources/extensions/gsd/repo-identity.ts +23 -4
  297. package/src/resources/extensions/gsd/resource-version.ts +3 -1
  298. package/src/resources/extensions/gsd/roadmap-mutations.ts +29 -0
  299. package/src/resources/extensions/gsd/state.ts +39 -21
  300. package/src/resources/extensions/gsd/templates/runtime.md +21 -0
  301. package/src/resources/extensions/gsd/templates/task-plan.md +3 -0
  302. package/src/resources/extensions/gsd/tests/agent-end-retry.test.ts +21 -18
  303. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +135 -77
  304. package/src/resources/extensions/gsd/tests/auto-worktree-milestone-merge.test.ts +4 -3
  305. package/src/resources/extensions/gsd/tests/cmux.test.ts +93 -0
  306. package/src/resources/extensions/gsd/tests/derive-state.test.ts +43 -0
  307. package/src/resources/extensions/gsd/tests/doctor-enhancements.test.ts +266 -0
  308. package/src/resources/extensions/gsd/tests/doctor-proactive.test.ts +3 -3
  309. package/src/resources/extensions/gsd/tests/doctor-providers.test.ts +86 -3
  310. package/src/resources/extensions/gsd/tests/gitignore-tracked-gsd.test.ts +50 -0
  311. package/src/resources/extensions/gsd/tests/health-widget.test.ts +16 -54
  312. package/src/resources/extensions/gsd/tests/parsers.test.ts +131 -14
  313. package/src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +209 -0
  314. package/src/resources/extensions/gsd/tests/preferences.test.ts +2 -7
  315. package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +59 -0
  316. package/src/resources/extensions/gsd/tests/provider-errors.test.ts +16 -16
  317. package/src/resources/extensions/gsd/tests/repo-identity-worktree.test.ts +21 -1
  318. package/src/resources/extensions/gsd/tests/run-uat.test.ts +16 -4
  319. package/src/resources/extensions/gsd/tests/skill-activation.test.ts +140 -0
  320. package/src/resources/extensions/gsd/tests/visualizer-data.test.ts +10 -10
  321. package/src/resources/extensions/gsd/tests/worktree.test.ts +47 -0
  322. package/src/resources/extensions/gsd/types.ts +18 -1
  323. package/src/resources/extensions/gsd/verification-evidence.ts +16 -0
  324. package/src/resources/extensions/gsd/visualizer-data.ts +52 -2
  325. package/src/resources/extensions/gsd/visualizer-views.ts +58 -0
  326. package/src/resources/extensions/gsd/worktree.ts +35 -15
  327. package/src/resources/extensions/mcp-client/index.ts +17 -1
  328. package/src/resources/extensions/remote-questions/status.ts +5 -1
  329. package/src/resources/extensions/remote-questions/store.ts +5 -1
  330. package/src/resources/extensions/search-the-web/provider.ts +2 -1
  331. package/src/resources/extensions/shared/frontmatter.ts +1 -1
  332. package/src/resources/extensions/subagent/index.ts +12 -3
  333. package/src/resources/extensions/subagent/isolation.ts +3 -1
  334. package/src/resources/extensions/ttsr/rule-loader.ts +3 -1
  335. package/dist/resources/extensions/gsd/prompt-compressor.js +0 -393
  336. package/dist/resources/extensions/gsd/semantic-chunker.js +0 -254
  337. package/dist/resources/extensions/gsd/summary-distiller.js +0 -212
  338. package/src/resources/extensions/gsd/prompt-compressor.ts +0 -508
  339. package/src/resources/extensions/gsd/semantic-chunker.ts +0 -336
  340. package/src/resources/extensions/gsd/summary-distiller.ts +0 -258
  341. package/src/resources/extensions/gsd/tests/context-compression.test.ts +0 -193
  342. package/src/resources/extensions/gsd/tests/prompt-compressor.test.ts +0 -529
  343. package/src/resources/extensions/gsd/tests/semantic-chunker.test.ts +0 -426
  344. package/src/resources/extensions/gsd/tests/summary-distiller.test.ts +0 -323
  345. package/src/resources/extensions/gsd/tests/token-optimization-benchmark.test.ts +0 -1272
  346. package/src/resources/extensions/gsd/tests/token-optimization-prefs.test.ts +0 -164
@@ -31,7 +31,7 @@ import { syncProjectRootToWorktree, checkResourcesStale, escapeStaleWorktree, }
31
31
  import { resetRoutingHistory, recordOutcome } from "./routing-history.js";
32
32
  import { resetHookState, runPreDispatchHooks, restoreHookState, clearPersistedHookState, } from "./post-unit-hooks.js";
33
33
  import { runGSDDoctor, rebuildState } from "./doctor.js";
34
- import { preDispatchHealthGate, resetProactiveHealing, } from "./doctor-proactive.js";
34
+ import { preDispatchHealthGate, resetProactiveHealing, setLevelChangeCallback, } from "./doctor-proactive.js";
35
35
  import { clearSkillSnapshot } from "./skill-discovery.js";
36
36
  import { captureAvailableSkills, resetSkillTelemetry, } from "./skill-telemetry.js";
37
37
  import { initMetrics, resetMetrics, getLedger, getProjectTotals, formatCost, formatTokenCount, } from "./metrics.js";
@@ -56,7 +56,7 @@ import { startUnitSupervision } from "./auto-timers.js";
56
56
  import { runPostUnitVerification } from "./auto-verification.js";
57
57
  import { postUnitPreVerification, postUnitPostVerification, } from "./auto-post-unit.js";
58
58
  import { bootstrapAutoSession } from "./auto-start.js";
59
- import { autoLoop, resolveAgentEnd } from "./auto-loop.js";
59
+ import { autoLoop, resolveAgentEnd, isSessionSwitchInFlight } from "./auto-loop.js";
60
60
  import { WorktreeResolver, } from "./worktree-resolver.js";
61
61
  import { reorderForCaching } from "./prompt-ordering.js";
62
62
  // Worktree sync, resource staleness, stale worktree escape → auto-worktree-sync.ts
@@ -297,116 +297,164 @@ export async function stopAuto(ctx, pi, reason) {
297
297
  return;
298
298
  const loadedPreferences = loadEffectiveGSDPreferences()?.preferences;
299
299
  const reasonSuffix = reason ? ` — ${reason}` : "";
300
- clearUnitTimeout();
301
- if (lockBase())
302
- clearLock(lockBase());
303
- if (lockBase())
304
- releaseSessionLock(lockBase());
305
- clearSkillSnapshot();
306
- resetSkillTelemetry();
307
- // Remove SIGTERM handler registered at auto-mode start
308
- deregisterSigtermHandler();
309
- // ── Auto-worktree: exit worktree and reset s.basePath on stop ──
310
- if (s.currentMilestoneId) {
311
- const notifyCtx = ctx
312
- ? { notify: ctx.ui.notify.bind(ctx.ui) }
313
- : { notify: () => { } };
314
- buildResolver().exitMilestone(s.currentMilestoneId, notifyCtx, {
315
- preserveBranch: true,
316
- });
317
- }
318
- // ── DB cleanup: close the SQLite connection ──
319
- if (isDbAvailable()) {
300
+ try {
301
+ // ── Step 1: Timers and locks ──
320
302
  try {
321
- const { closeDatabase } = await import("./gsd-db.js");
322
- closeDatabase();
303
+ clearUnitTimeout();
304
+ if (lockBase())
305
+ clearLock(lockBase());
306
+ if (lockBase())
307
+ releaseSessionLock(lockBase());
323
308
  }
324
309
  catch (e) {
325
- debugLog("db-close-failed", {
326
- error: e instanceof Error ? e.message : String(e),
327
- });
310
+ debugLog("stop-cleanup-locks", { error: e instanceof Error ? e.message : String(e) });
328
311
  }
329
- }
330
- if (s.originalBasePath) {
331
- s.basePath = s.originalBasePath;
312
+ // ── Step 2: Skill state ──
332
313
  try {
333
- process.chdir(s.basePath);
314
+ clearSkillSnapshot();
315
+ resetSkillTelemetry();
334
316
  }
335
- catch {
336
- /* best-effort */
317
+ catch (e) {
318
+ debugLog("stop-cleanup-skills", { error: e instanceof Error ? e.message : String(e) });
337
319
  }
338
- }
339
- const ledger = getLedger();
340
- if (ledger && ledger.units.length > 0) {
341
- const totals = getProjectTotals(ledger.units);
342
- ctx?.ui.notify(`Auto-mode stopped${reasonSuffix}. Session: ${formatCost(totals.cost)} · ${formatTokenCount(totals.tokens.total)} tokens · ${ledger.units.length} units`, "info");
343
- }
344
- else {
345
- ctx?.ui.notify(`Auto-mode stopped${reasonSuffix}.`, "info");
346
- }
347
- if (s.basePath) {
320
+ // ── Step 3: SIGTERM handler ──
348
321
  try {
349
- await rebuildState(s.basePath);
322
+ deregisterSigtermHandler();
350
323
  }
351
324
  catch (e) {
352
- debugLog("stop-rebuild-state-failed", {
353
- error: e instanceof Error ? e.message : String(e),
354
- });
325
+ debugLog("stop-cleanup-sigterm", { error: e instanceof Error ? e.message : String(e) });
355
326
  }
356
- }
357
- clearCmuxSidebar(loadedPreferences);
358
- logCmuxEvent(loadedPreferences, `Auto-mode stopped${reasonSuffix || ""}.`, reason?.startsWith("Blocked:") ? "warning" : "info");
359
- if (isDebugEnabled()) {
360
- const logPath = writeDebugSummary();
361
- if (logPath) {
362
- ctx?.ui.notify(`Debug log written → ${logPath}`, "info");
327
+ // ── Step 4: Auto-worktree exit ──
328
+ try {
329
+ if (s.currentMilestoneId) {
330
+ const notifyCtx = ctx
331
+ ? { notify: ctx.ui.notify.bind(ctx.ui) }
332
+ : { notify: () => { } };
333
+ buildResolver().exitMilestone(s.currentMilestoneId, notifyCtx, {
334
+ preserveBranch: true,
335
+ });
336
+ }
337
+ }
338
+ catch (e) {
339
+ debugLog("stop-cleanup-worktree", { error: e instanceof Error ? e.message : String(e) });
340
+ }
341
+ // ── Step 5: DB cleanup ──
342
+ if (isDbAvailable()) {
343
+ try {
344
+ const { closeDatabase } = await import("./gsd-db.js");
345
+ closeDatabase();
346
+ }
347
+ catch (e) {
348
+ debugLog("db-close-failed", {
349
+ error: e instanceof Error ? e.message : String(e),
350
+ });
351
+ }
352
+ }
353
+ // ── Step 6: Restore basePath and chdir ──
354
+ try {
355
+ if (s.originalBasePath) {
356
+ s.basePath = s.originalBasePath;
357
+ try {
358
+ process.chdir(s.basePath);
359
+ }
360
+ catch {
361
+ /* best-effort */
362
+ }
363
+ }
364
+ }
365
+ catch (e) {
366
+ debugLog("stop-cleanup-basepath", { error: e instanceof Error ? e.message : String(e) });
367
+ }
368
+ // ── Step 7: Ledger notification ──
369
+ try {
370
+ const ledger = getLedger();
371
+ if (ledger && ledger.units.length > 0) {
372
+ const totals = getProjectTotals(ledger.units);
373
+ ctx?.ui.notify(`Auto-mode stopped${reasonSuffix}. Session: ${formatCost(totals.cost)} · ${formatTokenCount(totals.tokens.total)} tokens · ${ledger.units.length} units`, "info");
374
+ }
375
+ else {
376
+ ctx?.ui.notify(`Auto-mode stopped${reasonSuffix}.`, "info");
377
+ }
378
+ }
379
+ catch (e) {
380
+ debugLog("stop-cleanup-ledger", { error: e instanceof Error ? e.message : String(e) });
381
+ }
382
+ // ── Step 8: Rebuild state ──
383
+ if (s.basePath) {
384
+ try {
385
+ await rebuildState(s.basePath);
386
+ }
387
+ catch (e) {
388
+ debugLog("stop-rebuild-state-failed", {
389
+ error: e instanceof Error ? e.message : String(e),
390
+ });
391
+ }
392
+ }
393
+ // ── Step 9: Cmux sidebar / event log ──
394
+ try {
395
+ clearCmuxSidebar(loadedPreferences);
396
+ logCmuxEvent(loadedPreferences, `Auto-mode stopped${reasonSuffix || ""}.`, reason?.startsWith("Blocked:") ? "warning" : "info");
397
+ }
398
+ catch (e) {
399
+ debugLog("stop-cleanup-cmux", { error: e instanceof Error ? e.message : String(e) });
400
+ }
401
+ // ── Step 10: Debug summary ──
402
+ try {
403
+ if (isDebugEnabled()) {
404
+ const logPath = writeDebugSummary();
405
+ if (logPath) {
406
+ ctx?.ui.notify(`Debug log written → ${logPath}`, "info");
407
+ }
408
+ }
409
+ }
410
+ catch (e) {
411
+ debugLog("stop-cleanup-debug", { error: e instanceof Error ? e.message : String(e) });
412
+ }
413
+ // ── Step 11: Reset metrics, routing, hooks ──
414
+ try {
415
+ resetMetrics();
416
+ resetRoutingHistory();
417
+ resetHookState();
418
+ if (s.basePath)
419
+ clearPersistedHookState(s.basePath);
420
+ }
421
+ catch (e) {
422
+ debugLog("stop-cleanup-metrics", { error: e instanceof Error ? e.message : String(e) });
423
+ }
424
+ // ── Step 12: Remove paused-session metadata (#1383) ──
425
+ try {
426
+ const pausedPath = join(gsdRoot(s.originalBasePath || s.basePath), "runtime", "paused-session.json");
427
+ if (existsSync(pausedPath))
428
+ unlinkSync(pausedPath);
429
+ }
430
+ catch { /* non-fatal */ }
431
+ // ── Step 13: Restore original model (before reset clears IDs) ──
432
+ try {
433
+ if (pi && ctx && s.originalModelId && s.originalModelProvider) {
434
+ const original = ctx.modelRegistry.find(s.originalModelProvider, s.originalModelId);
435
+ if (original)
436
+ await pi.setModel(original);
437
+ }
438
+ }
439
+ catch (e) {
440
+ debugLog("stop-cleanup-model", { error: e instanceof Error ? e.message : String(e) });
363
441
  }
364
442
  }
365
- resetMetrics();
366
- resetRoutingHistory();
367
- resetHookState();
368
- if (s.basePath)
369
- clearPersistedHookState(s.basePath);
370
- // Remove paused-session metadata if present (#1383)
371
- try {
372
- const pausedPath = join(gsdRoot(s.originalBasePath || s.basePath), "runtime", "paused-session.json");
373
- if (existsSync(pausedPath))
374
- unlinkSync(pausedPath);
375
- }
376
- catch { /* non-fatal */ }
377
- s.active = false;
378
- s.paused = false;
379
- s.stepMode = false;
380
- s.unitDispatchCount.clear();
381
- s.unitRecoveryCount.clear();
382
- clearInFlightTools();
383
- s.lastBudgetAlertLevel = 0;
384
- s.lastStateRebuildAt = 0;
385
- s.unitLifetimeDispatches.clear();
386
- s.currentUnit = null;
387
- s.autoModeStartModel = null;
388
- s.currentMilestoneId = null;
389
- s.originalBasePath = "";
390
- s.completedUnits = [];
391
- s.pendingQuickTasks = [];
392
- clearSliceProgressCache();
393
- clearActivityLogState();
394
- resetProactiveHealing();
395
- s.pendingCrashRecovery = null;
396
- s.pendingVerificationRetry = null;
397
- s.verificationRetryCount.clear();
398
- s.pausedSessionFile = null;
399
- ctx?.ui.setStatus("gsd-auto", undefined);
400
- ctx?.ui.setWidget("gsd-progress", undefined);
401
- ctx?.ui.setFooter(undefined);
402
- if (pi && ctx && s.originalModelId && s.originalModelProvider) {
403
- const original = ctx.modelRegistry.find(s.originalModelProvider, s.originalModelId);
404
- if (original)
405
- await pi.setModel(original);
406
- s.originalModelId = null;
407
- s.originalModelProvider = null;
443
+ finally {
444
+ // ── Critical invariants: these MUST execute regardless of errors ──
445
+ // External cleanup (not covered by session reset)
446
+ clearInFlightTools();
447
+ clearSliceProgressCache();
448
+ clearActivityLogState();
449
+ setLevelChangeCallback(null);
450
+ resetProactiveHealing();
451
+ // UI cleanup
452
+ ctx?.ui.setStatus("gsd-auto", undefined);
453
+ ctx?.ui.setWidget("gsd-progress", undefined);
454
+ ctx?.ui.setFooter(undefined);
455
+ // Reset all session state in one call
456
+ s.reset();
408
457
  }
409
- s.cmdCtx = null;
410
458
  }
411
459
  /**
412
460
  * Pause auto-mode without destroying state. Context is preserved.
@@ -736,6 +784,7 @@ const widgetStateAccessors = {
736
784
  getCmdCtx: () => s.cmdCtx,
737
785
  getBasePath: () => s.basePath,
738
786
  isVerbose: () => s.verbose,
787
+ isSessionSwitching: isSessionSwitchInFlight,
739
788
  };
740
789
  // ─── Preconditions ────────────────────────────────────────────────────────────
741
790
  /**
@@ -777,8 +826,6 @@ function buildRecoveryContext() {
777
826
  unitRecoveryCount: s.unitRecoveryCount,
778
827
  };
779
828
  }
780
- // Re-export recovery functions for external consumers
781
- export { resolveExpectedArtifactPath, verifyExpectedArtifact, writeBlockerPlaceholder, skipExecuteTask, buildLoopRemediationSteps, } from "./auto-recovery.js";
782
829
  /**
783
830
  * Test-only: expose skip-loop state for unit tests.
784
831
  * Not part of the public API.
@@ -871,3 +918,5 @@ export async function dispatchHookUnit(ctx, pi, hookName, triggerUnitType, trigg
871
918
  }
872
919
  // Direct phase dispatch → auto-direct-dispatch.ts
873
920
  export { dispatchDirectPhase } from "./auto-direct-dispatch.js";
921
+ // Re-export recovery functions for external consumers
922
+ export { resolveExpectedArtifactPath, verifyExpectedArtifact, writeBlockerPlaceholder, skipExecuteTask, buildLoopRemediationSteps, } from "./auto-recovery.js";
@@ -0,0 +1,126 @@
1
+ import { checkAutoStartAfterDiscuss } from "../guided-flow.js";
2
+ import { getAutoDashboardData, getAutoModeStartModel, isAutoActive, pauseAuto } from "../auto.js";
3
+ import { getNextFallbackModel, isTransientNetworkError, resolveModelWithFallbacksForUnit } from "../preferences.js";
4
+ import { classifyProviderError, pauseAutoForProviderError } from "../provider-error-pause.js";
5
+ import { isSessionSwitchInFlight, resolveAgentEnd } from "../auto-loop.js";
6
+ import { clearDiscussionFlowState } from "./write-gate.js";
7
+ const networkRetryCounters = new Map();
8
+ const MAX_TRANSIENT_AUTO_RESUMES = 3;
9
+ let consecutiveTransientErrors = 0;
10
+ export async function handleAgentEnd(pi, event, ctx) {
11
+ if (checkAutoStartAfterDiscuss()) {
12
+ clearDiscussionFlowState();
13
+ return;
14
+ }
15
+ if (!isAutoActive())
16
+ return;
17
+ if (isSessionSwitchInFlight())
18
+ return;
19
+ const lastMsg = event.messages[event.messages.length - 1];
20
+ if (lastMsg && "stopReason" in lastMsg && lastMsg.stopReason === "aborted") {
21
+ await pauseAuto(ctx, pi);
22
+ return;
23
+ }
24
+ if (lastMsg && "stopReason" in lastMsg && lastMsg.stopReason === "error") {
25
+ const errorDetail = "errorMessage" in lastMsg && lastMsg.errorMessage ? `: ${lastMsg.errorMessage}` : "";
26
+ const errorMsg = ("errorMessage" in lastMsg && lastMsg.errorMessage) ? String(lastMsg.errorMessage) : "";
27
+ if (isTransientNetworkError(errorMsg)) {
28
+ const currentModelId = ctx.model?.id ?? "unknown";
29
+ const retryKey = `network-retry:${currentModelId}`;
30
+ const currentRetries = networkRetryCounters.get(retryKey) ?? 0;
31
+ const maxRetries = 2;
32
+ if (currentRetries < maxRetries) {
33
+ networkRetryCounters.set(retryKey, currentRetries + 1);
34
+ const attempt = currentRetries + 1;
35
+ const delayMs = attempt * 3000;
36
+ ctx.ui.notify(`Network error on ${currentModelId}${errorDetail}. Retry ${attempt}/${maxRetries} in ${delayMs / 1000}s...`, "warning");
37
+ setTimeout(() => {
38
+ pi.sendMessage({ customType: "gsd-auto-timeout-recovery", content: "Continue execution — retrying after transient network error.", display: false }, { triggerTurn: true });
39
+ }, delayMs);
40
+ return;
41
+ }
42
+ networkRetryCounters.delete(retryKey);
43
+ ctx.ui.notify(`Network retries exhausted for ${currentModelId}. Attempting model fallback.`, "warning");
44
+ }
45
+ const dash = getAutoDashboardData();
46
+ if (dash.currentUnit) {
47
+ const modelConfig = resolveModelWithFallbacksForUnit(dash.currentUnit.type);
48
+ if (modelConfig && modelConfig.fallbacks.length > 0) {
49
+ const availableModels = ctx.modelRegistry.getAvailable();
50
+ const nextModelId = getNextFallbackModel(ctx.model?.id, modelConfig);
51
+ if (nextModelId) {
52
+ networkRetryCounters.clear();
53
+ const slashIdx = nextModelId.indexOf("/");
54
+ const modelToSet = slashIdx !== -1
55
+ ? availableModels.find((m) => m.provider.toLowerCase() === nextModelId.substring(0, slashIdx).toLowerCase() && m.id.toLowerCase() === nextModelId.substring(slashIdx + 1).toLowerCase())
56
+ : (availableModels.find((m) => m.id === nextModelId && m.provider === ctx.model?.provider) ?? availableModels.find((m) => m.id === nextModelId));
57
+ if (modelToSet) {
58
+ const ok = await pi.setModel(modelToSet, { persist: false });
59
+ if (ok) {
60
+ ctx.ui.notify(`Model error${errorDetail}. Switched to fallback: ${nextModelId} and resuming.`, "warning");
61
+ pi.sendMessage({ customType: "gsd-auto-timeout-recovery", content: "Continue execution.", display: false }, { triggerTurn: true });
62
+ return;
63
+ }
64
+ }
65
+ }
66
+ }
67
+ }
68
+ const sessionModel = getAutoModeStartModel();
69
+ if (sessionModel) {
70
+ if (ctx.model?.id !== sessionModel.id || ctx.model?.provider !== sessionModel.provider) {
71
+ const startModel = ctx.modelRegistry.getAvailable().find((m) => m.provider === sessionModel.provider && m.id === sessionModel.id);
72
+ if (startModel) {
73
+ const ok = await pi.setModel(startModel, { persist: false });
74
+ if (ok) {
75
+ networkRetryCounters.clear();
76
+ ctx.ui.notify(`Model error${errorDetail}. Restored session model: ${sessionModel.provider}/${sessionModel.id} and resuming.`, "warning");
77
+ pi.sendMessage({ customType: "gsd-auto-timeout-recovery", content: "Continue execution.", display: false }, { triggerTurn: true });
78
+ return;
79
+ }
80
+ }
81
+ }
82
+ }
83
+ const classification = classifyProviderError(errorMsg);
84
+ const explicitRetryAfterMs = ("retryAfterMs" in lastMsg && typeof lastMsg.retryAfterMs === "number") ? lastMsg.retryAfterMs : undefined;
85
+ if (classification.isTransient) {
86
+ consecutiveTransientErrors += 1;
87
+ }
88
+ else {
89
+ consecutiveTransientErrors = 0;
90
+ }
91
+ const baseRetryAfterMs = explicitRetryAfterMs ?? classification.suggestedDelayMs;
92
+ const retryAfterMs = classification.isTransient
93
+ ? baseRetryAfterMs * 2 ** Math.max(0, consecutiveTransientErrors - 1)
94
+ : baseRetryAfterMs;
95
+ const allowAutoResume = classification.isTransient && consecutiveTransientErrors <= MAX_TRANSIENT_AUTO_RESUMES;
96
+ if (classification.isTransient && !allowAutoResume) {
97
+ ctx.ui.notify(`Transient provider errors persisted after ${MAX_TRANSIENT_AUTO_RESUMES} auto-resume attempts. Pausing for manual review.`, "warning");
98
+ }
99
+ await pauseAutoForProviderError(ctx.ui, errorDetail, () => pauseAuto(ctx, pi), {
100
+ isRateLimit: classification.isRateLimit,
101
+ isTransient: allowAutoResume,
102
+ retryAfterMs,
103
+ resume: allowAutoResume
104
+ ? () => {
105
+ pi.sendMessage({ customType: "gsd-auto-timeout-recovery", content: "Continue execution — provider error recovery delay elapsed.", display: false }, { triggerTurn: true });
106
+ }
107
+ : undefined,
108
+ });
109
+ return;
110
+ }
111
+ try {
112
+ consecutiveTransientErrors = 0;
113
+ networkRetryCounters.clear();
114
+ resolveAgentEnd(event);
115
+ }
116
+ catch (err) {
117
+ const message = err instanceof Error ? err.message : String(err);
118
+ ctx.ui.notify(`Auto-mode error in agent_end handler: ${message}. Stopping auto-mode.`, "error");
119
+ try {
120
+ await pauseAuto(ctx, pi);
121
+ }
122
+ catch {
123
+ // best-effort
124
+ }
125
+ }
126
+ }
@@ -0,0 +1,233 @@
1
+ import { Type } from "@sinclair/typebox";
2
+ import { findMilestoneIds, nextMilestoneId } from "../guided-flow.js";
3
+ import { loadEffectiveGSDPreferences } from "../preferences.js";
4
+ import { ensureDbOpen } from "./dynamic-tools.js";
5
+ export function registerDbTools(pi) {
6
+ pi.registerTool({
7
+ name: "gsd_save_decision",
8
+ label: "Save Decision",
9
+ description: "Record a project decision to the GSD database and regenerate DECISIONS.md. " +
10
+ "Decision IDs are auto-assigned — never provide an ID manually.",
11
+ promptSnippet: "Record a project decision to the GSD database (auto-assigns ID, regenerates DECISIONS.md)",
12
+ promptGuidelines: [
13
+ "Use gsd_save_decision when recording an architectural, pattern, library, or observability decision.",
14
+ "Decision IDs are auto-assigned (D001, D002, ...) — never guess or provide an ID.",
15
+ "All fields except revisable and when_context are required.",
16
+ "The tool writes to the DB and regenerates .gsd/DECISIONS.md automatically.",
17
+ ],
18
+ parameters: Type.Object({
19
+ scope: Type.String({ description: "Scope of the decision (e.g. 'architecture', 'library', 'observability')" }),
20
+ decision: Type.String({ description: "What is being decided" }),
21
+ choice: Type.String({ description: "The choice made" }),
22
+ rationale: Type.String({ description: "Why this choice was made" }),
23
+ revisable: Type.Optional(Type.String({ description: "Whether this can be revisited (default: 'Yes')" })),
24
+ when_context: Type.Optional(Type.String({ description: "When/context for the decision (e.g. milestone ID)" })),
25
+ }),
26
+ async execute(_toolCallId, params, _signal, _onUpdate, _ctx) {
27
+ const dbAvailable = await ensureDbOpen();
28
+ if (!dbAvailable) {
29
+ return {
30
+ content: [{ type: "text", text: "Error: GSD database is not available. Cannot save decision." }],
31
+ details: { operation: "save_decision", error: "db_unavailable" },
32
+ };
33
+ }
34
+ try {
35
+ const { saveDecisionToDb } = await import("../db-writer.js");
36
+ const { id } = await saveDecisionToDb({
37
+ scope: params.scope,
38
+ decision: params.decision,
39
+ choice: params.choice,
40
+ rationale: params.rationale,
41
+ revisable: params.revisable,
42
+ when_context: params.when_context,
43
+ }, process.cwd());
44
+ return {
45
+ content: [{ type: "text", text: `Saved decision ${id}` }],
46
+ details: { operation: "save_decision", id },
47
+ };
48
+ }
49
+ catch (err) {
50
+ const msg = err instanceof Error ? err.message : String(err);
51
+ process.stderr.write(`gsd-db: gsd_save_decision tool failed: ${msg}\n`);
52
+ return {
53
+ content: [{ type: "text", text: `Error saving decision: ${msg}` }],
54
+ details: { operation: "save_decision", error: msg },
55
+ };
56
+ }
57
+ },
58
+ });
59
+ pi.registerTool({
60
+ name: "gsd_update_requirement",
61
+ label: "Update Requirement",
62
+ description: "Update an existing requirement in the GSD database and regenerate REQUIREMENTS.md. " +
63
+ "Provide the requirement ID (e.g. R001) and any fields to update.",
64
+ promptSnippet: "Update an existing GSD requirement by ID (regenerates REQUIREMENTS.md)",
65
+ promptGuidelines: [
66
+ "Use gsd_update_requirement to change status, validation, notes, or other fields on an existing requirement.",
67
+ "The id parameter is required — it must be an existing RXXX identifier.",
68
+ "All other fields are optional — only provided fields are updated.",
69
+ "The tool verifies the requirement exists before updating.",
70
+ ],
71
+ parameters: Type.Object({
72
+ id: Type.String({ description: "The requirement ID (e.g. R001, R014)" }),
73
+ status: Type.Optional(Type.String({ description: "New status (e.g. 'active', 'validated', 'deferred')" })),
74
+ validation: Type.Optional(Type.String({ description: "Validation criteria or proof" })),
75
+ notes: Type.Optional(Type.String({ description: "Additional notes" })),
76
+ description: Type.Optional(Type.String({ description: "Updated description" })),
77
+ primary_owner: Type.Optional(Type.String({ description: "Primary owning slice" })),
78
+ supporting_slices: Type.Optional(Type.String({ description: "Supporting slices" })),
79
+ }),
80
+ async execute(_toolCallId, params, _signal, _onUpdate, _ctx) {
81
+ const dbAvailable = await ensureDbOpen();
82
+ if (!dbAvailable) {
83
+ return {
84
+ content: [{ type: "text", text: "Error: GSD database is not available. Cannot update requirement." }],
85
+ details: { operation: "update_requirement", id: params.id, error: "db_unavailable" },
86
+ };
87
+ }
88
+ try {
89
+ const db = await import("../gsd-db.js");
90
+ const existing = db.getRequirementById(params.id);
91
+ if (!existing) {
92
+ return {
93
+ content: [{ type: "text", text: `Error: Requirement ${params.id} not found.` }],
94
+ details: { operation: "update_requirement", id: params.id, error: "not_found" },
95
+ };
96
+ }
97
+ const { updateRequirementInDb } = await import("../db-writer.js");
98
+ const updates = {};
99
+ if (params.status !== undefined)
100
+ updates.status = params.status;
101
+ if (params.validation !== undefined)
102
+ updates.validation = params.validation;
103
+ if (params.notes !== undefined)
104
+ updates.notes = params.notes;
105
+ if (params.description !== undefined)
106
+ updates.description = params.description;
107
+ if (params.primary_owner !== undefined)
108
+ updates.primary_owner = params.primary_owner;
109
+ if (params.supporting_slices !== undefined)
110
+ updates.supporting_slices = params.supporting_slices;
111
+ await updateRequirementInDb(params.id, updates, process.cwd());
112
+ return {
113
+ content: [{ type: "text", text: `Updated requirement ${params.id}` }],
114
+ details: { operation: "update_requirement", id: params.id },
115
+ };
116
+ }
117
+ catch (err) {
118
+ const msg = err instanceof Error ? err.message : String(err);
119
+ process.stderr.write(`gsd-db: gsd_update_requirement tool failed: ${msg}\n`);
120
+ return {
121
+ content: [{ type: "text", text: `Error updating requirement: ${msg}` }],
122
+ details: { operation: "update_requirement", id: params.id, error: msg },
123
+ };
124
+ }
125
+ },
126
+ });
127
+ pi.registerTool({
128
+ name: "gsd_save_summary",
129
+ label: "Save Summary",
130
+ description: "Save a summary, research, context, or assessment artifact to the GSD database and write it to disk. " +
131
+ "Computes the file path from milestone/slice/task IDs automatically.",
132
+ promptSnippet: "Save a GSD artifact (summary/research/context/assessment) to DB and disk",
133
+ promptGuidelines: [
134
+ "Use gsd_save_summary to persist structured artifacts (SUMMARY, RESEARCH, CONTEXT, ASSESSMENT).",
135
+ "milestone_id is required. slice_id and task_id are optional — they determine the file path.",
136
+ "The tool computes the relative path automatically: milestones/M001/M001-SUMMARY.md, milestones/M001/slices/S01/S01-SUMMARY.md, etc.",
137
+ "artifact_type must be one of: SUMMARY, RESEARCH, CONTEXT, ASSESSMENT.",
138
+ ],
139
+ parameters: Type.Object({
140
+ milestone_id: Type.String({ description: "Milestone ID (e.g. M001)" }),
141
+ slice_id: Type.Optional(Type.String({ description: "Slice ID (e.g. S01)" })),
142
+ task_id: Type.Optional(Type.String({ description: "Task ID (e.g. T01)" })),
143
+ artifact_type: Type.String({ description: "One of: SUMMARY, RESEARCH, CONTEXT, ASSESSMENT" }),
144
+ content: Type.String({ description: "The full markdown content of the artifact" }),
145
+ }),
146
+ async execute(_toolCallId, params, _signal, _onUpdate, _ctx) {
147
+ const dbAvailable = await ensureDbOpen();
148
+ if (!dbAvailable) {
149
+ return {
150
+ content: [{ type: "text", text: "Error: GSD database is not available. Cannot save artifact." }],
151
+ details: { operation: "save_summary", error: "db_unavailable" },
152
+ };
153
+ }
154
+ const validTypes = ["SUMMARY", "RESEARCH", "CONTEXT", "ASSESSMENT"];
155
+ if (!validTypes.includes(params.artifact_type)) {
156
+ return {
157
+ content: [{ type: "text", text: `Error: Invalid artifact_type "${params.artifact_type}". Must be one of: ${validTypes.join(", ")}` }],
158
+ details: { operation: "save_summary", error: "invalid_artifact_type" },
159
+ };
160
+ }
161
+ try {
162
+ let relativePath;
163
+ if (params.task_id && params.slice_id) {
164
+ relativePath = `milestones/${params.milestone_id}/slices/${params.slice_id}/tasks/${params.task_id}-${params.artifact_type}.md`;
165
+ }
166
+ else if (params.slice_id) {
167
+ relativePath = `milestones/${params.milestone_id}/slices/${params.slice_id}/${params.slice_id}-${params.artifact_type}.md`;
168
+ }
169
+ else {
170
+ relativePath = `milestones/${params.milestone_id}/${params.milestone_id}-${params.artifact_type}.md`;
171
+ }
172
+ const { saveArtifactToDb } = await import("../db-writer.js");
173
+ await saveArtifactToDb({
174
+ path: relativePath,
175
+ artifact_type: params.artifact_type,
176
+ content: params.content,
177
+ milestone_id: params.milestone_id,
178
+ slice_id: params.slice_id,
179
+ task_id: params.task_id,
180
+ }, process.cwd());
181
+ return {
182
+ content: [{ type: "text", text: `Saved ${params.artifact_type} artifact to ${relativePath}` }],
183
+ details: { operation: "save_summary", path: relativePath, artifact_type: params.artifact_type },
184
+ };
185
+ }
186
+ catch (err) {
187
+ const msg = err instanceof Error ? err.message : String(err);
188
+ process.stderr.write(`gsd-db: gsd_save_summary tool failed: ${msg}\n`);
189
+ return {
190
+ content: [{ type: "text", text: `Error saving artifact: ${msg}` }],
191
+ details: { operation: "save_summary", error: msg },
192
+ };
193
+ }
194
+ },
195
+ });
196
+ const reservedMilestoneIds = new Set();
197
+ pi.registerTool({
198
+ name: "gsd_generate_milestone_id",
199
+ label: "Generate Milestone ID",
200
+ description: "Generate the next milestone ID for a new GSD milestone. " +
201
+ "Scans existing milestones on disk and respects the unique_milestone_ids preference. " +
202
+ "Always use this tool when creating a new milestone — never invent milestone IDs manually.",
203
+ promptSnippet: "Generate a valid milestone ID (respects unique_milestone_ids preference)",
204
+ promptGuidelines: [
205
+ "ALWAYS call gsd_generate_milestone_id before creating a new milestone directory or writing milestone files.",
206
+ "Never invent or hardcode milestone IDs like M001, M002 — always use this tool.",
207
+ "Call it once per milestone you need to create. For multi-milestone projects, call it once for each milestone in sequence.",
208
+ "The tool returns the correct format based on project preferences (e.g. M001 or M001-r5jzab).",
209
+ ],
210
+ parameters: Type.Object({}),
211
+ async execute(_toolCallId, _params, _signal, _onUpdate, _ctx) {
212
+ try {
213
+ const basePath = process.cwd();
214
+ const existingIds = findMilestoneIds(basePath);
215
+ const uniqueEnabled = !!loadEffectiveGSDPreferences()?.preferences?.unique_milestone_ids;
216
+ const allIds = [...new Set([...existingIds, ...reservedMilestoneIds])];
217
+ const newId = nextMilestoneId(allIds, uniqueEnabled);
218
+ reservedMilestoneIds.add(newId);
219
+ return {
220
+ content: [{ type: "text", text: newId }],
221
+ details: { operation: "generate_milestone_id", id: newId, existingCount: existingIds.length, reservedCount: reservedMilestoneIds.size, uniqueEnabled },
222
+ };
223
+ }
224
+ catch (err) {
225
+ const msg = err instanceof Error ? err.message : String(err);
226
+ return {
227
+ content: [{ type: "text", text: `Error generating milestone ID: ${msg}` }],
228
+ details: { operation: "generate_milestone_id", error: msg },
229
+ };
230
+ }
231
+ },
232
+ });
233
+ }