gsd-pi 2.59.0 → 2.60.0-dev.2580e65

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 (354) hide show
  1. package/dist/resources/extensions/ask-user-questions.js +7 -4
  2. package/dist/resources/extensions/gsd/auto/phases.js +62 -1
  3. package/dist/resources/extensions/gsd/auto-dashboard.js +21 -8
  4. package/dist/resources/extensions/gsd/auto-dispatch.js +6 -3
  5. package/dist/resources/extensions/gsd/auto-model-selection.js +57 -3
  6. package/dist/resources/extensions/gsd/auto-post-unit.js +43 -3
  7. package/dist/resources/extensions/gsd/auto-prompts.js +49 -20
  8. package/dist/resources/extensions/gsd/auto-recovery.js +37 -18
  9. package/dist/resources/extensions/gsd/auto-start.js +9 -5
  10. package/dist/resources/extensions/gsd/auto-timers.js +11 -5
  11. package/dist/resources/extensions/gsd/auto-unit-closeout.js +5 -3
  12. package/dist/resources/extensions/gsd/auto-verification.js +3 -2
  13. package/dist/resources/extensions/gsd/auto-worktree.js +120 -55
  14. package/dist/resources/extensions/gsd/auto.js +39 -17
  15. package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +6 -3
  16. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +72 -2
  17. package/dist/resources/extensions/gsd/bootstrap/dynamic-tools.js +4 -10
  18. package/dist/resources/extensions/gsd/bootstrap/journal-tools.js +2 -1
  19. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +58 -5
  20. package/dist/resources/extensions/gsd/bootstrap/system-context.js +11 -10
  21. package/dist/resources/extensions/gsd/captures.js +54 -1
  22. package/dist/resources/extensions/gsd/commands/catalog.js +2 -0
  23. package/dist/resources/extensions/gsd/commands-codebase.js +48 -21
  24. package/dist/resources/extensions/gsd/commands-inspect.js +2 -1
  25. package/dist/resources/extensions/gsd/commands-maintenance.js +32 -19
  26. package/dist/resources/extensions/gsd/complexity-classifier.js +9 -5
  27. package/dist/resources/extensions/gsd/context-masker.js +68 -0
  28. package/dist/resources/extensions/gsd/custom-verification.js +3 -2
  29. package/dist/resources/extensions/gsd/docs/preferences-reference.md +7 -0
  30. package/dist/resources/extensions/gsd/gsd-db.js +35 -15
  31. package/dist/resources/extensions/gsd/guided-flow.js +19 -9
  32. package/dist/resources/extensions/gsd/init-wizard.js +12 -0
  33. package/dist/resources/extensions/gsd/markdown-renderer.js +11 -9
  34. package/dist/resources/extensions/gsd/md-importer.js +5 -4
  35. package/dist/resources/extensions/gsd/milestone-actions.js +3 -2
  36. package/dist/resources/extensions/gsd/milestone-ids.js +2 -1
  37. package/dist/resources/extensions/gsd/model-router.js +199 -45
  38. package/dist/resources/extensions/gsd/parallel-merge.js +5 -3
  39. package/dist/resources/extensions/gsd/parallel-orchestrator.js +26 -14
  40. package/dist/resources/extensions/gsd/phase-anchor.js +56 -0
  41. package/dist/resources/extensions/gsd/preferences-types.js +2 -0
  42. package/dist/resources/extensions/gsd/preferences-validation.js +91 -0
  43. package/dist/resources/extensions/gsd/preferences.js +15 -3
  44. package/dist/resources/extensions/gsd/prompt-loader.js +3 -2
  45. package/dist/resources/extensions/gsd/prompts/execute-task.md +2 -0
  46. package/dist/resources/extensions/gsd/prompts/rethink.md +7 -0
  47. package/dist/resources/extensions/gsd/prompts/triage-captures.md +6 -1
  48. package/dist/resources/extensions/gsd/rethink.js +5 -2
  49. package/dist/resources/extensions/gsd/rule-registry.js +7 -6
  50. package/dist/resources/extensions/gsd/safe-fs.js +6 -8
  51. package/dist/resources/extensions/gsd/state.js +1 -1
  52. package/dist/resources/extensions/gsd/status-guards.js +4 -3
  53. package/dist/resources/extensions/gsd/tools/complete-milestone.js +3 -2
  54. package/dist/resources/extensions/gsd/tools/complete-slice.js +3 -2
  55. package/dist/resources/extensions/gsd/tools/complete-task.js +3 -2
  56. package/dist/resources/extensions/gsd/tools/plan-milestone.js +3 -2
  57. package/dist/resources/extensions/gsd/tools/plan-slice.js +3 -2
  58. package/dist/resources/extensions/gsd/tools/plan-task.js +2 -1
  59. package/dist/resources/extensions/gsd/tools/reassess-roadmap.js +4 -4
  60. package/dist/resources/extensions/gsd/tools/reopen-slice.js +2 -1
  61. package/dist/resources/extensions/gsd/tools/reopen-task.js +2 -1
  62. package/dist/resources/extensions/gsd/tools/replan-slice.js +2 -1
  63. package/dist/resources/extensions/gsd/tools/validate-milestone.js +2 -1
  64. package/dist/resources/extensions/gsd/triage-resolution.js +135 -1
  65. package/dist/resources/extensions/gsd/triage-ui.js +12 -3
  66. package/dist/resources/extensions/gsd/workflow-events.js +2 -1
  67. package/dist/resources/extensions/gsd/workflow-logger.js +37 -4
  68. package/dist/resources/extensions/gsd/workflow-migration.js +14 -12
  69. package/dist/resources/extensions/gsd/workflow-projections.js +2 -2
  70. package/dist/resources/extensions/gsd/workflow-reconcile.js +2 -2
  71. package/dist/resources/extensions/gsd/worktree-manager.js +26 -14
  72. package/dist/resources/extensions/shared/interview-ui.js +3 -1
  73. package/dist/resources/skills/btw/SKILL.md +42 -0
  74. package/dist/web/standalone/.next/BUILD_ID +1 -1
  75. package/dist/web/standalone/.next/app-path-routes-manifest.json +17 -17
  76. package/dist/web/standalone/.next/build-manifest.json +3 -3
  77. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  78. package/dist/web/standalone/.next/required-server-files.json +3 -3
  79. package/dist/web/standalone/.next/server/app/_global-error/page.js +3 -3
  80. package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  81. package/dist/web/standalone/.next/server/app/_global-error.html +2 -2
  82. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  83. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  84. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  85. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  86. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  87. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  88. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  89. package/dist/web/standalone/.next/server/app/_not-found/page.js +2 -2
  90. package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  91. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  92. package/dist/web/standalone/.next/server/app/_not-found.rsc +3 -3
  93. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +3 -3
  94. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  95. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +3 -3
  96. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  97. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  98. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  99. package/dist/web/standalone/.next/server/app/api/boot/route.js +1 -1
  100. package/dist/web/standalone/.next/server/app/api/boot/route_client-reference-manifest.js +1 -1
  101. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js +1 -1
  102. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route_client-reference-manifest.js +1 -1
  103. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js +1 -1
  104. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route_client-reference-manifest.js +1 -1
  105. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js +2 -2
  106. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route_client-reference-manifest.js +1 -1
  107. package/dist/web/standalone/.next/server/app/api/browse-directories/route.js +1 -1
  108. package/dist/web/standalone/.next/server/app/api/browse-directories/route_client-reference-manifest.js +1 -1
  109. package/dist/web/standalone/.next/server/app/api/captures/route.js +1 -1
  110. package/dist/web/standalone/.next/server/app/api/captures/route_client-reference-manifest.js +1 -1
  111. package/dist/web/standalone/.next/server/app/api/cleanup/route.js +1 -1
  112. package/dist/web/standalone/.next/server/app/api/cleanup/route_client-reference-manifest.js +1 -1
  113. package/dist/web/standalone/.next/server/app/api/dev-mode/route.js +1 -1
  114. package/dist/web/standalone/.next/server/app/api/dev-mode/route_client-reference-manifest.js +1 -1
  115. package/dist/web/standalone/.next/server/app/api/doctor/route.js +1 -1
  116. package/dist/web/standalone/.next/server/app/api/doctor/route_client-reference-manifest.js +1 -1
  117. package/dist/web/standalone/.next/server/app/api/experimental/route.js +2 -2
  118. package/dist/web/standalone/.next/server/app/api/experimental/route_client-reference-manifest.js +1 -1
  119. package/dist/web/standalone/.next/server/app/api/export-data/route.js +1 -1
  120. package/dist/web/standalone/.next/server/app/api/export-data/route_client-reference-manifest.js +1 -1
  121. package/dist/web/standalone/.next/server/app/api/files/route.js +1 -1
  122. package/dist/web/standalone/.next/server/app/api/files/route_client-reference-manifest.js +1 -1
  123. package/dist/web/standalone/.next/server/app/api/forensics/route.js +1 -1
  124. package/dist/web/standalone/.next/server/app/api/forensics/route_client-reference-manifest.js +1 -1
  125. package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
  126. package/dist/web/standalone/.next/server/app/api/git/route_client-reference-manifest.js +1 -1
  127. package/dist/web/standalone/.next/server/app/api/history/route.js +1 -1
  128. package/dist/web/standalone/.next/server/app/api/history/route_client-reference-manifest.js +1 -1
  129. package/dist/web/standalone/.next/server/app/api/hooks/route.js +1 -1
  130. package/dist/web/standalone/.next/server/app/api/hooks/route_client-reference-manifest.js +1 -1
  131. package/dist/web/standalone/.next/server/app/api/inspect/route.js +1 -1
  132. package/dist/web/standalone/.next/server/app/api/inspect/route_client-reference-manifest.js +1 -1
  133. package/dist/web/standalone/.next/server/app/api/knowledge/route.js +1 -1
  134. package/dist/web/standalone/.next/server/app/api/knowledge/route_client-reference-manifest.js +1 -1
  135. package/dist/web/standalone/.next/server/app/api/live-state/route.js +1 -1
  136. package/dist/web/standalone/.next/server/app/api/live-state/route_client-reference-manifest.js +1 -1
  137. package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
  138. package/dist/web/standalone/.next/server/app/api/onboarding/route_client-reference-manifest.js +1 -1
  139. package/dist/web/standalone/.next/server/app/api/preferences/route.js +1 -1
  140. package/dist/web/standalone/.next/server/app/api/preferences/route_client-reference-manifest.js +1 -1
  141. package/dist/web/standalone/.next/server/app/api/projects/route.js +1 -1
  142. package/dist/web/standalone/.next/server/app/api/projects/route_client-reference-manifest.js +1 -1
  143. package/dist/web/standalone/.next/server/app/api/recovery/route.js +1 -1
  144. package/dist/web/standalone/.next/server/app/api/recovery/route_client-reference-manifest.js +1 -1
  145. package/dist/web/standalone/.next/server/app/api/remote-questions/route.js +2 -2
  146. package/dist/web/standalone/.next/server/app/api/remote-questions/route_client-reference-manifest.js +1 -1
  147. package/dist/web/standalone/.next/server/app/api/session/browser/route.js +1 -1
  148. package/dist/web/standalone/.next/server/app/api/session/browser/route_client-reference-manifest.js +1 -1
  149. package/dist/web/standalone/.next/server/app/api/session/command/route.js +1 -1
  150. package/dist/web/standalone/.next/server/app/api/session/command/route_client-reference-manifest.js +1 -1
  151. package/dist/web/standalone/.next/server/app/api/session/events/route.js +2 -2
  152. package/dist/web/standalone/.next/server/app/api/session/events/route_client-reference-manifest.js +1 -1
  153. package/dist/web/standalone/.next/server/app/api/session/manage/route.js +1 -1
  154. package/dist/web/standalone/.next/server/app/api/session/manage/route_client-reference-manifest.js +1 -1
  155. package/dist/web/standalone/.next/server/app/api/settings-data/route.js +1 -1
  156. package/dist/web/standalone/.next/server/app/api/settings-data/route_client-reference-manifest.js +1 -1
  157. package/dist/web/standalone/.next/server/app/api/shutdown/route.js +1 -1
  158. package/dist/web/standalone/.next/server/app/api/shutdown/route_client-reference-manifest.js +1 -1
  159. package/dist/web/standalone/.next/server/app/api/skill-health/route.js +1 -1
  160. package/dist/web/standalone/.next/server/app/api/skill-health/route_client-reference-manifest.js +1 -1
  161. package/dist/web/standalone/.next/server/app/api/steer/route.js +1 -1
  162. package/dist/web/standalone/.next/server/app/api/steer/route_client-reference-manifest.js +1 -1
  163. package/dist/web/standalone/.next/server/app/api/switch-root/route.js +1 -1
  164. package/dist/web/standalone/.next/server/app/api/switch-root/route_client-reference-manifest.js +1 -1
  165. package/dist/web/standalone/.next/server/app/api/terminal/input/route.js +2 -2
  166. package/dist/web/standalone/.next/server/app/api/terminal/input/route_client-reference-manifest.js +1 -1
  167. package/dist/web/standalone/.next/server/app/api/terminal/resize/route.js +2 -2
  168. package/dist/web/standalone/.next/server/app/api/terminal/resize/route_client-reference-manifest.js +1 -1
  169. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js +2 -2
  170. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route_client-reference-manifest.js +1 -1
  171. package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js +4 -4
  172. package/dist/web/standalone/.next/server/app/api/terminal/stream/route_client-reference-manifest.js +1 -1
  173. package/dist/web/standalone/.next/server/app/api/terminal/upload/route.js +1 -1
  174. package/dist/web/standalone/.next/server/app/api/terminal/upload/route_client-reference-manifest.js +1 -1
  175. package/dist/web/standalone/.next/server/app/api/undo/route.js +1 -1
  176. package/dist/web/standalone/.next/server/app/api/undo/route_client-reference-manifest.js +1 -1
  177. package/dist/web/standalone/.next/server/app/api/update/route.js +1 -1
  178. package/dist/web/standalone/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
  179. package/dist/web/standalone/.next/server/app/api/visualizer/route.js +1 -1
  180. package/dist/web/standalone/.next/server/app/api/visualizer/route_client-reference-manifest.js +1 -1
  181. package/dist/web/standalone/.next/server/app/index.html +1 -1
  182. package/dist/web/standalone/.next/server/app/index.rsc +4 -4
  183. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  184. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +4 -4
  185. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  186. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +3 -3
  187. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  188. package/dist/web/standalone/.next/server/app/page.js +2 -2
  189. package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  190. package/dist/web/standalone/.next/server/app-paths-manifest.json +17 -17
  191. package/dist/web/standalone/.next/server/chunks/2229.js +1 -1
  192. package/dist/web/standalone/.next/server/chunks/7471.js +3 -3
  193. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  194. package/dist/web/standalone/.next/server/middleware.js +2 -2
  195. package/dist/web/standalone/.next/server/next-font-manifest.js +1 -1
  196. package/dist/web/standalone/.next/server/next-font-manifest.json +1 -1
  197. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  198. package/dist/web/standalone/.next/server/pages/500.html +2 -2
  199. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  200. package/dist/web/standalone/.next/static/chunks/app/_not-found/{page-2f24283c162b6ab3.js → page-f2a7482d42a5614b.js} +1 -1
  201. package/dist/web/standalone/.next/static/chunks/app/{layout-9ecfd95f343793f0.js → layout-a16c7a7ecdf0c2cf.js} +1 -1
  202. package/dist/web/standalone/.next/static/chunks/app/page-0c485498795110d6.js +1 -0
  203. package/dist/web/standalone/.next/static/chunks/main-app-fdab67f7802d7832.js +1 -0
  204. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-459824ffb8c323dd.js +1 -0
  205. package/dist/web/standalone/node_modules/node-pty/build/Makefile +2 -2
  206. package/dist/web/standalone/node_modules/node-pty/build/Release/pty.node +0 -0
  207. package/dist/web/standalone/node_modules/node-pty/build/pty.target.mk +14 -14
  208. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api.target.mk +14 -14
  209. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_except.target.mk +14 -14
  210. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_maybe.target.mk +14 -14
  211. package/dist/web/standalone/server.js +1 -1
  212. package/package.json +1 -1
  213. package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts.map +1 -1
  214. package/packages/pi-coding-agent/dist/core/extensions/loader.js +5 -0
  215. package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
  216. package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts +2 -1
  217. package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts.map +1 -1
  218. package/packages/pi-coding-agent/dist/core/extensions/runner.js +16 -0
  219. package/packages/pi-coding-agent/dist/core/extensions/runner.js.map +1 -1
  220. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts +26 -0
  221. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts.map +1 -1
  222. package/packages/pi-coding-agent/dist/core/extensions/types.js.map +1 -1
  223. package/packages/pi-coding-agent/dist/core/lsp/config.d.ts.map +1 -1
  224. package/packages/pi-coding-agent/dist/core/lsp/config.js +6 -1
  225. package/packages/pi-coding-agent/dist/core/lsp/config.js.map +1 -1
  226. package/packages/pi-coding-agent/dist/core/lsp/defaults.json +2 -2
  227. package/packages/pi-coding-agent/dist/core/lsp/lsp-legacy-alias.test.d.ts +2 -0
  228. package/packages/pi-coding-agent/dist/core/lsp/lsp-legacy-alias.test.d.ts.map +1 -0
  229. package/packages/pi-coding-agent/dist/core/lsp/lsp-legacy-alias.test.js +47 -0
  230. package/packages/pi-coding-agent/dist/core/lsp/lsp-legacy-alias.test.js.map +1 -0
  231. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.d.ts +1 -0
  232. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.d.ts.map +1 -1
  233. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js +6 -0
  234. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js.map +1 -1
  235. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.d.ts +2 -0
  236. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.d.ts.map +1 -0
  237. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.js +122 -0
  238. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.js.map +1 -0
  239. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts +1 -0
  240. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  241. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +30 -0
  242. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  243. package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.d.ts.map +1 -1
  244. package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.js +1 -7
  245. package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.js.map +1 -1
  246. package/packages/pi-coding-agent/package.json +1 -1
  247. package/packages/pi-coding-agent/src/core/extensions/loader.ts +6 -0
  248. package/packages/pi-coding-agent/src/core/extensions/runner.ts +19 -0
  249. package/packages/pi-coding-agent/src/core/extensions/types.ts +26 -0
  250. package/packages/pi-coding-agent/src/core/lsp/config.ts +7 -1
  251. package/packages/pi-coding-agent/src/core/lsp/defaults.json +2 -2
  252. package/packages/pi-coding-agent/src/core/lsp/lsp-legacy-alias.test.ts +70 -0
  253. package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.test.ts +156 -0
  254. package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.ts +7 -0
  255. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +38 -0
  256. package/packages/pi-coding-agent/src/modes/interactive/slash-command-handlers.ts +1 -8
  257. package/pkg/package.json +1 -1
  258. package/src/resources/extensions/ask-user-questions.ts +7 -3
  259. package/src/resources/extensions/gsd/auto/phases.ts +70 -1
  260. package/src/resources/extensions/gsd/auto-dashboard.ts +22 -8
  261. package/src/resources/extensions/gsd/auto-dispatch.ts +7 -3
  262. package/src/resources/extensions/gsd/auto-model-selection.ts +77 -6
  263. package/src/resources/extensions/gsd/auto-post-unit.ts +52 -5
  264. package/src/resources/extensions/gsd/auto-prompts.ts +54 -20
  265. package/src/resources/extensions/gsd/auto-recovery.ts +38 -18
  266. package/src/resources/extensions/gsd/auto-start.ts +10 -9
  267. package/src/resources/extensions/gsd/auto-timers.ts +12 -5
  268. package/src/resources/extensions/gsd/auto-unit-closeout.ts +6 -2
  269. package/src/resources/extensions/gsd/auto-verification.ts +3 -6
  270. package/src/resources/extensions/gsd/auto-worktree.ts +121 -55
  271. package/src/resources/extensions/gsd/auto.ts +40 -17
  272. package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +4 -3
  273. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +80 -2
  274. package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +4 -16
  275. package/src/resources/extensions/gsd/bootstrap/journal-tools.ts +2 -1
  276. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +61 -4
  277. package/src/resources/extensions/gsd/bootstrap/system-context.ts +11 -10
  278. package/src/resources/extensions/gsd/captures.ts +71 -2
  279. package/src/resources/extensions/gsd/commands/catalog.ts +2 -0
  280. package/src/resources/extensions/gsd/commands-codebase.ts +52 -20
  281. package/src/resources/extensions/gsd/commands-inspect.ts +2 -1
  282. package/src/resources/extensions/gsd/commands-maintenance.ts +28 -19
  283. package/src/resources/extensions/gsd/complexity-classifier.ts +10 -5
  284. package/src/resources/extensions/gsd/context-masker.ts +74 -0
  285. package/src/resources/extensions/gsd/custom-verification.ts +3 -2
  286. package/src/resources/extensions/gsd/docs/preferences-reference.md +7 -0
  287. package/src/resources/extensions/gsd/gsd-db.ts +14 -16
  288. package/src/resources/extensions/gsd/guided-flow.ts +9 -8
  289. package/src/resources/extensions/gsd/init-wizard.ts +12 -0
  290. package/src/resources/extensions/gsd/markdown-renderer.ts +11 -17
  291. package/src/resources/extensions/gsd/md-importer.ts +5 -4
  292. package/src/resources/extensions/gsd/milestone-actions.ts +3 -2
  293. package/src/resources/extensions/gsd/milestone-ids.ts +2 -1
  294. package/src/resources/extensions/gsd/model-router.ts +245 -56
  295. package/src/resources/extensions/gsd/parallel-merge.ts +5 -3
  296. package/src/resources/extensions/gsd/parallel-orchestrator.ts +18 -14
  297. package/src/resources/extensions/gsd/phase-anchor.ts +71 -0
  298. package/src/resources/extensions/gsd/preferences-types.ts +22 -0
  299. package/src/resources/extensions/gsd/preferences-validation.ts +83 -0
  300. package/src/resources/extensions/gsd/preferences.ts +16 -3
  301. package/src/resources/extensions/gsd/prompt-loader.ts +3 -2
  302. package/src/resources/extensions/gsd/prompts/execute-task.md +2 -0
  303. package/src/resources/extensions/gsd/prompts/rethink.md +7 -0
  304. package/src/resources/extensions/gsd/prompts/triage-captures.md +6 -1
  305. package/src/resources/extensions/gsd/rethink.ts +5 -2
  306. package/src/resources/extensions/gsd/rule-registry.ts +7 -6
  307. package/src/resources/extensions/gsd/safe-fs.ts +6 -5
  308. package/src/resources/extensions/gsd/state.ts +1 -1
  309. package/src/resources/extensions/gsd/status-guards.ts +4 -3
  310. package/src/resources/extensions/gsd/tests/capability-router.test.ts +347 -0
  311. package/src/resources/extensions/gsd/tests/codebase-generator.test.ts +63 -0
  312. package/src/resources/extensions/gsd/tests/complexity-classifier.test.ts +27 -2
  313. package/src/resources/extensions/gsd/tests/context-masker.test.ts +122 -0
  314. package/src/resources/extensions/gsd/tests/db-path-worktree-symlink.test.ts +4 -4
  315. package/src/resources/extensions/gsd/tests/integration/state-machine-edge-cases.test.ts +1188 -0
  316. package/src/resources/extensions/gsd/tests/integration/state-machine-runtime-failures.test.ts +841 -0
  317. package/src/resources/extensions/gsd/tests/model-router.test.ts +488 -2
  318. package/src/resources/extensions/gsd/tests/phase-anchor.test.ts +83 -0
  319. package/src/resources/extensions/gsd/tests/preferences.test.ts +62 -0
  320. package/src/resources/extensions/gsd/tests/remote-questions.test.ts +21 -0
  321. package/src/resources/extensions/gsd/tests/silent-catch-diagnostics.test.ts +284 -0
  322. package/src/resources/extensions/gsd/tests/status-guards.test.ts +4 -0
  323. package/src/resources/extensions/gsd/tests/stop-backtrack.test.ts +216 -0
  324. package/src/resources/extensions/gsd/tests/tool-naming.test.ts +1 -1
  325. package/src/resources/extensions/gsd/tests/workflow-logger-audit.test.ts +120 -0
  326. package/src/resources/extensions/gsd/tests/workflow-logger.test.ts +6 -6
  327. package/src/resources/extensions/gsd/tools/complete-milestone.ts +3 -6
  328. package/src/resources/extensions/gsd/tools/complete-slice.ts +3 -6
  329. package/src/resources/extensions/gsd/tools/complete-task.ts +3 -6
  330. package/src/resources/extensions/gsd/tools/plan-milestone.ts +3 -6
  331. package/src/resources/extensions/gsd/tools/plan-slice.ts +3 -6
  332. package/src/resources/extensions/gsd/tools/plan-task.ts +2 -3
  333. package/src/resources/extensions/gsd/tools/reassess-roadmap.ts +4 -6
  334. package/src/resources/extensions/gsd/tools/reopen-slice.ts +2 -3
  335. package/src/resources/extensions/gsd/tools/reopen-task.ts +2 -3
  336. package/src/resources/extensions/gsd/tools/replan-slice.ts +2 -3
  337. package/src/resources/extensions/gsd/tools/validate-milestone.ts +2 -3
  338. package/src/resources/extensions/gsd/triage-resolution.ts +151 -1
  339. package/src/resources/extensions/gsd/triage-ui.ts +12 -3
  340. package/src/resources/extensions/gsd/types.ts +1 -0
  341. package/src/resources/extensions/gsd/workflow-events.ts +2 -1
  342. package/src/resources/extensions/gsd/workflow-logger.ts +52 -5
  343. package/src/resources/extensions/gsd/workflow-migration.ts +14 -12
  344. package/src/resources/extensions/gsd/workflow-projections.ts +2 -2
  345. package/src/resources/extensions/gsd/workflow-reconcile.ts +2 -2
  346. package/src/resources/extensions/gsd/worktree-manager.ts +16 -14
  347. package/src/resources/extensions/shared/interview-ui.ts +3 -1
  348. package/src/resources/extensions/shared/tests/interview-notes-loop.test.ts +144 -0
  349. package/src/resources/skills/btw/SKILL.md +42 -0
  350. package/dist/web/standalone/.next/static/chunks/app/page-62be3b5fa91e4c8f.js +0 -1
  351. package/dist/web/standalone/.next/static/chunks/main-app-d3d4c336195465f9.js +0 -1
  352. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-ab5a8926e07ec673.js +0 -1
  353. /package/dist/web/standalone/.next/static/{DGvT_c5Vb7Wu3X-fEOVUU → ogyMN7M-3bGGuRY08L5HR}/_buildManifest.js +0 -0
  354. /package/dist/web/standalone/.next/static/{DGvT_c5Vb7Wu3X-fEOVUU → ogyMN7M-3bGGuRY08L5HR}/_ssgManifest.js +0 -0
