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
@@ -14,6 +14,7 @@ import { isClosedStatus } from "../status-guards.js";
14
14
  import { renderAllProjections } from "../workflow-projections.js";
15
15
  import { writeManifest } from "../workflow-manifest.js";
16
16
  import { appendEvent } from "../workflow-events.js";
17
+ import { logWarning } from "../workflow-logger.js";
17
18
  export async function handleReopenTask(params, basePath) {
18
19
  // ── Validate required fields ────────────────────────────────────────────
19
20
  if (!params.taskId || typeof params.taskId !== "string" || params.taskId.trim() === "") {
@@ -81,7 +82,7 @@ export async function handleReopenTask(params, basePath) {
81
82
  });
82
83
  }
83
84
  catch (hookErr) {
84
- process.stderr.write(`gsd: reopen-task post-mutation hook warning: ${hookErr.message}\n`);
85
+ logWarning("tool", `reopen-task post-mutation hook warning: ${hookErr.message}`);
85
86
  }
86
87
  return {
87
88
  milestoneId: params.milestoneId,
@@ -7,6 +7,7 @@ import { renderPlanFromDb, renderReplanFromDb } 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
  function validateParams(params) {
11
12
  if (!isNonEmptyString(params?.milestoneId))
12
13
  throw new Error("milestoneId is required");
@@ -173,7 +174,7 @@ export async function handleReplanSlice(rawParams, basePath) {
173
174
  });
174
175
  }
175
176
  catch (hookErr) {
176
- process.stderr.write(`gsd: replan-slice post-mutation hook warning: ${hookErr.message}\n`);
177
+ logWarning("tool", `replan-slice post-mutation hook warning: ${hookErr.message}`);
177
178
  }
