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,14 +14,21 @@ import {
14
14
  getCodebaseMapStats,
15
15
  readCodebaseMap,
16
16
  } from "./codebase-generator.js";
17
+ import { loadEffectiveGSDPreferences } from "./preferences.js";
18
+ import type { CodebaseMapOptions } from "./codebase-generator.js";
17
19
 
18
20
  const USAGE =
19
21
  "Usage: /gsd codebase [generate|update|stats]\n\n" +
20
- " generate [--max-files N] — Generate or regenerate CODEBASE.md\n" +
21
- " update — Incremental update (preserves descriptions)\n" +
22
- " stats — Show file count, coverage, and generation time\n" +
23
- " help — Show this help\n\n" +
24
- "With no subcommand, shows stats if a map exists or help if not.";
22
+ " generate [--max-files N] [--collapse-threshold N] — Generate or regenerate CODEBASE.md\n" +
23
+ " update [--max-files N] [--collapse-threshold N] — Incremental update (preserves descriptions)\n" +
24
+ " stats — Show file count, coverage, and generation time\n" +
25
+ " help — Show this help\n\n" +
26
+ "With no subcommand, shows stats if a map exists or help if not.\n\n" +
27
+ "Configure defaults via preferences.md:\n" +
28
+ " codebase:\n" +
29
+ " exclude_patterns: [\"docs/\", \"fixtures/\"]\n" +
30
+ " max_files: 1000\n" +
31
+ " collapse_threshold: 15";
25
32
 