@@ -240,13 +240,13 @@ describe("workflow-logger", () => {
240
240
 
241
241
  test("writes entry to .gsd/audit-log.jsonl after setLogBasePath", () => {
242
242
  setLogBasePath(dir);
243
- logWarning("engine", "audit test entry");
243
+ logError("engine", "audit test entry");
244
244
 
245
245
  const auditPath = join(dir, ".gsd", "audit-log.jsonl");
246
246
  assert.ok(existsSync(auditPath), "audit-log.jsonl should exist");
247
247
  const content = readFileSync(auditPath, "utf-8");
248
248
  const entry = JSON.parse(content.trim());
249
- assert.equal(entry.severity, "warn");
249
+ assert.equal(entry.severity, "error");
250
250
  assert.equal(entry.component, "engine");
251
251
  assert.equal(entry.message, "audit test entry");
252
252
  });
@@ -254,7 +254,7 @@ describe("workflow-logger", () => {
254
254
  test("_resetLogs does not clear the audit base path", () => {
255
255
  setLogBasePath(dir);
256
256
  _resetLogs();
257
- logWarning("engine", "post-reset entry");
257
+ logError("engine", "post-reset entry");
258
258
 
259
259
  const auditPath = join(dir, ".gsd", "audit-log.jsonl");
260
260
  assert.ok(existsSync(auditPath), "audit-log.jsonl should exist after _resetLogs");
@@ -293,13 +293,13 @@ describe("workflow-logger", () => {
293
293
 
294
294
  test("writes entry to .gsd/audit-log.jsonl after setLogBasePath", () => {
295
295
  setLogBasePath(dir);
296
- logWarning("engine", "audit test entry");
296
+ logError("engine", "audit test entry");
297
297
 
298
298
  const auditPath = join(dir, ".gsd", "audit-log.jsonl");
299
299
  assert.ok(existsSync(auditPath), "audit-log.jsonl should exist");
300
300
  const content = readFileSync(auditPath, "utf-8");
301
301
  const entry = JSON.parse(content.trim());
302
- assert.equal(entry.severity, "warn");
302
+ assert.equal(entry.severity, "error");
303
303
  assert.equal(entry.component, "engine");
304
304
  assert.equal(entry.message, "audit test entry");
305
305
  });
@@ -307,7 +307,7 @@ describe("workflow-logger", () => {
307
307
  test("_resetLogs does not clear the audit base path", () => {
308
308
  setLogBasePath(dir);
309
309
  _resetLogs();
310
- logWarning("engine", "post-reset entry");
310
+ logError("engine", "post-reset entry");
311
311
 
312
312
  const auditPath = join(dir, ".gsd", "audit-log.jsonl");
313
313
  assert.ok(existsSync(auditPath), "audit-log.jsonl should exist after _resetLogs");
@@ -23,6 +23,7 @@ import { invalidateStateCache } from "../state.js";
23
23
  import { renderAllProjections } from "../workflow-projections.js";
24
24
  import { writeManifest } from "../workflow-manifest.js";
25
25
  import { appendEvent } from "../workflow-events.js";
26
+ import { logWarning } from "../workflow-logger.js";
26
27
 
27
28
  export interface CompleteMilestoneParams {
28
29
  milestoneId: string;
@@ -191,9 +192,7 @@ export async function handleCompleteMilestone(
191
192
  await saveFile(summaryPath, summaryMd);
192
193
  } catch (renderErr) {
193
194
  // Disk render failed — roll back DB status so state stays consistent
194
- process.stderr.write(
195
- `gsd-db: complete_milestone — disk render failed, rolling back DB status: ${(renderErr as Error).message}\n`,
196
- );
195
+ logWarning("tool", `complete_milestone — disk render failed, rolling back DB status: ${(renderErr as Error).message}`);
197
196
  updateMilestoneStatus(params.milestoneId, 'active', null);
198
197
  invalidateStateCache();
199
198
  return { error: `disk render failed: ${(renderErr as Error).message}` };
@@ -217,9 +216,7 @@ export async function handleCompleteMilestone(
217
216
  trigger_reason: params.triggerReason,
218
217
  });
219
218
  } catch (hookErr) {
220
- process.stderr.write(
221
- `gsd: complete-milestone post-mutation hook warning: ${(hookErr as Error).message}\n`,
222
- );
219
+ logWarning("tool", `complete-milestone post-mutation hook warning: ${(hookErr as Error).message}`);
223
220
  }
224
221
 
225
222
  return {
@@ -30,6 +30,7 @@ import { renderRoadmapCheckboxes } from "../markdown-renderer.js";
30
30
  import { renderAllProjections } from "../workflow-projections.js";
31
31
  import { writeManifest } from "../workflow-manifest.js";
32
32
  import { appendEvent } from "../workflow-events.js";
33
+ import { logWarning } from "../workflow-logger.js";
33
34
 
34
35
  export interface CompleteSliceResult {
35
36
  sliceId: string;
@@ -297,9 +298,7 @@ export async function handleCompleteSlice(
297
298
  }
298
299
  } catch (renderErr) {
299
300
  // Disk render failed — roll back DB status so state stays consistent
300
- process.stderr.write(
301
- `gsd-db: complete_slice — disk render failed, rolling back DB status: ${(renderErr as Error).message}\n`,
302
- );
301
+ logWarning("tool", `complete_slice — disk render failed, rolling back DB status: ${(renderErr as Error).message}`);
303
302
  updateSliceStatus(params.milestoneId, params.sliceId, 'pending');
304
303
  invalidateStateCache();
305
304
  return { error: `disk render failed: ${(renderErr as Error).message}` };
@@ -326,9 +325,7 @@ export async function handleCompleteSlice(
326
325
  trigger_reason: params.triggerReason,
327
326
  });
328
327
  } catch (hookErr) {
329
- process.stderr.write(
330
- `gsd: complete-slice post-mutation hook warning: ${(hookErr as Error).message}\n`,
331
- );
328
+ logWarning("tool", `complete-slice post-mutation hook warning: ${(hookErr as Error).message}`);
332
329
  }
333
330
 
334
331
  return {
@@ -33,6 +33,7 @@ import { renderPlanCheckboxes } from "../markdown-renderer.js";
33
33
  import { renderAllProjections, renderSummaryContent } from "../workflow-projections.js";
34
34
  import { writeManifest } from "../workflow-manifest.js";
35
35
  import { appendEvent } from "../workflow-events.js";
36
+ import { logWarning } from "../workflow-logger.js";
36
37
 
37
38
  export interface CompleteTaskResult {
38
39
  taskId: string;
@@ -210,9 +211,7 @@ export async function handleCompleteTask(
210
211
  }
211
212
  } catch (renderErr) {
212
213
  // Disk render failed — roll back DB status so state stays consistent
213
- process.stderr.write(
214
- `gsd-db: complete_task — disk render failed, rolling back DB status: ${(renderErr as Error).message}\n`,
215
- );
214
+ logWarning("tool", `complete_task — disk render failed, rolling back DB status: ${(renderErr as Error).message}`);
216
215
  // Delete orphaned verification_evidence rows first (FK constraint
217
216
  // references tasks, so evidence must go before status change).
218
217
  // Without this, retries accumulate duplicate evidence rows (#2724).
@@ -243,9 +242,7 @@ export async function handleCompleteTask(
243
242
  trigger_reason: params.triggerReason,
244
243
  });
245
244
  } catch (hookErr) {
246
- process.stderr.write(
247
- `gsd: complete-task post-mutation hook warning: ${(hookErr as Error).message}\n`,
248
- );
245
+ logWarning("tool", `complete-task post-mutation hook warning: ${(hookErr as Error).message}`);
249
246
  }
250
247
 
251
248
  return {
@@ -15,6 +15,7 @@ import { renderRoadmapFromDb } from "../markdown-renderer.js";
15
15
  import { renderAllProjections } from "../workflow-projections.js";
16
16
  import { writeManifest } from "../workflow-manifest.js";
17
17
  import { appendEvent } from "../workflow-events.js";
18
+ import { logWarning } from "../workflow-logger.js";
18
19
 
19
20
  export interface PlanMilestoneSliceInput {
20
21
  sliceId: string;
@@ -269,9 +270,7 @@ export async function handlePlanMilestone(
269
270
  const renderResult = await renderRoadmapFromDb(basePath, params.milestoneId);
270
271
  roadmapPath = renderResult.roadmapPath;
271
272
  } catch (renderErr) {
272
- process.stderr.write(
273
- `gsd-db: plan_milestone — render failed (DB rows preserved for debugging): ${(renderErr as Error).message}\n`,
274
- );
273
+ logWarning("tool", `plan_milestone — render failed (DB rows preserved for debugging): ${(renderErr as Error).message}`);
275
274
  invalidateStateCache();
276
275
  return { error: `render failed: ${(renderErr as Error).message}` };
277
276
  }
@@ -292,9 +291,7 @@ export async function handlePlanMilestone(
292
291
  trigger_reason: params.triggerReason,
293
292
  });
294
293
  } catch (hookErr) {
295
- process.stderr.write(
296
- `gsd: plan-milestone post-mutation hook warning: ${(hookErr as Error).message}\n`,
297
- );
294
+ logWarning("tool", `plan-milestone post-mutation hook warning: ${(hookErr as Error).message}`);
298
295
  }
299
296
 
300
297
  return {
@@ -16,6 +16,7 @@ import { renderPlanFromDb } from "../markdown-renderer.js";
16
16
  import { renderAllProjections } from "../workflow-projections.js";
17
17
  import { writeManifest } from "../workflow-manifest.js";
18
18
  import { appendEvent } from "../workflow-events.js";
19
+ import { logWarning } from "../workflow-logger.js";
19
20
 
20
21
  export interface PlanSliceTaskInput {
21
22
  taskId: string;
@@ -229,9 +230,7 @@ export async function handlePlanSlice(
229
230
  trigger_reason: params.triggerReason,
230
231
  });
231
232
  } catch (hookErr) {
232
- process.stderr.write(
233
- `gsd: plan-slice post-mutation hook warning: ${(hookErr as Error).message}\n`,
234
- );
233
+ logWarning("tool", `plan-slice post-mutation hook warning: ${(hookErr as Error).message}`);
235
234
  }
236
235
 
237
236
  return {
@@ -241,9 +240,7 @@ export async function handlePlanSlice(
241
240
  taskPlanPaths: renderResult.taskPlanPaths,
242
241
  };
243
242
  } catch (renderErr) {
244
- process.stderr.write(
245
- `gsd-db: plan_slice — render failed (DB rows preserved for debugging): ${(renderErr as Error).message}\n`,
246
- );
243
+ logWarning("tool", `plan_slice — render failed (DB rows preserved for debugging): ${(renderErr as Error).message}`);
247
244
  invalidateStateCache();
248
245
  return { error: `render failed: ${(renderErr as Error).message}` };
249
246
  }
@@ -7,6 +7,7 @@ import { renderTaskPlanFromDb } from "../markdown-renderer.js";
7
7
  import { renderAllProjections } from "../workflow-projections.js";
8
8
  import { writeManifest } from "../workflow-manifest.js";
9
9
  import { appendEvent } from "../workflow-events.js";
10
+ import { logWarning } from "../workflow-logger.js";
10
11
 
11
12
  export interface PlanTaskParams {
12
13
  milestoneId: string;
@@ -135,9 +136,7 @@ export async function handlePlanTask(
135
136
  trigger_reason: params.triggerReason,
136
137
  });
137
138
  } catch (hookErr) {
138
- process.stderr.write(
139
- `gsd: plan-task post-mutation hook warning: ${(hookErr as Error).message}\n`,
140
- );
139
+ logWarning("tool", `plan-task post-mutation hook warning: ${(hookErr as Error).message}`);
141
140
  }
142
141
 
143
142
  return {
@@ -19,6 +19,7 @@ import { renderRoadmapFromDb, renderAssessmentFromDb } from "../markdown-rendere
19
19
  import { renderAllProjections } from "../workflow-projections.js";
20
20
  import { writeManifest } from "../workflow-manifest.js";
21
21
  import { appendEvent } from "../workflow-events.js";
22
+ import { logWarning } from "../workflow-logger.js";
22
23
 
23
24
  export interface SliceChangeInput {
24
25
  sliceId: string;
@@ -248,9 +249,8 @@ export async function handleReassessRoadmap(
248
249
  );
249
250
  try {
250
251
  if (existsSync(validationFile)) unlinkSync(validationFile);
251
- } catch {
252
- // Best-effort: DB row is already deleted, so state derivation
253
- // will not see the file-based verdict as authoritative.
252
+ } catch (e) {
253
+ logWarning("tool", `validation file cleanup failed: ${(e as Error).message}`);
254
254
  }
255
255
  }
256
256
 
@@ -271,9 +271,7 @@ export async function handleReassessRoadmap(
271
271
  trigger_reason: params.triggerReason,
272
272
  });
273
273
  } catch (hookErr) {
274
- process.stderr.write(
275
- `gsd: reassess-roadmap post-mutation hook warning: ${(hookErr as Error).message}\n`,
276
- );
274
+ logWarning("tool", `reassess-roadmap post-mutation hook warning: ${(hookErr as Error).message}`);
277
275
  }
278
276
 
279
277
  return {
@@ -24,6 +24,7 @@ import { isClosedStatus } from "../status-guards.js";
24
24
  import { renderAllProjections } from "../workflow-projections.js";
25
25
  import { writeManifest } from "../workflow-manifest.js";
26
26
  import { appendEvent } from "../workflow-events.js";
27
+ import { logWarning } from "../workflow-logger.js";
27
28
 
28
29
  export interface ReopenSliceParams {
29
30
  milestoneId: string;
@@ -113,9 +114,7 @@ export async function handleReopenSlice(
113
114
  trigger_reason: params.triggerReason,
114
115
  });
115
116
  } catch (hookErr) {
116
- process.stderr.write(
117
- `gsd: reopen-slice post-mutation hook warning: ${(hookErr as Error).message}\n`,
118
- );
117
+ logWarning("tool", `reopen-slice post-mutation hook warning: ${(hookErr as Error).message}`);
119
118
  }
120
119
 
121
120
  return {
@@ -22,6 +22,7 @@ import { isClosedStatus } from "../status-guards.js";
22
22
  import { renderAllProjections } from "../workflow-projections.js";
23
23
  import { writeManifest } from "../workflow-manifest.js";
24
24
  import { appendEvent } from "../workflow-events.js";
25
+ import { logWarning } from "../workflow-logger.js";
25
26
 
26
27
  export interface ReopenTaskParams {
27
28
  milestoneId: string;
@@ -117,9 +118,7 @@ export async function handleReopenTask(
117
118
  trigger_reason: params.triggerReason,
118
119
  });
119
120
  } catch (hookErr) {
120
- process.stderr.write(
121
- `gsd: reopen-task post-mutation hook warning: ${(hookErr as Error).message}\n`,
122
- );
121
+ logWarning("tool", `reopen-task post-mutation hook warning: ${(hookErr as Error).message}`);
123
122
  }
124
123
 
125
124
  return {
@@ -16,6 +16,7 @@ import { renderPlanFromDb, renderReplanFromDb } from "../markdown-renderer.js";
16
16
  import { renderAllProjections } from "../workflow-projections.js";
17
17
  import { writeManifest } from "../workflow-manifest.js";
18
18
  import { appendEvent } from "../workflow-events.js";
19
+ import { logWarning } from "../workflow-logger.js";
19
20
 
20
21
  export interface ReplanSliceTaskInput {
21
22
  taskId: string;
@@ -226,9 +227,7 @@ export async function handleReplanSlice(
226
227
  trigger_reason: params.triggerReason,
227
228
  });
228
229
  } catch (hookErr) {
229
- process.stderr.write(
230
- `gsd: replan-slice post-mutation hook warning: ${(hookErr as Error).message}\n`,
231
- );
230
+ logWarning("tool", `replan-slice post-mutation hook warning: ${(hookErr as Error).message}`);
232
231
  }
233
232
 
234
233
  return {
@@ -22,6 +22,7 @@ import { saveFile, clearParseCache } from "../files.js";
22
22
  import { invalidateStateCache } from "../state.js";
23
23
  import { VALIDATION_VERDICTS, isValidMilestoneVerdict } from "../verdict-parser.js";
24
24
  import { insertMilestoneValidationGates } from "../milestone-validation-gates.js";
25
+ import { logWarning } from "../workflow-logger.js";
25
26
 
26
27
  export interface ValidateMilestoneParams {
27
28
  milestoneId: string;
@@ -137,9 +138,7 @@ export async function handleValidateMilestone(
137
138
  try {
138
139
  await saveFile(validationPath, validationMd);
139
140
  } catch (renderErr) {
140
- process.stderr.write(
141
- `gsd-db: validate_milestone — disk render failed, rolling back DB row: ${(renderErr as Error).message}\n`,
142
- );
141
+ logWarning("tool", `validate_milestone — disk render failed, rolling back DB row: ${(renderErr as Error).message}`);
143
142
  deleteAssessmentByScope(params.milestoneId, 'milestone-validation');
144
143
  return { error: `disk render failed: ${(renderErr as Error).message}` };
145
144
  }
@@ -10,7 +10,7 @@
10
10
  * Also provides detectFileOverlap() for surfacing downstream impact on quick tasks.
11
11
  */
12
12
 
13
- import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
13
+ import { existsSync, mkdirSync, readFileSync, writeFileSync, unlinkSync } from "node:fs";
14
14
  import { join } from "node:path";
15
15
  import { createRequire } from "node:module";
16
16
  import { gsdRoot, milestonesDir } from "./paths.js";
@@ -129,6 +129,136 @@ export function executeReplan(
129
129
  }
130
130
  }
131
131
 
132
+ // ─── Backtrack (Milestone Regression) ────────────────────────────────────────
133
+
134
+ /**
135
+ * Execute a backtrack directive — user wants to abandon current milestone
136
+ * and return to a previous one (milestone regression).
137
+ *
138
+ * Writes a BACKTRACK-TRIGGER.md marker at `.gsd/BACKTRACK-TRIGGER.md` with
139
+ * the target milestone, reason, and timestamp. The state machine (deriveState)
140
+ * detects this and transitions the project to the target milestone, resetting
141
+ * its slices to allow re-planning.
142
+ *
143
+ * Returns the extracted target milestone ID, or null if extraction failed.
144
+ */
145
+ export function executeBacktrack(
146
+ basePath: string,
147
+ currentMilestoneId: string,
148
+ capture: CaptureEntry,
149
+ ): string | null {
150
+ try {
151
+ // Extract target milestone from capture text or resolution.
152
+ // Filter out the current milestone ID to avoid picking it as the backtrack target
153
+ // when the text mentions both current and target milestones (e.g. "backtrack from M004 to M003").
154
+ const sourceText = capture.resolution ?? capture.text;
155
+ const allMatches = [...sourceText.matchAll(/\b(M\d{3}(?:-[a-z0-9]{6})?)\b/g)]
156
+ .map(m => m[1])
157
+ .filter(id => id !== currentMilestoneId);
158
+ // Reject ambiguous multi-target strings — if more than one distinct target remains,
159
+ // don't guess; let the user clarify.
160
+ const uniqueTargets = [...new Set(allMatches)];
161
+ const targetMilestoneId = uniqueTargets.length === 1 ? uniqueTargets[0] : null;
162
+
163
+ const ts = new Date().toISOString();
164
+ const triggerPath = join(gsdRoot(basePath), "BACKTRACK-TRIGGER.md");
165
+ const content = [
166
+ `# Backtrack Trigger`,
167
+ ``,
168
+ `**Source:** Capture ${capture.id}`,
169
+ `**Capture:** ${capture.text}`,
170
+ `**Rationale:** ${capture.rationale ?? "User-initiated milestone backtrack"}`,
171
+ `**From:** ${currentMilestoneId}`,
172
+ `**Target:** ${targetMilestoneId ?? "(user to specify)"}`,
173
+ `**Triggered:** ${ts}`,
174
+ ``,
175
+ `Auto-mode was paused by this backtrack directive. The user directed`,
176
+ `that the current milestone (${currentMilestoneId}) be abandoned and work`,
177
+ `should return to ${targetMilestoneId ?? "a previous milestone"}.`,
178
+ ``,
179
+ `## Recovery Steps`,
180
+ ``,
181
+ `1. Review what went wrong in ${currentMilestoneId}`,
182
+ `2. Identify missing features/requirements from the target milestone`,
183
+ `3. Resume auto-mode — the state machine will re-enter discussion for the target`,
184
+ ].join("\n");
185
+
186
+ writeFileSync(triggerPath, content, "utf-8");
187
+
188
+ // If we have a valid target, also reset that milestone's completion status
189
+ // so deriveState() will re-enter it as the active milestone.
190
+ if (targetMilestoneId) {
191
+ try {
192
+ const targetDir = join(milestonesDir(basePath), targetMilestoneId);
193
+ if (existsSync(targetDir)) {
194
+ // Write a regression marker so the state machine knows this milestone
195
+ // needs re-discussion, not just re-execution
196
+ const regressionPath = join(targetDir, `${targetMilestoneId}-REGRESSION.md`);
197
+ writeFileSync(regressionPath, [
198
+ `# Milestone Regression`,
199
+ ``,
200
+ `**From:** ${currentMilestoneId}`,
201
+ `**Reason:** ${capture.text}`,
202
+ `**Triggered:** ${ts}`,
203
+ ``,
204
+ `This milestone is being revisited because downstream milestone`,
205
+ `${currentMilestoneId} failed or missed critical features that should`,
206
+ `have been part of this milestone's scope.`,
207
+ ``,
208
+ `The discuss phase should re-evaluate requirements and identify gaps.`,
209
+ ].join("\n"), "utf-8");
210
+ }
211
+ } catch { /* best-effort */ }
212
+ }
213
+
214
+ return targetMilestoneId;
215
+ } catch {
216
+ return null;
217
+ }
218
+ }
219
+
220
+ /**
221
+ * Read the backtrack trigger file if it exists.
222
+ * Returns the parsed target milestone and metadata, or null.
223
+ */
224
+ export function readBacktrackTrigger(basePath: string): {
225
+ target: string | null;
226
+ from: string | null;
227
+ capture: string;
228
+ triggeredAt: string;
229
+ } | null {
230
+ const triggerPath = join(gsdRoot(basePath), "BACKTRACK-TRIGGER.md");
231
+ if (!existsSync(triggerPath)) return null;
232
+
233
+ try {
234
+ const content = readFileSync(triggerPath, "utf-8");
235
+ const target = content.match(/\*\*Target:\*\*\s*(.+)/)?.[1]?.trim() ?? null;
236
+ const from = content.match(/\*\*From:\*\*\s*(.+)/)?.[1]?.trim() ?? null;
237
+ const capture = content.match(/\*\*Capture:\*\*\s*(.+)/)?.[1]?.trim() ?? "";
238
+ const triggeredAt = content.match(/\*\*Triggered:\*\*\s*(.+)/)?.[1]?.trim() ?? "";
239
+ return {
240
+ target: target === "(user to specify)" ? null : target,
241
+ from,
242
+ capture,
243
+ triggeredAt,
244
+ };
245
+ } catch {
246
+ return null;
247
+ }
248
+ }
249
+
250
+ /**
251
+ * Remove the backtrack trigger after it has been processed.
252
+ */
253
+ export function clearBacktrackTrigger(basePath: string): void {
254
+ const triggerPath = join(gsdRoot(basePath), "BACKTRACK-TRIGGER.md");
255
+ try {
256
+ if (existsSync(triggerPath)) {
257
+ unlinkSync(triggerPath);
258
+ }
259
+ } catch { /* best-effort */ }
260
+ }
261
+
132
262
  // ─── File Overlap Detection ───────────────────────────────────────────────────
133
263
 
134
264
  /**
@@ -298,6 +428,10 @@ export interface TriageExecutionResult {
298
428
  deferredMilestones: number;
299
429
  /** Captures classified as quick-task that need dispatch */
300
430
  quickTasks: CaptureEntry[];
431
+ /** Number of stop directives (will pause auto-mode via guard) */
432
+ stopped: number;
433
+ /** Backtrack captures (will trigger milestone regression via guard) */
434
+ backtracks: CaptureEntry[];
301
435
  /** Details of each action taken, for logging */
302
436
  actions: string[];
303
437
  }
@@ -326,6 +460,8 @@ export function executeTriageResolutions(
326
460
  replanned: 0,
327
461
  deferredMilestones: 0,
328
462
  quickTasks: [],
463
+ stopped: 0,
464
+ backtracks: [],
329
465
  actions: [],
330
466
  };
331
467
 
@@ -409,5 +545,19 @@ export function executeTriageResolutions(
409
545
  }
410
546
  }
411
547
 
548
+ // Count stop/backtrack captures — these are handled by the pre-dispatch guard
549
+ // in runGuards(), not here. We just report them for logging purposes.
550
+ const allCaptures = loadAllCaptures(basePath);
551
+ for (const cap of allCaptures) {
552
+ if (cap.status !== "resolved" || cap.executed) continue;
553
+ if (cap.classification === "stop") {
554
+ result.stopped++;
555
+ result.actions.push(`Stop directive from ${cap.id}: "${cap.text}" — will pause on next dispatch`);
556
+ } else if (cap.classification === "backtrack") {
557
+ result.backtracks.push(cap);
558
+ result.actions.push(`Backtrack directive from ${cap.id}: "${cap.text}" — will trigger milestone regression on next dispatch`);
559
+ }
560
+ }
561
+
412
562
  return result;
413
563
  }
@@ -49,10 +49,18 @@ const CLASSIFICATION_LABELS: Record<Classification, { label: string; description
49
49
  label: "Note",
50
50
  description: "Informational only — no action needed.",
51
51
  },
52
+ "stop": {
53
+ label: "Stop",
54
+ description: "Halt auto-mode immediately — user directive to cease execution.",
55
+ },
56
+ "backtrack": {
57
+ label: "Backtrack",
58
+ description: "Abandon current milestone and return to a previous one.",
59
+ },
52
60
  };
53
61
 
54
62
  const ALL_CLASSIFICATIONS: Classification[] = [
55
- "quick-task", "inject", "defer", "replan", "note",
63
+ "quick-task", "inject", "defer", "replan", "note", "stop", "backtrack",
56
64
  ];
57
65
 
58
66
  // ─── Public API ───────────────────────────────────────────────────────────────
@@ -83,8 +91,9 @@ export async function showTriageConfirmation(
83
91
  const capture = captureMap.get(result.captureId);
84
92
  if (!capture) continue;
85
93
 
86
- // Auto-confirm note and defer — low-impact, no plan modification
87
- if (result.classification === "note" || result.classification === "defer") {
94
+ // Auto-confirm note, defer, stop, and backtrack — low-impact or urgent directives
95
+ if (result.classification === "note" || result.classification === "defer"
96
+ || result.classification === "stop" || result.classification === "backtrack") {
88
97
  const resolution = result.classification === "note"
89
98
  ? "acknowledged as note"
90
99
  : `deferred${result.targetSlice ? ` to ${result.targetSlice}` : ""}`;
@@ -316,6 +316,7 @@ export interface ClassificationResult {
316
316
  tier: ComplexityTier;
317
317
  reason: string;
318
318
  downgraded: boolean;
319
+ taskMetadata?: TaskMetadata;
319
320
  }
320
321
 
321
322
  export interface TaskMetadata {
@@ -2,6 +2,7 @@ import { createHash, randomUUID } from "node:crypto";
2
2
  import { appendFileSync, readFileSync, existsSync, mkdirSync } from "node:fs";
3
3
  import { join } from "node:path";
4
4
  import { atomicWriteSync } from "./atomic-write.js";
5
+ import { logWarning } from "./workflow-logger.js";
5
6
 
6
7
  // ─── Session ID ───────────────────────────────────────────────────────────
7
8
 
@@ -74,7 +75,7 @@ export function readEvents(logPath: string): WorkflowEvent[] {
74
75
  try {
75
76
  events.push(JSON.parse(line) as WorkflowEvent);
76
77
  } catch {
77
- process.stderr.write(`workflow-events: skipping corrupted event line: ${line.slice(0, 80)}\n`);
78
+ logWarning("event-log", `skipping corrupted event line (${line.length} bytes)`);
78
79
  }
79
80
  }
80
81
 
@@ -2,7 +2,9 @@
2
2
  // Centralized warning/error accumulator for the workflow engine pipeline.
3
3
  // Captures structured entries that the auto-loop can drain after each unit
4
4
  // to surface root causes for stuck loops, silent degradation, and blocked writes.
5
- // All entries are also persisted to .gsd/audit-log.jsonl for post-mortem analysis.
5
+ // Error-severity entries are persisted to .gsd/audit-log.jsonl (sanitized) for
6
+ // post-mortem analysis. Warnings are ephemeral (stderr + buffer only) to avoid
7
+ // log amplification from expected-control-flow catch paths.
6
8
  //
7
9
  // Stderr policy: every logWarning/logError call writes immediately to stderr
8
10
  // for terminal visibility. This is intentional — unlike debug-logger (which is
@@ -33,7 +35,20 @@ export type LogComponent =
33
35
  | "compaction" // Event compaction
34
36
  | "reconcile" // Worktree reconciliation
35
37
  | "db" // Database operations (gsd-db)
36
- | "dispatch"; // Auto-dispatch rule evaluation
38
+ | "dispatch" // Auto-dispatch rule evaluation
39
+ | "recovery" // Auto-recovery and timeout recovery
40
+ | "session" // Session lock and session state I/O
41
+ | "prompt" // Prompt construction and context injection
42
+ | "dashboard" // Auto-dashboard rendering
43
+ | "timer" // Auto-timers (idle watchdog, hard timeout)
44
+ | "worktree" // Worktree lifecycle (create, sync, merge)
45
+ | "command" // Slash command execution and maintenance
46
+ | "parallel" // Parallel orchestrator and merge
47
+ | "fs" // Safe filesystem operations
48
+ | "bootstrap" // Extension bootstrap (system-context, agent-end)
49
+ | "guided" // Guided flow (discuss, plan wizards)
50
+ | "registry" // Rule registry hook state
51
+ | "renderer"; // Markdown renderer and projections
37
52
 
38
53
  export interface LogEntry {
39
54
  ts: string;
@@ -230,15 +245,47 @@ function _push(
230
245
  _buffer.shift();
231
246
  }
232
247
 
233
- // Persist to .gsd/audit-log.jsonl so entries survive context resets
234
- if (_auditBasePath) {
248
+ // Persist errors to .gsd/audit-log.jsonl so they survive context resets.
249
+ // Only error-severity entries are persisted — warnings are ephemeral (stderr + buffer)
250
+ // to avoid log amplification from expected-control-flow catch paths.
251
+ if (_auditBasePath && severity === "error") {
235
252
  try {
236
253
  const auditDir = join(_auditBasePath, ".gsd");
237
254
  mkdirSync(auditDir, { recursive: true });
238
- appendFileSync(join(auditDir, "audit-log.jsonl"), JSON.stringify(entry) + "\n", "utf-8");
255
+ const sanitized = _sanitizeForAudit(entry);
256
+ appendFileSync(join(auditDir, "audit-log.jsonl"), JSON.stringify(sanitized) + "\n", "utf-8");
239
257
  } catch (auditErr) {
240
258
  // Best-effort — never let audit write failures bubble up
241
259
  process.stderr.write(`[gsd:audit] failed to persist log entry: ${(auditErr as Error).message}\n`);
242
260
  }
243
261
  }
244
262
  }
263
+
264
+ /**
265
+ * Sanitize a log entry before persisting to the audit JSONL file.
266
+ * Strips potentially sensitive context (raw paths, cwd, full error text)
267
+ * to avoid leaking local environment details into durable telemetry.
268
+ */
269
+ function _sanitizeForAudit(entry: LogEntry): LogEntry {
270
+ const sanitized: LogEntry = {
271
+ ts: entry.ts,
272
+ severity: entry.severity,
273
+ component: entry.component,
274
+ // Truncate message to avoid persisting oversized raw error dumps
275
+ message: entry.message.length > 200 ? entry.message.slice(0, 200) + "…[truncated]" : entry.message,
276
+ };
277
+ if (entry.context) {
278
+ // Allowlist: only persist known-safe structured keys
279
+ const SAFE_KEYS = new Set(["fn", "tool", "mid", "sid", "tid", "worktree"]);
280
+ const filtered: Record<string, string> = {};
281
+ for (const [k, v] of Object.entries(entry.context)) {
282
+ if (SAFE_KEYS.has(k)) {
283
+ filtered[k] = v;
284
+ }
285
+ }
286
+ if (Object.keys(filtered).length > 0) {
287
+ sanitized.context = filtered;
288
+ }
289
+ }
290
+ return sanitized;
291
+ }