178
179
  return {
179
180
  milestoneId: params.milestoneId,
@@ -15,6 +15,7 @@ import { saveFile, clearParseCache } from "../files.js";
15
15
  import { invalidateStateCache } from "../state.js";
16
16
  import { VALIDATION_VERDICTS, isValidMilestoneVerdict } from "../verdict-parser.js";
17
17
  import { insertMilestoneValidationGates } from "../milestone-validation-gates.js";
18
+ import { logWarning } from "../workflow-logger.js";
18
19
  function renderValidationMarkdown(params) {
19
20
  let md = `---
20
21
  verdict: ${params.verdict}
@@ -95,7 +96,7 @@ export async function handleValidateMilestone(params, basePath) {
95
96
  await saveFile(validationPath, validationMd);
96
97
  }
97
98
  catch (renderErr) {
98
- process.stderr.write(`gsd-db: validate_milestone — disk render failed, rolling back DB row: ${renderErr.message}\n`);
99
+ logWarning("tool", `validate_milestone — disk render failed, rolling back DB row: ${renderErr.message}`);
99
100
  deleteAssessmentByScope(params.milestoneId, 'milestone-validation');
100
101
  return { error: `disk render failed: ${renderErr.message}` };
101
102
  }
@@ -9,7 +9,7 @@
9
9
  *
10
10
  * Also provides detectFileOverlap() for surfacing downstream impact on quick tasks.
11
11
  */
12
- import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
12
+ import { existsSync, mkdirSync, readFileSync, writeFileSync, unlinkSync } from "node:fs";
13
13
  import { join } from "node:path";
14
14
  import { createRequire } from "node:module";
15
15
  import { gsdRoot, milestonesDir } from "./paths.js";
@@ -99,6 +99,123 @@ export function executeReplan(basePath, mid, sid, capture) {
99
99
  return false;
100
100
  }
101
101
  }
102
+ // ─── Backtrack (Milestone Regression) ────────────────────────────────────────
103
+ /**
104
+ * Execute a backtrack directive — user wants to abandon current milestone
105
+ * and return to a previous one (milestone regression).
106
+ *
107
+ * Writes a BACKTRACK-TRIGGER.md marker at `.gsd/BACKTRACK-TRIGGER.md` with
108
+ * the target milestone, reason, and timestamp. The state machine (deriveState)
109
+ * detects this and transitions the project to the target milestone, resetting
110
+ * its slices to allow re-planning.
111
+ *
112
+ * Returns the extracted target milestone ID, or null if extraction failed.
113
+ */
114
+ export function executeBacktrack(basePath, currentMilestoneId, capture) {
115
+ try {
116
+ // Extract target milestone from capture text or resolution.
117
+ // Filter out the current milestone ID to avoid picking it as the backtrack target
118
+ // when the text mentions both current and target milestones (e.g. "backtrack from M004 to M003").
119
+ const sourceText = capture.resolution ?? capture.text;
120
+ const allMatches = [...sourceText.matchAll(/\b(M\d{3}(?:-[a-z0-9]{6})?)\b/g)]
121
+ .map(m => m[1])
122
+ .filter(id => id !== currentMilestoneId);
123
+ // Reject ambiguous multi-target strings — if more than one distinct target remains,
124
+ // don't guess; let the user clarify.
125
+ const uniqueTargets = [...new Set(allMatches)];
126
+ const targetMilestoneId = uniqueTargets.length === 1 ? uniqueTargets[0] : null;
127
+ const ts = new Date().toISOString();
128
+ const triggerPath = join(gsdRoot(basePath), "BACKTRACK-TRIGGER.md");
129
+ const content = [
130
+ `# Backtrack Trigger`,
131
+ ``,
132
+ `**Source:** Capture ${capture.id}`,
133
+ `**Capture:** ${capture.text}`,
134
+ `**Rationale:** ${capture.rationale ?? "User-initiated milestone backtrack"}`,
135
+ `**From:** ${currentMilestoneId}`,
136
+ `**Target:** ${targetMilestoneId ?? "(user to specify)"}`,
137
+ `**Triggered:** ${ts}`,
138
+ ``,
139
+ `Auto-mode was paused by this backtrack directive. The user directed`,
140
+ `that the current milestone (${currentMilestoneId}) be abandoned and work`,
141
+ `should return to ${targetMilestoneId ?? "a previous milestone"}.`,
142
+ ``,
143
+ `## Recovery Steps`,
144
+ ``,
145
+ `1. Review what went wrong in ${currentMilestoneId}`,
146
+ `2. Identify missing features/requirements from the target milestone`,
147
+ `3. Resume auto-mode — the state machine will re-enter discussion for the target`,
148
+ ].join("\n");
149
+ writeFileSync(triggerPath, content, "utf-8");
150
+ // If we have a valid target, also reset that milestone's completion status
151
+ // so deriveState() will re-enter it as the active milestone.
152
+ if (targetMilestoneId) {
153
+ try {
154
+ const targetDir = join(milestonesDir(basePath), targetMilestoneId);
155
+ if (existsSync(targetDir)) {
156
+ // Write a regression marker so the state machine knows this milestone
157
+ // needs re-discussion, not just re-execution
158
+ const regressionPath = join(targetDir, `${targetMilestoneId}-REGRESSION.md`);
159
+ writeFileSync(regressionPath, [
160
+ `# Milestone Regression`,
161
+ ``,
162
+ `**From:** ${currentMilestoneId}`,
163
+ `**Reason:** ${capture.text}`,
164
+ `**Triggered:** ${ts}`,
165
+ ``,
166
+ `This milestone is being revisited because downstream milestone`,
167
+ `${currentMilestoneId} failed or missed critical features that should`,
168
+ `have been part of this milestone's scope.`,
169
+ ``,
170
+ `The discuss phase should re-evaluate requirements and identify gaps.`,
171
+ ].join("\n"), "utf-8");
172
+ }
173
+ }
174
+ catch { /* best-effort */ }
175
+ }
176
+ return targetMilestoneId;
177
+ }
178
+ catch {
179
+ return null;
180
+ }
181
+ }
182
+ /**
183
+ * Read the backtrack trigger file if it exists.
184
+ * Returns the parsed target milestone and metadata, or null.
185
+ */
186
+ export function readBacktrackTrigger(basePath) {
187
+ const triggerPath = join(gsdRoot(basePath), "BACKTRACK-TRIGGER.md");
188
+ if (!existsSync(triggerPath))
189
+ return null;
190
+ try {
191
+ const content = readFileSync(triggerPath, "utf-8");
192
+ const target = content.match(/\*\*Target:\*\*\s*(.+)/)?.[1]?.trim() ?? null;
193
+ const from = content.match(/\*\*From:\*\*\s*(.+)/)?.[1]?.trim() ?? null;
194
+ const capture = content.match(/\*\*Capture:\*\*\s*(.+)/)?.[1]?.trim() ?? "";
195
+ const triggeredAt = content.match(/\*\*Triggered:\*\*\s*(.+)/)?.[1]?.trim() ?? "";
196
+ return {
197
+ target: target === "(user to specify)" ? null : target,
198
+ from,
199
+ capture,
200
+ triggeredAt,
201
+ };
202
+ }
203
+ catch {
204
+ return null;
205
+ }
206
+ }
207
+ /**
208
+ * Remove the backtrack trigger after it has been processed.
209
+ */
210
+ export function clearBacktrackTrigger(basePath) {
211
+ const triggerPath = join(gsdRoot(basePath), "BACKTRACK-TRIGGER.md");
212
+ try {
213
+ if (existsSync(triggerPath)) {
214
+ unlinkSync(triggerPath);
215
+ }
216
+ }
217
+ catch { /* best-effort */ }
218
+ }
102
219
  // ─── File Overlap Detection ───────────────────────────────────────────────────
