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
@@ -5,26 +5,32 @@
5
5
  * Subcommands: generate, update, stats, help
6
6
  */
7
7
  import { generateCodebaseMap, updateCodebaseMap, writeCodebaseMap, getCodebaseMapStats, readCodebaseMap, } from "./codebase-generator.js";
8
+ import { loadEffectiveGSDPreferences } from "./preferences.js";
8
9
  const USAGE = "Usage: /gsd codebase [generate|update|stats]\n\n" +
9
- " generate [--max-files N] — Generate or regenerate CODEBASE.md\n" +
10
- " update — Incremental update (preserves descriptions)\n" +
11
- " stats — Show file count, coverage, and generation time\n" +
12
- " help — Show this help\n\n" +
13
- "With no subcommand, shows stats if a map exists or help if not.";
10
+ " generate [--max-files N] [--collapse-threshold N] — Generate or regenerate CODEBASE.md\n" +
11
+ " update [--max-files N] [--collapse-threshold N] — Incremental update (preserves descriptions)\n" +
12
+ " stats — Show file count, coverage, and generation time\n" +
13
+ " help — Show this help\n\n" +
14
+ "With no subcommand, shows stats if a map exists or help if not.\n\n" +
15
+ "Configure defaults via preferences.md:\n" +
16
+ " codebase:\n" +
17
+ " exclude_patterns: [\"docs/\", \"fixtures/\"]\n" +
18
+ " max_files: 1000\n" +
19
+ " collapse_threshold: 15";
14
20
  export async function handleCodebase(args, ctx, _pi) {
15
21
  const basePath = process.cwd();
16
22
  const parts = args.trim().split(/\s+/);
17
23
  const sub = parts[0] ?? "";
18
24
  switch (sub) {
19
25
  case "generate": {
20
- const maxFiles = parseMaxFiles(args, ctx);
21
- if (maxFiles === false)
26
+ const options = resolveCodebaseOptions(args, ctx);
27
+ if (options === false)
22
28
  return; // validation failed, message already shown
23
29
  const existing = readCodebaseMap(basePath);
24
30
  const existingDescriptions = existing
25
31
  ? (await import("./codebase-generator.js")).parseCodebaseMap(existing)
26
32
  : undefined;
27
- const result = generateCodebaseMap(basePath, { maxFiles: maxFiles ?? undefined }, existingDescriptions);
33
+ const result = generateCodebaseMap(basePath, options, existingDescriptions);
28
34
  if (result.fileCount === 0) {
29
35
  ctx.ui.notify("Codebase map generated with 0 files.\n" +
30
36
  "Is this a git repository? Run 'git ls-files' to verify.", "warning");
@@ -42,10 +48,10 @@ export async function handleCodebase(args, ctx, _pi) {
42
48
  ctx.ui.notify("No codebase map found. Run /gsd codebase generate to create one.", "warning");
43
49
  return;
44
50
  }
45
- const maxFiles = parseMaxFiles(args, ctx);
46
- if (maxFiles === false)
51
+ const options = resolveCodebaseOptions(args, ctx);
52
+ if (options === false)
47
53
  return;
48
- const result = updateCodebaseMap(basePath, { maxFiles: maxFiles ?? undefined });
54
+ const result = updateCodebaseMap(basePath, options);
49
55
  writeCodebaseMap(basePath, result.content);
50
56
  ctx.ui.notify(`Codebase map updated: ${result.fileCount} files\n` +
51
57
  ` Added: ${result.added} | Removed: ${result.removed} | Unchanged: ${result.unchanged}` +
@@ -93,19 +99,40 @@ function showStats(basePath, ctx) {
93
99
  : `Coverage is complete.`), "info");
94
100
  }
95
101
  /**
96
- * Parse and validate --max-files flag.
97
- * Returns the parsed number, undefined if flag not present, or false if invalid.
102
+ * Resolve codebase map options by merging preferences with CLI flags.
103
+ * CLI flags override preferences; preferences override built-in defaults.
104
+ * Returns false if validation failed (error already shown to user).
98
105
  */
99
- function parseMaxFiles(args, ctx) {
106
+ function resolveCodebaseOptions(args, ctx) {
107
+ // Load preferences defaults
108
+ const prefs = loadEffectiveGSDPreferences()?.preferences?.codebase;
109
+ // Parse CLI flags
100
110
  const maxFilesStr = extractFlag(args, "--max-files");
101
- if (!maxFilesStr)
102
- return undefined;
103
- const maxFiles = parseInt(maxFilesStr, 10);
104
- if (isNaN(maxFiles) || maxFiles < 1) {
105
- ctx.ui.notify("--max-files must be a positive integer (e.g. --max-files 200).", "warning");
106
- return false;
111
+ const collapseStr = extractFlag(args, "--collapse-threshold");
112
+ // Validate --max-files
113
+ let maxFiles;
114
+ if (maxFilesStr) {
115
+ maxFiles = parseInt(maxFilesStr, 10);
116
+ if (isNaN(maxFiles) || maxFiles < 1) {
117
+ ctx.ui.notify("--max-files must be a positive integer (e.g. --max-files 200).", "warning");
118
+ return false;
119
+ }
120
+ }
121
+ // Validate --collapse-threshold
122
+ let collapseThreshold;
123
+ if (collapseStr) {
124
+ collapseThreshold = parseInt(collapseStr, 10);
125
+ if (isNaN(collapseThreshold) || collapseThreshold < 1) {
126
+ ctx.ui.notify("--collapse-threshold must be a positive integer (e.g. --collapse-threshold 15).", "warning");
127
+ return false;
128
+ }
107
129
  }
108
- return maxFiles;
130
+ return {
131
+ // CLI flags override preferences
132
+ maxFiles: maxFiles ?? prefs?.max_files,
133
+ collapseThreshold: collapseThreshold ?? prefs?.collapse_threshold,
134
+ excludePatterns: prefs?.exclude_patterns,
135
+ };
109
136
  }
110
137
  function extractFlag(args, flag) {
111
138
  const escaped = flag.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
@@ -6,6 +6,7 @@
6
6
  import { existsSync } from "node:fs";
7
7
  import { join } from "node:path";
8
8
  import { gsdRoot } from "./paths.js";
9
+ import { logWarning } from "./workflow-logger.js";
9
10
  import { getErrorMessage } from "./error-utils.js";
10
11
  export function formatInspectOutput(data) {
11
12
  const lines = [];
@@ -71,7 +72,7 @@ export async function handleInspect(ctx) {
71
72
  ctx.ui.notify(formatInspectOutput(data), "info");
72
73
  }
73
74
  catch (err) {
74
- process.stderr.write(`gsd-db: /gsd inspect failed: ${getErrorMessage(err)}\n`);
75
+ logWarning("command", `/gsd inspect failed: ${getErrorMessage(err)}`);
75
76
  ctx.ui.notify("Failed to inspect GSD database. Check stderr for details.", "error");
76
77
  }
77
78
  }
@@ -5,12 +5,14 @@
5
5
  */
6
6
  import { deriveState } from "./state.js";
7
7
  import { nativeBranchList, nativeDetectMainBranch, nativeBranchListMerged, nativeBranchDelete, nativeForEachRef, nativeUpdateRef } from "./native-git-bridge.js";
8
+ import { logWarning } from "./workflow-logger.js";
8
9
  export async function handleCleanupBranches(ctx, basePath) {
9
10
  let branches;
10
11
  try {
11
12
  branches = nativeBranchList(basePath, "gsd/*");
12
13
  }
13
- catch {
14
+ catch (e) {
15
+ logWarning("command", `branch list failed: ${e.message}`);
14
16
  ctx.ui.notify("No GSD branches to clean up.", "info");
15
17
  return;
16
18
  }
@@ -20,7 +22,8 @@ export async function handleCleanupBranches(ctx, basePath) {
20
22
  try {
21
23
  merged = nativeBranchListMerged(basePath, mainBranch, "gsd/*");
22
24
  }
23
- catch {
25
+ catch (e) {
26
+ logWarning("command", `merged branch list failed: ${e.message}`);
24
27
  merged = [];
25
28
  }
26
29
  const mergedNonQuick = merged.filter((b) => !b.startsWith("gsd/quick/"));
@@ -30,8 +33,8 @@ export async function handleCleanupBranches(ctx, basePath) {
30
33
  nativeBranchDelete(basePath, branch, false);
31
34
  deletedMerged++;
32
35
  }
33
- catch {
34
- /* skip branches that cannot be deleted */
36
+ catch (e) {
37
+ logWarning("command", `branch delete failed for ${branch}: ${e.message}`);
35
38
  }
36
39
  }
37
40
  // Also delete stale milestone branches for completed milestones when detached
@@ -61,7 +64,9 @@ export async function handleCleanupBranches(ctx, basePath) {
61
64
  nativeBranchDelete(basePath, branch, true);
62
65
  deletedStaleMilestones++;
63
66
  }
64
- catch { /* non-fatal */ }
67
+ catch (e) {
68
+ logWarning("command", `stale milestone branch delete failed for ${branch}: ${e.message}`);
69
+ }
65
70
  continue;
66
71
  }
67
72
  }
@@ -73,7 +78,8 @@ export async function handleCleanupBranches(ctx, basePath) {
73
78
  try {
74
79
  roadmapContent = await loadFile(roadmapPath);
75
80
  }
76
- catch {
81
+ catch (e) {
82
+ logWarning("command", `loadFile failed for ${roadmapPath}: ${e.message}`);
77
83
  roadmapContent = null;
78
84
  }
79
85
  if (!roadmapContent)
@@ -84,13 +90,13 @@ export async function handleCleanupBranches(ctx, basePath) {
84
90
  nativeBranchDelete(basePath, branch, true);
85
91
  deletedStaleMilestones++;
86
92
  }
87
- catch {
88
- /* non-fatal */
93
+ catch (e) {
94
+ logWarning("command", `milestone branch delete failed for ${branch}: ${e.message}`);
89
95
  }
90
96
  }
91
97
  }
92
- catch {
93
- /* non-fatal */
98
+ catch (e) {
99
+ logWarning("command", `stale milestone cleanup failed: ${e.message}`);
94
100
  }
95
101
  const summary = [];
96
102
  if (deletedMerged > 0) {
@@ -116,7 +122,8 @@ export async function handleCleanupSnapshots(ctx, basePath) {
116
122
  try {
117
123
  refs = nativeForEachRef(basePath, "refs/gsd/snapshots/");
118
124
  }
119
- catch {
125
+ catch (e) {
126
+ logWarning("command", `snapshot ref list failed: ${e.message}`);
120
127
  ctx.ui.notify("No snapshot refs to clean up.", "info");
121
128
  return;
122
129
  }
@@ -140,8 +147,8 @@ export async function handleCleanupSnapshots(ctx, basePath) {
140
147
  nativeUpdateRef(basePath, old);
141
148
  pruned++;
142
149
  }
143
- catch {
144
- /* skip individual failures */
150
+ catch (e) {
151
+ logWarning("command", `snapshot ref update failed for ${old}: ${e.message}`);
145
152
  }
146
153
  }
147
154
  }
@@ -155,7 +162,8 @@ export async function handleCleanupWorktrees(ctx, basePath) {
155
162
  try {
156
163
  statuses = getAllWorktreeHealth(basePath);
157
164
  }
158
- catch {
165
+ catch (e) {
166
+ logWarning("command", `worktree health inspection failed: ${e.message}`);
159
167
  ctx.ui.notify("Failed to inspect worktrees.", "error");
160
168
  return;
161
169
  }
@@ -185,7 +193,8 @@ export async function handleCleanupWorktrees(ctx, basePath) {
185
193
  lines.push(` ✓ ${wt.name} removed (branch ${wt.branch} deleted)`);
186
194
  removed++;
187
195
  }
188
- catch {
196
+ catch (e) {
197
+ logWarning("command", `worktree removal failed for ${wt.name}: ${e.message}`);
189
198
  lines.push(` ✗ ${wt.name} failed to remove`);
190
199
  }
191
200
  }
@@ -228,7 +237,9 @@ export async function handleSkip(unitArg, ctx, basePath) {
228
237
  keys = JSON.parse(readFile(completedKeysFile, "utf-8"));
229
238
  }
230
239
  }
231
- catch { /* start fresh */ }
240
+ catch (e) {
241
+ logWarning("command", `completed-units.json parse failed: ${e.message}`);
242
+ }
232
243
  // Normalize: accept "execute-task/M001/S01/T03", "M001/S01/T03", or just "T03"
233
244
  let skipKey = unitArg;
234
245
  if (!skipKey.includes("execute-task") && !skipKey.includes("plan-") && !skipKey.includes("research-") && !skipKey.includes("complete-")) {
@@ -339,7 +350,8 @@ export async function handleCleanupProjects(args, ctx) {
339
350
  .filter(e => e.isDirectory())
340
351
  .map(e => e.name);
341
352
  }
342
- catch {
353
+ catch (e) {
354
+ logWarning("command", `readdir failed for project-state directory: ${e.message}`);
343
355
  ctx.ui.notify(`Failed to read project-state directory at ${projectsDir}.`, "error");
344
356
  return;
345
357
  }
@@ -413,7 +425,8 @@ export async function handleCleanupProjects(args, ctx) {
413
425
  fsRmSync(pathJoin(projectsDir, e.hash), { recursive: true, force: true });
414
426
  removed++;
415
427
  }
416
- catch {
428
+ catch (err) {
429
+ logWarning("command", `project cleanup rm failed for ${e.hash}: ${err.message}`);
417
430
  failed.push(e.hash);
418
431
  }
419
432
  }
@@ -479,7 +492,7 @@ export async function handleRecover(ctx, basePath) {
479
492
  }
480
493
  catch (err) {
481
494
  const msg = err instanceof Error ? err.message : String(err);
482
- process.stderr.write(`gsd-recover: failed: ${msg}\n`);
495
+ logWarning("command", `recover failed: ${msg}`);
483
496
  ctx.ui.notify(`gsd recover failed: ${msg}`, "error");
484
497
  }
485
498
  }
@@ -38,15 +38,18 @@ const UNIT_TYPE_TIERS = {
38
38
  export function classifyUnitComplexity(unitType, unitId, basePath, budgetPct, metadata) {
39
39
  // Hook units default to light
40
40
  if (unitType.startsWith("hook/")) {
41
- const result = { tier: "light", reason: "hook unit", downgraded: false };
41
+ const result = { tier: "light", reason: "hook unit", downgraded: false, taskMetadata: undefined };
42
42
  return applyBudgetPressure(result, budgetPct);
43
43
  }
44
44
  // Start with the default tier for this unit type
45
45
  let tier = UNIT_TYPE_TIERS[unitType] ?? "standard";
46
46
  let reason = `unit type: ${unitType}`;
47
+ let taskMeta;
47
48
  // For execute-task, analyze task metadata for complexity signals
48
49
  if (unitType === "execute-task") {
49
- const taskAnalysis = analyzeTaskComplexity(unitId, basePath, metadata);
50
+ // Extract metadata once and reuse throughout to avoid double-extraction
51
+ taskMeta = metadata ?? extractTaskMetadata(unitId, basePath);
52
+ const taskAnalysis = analyzeTaskComplexity(unitId, basePath, taskMeta);
50
53
  tier = taskAnalysis.tier;
51
54
  reason = taskAnalysis.reason;
52
55
  }
@@ -59,13 +62,14 @@ export function classifyUnitComplexity(unitType, unitId, basePath, budgetPct, me
59
62
  }
60
63
  }
61
64
  // Adaptive learning: check if history suggests bumping the tier
62
- const tags = metadata?.tags ?? extractTaskMetadata(unitId, basePath).tags;
65
+ // Use already-extracted taskMeta.tags if available to avoid double-extraction
66
+ const tags = taskMeta?.tags ?? metadata?.tags;
63
67
  const adaptiveAdjustment = getAdaptiveTierAdjustment(unitType, tier, tags);
64
68
  if (adaptiveAdjustment && tierOrdinal(adaptiveAdjustment) > tierOrdinal(tier)) {
65
69
  reason = `${reason} (adaptive: high failure rate at ${tier})`;
66
70
  tier = adaptiveAdjustment;
67
71
  }
68
- const result = { tier, reason, downgraded: false };
72
+ const result = { tier, reason, downgraded: false, taskMetadata: taskMeta };
69
73
  return applyBudgetPressure(result, budgetPct);
70
74
  }
71
75
  /**
@@ -149,7 +153,7 @@ function analyzePlanComplexity(unitId, basePath) {
149
153
  /**
150
154
  * Extract task metadata from the task plan file on disk.
151
155
  */
152
- function extractTaskMetadata(unitId, basePath) {
156
+ export function extractTaskMetadata(unitId, basePath) {
153
157
  const meta = {};
154
158
  const { milestone: mid, slice: sid, task: tid } = parseUnitId(unitId);
155
159
  if (!mid || !sid || !tid)
@@ -0,0 +1,68 @@
1
+ /**
2
+ * Observation masking for GSD auto-mode sessions.
3
+ *
4
+ * Replaces tool result content older than N turns with a placeholder.
5
+ * Reduces context bloat between compactions with zero LLM overhead.
6
+ * Preserves message ordering, roles, and all assistant/user messages.
7
+ *
8
+ * Operates on the pi-ai Message[] format (post-convertToLlm, pre-provider):
9
+ * - toolResult messages: { role: "toolResult", content: TextContent[] }
10
+ * - bash results are already converted to: { role: "user", content: [{type:"text",text:"..."}] }
11
+ * and start with "Ran `" from bashExecutionToText.
12
+ */
13
+ const MASK_PLACEHOLDER = "[result masked — within summarized history]";
14
+ const MASK_CONTENT_BLOCK = [{ type: "text", text: MASK_PLACEHOLDER }];
15
+ function findTurnBoundary(messages, keepRecentTurns) {
16
+ let turnsSeen = 0;
17
+ for (let i = messages.length - 1; i >= 0; i--) {
18
+ const m = messages[i];
19
+ // In the LLM payload, genuine user turns have role "user".
20
+ // Tool results have role "toolResult" and are excluded by this check.
21
+ if (m.role === "user") {
22
+ // Skip bash-result user messages (converted from bashExecution) — these aren't real user turns
23
+ if (isBashResultUserMessage(m))
24
+ continue;
25
+ turnsSeen++;
26
+ if (turnsSeen >= keepRecentTurns)
27
+ return i;
28
+ }
29
+ }
30
+ return 0;
31
+ }
32
+ /**
33
+ * Detect user messages that originated from bashExecution.
34
+ * After convertToLlm, these are {role: "user", content: [{type:"text", text:"Ran `cmd`\n..."}]}.
35
+ * The bashExecutionToText format always starts with "Ran `".
36
+ */
37
+ function isBashResultUserMessage(m) {
38
+ if (m.role !== "user" || !Array.isArray(m.content))
39
+ return false;
40
+ const first = m.content[0];
41
+ return first && typeof first === "object" && "text" in first &&
42
+ typeof first.text === "string" && first.text.startsWith("Ran `");
43
+ }
44
+ function isMaskableMessage(m) {
45
+ // Tool result messages (role: "toolResult" in pi-ai format)
46
+ if (m.role === "toolResult")
47
+ return true;
48
+ // Bash-result user messages (converted from bashExecution by convertToLlm)
49
+ if (isBashResultUserMessage(m))
50
+ return true;
51
+ return false;
52
+ }
53
+ export function createObservationMask(keepRecentTurns = 8) {
54
+ return (messages) => {
55
+ const boundary = findTurnBoundary(messages, keepRecentTurns);
56
+ if (boundary === 0)
57
+ return messages;
58
+ return messages.map((m, i) => {
59
+ if (i >= boundary)
60
+ return m;
61
+ if (isMaskableMessage(m)) {
62
+ // Content may be string or array of content blocks — always replace with array
63
+ return { ...m, content: MASK_CONTENT_BLOCK };
64
+ }
65
+ return m;
66
+ });
67
+ };
68
+ }
@@ -16,6 +16,7 @@
16
16
  * - content-heuristic logs the specific failure (missing file, below minSize, pattern mismatch).
17
17
  * - The frozen DEFINITION.yaml on disk is the single source of truth for step policies.
18
18
  */
19
+ import { logWarning } from "./workflow-logger.js";
19
20
  import { readFileSync, existsSync, statSync } from "node:fs";
20
21
  import { resolve, sep } from "node:path";
21
22
  import { spawnSync } from "node:child_process";
@@ -105,8 +106,8 @@ function handleContentHeuristic(runDir, step, verify) {
105
106
  return "pause";
106
107
  }
107
108
  }
108
- catch {
109
- // Invalid regex at runtime — treat as verification failure
109
+ catch (e) {
110
+ logWarning("engine", `content-heuristic regex failed: ${e.message}`);
110
111
  return "pause";
111
112
  }
112
113
  }
@@ -189,6 +189,13 @@ Setting `prefer_skills: []` does **not** disable skill discovery — it just mea
189
189
  - `budget_pressure`: boolean — downgrade model tier when budget is under pressure. Default: `true`.
190
190
  - `cross_provider`: boolean — allow routing across different providers. Default: `true`.
191
191
  - `hooks`: boolean — enable routing hooks. Default: `true`.
192
+ - `capability_routing`: boolean — enable capability-profile scoring for model selection within a tier. Requires `enabled: true`. Default: `false`.
193
+
194
+ - `context_management`: configures context hygiene for auto-mode sessions. Keys:
195
+ - `observation_masking`: boolean — mask old tool results to reduce context bloat. Default: `true`.
196
+ - `observation_mask_turns`: number — keep this many recent turns verbatim (1-50). Default: `8`.
197
+ - `compaction_threshold_percent`: number — trigger compaction at this % of context window (0.5-0.95). Lower values fire compaction earlier, reducing drift. Default: `0.70`.
198
+ - `tool_result_max_chars`: number — max chars per tool result in GSD sessions (200-10000). Default: `800`.
192
199
 
193
200
  - `auto_visualize`: boolean — show a visualizer hint after each milestone completion in auto-mode. Default: `false`.
194
201
 
@@ -8,7 +8,7 @@ import { createRequire } from "node:module";
8
8
  import { existsSync, copyFileSync, mkdirSync, realpathSync } from "node:fs";
9
9
  import { dirname } from "node:path";
10
10
  import { GSDError, GSD_STALE_STATE } from "./errors.js";
11
- import { logError } from "./workflow-logger.js";
11
+ import { logError, logWarning } from "./workflow-logger.js";
12
12
  const _require = createRequire(import.meta.url);
13
13
  let providerName = null;
14
14
  let providerModule = null;
@@ -710,7 +710,9 @@ export function openDatabase(path) {
710
710
  try {
711
711
  adapter.close();
712
712
  }
713
- catch { /* swallow */ }
713
+ catch (e) {
714
+ logWarning("db", `close after VACUUM failed: ${e.message}`);
715
+ }
714
716
  throw retryErr;
715
717
  }
716
718
  }
@@ -718,7 +720,9 @@ export function openDatabase(path) {
718
720
  try {
719
721
  adapter.close();
720
722
  }
721
- catch { /* swallow */ }
723
+ catch (e) {
724
+ logWarning("db", `close after VACUUM failed: ${e.message}`);
725
+ }
722
726
  throw err;
723
727
  }
724
728
  }
@@ -730,7 +734,9 @@ export function openDatabase(path) {
730
734
  process.on("exit", () => { try {
731
735
  closeDatabase();
732
736
  }
733
- catch { } });
737
+ catch (e) {
738
+ logWarning("db", `exit handler close failed: ${e.message}`);
739
+ } });
734
740
  }
735
741
  return true;
736
742
  }
@@ -739,17 +745,21 @@ export function closeDatabase() {
739
745
  try {
740
746
  currentDb.exec('PRAGMA wal_checkpoint(TRUNCATE)');
741
747
  }
742
- catch { /* non-fatal — best effort before close */ }
748
+ catch (e) {
749
+ logWarning("db", `WAL checkpoint failed: ${e.message}`);
750
+ }
743
751
  try {
744
752
  // Incremental vacuum to reclaim space without blocking
745
753
  currentDb.exec('PRAGMA incremental_vacuum(64)');
746
754
  }
747
- catch { /* non-fatal */ }
755
+ catch (e) {
756
+ logWarning("db", `incremental vacuum failed: ${e.message}`);
757
+ }
748
758
  try {
749
759
  currentDb.close();
750
760
  }
751
- catch {
752
- // swallow close errors
761
+ catch (e) {
762
+ logWarning("db", `database close failed: ${e.message}`);
753
763
  }
754
764
  currentDb = null;
755
765
  currentPath = null;
@@ -763,7 +773,9 @@ export function vacuumDatabase() {
763
773
  try {
764
774
  currentDb.exec('VACUUM');
765
775
  }
766
- catch { /* non-fatal */ }
776
+ catch (e) {
777
+ logWarning("db", `VACUUM failed: ${e.message}`);
778
+ }
767
779
  }
768
780
  let _txDepth = 0;
769
781
  export function transaction(fn) {
@@ -961,7 +973,9 @@ export function clearArtifacts() {
961
973
  try {
962
974
  currentDb.exec("DELETE FROM artifacts");
963
975
  }
964
- catch { /* cache clear is best effort */ }
976
+ catch (e) {
977
+ logWarning("db", `clearArtifacts failed: ${e.message}`);
978
+ }
965
979
  }
966
980
  export function insertArtifact(a) {
967
981
  if (!currentDb)
@@ -1374,11 +1388,11 @@ export function getActiveSliceFromDb(milestoneId) {
1374
1388
  // Uses json_each() to expand the JSON depends array and checks each dep is complete.
1375
1389
  const row = currentDb.prepare(`SELECT s.* FROM slices s
1376
1390
  WHERE s.milestone_id = :mid
1377
- AND s.status NOT IN ('complete', 'done')
1391
+ AND s.status NOT IN ('complete', 'done', 'skipped')
1378
1392
  AND NOT EXISTS (
1379
1393
  SELECT 1 FROM json_each(s.depends) AS dep
1380
1394
  WHERE dep.value NOT IN (
1381
- SELECT id FROM slices WHERE milestone_id = :mid AND status IN ('complete', 'done')
1395
+ SELECT id FROM slices WHERE milestone_id = :mid AND status IN ('complete', 'done', 'skipped')
1382
1396
  )
1383
1397
  )
1384
1398
  ORDER BY s.sequence, s.id
@@ -1488,7 +1502,9 @@ export function reconcileWorktreeDb(mainDbPath, worktreeDbPath) {
1488
1502
  if (realpathSync(mainDbPath) === realpathSync(worktreeDbPath))
1489
1503
  return zero;
1490
1504
  }
1491
- catch { /* path resolution failed — fall through to existing checks */ }
1505
+ catch (e) {
1506
+ logWarning("db", `realpathSync failed: ${e.message}`);
1507
+ }
1492
1508
  // Sanitize path: reject any characters that could break ATTACH syntax.
1493
1509
  // ATTACH DATABASE doesn't support parameterized paths in all providers,
1494
1510
  // so we use strict allowlist validation instead.
@@ -1610,7 +1626,9 @@ export function reconcileWorktreeDb(mainDbPath, worktreeDbPath) {
1610
1626
  try {
1611
1627
  adapter.exec("ROLLBACK");
1612
1628
  }
1613
- catch { /* best effort */ }
1629
+ catch (e) {
1630
+ logWarning("db", `rollback failed: ${e.message}`);
1631
+ }
1614
1632
  throw txErr;
1615
1633
  }
1616
1634
  return { ...merged, conflicts };
@@ -1619,7 +1637,9 @@ export function reconcileWorktreeDb(mainDbPath, worktreeDbPath) {
1619
1637
  try {
1620
1638
  adapter.exec("DETACH DATABASE wt");
1621
1639
  }
1622
- catch { /* best effort */ }
1640
+ catch (e) {
1641
+ logWarning("db", `detach worktree DB failed: ${e.message}`);
1642
+ }
1623
1643
  }
1624
1644
  }
1625
1645
  catch (err) {
@@ -37,6 +37,7 @@ import { selectAndApplyModel } from "./auto-model-selection.js";
37
37
  export { MILESTONE_ID_RE, generateMilestoneSuffix, nextMilestoneId, extractMilestoneSeq, parseMilestoneId, milestoneIdSort, maxMilestoneNum, findMilestoneIds, reserveMilestoneId, claimReservedId, getReservedMilestoneIds, clearReservedMilestoneIds, } from "./milestone-ids.js";
38
38
  export { showQueue, handleQueueReorder, showQueueAdd, buildExistingMilestonesContext, } from "./guided-flow-queue.js";
39
39
  import { getErrorMessage } from "./error-utils.js";
40
+ import { logWarning } from "./workflow-logger.js";
40
41
  // ─── ID Generation with Reservation ─────────────────────────────────────────
41
42
  /**
42
43
  * Generate the next milestone ID, accounting for reserved IDs, and reserve it.
@@ -144,7 +145,9 @@ export function checkAutoStartAfterDiscuss() {
144
145
  }
145
146
  }
146
147
  }
147
- catch { /* non-fatal — PROJECT.md parsing failure shouldn't block auto-start */ }
148
+ catch (e) {
149
+ logWarning("guided", `PROJECT.md parsing failed: ${e.message}`);
150
+ }
148
151
  }
149
152
  // Gate 4: Discussion manifest process verification (multi-milestone only)
150
153
  // The LLM writes DISCUSSION-MANIFEST.json after each Phase 3 gate decision.
@@ -171,7 +174,9 @@ export function checkAutoStartAfterDiscuss() {
171
174
  }
172
175
  }
173
176
  }
174
- catch { /* malformed manifest — warn but don't block */ }
177
+ catch (e) {
178
+ logWarning("guided", `discussion manifest verification failed: ${e.message}`);
179
+ }
175
180
  }
176
181
  // Draft promotion cleanup: if a CONTEXT-DRAFT.md exists alongside the new
177
182
  // CONTEXT.md, delete the draft — it's been consumed by the discussion.
@@ -180,18 +185,21 @@ export function checkAutoStartAfterDiscuss() {
180
185
  if (draftFile)
181
186
  unlinkSync(draftFile);
182
187
  }
183
- catch { /* non-fatal — stale draft doesn't break anything, CONTEXT.md wins */ }
188
+ catch (e) {
189
+ logWarning("guided", `CONTEXT-DRAFT.md unlink failed: ${e.message}`);
190
+ }
184
191
  // Cleanup: remove discussion manifest after auto-start (only needed during discussion)
185
192
  try {
186
193
  unlinkSync(manifestPath);
187
194
  }
188
- catch { /* may not exist for single-milestone */ }
195
+ catch (e) {
196
+ logWarning("guided", `manifest unlink failed: ${e.message}`);
197
+ }
189
198
  pendingAutoStartMap.delete(basePath);
190
199
  ctx.ui.notify(`Milestone ${milestoneId} ready.`, "info");
191
200
  startAuto(ctx, pi, basePath, false, { step }).catch((err) => {
192
201
  ctx.ui.notify(`Auto-start failed: ${getErrorMessage(err)}`, "error");
193
- if (process.env.GSD_DEBUG)
194
- console.error('[gsd] auto start error:', err);
202
+ logWarning("guided", `auto start error: ${getErrorMessage(err)}`);
195
203
  debugLog("auto-start-failed", { error: getErrorMessage(err) });
196
204
  });
197
205
  return true;
@@ -744,8 +752,8 @@ function selfHealRuntimeRecords(basePath, ctx) {
744
752
  }
745
753
  return { cleared };
746
754
  }
747
- catch {
748
- // Non-fatal — self-heal should never block the wizard
755
+ catch (e) {
756
+ logWarning("guided", `self-heal stale runtime records failed: ${e.message}`);
749
757
  return { cleared: 0 };
750
758
  }
751
759
  }
@@ -952,7 +960,9 @@ export async function showSmartEntry(ctx, pi, basePath, options) {
952
960
  return;
953
961
  }
954
962
  }
955
- catch { /* directory exists but unreadable — fall through to normal flow */ }
963
+ catch (e) {
964
+ logWarning("guided", `directory read failed: ${e.message}`);
965
+ }
956
966
  }
957
967
  }
958
968
  const uniqueMilestoneIds = !!loadEffectiveGSDPreferences()?.preferences?.unique_milestone_ids;
@@ -13,6 +13,7 @@ import { ensureGitignore, untrackRuntimeFiles } from "./gitignore.js";
13
13
  import { gsdRoot } from "./paths.js";
14
14
  import { assertSafeDirectory } from "./validate-directory.js";
15
15
  import { runSkillInstallStep } from "./skill-catalog.js";
16
+ import { generateCodebaseMap, writeCodebaseMap } from "./codebase-generator.js";
16
17
  // ─── Defaults ───────────────────────────────────────────────────────────────────
17
18
  const DEFAULT_PREFS = {
18
19
  mode: "solo",
@@ -189,6 +190,17 @@ export async function showProjectInit(ctx, pi, basePath, detection) {
189
190
  // Ensure .gitignore
190
191
  ensureGitignore(basePath);
191
192
  untrackRuntimeFiles(basePath);
193
+ // Auto-generate codebase map for instant agent orientation
194
+ try {
195
+ const result = generateCodebaseMap(basePath);
196
+ if (result.fileCount > 0) {
197
+ writeCodebaseMap(basePath, result.content);
198
+ ctx.ui.notify(`Codebase map generated: ${result.fileCount} files`, "info");
199
+ }
200
+ }
201
+ catch {
202
+ // Non-fatal — codebase map generation failure should never block project init
203
+ }
192
204
  ctx.ui.notify("GSD initialized. Starting your first milestone...", "info");
193
205
  return { completed: true, bootstrapped: true };
194
206
  }