26
33
  export async function handleCodebase(
27
34
  args: string,
@@ -34,15 +41,15 @@ export async function handleCodebase(
34
41
 
35
42
  switch (sub) {
36
43
  case "generate": {
37
- const maxFiles = parseMaxFiles(args, ctx);
38
- if (maxFiles === false) return; // validation failed, message already shown
44
+ const options = resolveCodebaseOptions(args, ctx);
45
+ if (options === false) return; // validation failed, message already shown
39
46
 
40
47
  const existing = readCodebaseMap(basePath);
41
48
  const existingDescriptions = existing
42
49
  ? (await import("./codebase-generator.js")).parseCodebaseMap(existing)
43
50
  : undefined;
44
51
 
45
- const result = generateCodebaseMap(basePath, { maxFiles: maxFiles ?? undefined }, existingDescriptions);
52
+ const result = generateCodebaseMap(basePath, options, existingDescriptions);
46
53
 
47
54
  if (result.fileCount === 0) {
48
55
  ctx.ui.notify(
@@ -73,10 +80,10 @@ export async function handleCodebase(
73
80
  return;
74
81
  }
75
82
 
76
- const maxFiles = parseMaxFiles(args, ctx);
77
- if (maxFiles === false) return;
83
+ const options = resolveCodebaseOptions(args, ctx);
84
+ if (options === false) return;
78
85
 
79
- const result = updateCodebaseMap(basePath, { maxFiles: maxFiles ?? undefined });
86
+ const result = updateCodebaseMap(basePath, options);
80
87
  writeCodebaseMap(basePath, result.content);
81
88
 
82
89
  ctx.ui.notify(
@@ -141,19 +148,44 @@ function showStats(basePath: string, ctx: ExtensionCommandContext): void {
141
148
  }
142
149
 
143
150
  /**
144
- * Parse and validate --max-files flag.
145
- * Returns the parsed number, undefined if flag not present, or false if invalid.
151
+ * Resolve codebase map options by merging preferences with CLI flags.
152
+ * CLI flags override preferences; preferences override built-in defaults.
153
+ * Returns false if validation failed (error already shown to user).
146
154
  */
147
- function parseMaxFiles(args: string, ctx: ExtensionCommandContext): number | undefined | false {
155
+ function resolveCodebaseOptions(args: string, ctx: ExtensionCommandContext): CodebaseMapOptions | false {
156
+ // Load preferences defaults
157
+ const prefs = loadEffectiveGSDPreferences()?.preferences?.codebase;
158
+
159
+ // Parse CLI flags
148
160
  const maxFilesStr = extractFlag(args, "--max-files");
149
- if (!maxFilesStr) return undefined;
161
+ const collapseStr = extractFlag(args, "--collapse-threshold");
162
+
163
+ // Validate --max-files
164
+ let maxFiles: number | undefined;
165
+ if (maxFilesStr) {
166
+ maxFiles = parseInt(maxFilesStr, 10);
167
+ if (isNaN(maxFiles) || maxFiles < 1) {
168
+ ctx.ui.notify("--max-files must be a positive integer (e.g. --max-files 200).", "warning");
169
+ return false;
170
+ }
171
+ }
150
172
 
151
- const maxFiles = parseInt(maxFilesStr, 10);
152
- if (isNaN(maxFiles) || maxFiles < 1) {
153
- ctx.ui.notify("--max-files must be a positive integer (e.g. --max-files 200).", "warning");
154
- return false;
173
+ // Validate --collapse-threshold
174
+ let collapseThreshold: number | undefined;
175
+ if (collapseStr) {
176
+ collapseThreshold = parseInt(collapseStr, 10);
177
+ if (isNaN(collapseThreshold) || collapseThreshold < 1) {
178
+ ctx.ui.notify("--collapse-threshold must be a positive integer (e.g. --collapse-threshold 15).", "warning");
179
+ return false;
180
+ }
155
181
  }
156
- return maxFiles;
182
+
183
+ return {
184
+ // CLI flags override preferences
185
+ maxFiles: maxFiles ?? prefs?.max_files,
186
+ collapseThreshold: collapseThreshold ?? prefs?.collapse_threshold,
187
+ excludePatterns: prefs?.exclude_patterns,
188
+ };
157
189
  }
158
190
 
159
191
  function extractFlag(args: string, flag: string): string | undefined {
@@ -8,6 +8,7 @@ import type { ExtensionCommandContext } from "@gsd/pi-coding-agent";
8
8
  import { existsSync } from "node:fs";
9
9
  import { join } from "node:path";
10
10
  import { gsdRoot } from "./paths.js";
11
+ import { logWarning } from "./workflow-logger.js";
11
12
  import { getErrorMessage } from "./error-utils.js";
12
13
 
13
14
  export interface InspectData {
@@ -92,7 +93,7 @@ export async function handleInspect(ctx: ExtensionCommandContext): Promise<void>
92
93
 
93
94
  ctx.ui.notify(formatInspectOutput(data), "info");
94
95
  } catch (err) {
95
- process.stderr.write(`gsd-db: /gsd inspect failed: ${getErrorMessage(err)}\n`);
96
+ logWarning("command", `/gsd inspect failed: ${getErrorMessage(err)}`);
96
97
  ctx.ui.notify("Failed to inspect GSD database. Check stderr for details.", "error");
97
98
  }
98
99
  }
@@ -7,12 +7,14 @@
7
7
  import type { ExtensionCommandContext } from "@gsd/pi-coding-agent";
8
8
  import { deriveState } from "./state.js";
9
9
  import { nativeBranchList, nativeDetectMainBranch, nativeBranchListMerged, nativeBranchDelete, nativeForEachRef, nativeUpdateRef } from "./native-git-bridge.js";
10
+ import { logWarning } from "./workflow-logger.js";
10
11
 
11
12
  export async function handleCleanupBranches(ctx: ExtensionCommandContext, basePath: string): Promise<void> {
12
13
  let branches: string[];
13
14
  try {
14
15
  branches = nativeBranchList(basePath, "gsd/*");
15
- } catch {
16
+ } catch (e) {
17
+ logWarning("command", `branch list failed: ${(e as Error).message}`);
16
18
  ctx.ui.notify("No GSD branches to clean up.", "info");
17
19
  return;
18
20
  }
@@ -23,7 +25,8 @@ export async function handleCleanupBranches(ctx: ExtensionCommandContext, basePa
23
25
  let merged: string[];
24
26
  try {
25
27
  merged = nativeBranchListMerged(basePath, mainBranch, "gsd/*");
26
- } catch {
28
+ } catch (e) {
29
+ logWarning("command", `merged branch list failed: ${(e as Error).message}`);
27
30
  merged = [];
28
31
  }
29
32
 
@@ -33,8 +36,8 @@ export async function handleCleanupBranches(ctx: ExtensionCommandContext, basePa
33
36
  try {
34
37
  nativeBranchDelete(basePath, branch, false);
35
38
  deletedMerged++;
36
- } catch {
37
- /* skip branches that cannot be deleted */
39
+ } catch (e) {
40
+ logWarning("command", `branch delete failed for ${branch}: ${(e as Error).message}`);
38
41
  }
39
42
  }
40
43
 
@@ -66,7 +69,7 @@ export async function handleCleanupBranches(ctx: ExtensionCommandContext, basePa
66
69
  try {
67
70
  nativeBranchDelete(basePath, branch, true);
68
71
  deletedStaleMilestones++;
69
- } catch { /* non-fatal */ }
72
+ } catch (e) { logWarning("command", `stale milestone branch delete failed for ${branch}: ${(e as Error).message}`); }
70
73
  continue;
71
74
  }
72
75
  }
@@ -77,7 +80,8 @@ export async function handleCleanupBranches(ctx: ExtensionCommandContext, basePa
77
80
  let roadmapContent: string | null = null;
78
81
  try {
79
82
  roadmapContent = await loadFile(roadmapPath);
80
- } catch {
83
+ } catch (e) {
84
+ logWarning("command", `loadFile failed for ${roadmapPath}: ${(e as Error).message}`);
81
85
  roadmapContent = null;
82
86
  }
83
87
  if (!roadmapContent) continue;
@@ -85,12 +89,12 @@ export async function handleCleanupBranches(ctx: ExtensionCommandContext, basePa
85
89
  try {
86
90
  nativeBranchDelete(basePath, branch, true);
87
91
  deletedStaleMilestones++;
88
- } catch {
89
- /* non-fatal */
92
+ } catch (e) {
93
+ logWarning("command", `milestone branch delete failed for ${branch}: ${(e as Error).message}`);
90
94
  }
91
95
  }
92
- } catch {
93
- /* non-fatal */
96
+ } catch (e) {
97
+ logWarning("command", `stale milestone cleanup failed: ${(e as Error).message}`);
94
98
  }
95
99
 
96
100
  const summary: string[] = [];
@@ -122,7 +126,8 @@ export async function handleCleanupSnapshots(ctx: ExtensionCommandContext, baseP
122
126
  let refs: string[];
123
127
  try {
124
128
  refs = nativeForEachRef(basePath, "refs/gsd/snapshots/");
125
- } catch {
129
+ } catch (e) {
130
+ logWarning("command", `snapshot ref list failed: ${(e as Error).message}`);
126
131
  ctx.ui.notify("No snapshot refs to clean up.", "info");
127
132
  return;
128
133
  }
@@ -147,8 +152,8 @@ export async function handleCleanupSnapshots(ctx: ExtensionCommandContext, baseP
147
152
  try {
148
153
  nativeUpdateRef(basePath, old);
149
154
  pruned++;
150
- } catch {
151
- /* skip individual failures */
155
+ } catch (e) {
156
+ logWarning("command", `snapshot ref update failed for ${old}: ${(e as Error).message}`);
152
157
  }
153
158
  }
154
159
  }
@@ -164,7 +169,8 @@ export async function handleCleanupWorktrees(ctx: ExtensionCommandContext, baseP
164
169
  let statuses;
165
170
  try {
166
171
  statuses = getAllWorktreeHealth(basePath);
167
- } catch {
172
+ } catch (e) {
173
+ logWarning("command", `worktree health inspection failed: ${(e as Error).message}`);
168
174
  ctx.ui.notify("Failed to inspect worktrees.", "error");
169
175
  return;
170
176
  }
@@ -197,7 +203,8 @@ export async function handleCleanupWorktrees(ctx: ExtensionCommandContext, baseP
197
203
  removeWorktree(basePath, wt.name, { deleteBranch: true });
198
204
  lines.push(` ✓ ${wt.name} removed (branch ${wt.branch} deleted)`);
199
205
  removed++;
200
- } catch {
206
+ } catch (e) {
207
+ logWarning("command", `worktree removal failed for ${wt.name}: ${(e as Error).message}`);
201
208
  lines.push(` ✗ ${wt.name} failed to remove`);
202
209
  }
203
210
  }
@@ -246,7 +253,7 @@ export async function handleSkip(unitArg: string, ctx: ExtensionCommandContext,
246
253
  if (fileExists(completedKeysFile)) {
247
254
  keys = JSON.parse(readFile(completedKeysFile, "utf-8"));
248
255
  }
249
- } catch { /* start fresh */ }
256
+ } catch (e) { logWarning("command", `completed-units.json parse failed: ${(e as Error).message}`); }
250
257
 
251
258
  // Normalize: accept "execute-task/M001/S01/T03", "M001/S01/T03", or just "T03"
252
259
  let skipKey = unitArg;
@@ -371,7 +378,8 @@ export async function handleCleanupProjects(args: string, ctx: ExtensionCommandC
371
378
  hashList = readdirSync(projectsDir, { withFileTypes: true })
372
379
  .filter(e => e.isDirectory())
373
380
  .map(e => e.name);
374
- } catch {
381
+ } catch (e) {
382
+ logWarning("command", `readdir failed for project-state directory: ${(e as Error).message}`);
375
383
  ctx.ui.notify(`Failed to read project-state directory at ${projectsDir}.`, "error");
376
384
  return;
377
385
  }
@@ -454,7 +462,8 @@ export async function handleCleanupProjects(args: string, ctx: ExtensionCommandC
454
462
  try {
455
463
  fsRmSync(pathJoin(projectsDir, e.hash), { recursive: true, force: true });
456
464
  removed++;
457
- } catch {
465
+ } catch (err) {
466
+ logWarning("command", `project cleanup rm failed for ${e.hash}: ${(err as Error).message}`);
458
467
  failed.push(e.hash);
459
468
  }
460
469
  }
@@ -529,7 +538,7 @@ export async function handleRecover(ctx: ExtensionCommandContext, basePath: stri
529
538
  ctx.ui.notify(lines.join("\n"), "success");
530
539
  } catch (err) {
531
540
  const msg = err instanceof Error ? err.message : String(err);
532
- process.stderr.write(`gsd-recover: failed: ${msg}\n`);
541
+ logWarning("command", `recover failed: ${msg}`);
533
542
  ctx.ui.notify(`gsd recover failed: ${msg}`, "error");
534
543
  }
535
544
  }
@@ -16,6 +16,7 @@ export interface ClassificationResult {
16
16
  tier: ComplexityTier;
17
17
  reason: string;
18
18
  downgraded: boolean; // true if budget pressure lowered the tier
19
+ taskMetadata?: TaskMetadata;
19
20
  }
20
21
 
21
22
  export interface TaskMetadata {
@@ -71,17 +72,20 @@ export function classifyUnitComplexity(
71
72
  ): ClassificationResult {
72
73
  // Hook units default to light
73
74
  if (unitType.startsWith("hook/")) {
74
- const result: ClassificationResult = { tier: "light", reason: "hook unit", downgraded: false };
75
+ const result: ClassificationResult = { tier: "light", reason: "hook unit", downgraded: false, taskMetadata: undefined };
75
76
  return applyBudgetPressure(result, budgetPct);
76
77
  }
77
78
 
78
79
  // Start with the default tier for this unit type
79
80
  let tier = UNIT_TYPE_TIERS[unitType] ?? "standard";
80
81
  let reason = `unit type: ${unitType}`;
82
+ let taskMeta: TaskMetadata | undefined;
81
83
 
82
84
  // For execute-task, analyze task metadata for complexity signals
83
85
  if (unitType === "execute-task") {
84
- const taskAnalysis = analyzeTaskComplexity(unitId, basePath, metadata);
86
+ // Extract metadata once and reuse throughout to avoid double-extraction
87
+ taskMeta = metadata ?? extractTaskMetadata(unitId, basePath);
88
+ const taskAnalysis = analyzeTaskComplexity(unitId, basePath, taskMeta);
85
89
  tier = taskAnalysis.tier;
86
90
  reason = taskAnalysis.reason;
87
91
  }
@@ -96,14 +100,15 @@ export function classifyUnitComplexity(
96
100
  }
97
101
 
98
102
  // Adaptive learning: check if history suggests bumping the tier
99
- const tags = metadata?.tags ?? extractTaskMetadata(unitId, basePath).tags;
103
+ // Use already-extracted taskMeta.tags if available to avoid double-extraction
104
+ const tags = taskMeta?.tags ?? metadata?.tags;
100
105
  const adaptiveAdjustment = getAdaptiveTierAdjustment(unitType, tier, tags);
101
106
  if (adaptiveAdjustment && tierOrdinal(adaptiveAdjustment) > tierOrdinal(tier)) {
102
107
  reason = `${reason} (adaptive: high failure rate at ${tier})`;
103
108
  tier = adaptiveAdjustment;
104
109
  }
105
110
 
106
- const result: ClassificationResult = { tier, reason, downgraded: false };
111
+ const result: ClassificationResult = { tier, reason, downgraded: false, taskMetadata: taskMeta };
107
112
  return applyBudgetPressure(result, budgetPct);
108
113
  }
109
114
 
@@ -212,7 +217,7 @@ function analyzePlanComplexity(
212
217
  /**
213
218
  * Extract task metadata from the task plan file on disk.
214
219
  */
215
- function extractTaskMetadata(unitId: string, basePath: string): TaskMetadata {
220
+ export function extractTaskMetadata(unitId: string, basePath: string): TaskMetadata {
216
221
  const meta: TaskMetadata = {};
217
222
  const { milestone: mid, slice: sid, task: tid } = parseUnitId(unitId);
218
223
  if (!mid || !sid || !tid) return meta;
@@ -0,0 +1,74 @@
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
+
14
+ interface MaskableMessage {
15
+ role: string;
16
+ content: unknown;
17
+ type?: string;
18
+ [key: string]: unknown;
19
+ }
20
+
21
+ const MASK_PLACEHOLDER = "[result masked — within summarized history]";
22
+ const MASK_CONTENT_BLOCK = [{ type: "text" as const, text: MASK_PLACEHOLDER }];
23
+
24
+ function findTurnBoundary(messages: MaskableMessage[], keepRecentTurns: number): number {
25
+ let turnsSeen = 0;
26
+ for (let i = messages.length - 1; i >= 0; i--) {
27
+ const m = messages[i];
28
+ // In the LLM payload, genuine user turns have role "user".
29
+ // Tool results have role "toolResult" and are excluded by this check.
30
+ if (m.role === "user") {
31
+ // Skip bash-result user messages (converted from bashExecution) — these aren't real user turns
32
+ if (isBashResultUserMessage(m)) continue;
33
+ turnsSeen++;
34
+ if (turnsSeen >= keepRecentTurns) return i;
35
+ }
36
+ }
37
+ return 0;
38
+ }
39
+
40
+ /**
41
+ * Detect user messages that originated from bashExecution.
42
+ * After convertToLlm, these are {role: "user", content: [{type:"text", text:"Ran `cmd`\n..."}]}.
43
+ * The bashExecutionToText format always starts with "Ran `".
44
+ */
45
+ function isBashResultUserMessage(m: MaskableMessage): boolean {
46
+ if (m.role !== "user" || !Array.isArray(m.content)) return false;
47
+ const first = m.content[0];
48
+ return first && typeof first === "object" && "text" in first &&
49
+ typeof first.text === "string" && first.text.startsWith("Ran `");
50
+ }
51
+
52
+ function isMaskableMessage(m: MaskableMessage): boolean {
53
+ // Tool result messages (role: "toolResult" in pi-ai format)
54
+ if (m.role === "toolResult") return true;
55
+ // Bash-result user messages (converted from bashExecution by convertToLlm)
56
+ if (isBashResultUserMessage(m)) return true;
57
+ return false;
58
+ }
59
+
60
+ export function createObservationMask(keepRecentTurns: number = 8) {
61
+ return (messages: MaskableMessage[]): MaskableMessage[] => {
62
+ const boundary = findTurnBoundary(messages, keepRecentTurns);
63
+ if (boundary === 0) return messages;
64
+
65
+ return messages.map((m, i) => {
66
+ if (i >= boundary) return m;
67
+ if (isMaskableMessage(m)) {
68
+ // Content may be string or array of content blocks — always replace with array
69
+ return { ...m, content: MASK_CONTENT_BLOCK };
70
+ }
71
+ return m;
72
+ });
73
+ };
74
+ }
@@ -17,6 +17,7 @@
17
17
  * - The frozen DEFINITION.yaml on disk is the single source of truth for step policies.
18
18
  */
19
19
 
20
+ import { logWarning } from "./workflow-logger.js";
20
21
  import { readFileSync, existsSync, statSync } from "node:fs";
21
22
  import { join, resolve, sep } from "node:path";
22
23
  import { spawnSync } from "node:child_process";
@@ -130,8 +131,8 @@ function handleContentHeuristic(
130
131
  if (!new RegExp(verify.pattern).test(content)) {
131
132
  return "pause";
132
133
  }
133
- } catch {
134
- // Invalid regex at runtime — treat as verification failure
134
+ } catch (e) {
135
+ logWarning("engine", `content-heuristic regex failed: ${(e as Error).message}`);
135
136
  return "pause";
136
137
  }
137
138
  }
@@ -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
 
@@ -10,7 +10,7 @@ import { existsSync, copyFileSync, mkdirSync, realpathSync } from "node:fs";
10
10
  import { dirname } from "node:path";
11
11
  import type { Decision, Requirement, GateRow, GateId, GateScope, GateStatus, GateVerdict } from "./types.js";
12
12
  import { GSDError, GSD_STALE_STATE } from "./errors.js";
13
- import { logError } from "./workflow-logger.js";
13
+ import { logError, logWarning } from "./workflow-logger.js";
14
14
 
15
15
  const _require = createRequire(import.meta.url);
16
16
 
@@ -787,11 +787,11 @@ export function openDatabase(path: string): boolean {
787
787
  initSchema(adapter, fileBacked);
788
788
  process.stderr.write("gsd-db: recovered corrupt database via VACUUM\n");
789
789
  } catch (retryErr) {
790
- try { adapter.close(); } catch { /* swallow */ }
790
+ try { adapter.close(); } catch (e) { logWarning("db", `close after VACUUM failed: ${(e as Error).message}`); }
791
791
  throw retryErr;
792
792
  }
793
793
  } else {
794
- try { adapter.close(); } catch { /* swallow */ }
794
+ try { adapter.close(); } catch (e) { logWarning("db", `close after VACUUM failed: ${(e as Error).message}`); }
795
795
  throw err;
796
796
  }
797
797
  }
@@ -802,7 +802,7 @@ export function openDatabase(path: string): boolean {
802
802
 
803
803
  if (!_exitHandlerRegistered) {
804
804
  _exitHandlerRegistered = true;
805
- process.on("exit", () => { try { closeDatabase(); } catch {} });
805
+ process.on("exit", () => { try { closeDatabase(); } catch (e) { logWarning("db", `exit handler close failed: ${(e as Error).message}`); } });
806
806
  }
807
807
 
808
808
  return true;
@@ -812,16 +812,14 @@ export function closeDatabase(): void {
812
812
  if (currentDb) {
813
813
  try {
814
814
  currentDb.exec('PRAGMA wal_checkpoint(TRUNCATE)');
815
- } catch { /* non-fatal best effort before close */ }
815
+ } catch (e) { logWarning("db", `WAL checkpoint failed: ${(e as Error).message}`); }
816
816
  try {
817
817
  // Incremental vacuum to reclaim space without blocking
818
818
  currentDb.exec('PRAGMA incremental_vacuum(64)');
819
- } catch { /* non-fatal */ }
819
+ } catch (e) { logWarning("db", `incremental vacuum failed: ${(e as Error).message}`); }
820
820
  try {
821
821
  currentDb.close();
822
- } catch {
823
- // swallow close errors
824
- }
822
+ } catch (e) { logWarning("db", `database close failed: ${(e as Error).message}`); }
825
823
  currentDb = null;
826
824
  currentPath = null;
827
825
  currentPid = 0;
@@ -833,7 +831,7 @@ export function vacuumDatabase(): void {
833
831
  if (!currentDb) return;
834
832
  try {
835
833
  currentDb.exec('VACUUM');
836
- } catch { /* non-fatal */ }
834
+ } catch (e) { logWarning("db", `VACUUM failed: ${(e as Error).message}`); }
837
835
  }
838
836
 
839
837
  let _txDepth = 0;
@@ -1038,7 +1036,7 @@ export function upsertRequirement(r: Requirement): void {
1038
1036
 
1039
1037
  export function clearArtifacts(): void {
1040
1038
  if (!currentDb) return;
1041
- try { currentDb.exec("DELETE FROM artifacts"); } catch { /* cache clear is best effort */ }
1039
+ try { currentDb.exec("DELETE FROM artifacts"); } catch (e) { logWarning("db", `clearArtifacts failed: ${(e as Error).message}`); }
1042
1040
  }
1043
1041
 
1044
1042
  export function insertArtifact(a: {
@@ -1661,11 +1659,11 @@ export function getActiveSliceFromDb(milestoneId: string): SliceRow | null {
1661
1659
  const row = currentDb.prepare(
1662
1660
  `SELECT s.* FROM slices s
1663
1661
  WHERE s.milestone_id = :mid
1664
- AND s.status NOT IN ('complete', 'done')
1662
+ AND s.status NOT IN ('complete', 'done', 'skipped')
1665
1663
  AND NOT EXISTS (
1666
1664
  SELECT 1 FROM json_each(s.depends) AS dep
1667
1665
  WHERE dep.value NOT IN (
1668
- SELECT id FROM slices WHERE milestone_id = :mid AND status IN ('complete', 'done')
1666
+ SELECT id FROM slices WHERE milestone_id = :mid AND status IN ('complete', 'done', 'skipped')
1669
1667
  )
1670
1668
  )
1671
1669
  ORDER BY s.sequence, s.id
@@ -1801,7 +1799,7 @@ export function reconcileWorktreeDb(
1801
1799
  // ATTACHing a WAL-mode DB to itself corrupts the WAL (#2823).
1802
1800
  try {
1803
1801
  if (realpathSync(mainDbPath) === realpathSync(worktreeDbPath)) return zero;
1804
- } catch { /* path resolution failed fall through to existing checks */ }
1802
+ } catch (e) { logWarning("db", `realpathSync failed: ${(e as Error).message}`); }
1805
1803
  // Sanitize path: reject any characters that could break ATTACH syntax.
1806
1804
  // ATTACH DATABASE doesn't support parameterized paths in all providers,
1807
1805
  // so we use strict allowlist validation instead.
@@ -1938,12 +1936,12 @@ export function reconcileWorktreeDb(
1938
1936
 
1939
1937
  adapter.exec("COMMIT");
1940
1938
  } catch (txErr) {
1941
- try { adapter.exec("ROLLBACK"); } catch { /* best effort */ }
1939
+ try { adapter.exec("ROLLBACK"); } catch (e) { logWarning("db", `rollback failed: ${(e as Error).message}`); }
1942
1940
  throw txErr;
1943
1941
  }
1944
1942
  return { ...merged, conflicts };
1945
1943
  } finally {
1946
- try { adapter.exec("DETACH DATABASE wt"); } catch { /* best effort */ }
1944
+ try { adapter.exec("DETACH DATABASE wt"); } catch (e) { logWarning("db", `detach worktree DB failed: ${(e as Error).message}`); }
1947
1945
  }
1948
1946
  } catch (err) {
1949
1947
  logError("db", "worktree DB reconciliation failed", { error: (err as Error).message });
@@ -52,6 +52,7 @@ export {
52
52
  buildExistingMilestonesContext,
53
53
  } from "./guided-flow-queue.js";
54
54
  import { getErrorMessage } from "./error-utils.js";
55
+ import { logWarning } from "./workflow-logger.js";
55
56
 
56
57
  // ─── ID Generation with Reservation ─────────────────────────────────────────
57
58
 
@@ -180,7 +181,7 @@ export function checkAutoStartAfterDiscuss(): boolean {
180
181
  );
181
182
  }
182
183
  }
183
- } catch { /* non-fatal — PROJECT.md parsing failure shouldn't block auto-start */ }
184
+ } catch (e) { logWarning("guided", `PROJECT.md parsing failed: ${(e as Error).message}`); }
184
185
  }
185
186
 
186
187
  // Gate 4: Discussion manifest process verification (multi-milestone only)
@@ -212,7 +213,7 @@ export function checkAutoStartAfterDiscuss(): boolean {
212
213
  );
213
214
  }
214
215
  }
215
- } catch { /* malformed manifest warn but don't block */ }
216
+ } catch (e) { logWarning("guided", `discussion manifest verification failed: ${(e as Error).message}`); }
216
217
  }
217
218
 
218
219
  // Draft promotion cleanup: if a CONTEXT-DRAFT.md exists alongside the new
@@ -220,16 +221,16 @@ export function checkAutoStartAfterDiscuss(): boolean {
220
221
  try {
221
222
  const draftFile = resolveMilestoneFile(basePath, milestoneId, "CONTEXT-DRAFT");
222
223
  if (draftFile) unlinkSync(draftFile);
223
- } catch { /* non-fatal stale draft doesn't break anything, CONTEXT.md wins */ }
224
+ } catch (e) { logWarning("guided", `CONTEXT-DRAFT.md unlink failed: ${(e as Error).message}`); }
224
225
 
225
226
  // Cleanup: remove discussion manifest after auto-start (only needed during discussion)
226
- try { unlinkSync(manifestPath); } catch { /* may not exist for single-milestone */ }
227
+ try { unlinkSync(manifestPath); } catch (e) { logWarning("guided", `manifest unlink failed: ${(e as Error).message}`); }
227
228
 
228
229
  pendingAutoStartMap.delete(basePath);
229
230
  ctx.ui.notify(`Milestone ${milestoneId} ready.`, "info");
230
231
  startAuto(ctx, pi, basePath, false, { step }).catch((err) => {
231
232
  ctx.ui.notify(`Auto-start failed: ${getErrorMessage(err)}`, "error");
232
- if (process.env.GSD_DEBUG) console.error('[gsd] auto start error:', err);
233
+ logWarning("guided", `auto start error: ${getErrorMessage(err)}`);
233
234
  debugLog("auto-start-failed", { error: getErrorMessage(err) });
234
235
  });
235
236
  return true;
@@ -895,8 +896,8 @@ function selfHealRuntimeRecords(basePath: string, ctx: ExtensionContext): { clea
895
896
  ctx.ui.notify(`Self-heal: cleared ${cleared} stale runtime record(s) from a previous session.`, "info");
896
897
  }
897
898
  return { cleared };
898
- } catch {
899
- // Non-fatal — self-heal should never block the wizard
899
+ } catch (e) {
900
+ logWarning("guided", `self-heal stale runtime records failed: ${(e as Error).message}`);
900
901
  return { cleared: 0 };
901
902
  }
902
903
  }
@@ -1142,7 +1143,7 @@ export async function showSmartEntry(
1142
1143
  );
1143
1144
  return;
1144
1145
  }
1145
- } catch { /* directory exists but unreadable fall through to normal flow */ }
1146
+ } catch (e) { logWarning("guided", `directory read failed: ${(e as Error).message}`); }
1146
1147
  }
1147
1148
  }
1148
1149
 
@@ -16,6 +16,7 @@ import { gsdRoot } from "./paths.js";
16
16
  import { assertSafeDirectory } from "./validate-directory.js";
17
17
  import type { ProjectDetection, ProjectSignals } from "./detection.js";
18
18
  import { runSkillInstallStep } from "./skill-catalog.js";
19
+ import { generateCodebaseMap, writeCodebaseMap } from "./codebase-generator.js";
19
20
 
20
21
  // ─── Types ──────────────────────────────────────────────────────────────────────
21
22
 
@@ -238,6 +239,17 @@ export async function showProjectInit(
238
239
  ensureGitignore(basePath);
239
240
  untrackRuntimeFiles(basePath);
240
241
 
242
+ // Auto-generate codebase map for instant agent orientation
243
+ try {
244
+ const result = generateCodebaseMap(basePath);
245
+ if (result.fileCount > 0) {
246
+ writeCodebaseMap(basePath, result.content);
247
+ ctx.ui.notify(`Codebase map generated: ${result.fileCount} files`, "info");
248
+ }
249
+ } catch {
250
+ // Non-fatal — codebase map generation failure should never block project init
251
+ }
252
+
241
253
  ctx.ui.notify("GSD initialized. Starting your first milestone...", "info");
242
254
 
243
255
  return { completed: true, bootstrapped: true };