103
220
  /**
104
221
  * Detect file overlap between a capture's affected files and planned tasks.
@@ -240,6 +357,8 @@ export function executeTriageResolutions(basePath, mid, sid) {
240
357
  replanned: 0,
241
358
  deferredMilestones: 0,
242
359
  quickTasks: [],
360
+ stopped: 0,
361
+ backtracks: [],
243
362
  actions: [],
244
363
  };
245
364
  const actionable = loadActionableCaptures(basePath, mid || undefined);
@@ -318,5 +437,20 @@ export function executeTriageResolutions(basePath, mid, sid) {
318
437
  }
319
438
  }
320
439
  }
440
+ // Count stop/backtrack captures — these are handled by the pre-dispatch guard
441
+ // in runGuards(), not here. We just report them for logging purposes.
442
+ const allCaptures = loadAllCaptures(basePath);
443
+ for (const cap of allCaptures) {
444
+ if (cap.status !== "resolved" || cap.executed)
445
+ continue;
446
+ if (cap.classification === "stop") {
447
+ result.stopped++;
448
+ result.actions.push(`Stop directive from ${cap.id}: "${cap.text}" — will pause on next dispatch`);
449
+ }
450
+ else if (cap.classification === "backtrack") {
451
+ result.backtracks.push(cap);
452
+ result.actions.push(`Backtrack directive from ${cap.id}: "${cap.text}" — will trigger milestone regression on next dispatch`);
453
+ }
454
+ }
321
455
  return result;
322
456
  }
@@ -33,9 +33,17 @@ const CLASSIFICATION_LABELS = {
33
33
  label: "Note",
34
34
  description: "Informational only — no action needed.",
35
35
  },
36
+ "stop": {
37
+ label: "Stop",
38
+ description: "Halt auto-mode immediately — user directive to cease execution.",
39
+ },
40
+ "backtrack": {
41
+ label: "Backtrack",
42
+ description: "Abandon current milestone and return to a previous one.",
43
+ },
36
44
  };
37
45
  const ALL_CLASSIFICATIONS = [
38
- "quick-task", "inject", "defer", "replan", "note",
46
+ "quick-task", "inject", "defer", "replan", "note", "stop", "backtrack",
39
47
  ];
40
48
  // ─── Public API ───────────────────────────────────────────────────────────────
41
49
  /**
@@ -57,8 +65,9 @@ export async function showTriageConfirmation(ctx, triageResults, captures, baseP
57
65
  const capture = captureMap.get(result.captureId);
58
66
  if (!capture)
59
67
  continue;
60
- // Auto-confirm note and defer — low-impact, no plan modification
61
- if (result.classification === "note" || result.classification === "defer") {
68
+ // Auto-confirm note, defer, stop, and backtrack — low-impact or urgent directives
69
+ if (result.classification === "note" || result.classification === "defer"
70
+ || result.classification === "stop" || result.classification === "backtrack") {
62
71
  const resolution = result.classification === "note"
63
72
  ? "acknowledged as note"
64
73
  : `deferred${result.targetSlice ? ` to ${result.targetSlice}` : ""}`;
@@ -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
  // ─── Session ID ───────────────────────────────────────────────────────────
6
7
  /**
7
8
  * Engine-generated session ID — stable for the lifetime of this process.
@@ -49,7 +50,7 @@ export function readEvents(logPath) {
49
50
  events.push(JSON.parse(line));
50
51
  }
51
52
  catch {
52
- process.stderr.write(`workflow-events: skipping corrupted event line: ${line.slice(0, 80)}\n`);
53
+ logWarning("event-log", `skipping corrupted event line (${line.length} bytes)`);
53
54
  }
54
55
  }
55
56
  return events;
@@ -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
@@ -177,12 +179,15 @@ function _push(severity, component, message, context) {
177
179
  if (_buffer.length > MAX_BUFFER) {
178
180
  _buffer.shift();
179
181
  }
180
- // Persist to .gsd/audit-log.jsonl so entries survive context resets
181
- if (_auditBasePath) {
182
+ // Persist errors to .gsd/audit-log.jsonl so they survive context resets.
183
+ // Only error-severity entries are persisted — warnings are ephemeral (stderr + buffer)
184
+ // to avoid log amplification from expected-control-flow catch paths.
185
+ if (_auditBasePath && severity === "error") {
182
186
  try {
183
187
  const auditDir = join(_auditBasePath, ".gsd");
184
188
  mkdirSync(auditDir, { recursive: true });
185
- appendFileSync(join(auditDir, "audit-log.jsonl"), JSON.stringify(entry) + "\n", "utf-8");
189
+ const sanitized = _sanitizeForAudit(entry);
190
+ appendFileSync(join(auditDir, "audit-log.jsonl"), JSON.stringify(sanitized) + "\n", "utf-8");
186
191
  }
187
192
  catch (auditErr) {
188
193
  // Best-effort — never let audit write failures bubble up
@@ -190,3 +195,31 @@ function _push(severity, component, message, context) {
190
195
  }
191
196
  }
192
197
  }
198
+ /**
199
+ * Sanitize a log entry before persisting to the audit JSONL file.
200
+ * Strips potentially sensitive context (raw paths, cwd, full error text)
201
+ * to avoid leaking local environment details into durable telemetry.
202
+ */
203
+ function _sanitizeForAudit(entry) {
204
+ const sanitized = {
205
+ ts: entry.ts,
206
+ severity: entry.severity,
207
+ component: entry.component,
208
+ // Truncate message to avoid persisting oversized raw error dumps
209
+ message: entry.message.length > 200 ? entry.message.slice(0, 200) + "…[truncated]" : entry.message,
210
+ };
211
+ if (entry.context) {
212
+ // Allowlist: only persist known-safe structured keys
213
+ const SAFE_KEYS = new Set(["fn", "tool", "mid", "sid", "tid", "worktree"]);
214
+ const filtered = {};
215
+ for (const [k, v] of Object.entries(entry.context)) {
216
+ if (SAFE_KEYS.has(k)) {
217
+ filtered[k] = v;
218
+ }
219
+ }
220
+ if (Object.keys(filtered).length > 0) {
221
+ sanitized.context = filtered;
222
+ }
223
+ }
224
+ return sanitized;
225
+ }
@@ -6,6 +6,7 @@ import { existsSync, readdirSync, readFileSync } from "node:fs";
6
6
  import { join } from "node:path";
7
7
  import { _getAdapter, transaction } from "./gsd-db.js";
8
8
  import { parseRoadmap, parsePlan } from "./parsers-legacy.js";
9
+ import { logWarning } from "./workflow-logger.js";
9
10
  // ─── needsAutoMigration ───────────────────────────────────────────────────
10
11
  /**
11
12
  * Returns true when engine tables are empty AND a .gsd/milestones/ directory
@@ -22,8 +23,8 @@ export function needsAutoMigration(basePath) {
22
23
  if (row && row["cnt"] > 0)
23
24
  return false;
24
25
  }
25
- catch {
26
- // Table might not exist yet — that's fine, we can still migrate
26
+ catch (e) {
27
+ logWarning("migration", `DB probe failed: ${e.message}`);
27
28
  return false;
28
29
  }
29
30
  // Check if .gsd/milestones/ directory exists
@@ -66,7 +67,7 @@ export function migrateFromMarkdown(basePath) {
66
67
  .map(e => e.name);
67
68
  }
68
69
  catch {
69
- process.stderr.write("workflow-migration: failed to read milestones directory\n");
70
+ logWarning("migration", "failed to read milestones directory");
70
71
  return;
71
72
  }
72
73
  if (milestoneDirs.length === 0) {
@@ -102,7 +103,7 @@ export function migrateFromMarkdown(basePath) {
102
103
  }));
103
104
  }
104
105
  catch (err) {
105
- process.stderr.write(`workflow-migration: failed to parse ROADMAP.md for ${mId}: ${err.message}\n`);
106
+ logWarning("migration", `failed to parse ROADMAP.md for ${mId}: ${err.message}`);
106
107
  // Still add milestone with ID as title
107
108
  milestoneInserts.push({ id: mId, title: mId, status: milestoneStatus });
108
109
  }
@@ -148,7 +149,7 @@ export function migrateFromMarkdown(basePath) {
148
149
  }
149
150
  }
150
151
  catch (err) {
151
- process.stderr.write(`workflow-migration: failed to parse ${slice.id}-PLAN.md for ${mId}: ${err.message}\n`);
152
+ logWarning("migration", `failed to parse ${slice.id}-PLAN.md for ${mId}: ${err.message}`);
152
153
  }
153
154
  }
154
155
  }
@@ -163,8 +164,8 @@ export function migrateFromMarkdown(basePath) {
163
164
  }
164
165
  }
165
166
  }
166
- catch {
167
- // Non-fatal
167
+ catch (e) {
168
+ logWarning("migration", `Orphaned summary check failed for ${mId}: ${e.message}`);
168
169
  }
169
170
  }
170
171
  // Execute all inserts atomically
@@ -245,19 +246,20 @@ export function validateMigration(basePath) {
245
246
  const plan = parsePlan(planContent);
246
247
  mdTaskCount += plan.tasks.length;
247
248
  }
248
- catch {
249
- // Skip unreadable plan
249
+ catch (e) {
250
+ logWarning("migration", `Failed to read plan ${slice.id}-PLAN.md: ${e.message}`);
250
251
  }
251
252
  }
252
253
  }
253
254
  }
254
- catch {
255
- // Skip unreadable roadmap
255
+ catch (e) {
256
+ logWarning("migration", `Failed to read roadmap for ${mId}: ${e.message}`);
256
257
  }
257
258
  }
258
259
  }
259
260
  }
260
- catch {
261
+ catch (e) {
262
+ logWarning("migration", `Validation failed to read markdown: ${e.message}`);
261
263
  return { discrepancies: ["Failed to read markdown for validation"] };
262
264
  }
263
265
  // Compare counts
@@ -371,7 +371,7 @@ export function regenerateIfMissing(basePath, milestoneId, sliceId, fileType) {
371
371
  regenerated++;
372
372
  }
373
373
  catch (err) {
374
- console.error(`[projections] regenerateIfMissing SUMMARY failed for ${task.id}:`, err);
374
+ logWarning("projection", `regenerateIfMissing SUMMARY failed for ${task.id}: ${err.message}`);
375
375
  }
376
376
  }
377
377
  }
@@ -399,7 +399,7 @@ export function regenerateIfMissing(basePath, milestoneId, sliceId, fileType) {
399
399
  return true;
400
400
  }
401
401
  catch (err) {
402
- console.error(`[projections] regenerateIfMissing ${fileType} failed:`, err);
402
+ logWarning("projection", `regenerateIfMissing ${fileType} failed: ${err.message}`);
403
403
  return false;
404
404
  }
405
405
  }
@@ -375,8 +375,8 @@ function parseEventBlock(block) {
375
375
  try {
376
376
  params = JSON.parse(paramsMatch[1]);
377
377
  }
378
- catch {
379
- // Keep empty params on parse error
378
+ catch (e) {
379
+ logWarning("reconcile", `tool call params parse failed: ${e.message}`);
380
380
  }
381
381
  i++; // consume params line
382
382
  }
@@ -51,8 +51,8 @@ export function resolveGitDir(basePath) {
51
51
  return resolve(basePath, content.slice(8));
52
52
  }
53
53
  }
54
- catch {
55
- // Not a file or unreadable — fall through to default
54
+ catch (e) {
55
+ logWarning("worktree", `.git file read failed: ${e.message}`);
56
56
  }
57
57
  return join(basePath, ".git");
58
58
  }
@@ -232,8 +232,9 @@ export function findNestedGitDirs(rootPath) {
232
232
  try {
233
233
  entries = readdirSync(dir);
234
234
  }
235
- catch {
236
- return; // Permission denied, broken symlink, etc.
235
+ catch (e) {
236
+ logWarning("worktree", `readdirSync failed: ${e.message}`);
237
+ return;
237
238
  }
238
239
  for (const entry of entries) {
239
240
  if (NESTED_GIT_SKIP_DIRS.has(entry))
@@ -244,7 +245,8 @@ export function findNestedGitDirs(rootPath) {
244
245
  try {
245
246
  stat = lstatSync(fullPath);
246
247
  }
247
- catch {
248
+ catch (e) {
249
+ logWarning("worktree", `lstatSync failed for ${fullPath}: ${e.message}`);
248
250
  continue;
249
251
  }
250
252
  if (!stat.isDirectory())
@@ -261,8 +263,8 @@ export function findNestedGitDirs(rootPath) {
261
263
  continue;
262
264
  }
263
265
  }
264
- catch {
265
- // No .git here continue scanning
266
+ catch (e) {
267
+ logWarning("worktree", `existsSync/.git check failed for ${fullPath}: ${e.message}`);
266
268
  }
267
269
  walk(fullPath, depth + 1);
268
270
  }
@@ -291,7 +293,9 @@ export function removeWorktree(basePath, name, opts = {}) {
291
293
  wtPath = entry.path;
292
294
  }
293
295
  }
294
- catch { /* fall back to computed path */ }
296
+ catch (e) {
297
+ logWarning("worktree", `nativeWorktreeList parse failed: ${e.message}`);
298
+ }
295
299
  const resolvedWtPath = existsSync(wtPath) ? realpathSync(wtPath) : wtPath;
296
300
  // If we're inside the worktree, move out first — git can't remove an in-use directory
297
301
  const cwd = process.cwd();
@@ -305,7 +309,9 @@ export function removeWorktree(basePath, name, opts = {}) {
305
309
  try {
306
310
  nativeBranchDelete(basePath, branch, true);
307
311
  }
308
- catch { /* branch may not exist */ }
312
+ catch (e) {
313
+ logWarning("worktree", `nativeBranchDelete failed: ${e.message}`);
314
+ }
309
315
  }
310
316
  return;
311
317
  }
@@ -332,8 +338,8 @@ export function removeWorktree(basePath, name, opts = {}) {
332
338
  }
333
339
  }
334
340
  }
335
- catch {
336
- // submodule status failed — proceed with normal removal
341
+ catch (e) {
342
+ logWarning("worktree", `submodule status check failed: ${e.message}`);
337
343
  }
338
344
  }
339
345
  // Nested .git safety (#2616): detect nested .git directories created by
@@ -360,13 +366,17 @@ export function removeWorktree(basePath, name, opts = {}) {
360
366
  try {
361
367
  nativeWorktreeRemove(basePath, resolvedWtPath, useForce);
362
368
  }
363
- catch { /* may fail */ }
369
+ catch (e) {
370
+ logWarning("worktree", `nativeWorktreeRemove failed: ${e.message}`);
371
+ }
364
372
  // If the directory is still there (e.g. locked), try harder with force
365
373
  if (existsSync(resolvedWtPath)) {
366
374
  try {
367
375
  nativeWorktreeRemove(basePath, resolvedWtPath, true);
368
376
  }
369
- catch { /* may fail */ }
377
+ catch (e) {
378
+ logWarning("worktree", `nativeWorktreeRemove (force) failed: ${e.message}`);
379
+ }
370
380
  }
371
381
  // (#2821) If the worktree directory STILL exists after both native removal
372
382
  // attempts (e.g. untracked files like ASSESSMENT/UAT-RESULT prevent git
@@ -393,7 +403,9 @@ export function removeWorktree(basePath, name, opts = {}) {
393
403
  try {
394
404
  nativeBranchDelete(basePath, branch, true);
395
405
  }
396
- catch { /* branch may not exist */ }
406
+ catch (e) {
407
+ logWarning("worktree", `final branch delete failed: ${e.message}`);
408
+ }
397
409
  }
398
410
  }
399
411
  /** Paths to skip in all worktree diffs (internal/runtime artifacts). */
@@ -202,7 +202,9 @@ export async function showInterviewRound(questions, opts, ctx) {
202
202
  // Auto-open the notes field when "None of the above" is selected
203
203
  // so the user can immediately provide a free-text explanation
204
204
  // instead of being trapped in a re-asking loop (bug #2715).
205
- if (!isMultiSelect(currentIdx) && states[currentIdx].cursorIndex === noneOrDoneIdx(currentIdx)) {
205
+ // Only auto-open if the user hasn't already provided notes —
206
+ // otherwise Enter from notes mode loops back here endlessly.
207
+ if (!isMultiSelect(currentIdx) && states[currentIdx].cursorIndex === noneOrDoneIdx(currentIdx) && !states[currentIdx].notes) {
206
208
  states[currentIdx].notesVisible = true;
207
209
  focusNotes = true;
208
210
  loadStateToEditor();
@@ -0,0 +1,42 @@
1
+ ---
2
+ name: btw
3
+ description: Ask a quick side question about your current work without derailing the main task. Answers from existing conversation context only — no tool calls, no file reads, single concise response. Use when you need a fast answer from what is already in this session.
4
+ ---
5
+
6
+ <objective>
7
+ Answer a quick side question using only what is already present in the current conversation context. Do not read files, run commands, search, or use any tools. Give a single, concise response and return focus to the main work.
8
+ </objective>
9
+
10
+ <behavior>
11
+ **This is a side question, not a task.**
12
+
13
+ - Answer only from information already in the conversation (files read, decisions made, code seen, context established)
14
+ - Do NOT use any tools — no Read, no Bash, no Grep, no Search
15
+ - If the answer requires reading something new, say so briefly and suggest the user ask as a normal prompt instead
16
+ - Keep the response short and direct — one to a few sentences unless the question genuinely needs more
17
+ - Do not summarize the main work, ask follow-up questions, or offer to do anything else
18
+ - After answering, stop — do not prompt for next steps
19
+ </behavior>
20
+
21
+ <quick_start>
22
+ Parse the argument after `/btw` as the question. Answer it directly from context.
23
+
24
+ If no argument is provided, ask: "What did you want to know?"
25
+
26
+ If the question cannot be answered from current context (requires reading a file, running a command, or information not yet in the session), respond with:
27
+ "I'd need to [read X / run Y / look up Z] to answer that — ask it as a normal prompt when you're ready."
28
+ </quick_start>
29
+
30
+ <examples>
31
+ **Good uses of /btw:**
32
+ - `/btw what was the name of that config file again?` → answers from files already read in session
33
+ - `/btw which branch are we on?` → answers from git context already established
34
+ - `/btw did we already handle the null case in that function?` → answers from code already reviewed
35
+ - `/btw what model does this use?` → answers from code or config already in context
36
+
37
+ **Not a good fit for /btw (suggest normal prompt):**
38
+ - Questions requiring reading a file not yet seen
39
+ - Questions requiring running a command
40
+ - Questions needing a multi-step answer or follow-up
41
+ - Starting a new task or changing direction
42
+ </examples>
@@ -1 +1 @@
1
- DGvT_c5Vb7Wu3X-fEOVUU
1
+ ogyMN7M-3bGGuRY08L5HR