gsd-pi 2.18.0 → 2.20.0

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 (289) hide show
  1. package/README.md +5 -1
  2. package/dist/cli.js +3 -3
  3. package/dist/onboarding.d.ts +3 -1
  4. package/dist/onboarding.js +77 -3
  5. package/dist/remote-questions-config.d.ts +1 -1
  6. package/dist/resources/extensions/google-search/index.ts +164 -47
  7. package/dist/resources/extensions/gsd/auto-dashboard.ts +14 -2
  8. package/dist/resources/extensions/gsd/auto-prompts.ts +148 -39
  9. package/dist/resources/extensions/gsd/auto-worktree.ts +93 -9
  10. package/dist/resources/extensions/gsd/auto.ts +690 -39
  11. package/dist/resources/extensions/gsd/captures.ts +384 -0
  12. package/dist/resources/extensions/gsd/commands.ts +654 -36
  13. package/dist/resources/extensions/gsd/complexity-classifier.ts +322 -0
  14. package/dist/resources/extensions/gsd/context-budget.ts +243 -0
  15. package/dist/resources/extensions/gsd/context-store.ts +195 -0
  16. package/dist/resources/extensions/gsd/dashboard-overlay.ts +51 -3
  17. package/dist/resources/extensions/gsd/db-writer.ts +341 -0
  18. package/dist/resources/extensions/gsd/debug-logger.ts +178 -0
  19. package/dist/resources/extensions/gsd/dispatch-guard.ts +0 -1
  20. package/dist/resources/extensions/gsd/docs/preferences-reference.md +54 -0
  21. package/dist/resources/extensions/gsd/doctor-proactive.ts +286 -0
  22. package/dist/resources/extensions/gsd/doctor.ts +283 -2
  23. package/dist/resources/extensions/gsd/export.ts +81 -2
  24. package/dist/resources/extensions/gsd/files.ts +39 -9
  25. package/dist/resources/extensions/gsd/git-service.ts +6 -0
  26. package/dist/resources/extensions/gsd/gsd-db.ts +752 -0
  27. package/dist/resources/extensions/gsd/guided-flow.ts +26 -1
  28. package/dist/resources/extensions/gsd/history.ts +0 -1
  29. package/dist/resources/extensions/gsd/index.ts +277 -1
  30. package/dist/resources/extensions/gsd/md-importer.ts +526 -0
  31. package/dist/resources/extensions/gsd/metrics.ts +84 -0
  32. package/dist/resources/extensions/gsd/model-cost-table.ts +65 -0
  33. package/dist/resources/extensions/gsd/model-router.ts +256 -0
  34. package/dist/resources/extensions/gsd/notifications.ts +0 -1
  35. package/dist/resources/extensions/gsd/post-unit-hooks.ts +72 -2
  36. package/dist/resources/extensions/gsd/preferences.ts +198 -150
  37. package/dist/resources/extensions/gsd/prompt-loader.ts +45 -9
  38. package/dist/resources/extensions/gsd/prompts/execute-task.md +3 -5
  39. package/dist/resources/extensions/gsd/prompts/heal-skill.md +45 -0
  40. package/dist/resources/extensions/gsd/prompts/plan-slice.md +5 -1
  41. package/dist/resources/extensions/gsd/prompts/quick-task.md +48 -0
  42. package/dist/resources/extensions/gsd/prompts/reassess-roadmap.md +6 -0
  43. package/dist/resources/extensions/gsd/prompts/replan-slice.md +8 -0
  44. package/dist/resources/extensions/gsd/prompts/system.md +2 -1
  45. package/dist/resources/extensions/gsd/prompts/triage-captures.md +62 -0
  46. package/dist/resources/extensions/gsd/quick.ts +156 -0
  47. package/dist/resources/extensions/gsd/skill-discovery.ts +5 -3
  48. package/dist/resources/extensions/gsd/skill-health.ts +417 -0
  49. package/dist/resources/extensions/gsd/skill-telemetry.ts +127 -0
  50. package/dist/resources/extensions/gsd/state.ts +30 -0
  51. package/dist/resources/extensions/gsd/templates/preferences.md +1 -0
  52. package/dist/resources/extensions/gsd/tests/captures.test.ts +438 -0
  53. package/dist/resources/extensions/gsd/tests/complexity-classifier.test.ts +181 -0
  54. package/dist/resources/extensions/gsd/tests/context-budget.test.ts +283 -0
  55. package/dist/resources/extensions/gsd/tests/context-compression.test.ts +1 -1
  56. package/dist/resources/extensions/gsd/tests/context-store.test.ts +462 -0
  57. package/dist/resources/extensions/gsd/tests/continue-here.test.ts +204 -0
  58. package/dist/resources/extensions/gsd/tests/dashboard-budget.test.ts +346 -0
  59. package/dist/resources/extensions/gsd/tests/db-writer.test.ts +602 -0
  60. package/dist/resources/extensions/gsd/tests/debug-logger.test.ts +185 -0
  61. package/dist/resources/extensions/gsd/tests/derive-state-db.test.ts +406 -0
  62. package/dist/resources/extensions/gsd/tests/dispatch-guard.test.ts +0 -1
  63. package/dist/resources/extensions/gsd/tests/dist-redirect.mjs +22 -0
  64. package/dist/resources/extensions/gsd/tests/doctor-proactive.test.ts +244 -0
  65. package/dist/resources/extensions/gsd/tests/doctor-runtime.test.ts +303 -0
  66. package/dist/resources/extensions/gsd/tests/feature-branch-lifecycle-integration.test.ts +434 -0
  67. package/dist/resources/extensions/gsd/tests/gsd-db.test.ts +353 -0
  68. package/dist/resources/extensions/gsd/tests/gsd-inspect.test.ts +125 -0
  69. package/dist/resources/extensions/gsd/tests/gsd-tools.test.ts +326 -0
  70. package/dist/resources/extensions/gsd/tests/integration-edge.test.ts +228 -0
  71. package/dist/resources/extensions/gsd/tests/integration-lifecycle.test.ts +277 -0
  72. package/dist/resources/extensions/gsd/tests/md-importer.test.ts +411 -0
  73. package/dist/resources/extensions/gsd/tests/metrics.test.ts +197 -0
  74. package/dist/resources/extensions/gsd/tests/milestone-transition-worktree.test.ts +144 -0
  75. package/dist/resources/extensions/gsd/tests/model-cost-table.test.ts +69 -0
  76. package/dist/resources/extensions/gsd/tests/model-isolation.test.ts +99 -0
  77. package/dist/resources/extensions/gsd/tests/model-router.test.ts +167 -0
  78. package/dist/resources/extensions/gsd/tests/parsers.test.ts +40 -0
  79. package/dist/resources/extensions/gsd/tests/post-unit-hooks.test.ts +41 -1
  80. package/dist/resources/extensions/gsd/tests/preferences-git.test.ts +0 -1
  81. package/dist/resources/extensions/gsd/tests/preferences-hooks.test.ts +0 -1
  82. package/dist/resources/extensions/gsd/tests/preferences-mode.test.ts +110 -0
  83. package/dist/resources/extensions/gsd/tests/preferences-models.test.ts +0 -1
  84. package/dist/resources/extensions/gsd/tests/prompt-budget-enforcement.test.ts +464 -0
  85. package/dist/resources/extensions/gsd/tests/prompt-db.test.ts +385 -0
  86. package/dist/resources/extensions/gsd/tests/remote-questions.test.ts +488 -1
  87. package/dist/resources/extensions/gsd/tests/resolve-ts-hooks.mjs +17 -29
  88. package/dist/resources/extensions/gsd/tests/resolve-ts.mjs +2 -8
  89. package/dist/resources/extensions/gsd/tests/routing-history.test.ts +215 -62
  90. package/dist/resources/extensions/gsd/tests/skill-lifecycle.test.ts +126 -0
  91. package/dist/resources/extensions/gsd/tests/stop-auto-remote.test.ts +31 -8
  92. package/dist/resources/extensions/gsd/tests/token-savings.test.ts +366 -0
  93. package/dist/resources/extensions/gsd/tests/triage-dispatch.test.ts +224 -0
  94. package/dist/resources/extensions/gsd/tests/triage-resolution.test.ts +215 -0
  95. package/dist/resources/extensions/gsd/tests/unit-runtime.test.ts +25 -1
  96. package/dist/resources/extensions/gsd/tests/visualizer-critical-path.test.ts +145 -0
  97. package/dist/resources/extensions/gsd/tests/visualizer-data.test.ts +290 -0
  98. package/dist/resources/extensions/gsd/tests/visualizer-overlay.test.ts +120 -0
  99. package/dist/resources/extensions/gsd/tests/visualizer-views.test.ts +478 -0
  100. package/dist/resources/extensions/gsd/tests/worktree-db-integration.test.ts +205 -0
  101. package/dist/resources/extensions/gsd/tests/worktree-db.test.ts +442 -0
  102. package/dist/resources/extensions/gsd/tests/worktree-post-create-hook.test.ts +165 -0
  103. package/dist/resources/extensions/gsd/triage-resolution.ts +200 -0
  104. package/dist/resources/extensions/gsd/triage-ui.ts +175 -0
  105. package/dist/resources/extensions/gsd/types.ts +29 -0
  106. package/dist/resources/extensions/gsd/undo.ts +0 -1
  107. package/dist/resources/extensions/gsd/unit-runtime.ts +5 -1
  108. package/dist/resources/extensions/gsd/visualizer-data.ts +505 -0
  109. package/dist/resources/extensions/gsd/visualizer-overlay.ts +337 -0
  110. package/dist/resources/extensions/gsd/visualizer-views.ts +755 -0
  111. package/dist/resources/extensions/gsd/worktree-command.ts +18 -0
  112. package/dist/resources/extensions/gsd/worktree-manager.ts +11 -4
  113. package/dist/resources/extensions/remote-questions/config.ts +4 -2
  114. package/dist/resources/extensions/remote-questions/discord-adapter.ts +35 -4
  115. package/dist/resources/extensions/remote-questions/format.ts +166 -14
  116. package/dist/resources/extensions/remote-questions/manager.ts +14 -4
  117. package/dist/resources/extensions/remote-questions/remote-command.ts +100 -4
  118. package/dist/resources/extensions/remote-questions/slack-adapter.ts +58 -2
  119. package/dist/resources/extensions/remote-questions/telegram-adapter.ts +161 -0
  120. package/dist/resources/extensions/remote-questions/types.ts +2 -1
  121. package/dist/resources/extensions/ttsr/ttsr-manager.ts +26 -0
  122. package/dist/resources/extensions/voice/index.ts +4 -3
  123. package/package.json +1 -1
  124. package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
  125. package/packages/pi-coding-agent/dist/core/agent-session.js +12 -1
  126. package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
  127. package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts.map +1 -1
  128. package/packages/pi-coding-agent/dist/core/extensions/loader.js +5 -0
  129. package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
  130. package/packages/pi-coding-agent/dist/core/lsp/client.d.ts +6 -0
  131. package/packages/pi-coding-agent/dist/core/lsp/client.d.ts.map +1 -1
  132. package/packages/pi-coding-agent/dist/core/lsp/client.js +25 -0
  133. package/packages/pi-coding-agent/dist/core/lsp/client.js.map +1 -1
  134. package/packages/pi-coding-agent/dist/core/lsp/index.d.ts +2 -0
  135. package/packages/pi-coding-agent/dist/core/lsp/index.d.ts.map +1 -1
  136. package/packages/pi-coding-agent/dist/core/lsp/index.js +106 -3
  137. package/packages/pi-coding-agent/dist/core/lsp/index.js.map +1 -1
  138. package/packages/pi-coding-agent/dist/core/lsp/lsp.md +6 -0
  139. package/packages/pi-coding-agent/dist/core/lsp/types.d.ts +35 -0
  140. package/packages/pi-coding-agent/dist/core/lsp/types.d.ts.map +1 -1
  141. package/packages/pi-coding-agent/dist/core/lsp/types.js +6 -0
  142. package/packages/pi-coding-agent/dist/core/lsp/types.js.map +1 -1
  143. package/packages/pi-coding-agent/dist/core/lsp/utils.d.ts +3 -1
  144. package/packages/pi-coding-agent/dist/core/lsp/utils.d.ts.map +1 -1
  145. package/packages/pi-coding-agent/dist/core/lsp/utils.js +45 -0
  146. package/packages/pi-coding-agent/dist/core/lsp/utils.js.map +1 -1
  147. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +6 -0
  148. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
  149. package/packages/pi-coding-agent/dist/core/settings-manager.js +43 -11
  150. package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
  151. package/packages/pi-coding-agent/dist/core/system-prompt.d.ts.map +1 -1
  152. package/packages/pi-coding-agent/dist/core/system-prompt.js +7 -1
  153. package/packages/pi-coding-agent/dist/core/system-prompt.js.map +1 -1
  154. package/packages/pi-coding-agent/dist/core/tools/edit.d.ts.map +1 -1
  155. package/packages/pi-coding-agent/dist/core/tools/edit.js +5 -0
  156. package/packages/pi-coding-agent/dist/core/tools/edit.js.map +1 -1
  157. package/packages/pi-coding-agent/dist/core/tools/index.d.ts +2 -0
  158. package/packages/pi-coding-agent/dist/core/tools/index.d.ts.map +1 -1
  159. package/packages/pi-coding-agent/dist/core/tools/write.d.ts.map +1 -1
  160. package/packages/pi-coding-agent/dist/core/tools/write.js +5 -0
  161. package/packages/pi-coding-agent/dist/core/tools/write.js.map +1 -1
  162. package/packages/pi-coding-agent/src/core/agent-session.ts +13 -1
  163. package/packages/pi-coding-agent/src/core/extensions/loader.ts +6 -0
  164. package/packages/pi-coding-agent/src/core/lsp/client.ts +26 -0
  165. package/packages/pi-coding-agent/src/core/lsp/index.ts +157 -2
  166. package/packages/pi-coding-agent/src/core/lsp/lsp.md +6 -0
  167. package/packages/pi-coding-agent/src/core/lsp/types.ts +53 -0
  168. package/packages/pi-coding-agent/src/core/lsp/utils.ts +56 -0
  169. package/packages/pi-coding-agent/src/core/settings-manager.ts +41 -11
  170. package/packages/pi-coding-agent/src/core/system-prompt.ts +7 -1
  171. package/packages/pi-coding-agent/src/core/tools/edit.ts +3 -0
  172. package/packages/pi-coding-agent/src/core/tools/write.ts +3 -0
  173. package/src/resources/extensions/google-search/index.ts +164 -47
  174. package/src/resources/extensions/gsd/auto-dashboard.ts +14 -2
  175. package/src/resources/extensions/gsd/auto-prompts.ts +148 -39
  176. package/src/resources/extensions/gsd/auto-worktree.ts +93 -9
  177. package/src/resources/extensions/gsd/auto.ts +690 -39
  178. package/src/resources/extensions/gsd/captures.ts +384 -0
  179. package/src/resources/extensions/gsd/commands.ts +654 -36
  180. package/src/resources/extensions/gsd/complexity-classifier.ts +322 -0
  181. package/src/resources/extensions/gsd/context-budget.ts +243 -0
  182. package/src/resources/extensions/gsd/context-store.ts +195 -0
  183. package/src/resources/extensions/gsd/dashboard-overlay.ts +51 -3
  184. package/src/resources/extensions/gsd/db-writer.ts +341 -0
  185. package/src/resources/extensions/gsd/debug-logger.ts +178 -0
  186. package/src/resources/extensions/gsd/dispatch-guard.ts +0 -1
  187. package/src/resources/extensions/gsd/docs/preferences-reference.md +54 -0
  188. package/src/resources/extensions/gsd/doctor-proactive.ts +286 -0
  189. package/src/resources/extensions/gsd/doctor.ts +283 -2
  190. package/src/resources/extensions/gsd/export.ts +81 -2
  191. package/src/resources/extensions/gsd/files.ts +39 -9
  192. package/src/resources/extensions/gsd/git-service.ts +6 -0
  193. package/src/resources/extensions/gsd/gsd-db.ts +752 -0
  194. package/src/resources/extensions/gsd/guided-flow.ts +26 -1
  195. package/src/resources/extensions/gsd/history.ts +0 -1
  196. package/src/resources/extensions/gsd/index.ts +277 -1
  197. package/src/resources/extensions/gsd/md-importer.ts +526 -0
  198. package/src/resources/extensions/gsd/metrics.ts +84 -0
  199. package/src/resources/extensions/gsd/model-cost-table.ts +65 -0
  200. package/src/resources/extensions/gsd/model-router.ts +256 -0
  201. package/src/resources/extensions/gsd/notifications.ts +0 -1
  202. package/src/resources/extensions/gsd/post-unit-hooks.ts +72 -2
  203. package/src/resources/extensions/gsd/preferences.ts +198 -150
  204. package/src/resources/extensions/gsd/prompt-loader.ts +45 -9
  205. package/src/resources/extensions/gsd/prompts/execute-task.md +3 -5
  206. package/src/resources/extensions/gsd/prompts/heal-skill.md +45 -0
  207. package/src/resources/extensions/gsd/prompts/plan-slice.md +5 -1
  208. package/src/resources/extensions/gsd/prompts/quick-task.md +48 -0
  209. package/src/resources/extensions/gsd/prompts/reassess-roadmap.md +6 -0
  210. package/src/resources/extensions/gsd/prompts/replan-slice.md +8 -0
  211. package/src/resources/extensions/gsd/prompts/system.md +2 -1
  212. package/src/resources/extensions/gsd/prompts/triage-captures.md +62 -0
  213. package/src/resources/extensions/gsd/quick.ts +156 -0
  214. package/src/resources/extensions/gsd/skill-discovery.ts +5 -3
  215. package/src/resources/extensions/gsd/skill-health.ts +417 -0
  216. package/src/resources/extensions/gsd/skill-telemetry.ts +127 -0
  217. package/src/resources/extensions/gsd/state.ts +30 -0
  218. package/src/resources/extensions/gsd/templates/preferences.md +1 -0
  219. package/src/resources/extensions/gsd/tests/captures.test.ts +438 -0
  220. package/src/resources/extensions/gsd/tests/complexity-classifier.test.ts +181 -0
  221. package/src/resources/extensions/gsd/tests/context-budget.test.ts +283 -0
  222. package/src/resources/extensions/gsd/tests/context-compression.test.ts +1 -1
  223. package/src/resources/extensions/gsd/tests/context-store.test.ts +462 -0
  224. package/src/resources/extensions/gsd/tests/continue-here.test.ts +204 -0
  225. package/src/resources/extensions/gsd/tests/dashboard-budget.test.ts +346 -0
  226. package/src/resources/extensions/gsd/tests/db-writer.test.ts +602 -0
  227. package/src/resources/extensions/gsd/tests/debug-logger.test.ts +185 -0
  228. package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +406 -0
  229. package/src/resources/extensions/gsd/tests/dispatch-guard.test.ts +0 -1
  230. package/src/resources/extensions/gsd/tests/dist-redirect.mjs +22 -0
  231. package/src/resources/extensions/gsd/tests/doctor-proactive.test.ts +244 -0
  232. package/src/resources/extensions/gsd/tests/doctor-runtime.test.ts +303 -0
  233. package/src/resources/extensions/gsd/tests/feature-branch-lifecycle-integration.test.ts +434 -0
  234. package/src/resources/extensions/gsd/tests/gsd-db.test.ts +353 -0
  235. package/src/resources/extensions/gsd/tests/gsd-inspect.test.ts +125 -0
  236. package/src/resources/extensions/gsd/tests/gsd-tools.test.ts +326 -0
  237. package/src/resources/extensions/gsd/tests/integration-edge.test.ts +228 -0
  238. package/src/resources/extensions/gsd/tests/integration-lifecycle.test.ts +277 -0
  239. package/src/resources/extensions/gsd/tests/md-importer.test.ts +411 -0
  240. package/src/resources/extensions/gsd/tests/metrics.test.ts +197 -0
  241. package/src/resources/extensions/gsd/tests/milestone-transition-worktree.test.ts +144 -0
  242. package/src/resources/extensions/gsd/tests/model-cost-table.test.ts +69 -0
  243. package/src/resources/extensions/gsd/tests/model-isolation.test.ts +99 -0
  244. package/src/resources/extensions/gsd/tests/model-router.test.ts +167 -0
  245. package/src/resources/extensions/gsd/tests/parsers.test.ts +40 -0
  246. package/src/resources/extensions/gsd/tests/post-unit-hooks.test.ts +41 -1
  247. package/src/resources/extensions/gsd/tests/preferences-git.test.ts +0 -1
  248. package/src/resources/extensions/gsd/tests/preferences-hooks.test.ts +0 -1
  249. package/src/resources/extensions/gsd/tests/preferences-mode.test.ts +110 -0
  250. package/src/resources/extensions/gsd/tests/preferences-models.test.ts +0 -1
  251. package/src/resources/extensions/gsd/tests/prompt-budget-enforcement.test.ts +464 -0
  252. package/src/resources/extensions/gsd/tests/prompt-db.test.ts +385 -0
  253. package/src/resources/extensions/gsd/tests/remote-questions.test.ts +488 -1
  254. package/src/resources/extensions/gsd/tests/resolve-ts-hooks.mjs +17 -29
  255. package/src/resources/extensions/gsd/tests/resolve-ts.mjs +2 -8
  256. package/src/resources/extensions/gsd/tests/routing-history.test.ts +215 -62
  257. package/src/resources/extensions/gsd/tests/skill-lifecycle.test.ts +126 -0
  258. package/src/resources/extensions/gsd/tests/stop-auto-remote.test.ts +31 -8
  259. package/src/resources/extensions/gsd/tests/token-savings.test.ts +366 -0
  260. package/src/resources/extensions/gsd/tests/triage-dispatch.test.ts +224 -0
  261. package/src/resources/extensions/gsd/tests/triage-resolution.test.ts +215 -0
  262. package/src/resources/extensions/gsd/tests/unit-runtime.test.ts +25 -1
  263. package/src/resources/extensions/gsd/tests/visualizer-critical-path.test.ts +145 -0
  264. package/src/resources/extensions/gsd/tests/visualizer-data.test.ts +290 -0
  265. package/src/resources/extensions/gsd/tests/visualizer-overlay.test.ts +120 -0
  266. package/src/resources/extensions/gsd/tests/visualizer-views.test.ts +478 -0
  267. package/src/resources/extensions/gsd/tests/worktree-db-integration.test.ts +205 -0
  268. package/src/resources/extensions/gsd/tests/worktree-db.test.ts +442 -0
  269. package/src/resources/extensions/gsd/tests/worktree-post-create-hook.test.ts +165 -0
  270. package/src/resources/extensions/gsd/triage-resolution.ts +200 -0
  271. package/src/resources/extensions/gsd/triage-ui.ts +175 -0
  272. package/src/resources/extensions/gsd/types.ts +29 -0
  273. package/src/resources/extensions/gsd/undo.ts +0 -1
  274. package/src/resources/extensions/gsd/unit-runtime.ts +5 -1
  275. package/src/resources/extensions/gsd/visualizer-data.ts +505 -0
  276. package/src/resources/extensions/gsd/visualizer-overlay.ts +337 -0
  277. package/src/resources/extensions/gsd/visualizer-views.ts +755 -0
  278. package/src/resources/extensions/gsd/worktree-command.ts +18 -0
  279. package/src/resources/extensions/gsd/worktree-manager.ts +11 -4
  280. package/src/resources/extensions/remote-questions/config.ts +4 -2
  281. package/src/resources/extensions/remote-questions/discord-adapter.ts +35 -4
  282. package/src/resources/extensions/remote-questions/format.ts +166 -14
  283. package/src/resources/extensions/remote-questions/manager.ts +14 -4
  284. package/src/resources/extensions/remote-questions/remote-command.ts +100 -4
  285. package/src/resources/extensions/remote-questions/slack-adapter.ts +58 -2
  286. package/src/resources/extensions/remote-questions/telegram-adapter.ts +161 -0
  287. package/src/resources/extensions/remote-questions/types.ts +2 -1
  288. package/src/resources/extensions/ttsr/ttsr-manager.ts +26 -0
  289. package/src/resources/extensions/voice/index.ts +4 -3
@@ -55,7 +55,7 @@ export async function inlineFileOptional(
55
55
  * Load and inline dependency slice summaries (full content, not just paths).
56
56
  */
57
57
  export async function inlineDependencySummaries(
58
- mid: string, sid: string, base: string,
58
+ mid: string, sid: string, base: string, budgetChars?: number,
59
59
  ): Promise<string> {
60
60
  const roadmapFile = resolveMilestoneFile(base, mid, "ROADMAP");
61
61
  const roadmapContent = roadmapFile ? await loadFile(roadmapFile) : null;
@@ -79,7 +79,14 @@ export async function inlineDependencySummaries(
79
79
  sections.push(`- \`${relPath}\` _(not found)_`);
80
80
  }
81
81
  }
82
- return sections.join("\n\n");
82
+
83
+ const result = sections.join("\n\n");
84
+ // When a budget is provided, truncate at section boundaries to fit
85
+ if (budgetChars !== undefined && result.length > budgetChars) {
86
+ const { truncateAtSectionBoundary } = await import("./context-budget.js");
87
+ return truncateAtSectionBoundary(result, budgetChars).content;
88
+ }
89
+ return result;
83
90
  }
84
91
 
85
92
  /**
@@ -95,6 +102,76 @@ export async function inlineGsdRootFile(
95
102
  return inlineFileOptional(absPath, relGsdRootFile(key), label);
96
103
  }
97
104
 
105
+ // ─── DB-Aware Inline Helpers ──────────────────────────────────────────────
106
+
107
+ /**
108
+ * Inline decisions with optional milestone scoping from the DB.
109
+ * Falls back to filesystem via inlineGsdRootFile when DB unavailable or empty.
110
+ */
111
+ export async function inlineDecisionsFromDb(
112
+ base: string, milestoneId?: string, scope?: string,
113
+ ): Promise<string | null> {
114
+ try {
115
+ const { isDbAvailable } = await import("./gsd-db.js");
116
+ if (isDbAvailable()) {
117
+ const { queryDecisions, formatDecisionsForPrompt } = await import("./context-store.js");
118
+ const decisions = queryDecisions({ milestoneId, scope });
119
+ if (decisions.length > 0) {
120
+ const formatted = formatDecisionsForPrompt(decisions);
121
+ return `### Decisions\nSource: \`.gsd/DECISIONS.md\`\n\n${formatted}`;
122
+ }
123
+ }
124
+ } catch {
125
+ // DB not available — fall through to filesystem
126
+ }
127
+ return inlineGsdRootFile(base, "decisions.md", "Decisions");
128
+ }
129
+
130
+ /**
131
+ * Inline requirements with optional slice scoping from the DB.
132
+ * Falls back to filesystem via inlineGsdRootFile when DB unavailable or empty.
133
+ */
134
+ export async function inlineRequirementsFromDb(
135
+ base: string, sliceId?: string,
136
+ ): Promise<string | null> {
137
+ try {
138
+ const { isDbAvailable } = await import("./gsd-db.js");
139
+ if (isDbAvailable()) {
140
+ const { queryRequirements, formatRequirementsForPrompt } = await import("./context-store.js");
141
+ const requirements = queryRequirements({ sliceId });
142
+ if (requirements.length > 0) {
143
+ const formatted = formatRequirementsForPrompt(requirements);
144
+ return `### Requirements\nSource: \`.gsd/REQUIREMENTS.md\`\n\n${formatted}`;
145
+ }
146
+ }
147
+ } catch {
148
+ // DB not available — fall through to filesystem
149
+ }
150
+ return inlineGsdRootFile(base, "requirements.md", "Requirements");
151
+ }
152
+
153
+ /**
154
+ * Inline project context from the DB.
155
+ * Falls back to filesystem via inlineGsdRootFile when DB unavailable or empty.
156
+ */
157
+ export async function inlineProjectFromDb(
158
+ base: string,
159
+ ): Promise<string | null> {
160
+ try {
161
+ const { isDbAvailable } = await import("./gsd-db.js");
162
+ if (isDbAvailable()) {
163
+ const { queryProject } = await import("./context-store.js");
164
+ const content = queryProject();
165
+ if (content) {
166
+ return `### Project\nSource: \`.gsd/PROJECT.md\`\n\n${content}`;
167
+ }
168
+ }
169
+ } catch {
170
+ // DB not available — fall through to filesystem
171
+ }
172
+ return inlineGsdRootFile(base, "project.md", "Project");
173
+ }
174
+
98
175
  // ─── Skill Discovery ──────────────────────────────────────────────────────
99
176
 
100
177
  /**
@@ -371,11 +448,11 @@ export async function buildResearchMilestonePrompt(mid: string, midTitle: string
371
448
 
372
449
  const inlined: string[] = [];
373
450
  inlined.push(await inlineFile(contextPath, contextRel, "Milestone Context"));
374
- const projectInline = await inlineGsdRootFile(base, "project.md", "Project");
451
+ const projectInline = await inlineProjectFromDb(base);
375
452
  if (projectInline) inlined.push(projectInline);
376
- const requirementsInline = await inlineGsdRootFile(base, "requirements.md", "Requirements");
453
+ const requirementsInline = await inlineRequirementsFromDb(base);
377
454
  if (requirementsInline) inlined.push(requirementsInline);
378
- const decisionsInline = await inlineGsdRootFile(base, "decisions.md", "Decisions");
455
+ const decisionsInline = await inlineDecisionsFromDb(base, mid);
379
456
  if (decisionsInline) inlined.push(decisionsInline);
380
457
  const knowledgeInlineRM = await inlineGsdRootFile(base, "knowledge.md", "Project Knowledge");
381
458
  if (knowledgeInlineRM) inlined.push(knowledgeInlineRM);
@@ -389,7 +466,7 @@ export async function buildResearchMilestonePrompt(mid: string, midTitle: string
389
466
  milestoneId: mid, milestoneTitle: midTitle,
390
467
  milestonePath: relMilestonePath(base, mid),
391
468
  contextPath: contextRel,
392
- outputPath: outputRelPath,
469
+ outputPath: join(base, outputRelPath),
393
470
  inlinedContext,
394
471
  ...buildSkillDiscoveryVars(),
395
472
  });
@@ -409,12 +486,14 @@ export async function buildPlanMilestonePrompt(mid: string, midTitle: string, ba
409
486
  const { inlinePriorMilestoneSummary } = await import("./files.js");
410
487
  const priorSummaryInline = await inlinePriorMilestoneSummary(mid, base);
411
488
  if (priorSummaryInline) inlined.push(priorSummaryInline);
412
- const projectInline = inlineLevel !== "minimal" ? await inlineGsdRootFile(base, "project.md", "Project") : null;
413
- if (projectInline) inlined.push(projectInline);
414
- const requirementsInline = inlineLevel !== "minimal" ? await inlineGsdRootFile(base, "requirements.md", "Requirements") : null;
415
- if (requirementsInline) inlined.push(requirementsInline);
416
- const decisionsInline = inlineLevel !== "minimal" ? await inlineGsdRootFile(base, "decisions.md", "Decisions") : null;
417
- if (decisionsInline) inlined.push(decisionsInline);
489
+ if (inlineLevel !== "minimal") {
490
+ const projectInline = await inlineProjectFromDb(base);
491
+ if (projectInline) inlined.push(projectInline);
492
+ const requirementsInline = await inlineRequirementsFromDb(base);
493
+ if (requirementsInline) inlined.push(requirementsInline);
494
+ const decisionsInline = await inlineDecisionsFromDb(base, mid);
495
+ if (decisionsInline) inlined.push(decisionsInline);
496
+ }
418
497
  const knowledgeInlinePM = await inlineGsdRootFile(base, "knowledge.md", "Project Knowledge");
419
498
  if (knowledgeInlinePM) inlined.push(knowledgeInlinePM);
420
499
  inlined.push(inlineTemplate("roadmap", "Roadmap"));
@@ -432,14 +511,14 @@ export async function buildPlanMilestonePrompt(mid: string, midTitle: string, ba
432
511
  const inlinedContext = `## Inlined Context (preloaded — do not re-read these files)\n\n${inlined.join("\n\n---\n\n")}`;
433
512
 
434
513
  const outputRelPath = relMilestoneFile(base, mid, "ROADMAP");
435
- const secretsOutputPath = relMilestoneFile(base, mid, "SECRETS");
514
+ const secretsOutputPath = join(base, relMilestoneFile(base, mid, "SECRETS"));
436
515
  return loadPrompt("plan-milestone", {
437
516
  workingDirectory: base,
438
517
  milestoneId: mid, milestoneTitle: midTitle,
439
518
  milestonePath: relMilestonePath(base, mid),
440
519
  contextPath: contextRel,
441
520
  researchPath: researchRel,
442
- outputPath: outputRelPath,
521
+ outputPath: join(base, outputRelPath),
443
522
  secretsOutputPath,
444
523
  inlinedContext,
445
524
  });
@@ -461,9 +540,9 @@ export async function buildResearchSlicePrompt(
461
540
  if (contextInline) inlined.push(contextInline);
462
541
  const researchInline = await inlineFileOptional(milestoneResearchPath, milestoneResearchRel, "Milestone Research");
463
542
  if (researchInline) inlined.push(researchInline);
464
- const decisionsInline = await inlineGsdRootFile(base, "decisions.md", "Decisions");
543
+ const decisionsInline = await inlineDecisionsFromDb(base, mid);
465
544
  if (decisionsInline) inlined.push(decisionsInline);
466
- const requirementsInline = await inlineGsdRootFile(base, "requirements.md", "Requirements");
545
+ const requirementsInline = await inlineRequirementsFromDb(base, sid);
467
546
  if (requirementsInline) inlined.push(requirementsInline);
468
547
  const knowledgeInlineRS = await inlineGsdRootFile(base, "knowledge.md", "Project Knowledge");
469
548
  if (knowledgeInlineRS) inlined.push(knowledgeInlineRS);
@@ -484,7 +563,7 @@ export async function buildResearchSlicePrompt(
484
563
  roadmapPath: roadmapRel,
485
564
  contextPath: contextRel,
486
565
  milestoneResearchPath: milestoneResearchRel,
487
- outputPath: outputRelPath,
566
+ outputPath: join(base, outputRelPath),
488
567
  inlinedContext,
489
568
  dependencySummaries: depContent,
490
569
  ...buildSkillDiscoveryVars(),
@@ -505,9 +584,9 @@ export async function buildPlanSlicePrompt(
505
584
  const researchInline = await inlineFileOptional(researchPath, researchRel, "Slice Research");
506
585
  if (researchInline) inlined.push(researchInline);
507
586
  if (inlineLevel !== "minimal") {
508
- const decisionsInline = await inlineGsdRootFile(base, "decisions.md", "Decisions");
587
+ const decisionsInline = await inlineDecisionsFromDb(base, mid);
509
588
  if (decisionsInline) inlined.push(decisionsInline);
510
- const requirementsInline = await inlineGsdRootFile(base, "requirements.md", "Requirements");
589
+ const requirementsInline = await inlineRequirementsFromDb(base, sid);
511
590
  if (requirementsInline) inlined.push(requirementsInline);
512
591
  }
513
592
  const knowledgeInlinePS = await inlineGsdRootFile(base, "knowledge.md", "Project Knowledge");
@@ -531,7 +610,7 @@ export async function buildPlanSlicePrompt(
531
610
  slicePath: relSlicePath(base, mid, sid),
532
611
  roadmapPath: roadmapRel,
533
612
  researchPath: researchRel,
534
- outputPath: outputRelPath,
613
+ outputPath: join(base, outputRelPath),
535
614
  inlinedContext,
536
615
  dependencySummaries: depContent,
537
616
  });
@@ -598,7 +677,7 @@ export async function buildExecuteTaskPrompt(
598
677
  ...(knowledgeInlineET ? [knowledgeInlineET] : []),
599
678
  ].join("\n\n---\n\n");
600
679
 
601
- const taskSummaryPath = `${relSlicePath(base, mid, sid)}/tasks/${tid}-SUMMARY.md`;
680
+ const taskSummaryPath = join(base, `${relSlicePath(base, mid, sid)}/tasks/${tid}-SUMMARY.md`);
602
681
 
603
682
  const activeOverrides = await loadActiveOverrides(base);
604
683
  const overridesSection = formatOverridesSection(activeOverrides);
@@ -607,7 +686,7 @@ export async function buildExecuteTaskPrompt(
607
686
  overridesSection,
608
687
  workingDirectory: base,
609
688
  milestoneId: mid, sliceId: sid, sliceTitle: sTitle, taskId: tid, taskTitle: tTitle,
610
- planPath: relSliceFile(base, mid, sid, "PLAN"),
689
+ planPath: join(base, relSliceFile(base, mid, sid, "PLAN")),
611
690
  slicePath: relSlicePath(base, mid, sid),
612
691
  taskPlanPath: taskPlanRelPath,
613
692
  taskPlanInline,
@@ -634,7 +713,7 @@ export async function buildCompleteSlicePrompt(
634
713
  inlined.push(await inlineFile(roadmapPath, roadmapRel, "Milestone Roadmap"));
635
714
  inlined.push(await inlineFile(slicePlanPath, slicePlanRel, "Slice Plan"));
636
715
  if (inlineLevel !== "minimal") {
637
- const requirementsInline = await inlineGsdRootFile(base, "requirements.md", "Requirements");
716
+ const requirementsInline = await inlineRequirementsFromDb(base, sid);
638
717
  if (requirementsInline) inlined.push(requirementsInline);
639
718
  }
640
719
  const knowledgeInlineCS = await inlineGsdRootFile(base, "knowledge.md", "Project Knowledge");
@@ -665,14 +744,14 @@ export async function buildCompleteSlicePrompt(
665
744
  const inlinedContext = `## Inlined Context (preloaded — do not re-read these files)\n\n${inlined.join("\n\n---\n\n")}`;
666
745
 
667
746
  const sliceRel = relSlicePath(base, mid, sid);
668
- const sliceSummaryPath = `${sliceRel}/${sid}-SUMMARY.md`;
669
- const sliceUatPath = `${sliceRel}/${sid}-UAT.md`;
747
+ const sliceSummaryPath = join(base, `${sliceRel}/${sid}-SUMMARY.md`);
748
+ const sliceUatPath = join(base, `${sliceRel}/${sid}-UAT.md`);
670
749
 
671
750
  return loadPrompt("complete-slice", {
672
751
  workingDirectory: base,
673
752
  milestoneId: mid, sliceId: sid, sliceTitle: sTitle,
674
753
  slicePath: sliceRel,
675
- roadmapPath: roadmapRel,
754
+ roadmapPath: join(base, roadmapRel),
676
755
  inlinedContext,
677
756
  sliceSummaryPath,
678
757
  sliceUatPath,
@@ -705,11 +784,11 @@ export async function buildCompleteMilestonePrompt(
705
784
 
706
785
  // Inline root GSD files (skip for minimal — completion can read these if needed)
707
786
  if (inlineLevel !== "minimal") {
708
- const requirementsInline = await inlineGsdRootFile(base, "requirements.md", "Requirements");
787
+ const requirementsInline = await inlineRequirementsFromDb(base);
709
788
  if (requirementsInline) inlined.push(requirementsInline);
710
- const decisionsInline = await inlineGsdRootFile(base, "decisions.md", "Decisions");
789
+ const decisionsInline = await inlineDecisionsFromDb(base, mid);
711
790
  if (decisionsInline) inlined.push(decisionsInline);
712
- const projectInline = await inlineGsdRootFile(base, "project.md", "Project");
791
+ const projectInline = await inlineProjectFromDb(base);
713
792
  if (projectInline) inlined.push(projectInline);
714
793
  }
715
794
  const knowledgeInlineCM = await inlineGsdRootFile(base, "knowledge.md", "Project Knowledge");
@@ -723,7 +802,7 @@ export async function buildCompleteMilestonePrompt(
723
802
 
724
803
  const inlinedContext = `## Inlined Context (preloaded — do not re-read these files)\n\n${inlined.join("\n\n---\n\n")}`;
725
804
 
726
- const milestoneSummaryPath = `${relMilestonePath(base, mid)}/${mid}-SUMMARY.md`;
805
+ const milestoneSummaryPath = join(base, `${relMilestonePath(base, mid)}/${mid}-SUMMARY.md`);
727
806
 
728
807
  return loadPrompt("complete-milestone", {
729
808
  workingDirectory: base,
@@ -767,7 +846,7 @@ export async function buildReplanSlicePrompt(
767
846
  }
768
847
 
769
848
  // Inline decisions
770
- const decisionsInline = await inlineGsdRootFile(base, "decisions.md", "Decisions");
849
+ const decisionsInline = await inlineDecisionsFromDb(base, mid);
771
850
  if (decisionsInline) inlined.push(decisionsInline);
772
851
  const replanActiveOverrides = await loadActiveOverrides(base);
773
852
  const replanOverridesInline = formatOverridesSection(replanActiveOverrides);
@@ -775,7 +854,21 @@ export async function buildReplanSlicePrompt(
775
854
 
776
855
  const inlinedContext = `## Inlined Context (preloaded — do not re-read these files)\n\n${inlined.join("\n\n---\n\n")}`;
777
856
 
778
- const replanPath = `${relSlicePath(base, mid, sid)}/${sid}-REPLAN.md`;
857
+ const replanPath = join(base, `${relSlicePath(base, mid, sid)}/${sid}-REPLAN.md`);
858
+
859
+ // Build capture context for replan prompt (captures that triggered this replan)
860
+ let captureContext = "(none)";
861
+ try {
862
+ const { loadReplanCaptures } = await import("./triage-resolution.js");
863
+ const replanCaptures = loadReplanCaptures(base);
864
+ if (replanCaptures.length > 0) {
865
+ captureContext = replanCaptures.map(c =>
866
+ `- **${c.id}**: "${c.text}" — ${c.rationale ?? "no rationale"}`
867
+ ).join("\n");
868
+ }
869
+ } catch {
870
+ // Non-fatal — captures module may not be available
871
+ }
779
872
 
780
873
  return loadPrompt("replan-slice", {
781
874
  workingDirectory: base,
@@ -783,10 +876,11 @@ export async function buildReplanSlicePrompt(
783
876
  sliceId: sid,
784
877
  sliceTitle: sTitle,
785
878
  slicePath: relSlicePath(base, mid, sid),
786
- planPath: slicePlanRel,
879
+ planPath: join(base, slicePlanRel),
787
880
  blockerTaskId,
788
881
  inlinedContext,
789
882
  replanPath,
883
+ captureContext,
790
884
  });
791
885
  }
792
886
 
@@ -803,12 +897,12 @@ export async function buildRunUatPrompt(
803
897
  if (summaryInline) inlined.push(summaryInline);
804
898
  }
805
899
 
806
- const projectInline = await inlineGsdRootFile(base, "project.md", "Project");
900
+ const projectInline = await inlineProjectFromDb(base);
807
901
  if (projectInline) inlined.push(projectInline);
808
902
 
809
903
  const inlinedContext = `## Inlined Context (preloaded — do not re-read these files)\n\n${inlined.join("\n\n---\n\n")}`;
810
904
 
811
- const uatResultPath = relSliceFile(base, mid, sliceId, "UAT-RESULT");
905
+ const uatResultPath = join(base, relSliceFile(base, mid, sliceId, "UAT-RESULT"));
812
906
  const uatType = extractUatType(uatContent) ?? "human-experience";
813
907
 
814
908
  return loadPrompt("run-uat", {
@@ -835,11 +929,11 @@ export async function buildReassessRoadmapPrompt(
835
929
  inlined.push(await inlineFile(roadmapPath, roadmapRel, "Current Roadmap"));
836
930
  inlined.push(await inlineFile(summaryPath, summaryRel, `${completedSliceId} Summary`));
837
931
  if (inlineLevel !== "minimal") {
838
- const projectInline = await inlineGsdRootFile(base, "project.md", "Project");
932
+ const projectInline = await inlineProjectFromDb(base);
839
933
  if (projectInline) inlined.push(projectInline);
840
- const requirementsInline = await inlineGsdRootFile(base, "requirements.md", "Requirements");
934
+ const requirementsInline = await inlineRequirementsFromDb(base);
841
935
  if (requirementsInline) inlined.push(requirementsInline);
842
- const decisionsInline = await inlineGsdRootFile(base, "decisions.md", "Decisions");
936
+ const decisionsInline = await inlineDecisionsFromDb(base, mid);
843
937
  if (decisionsInline) inlined.push(decisionsInline);
844
938
  }
845
939
  const knowledgeInlineRA = await inlineGsdRootFile(base, "knowledge.md", "Project Knowledge");
@@ -847,7 +941,21 @@ export async function buildReassessRoadmapPrompt(
847
941
 
848
942
  const inlinedContext = `## Inlined Context (preloaded — do not re-read these files)\n\n${inlined.join("\n\n---\n\n")}`;
849
943
 
850
- const assessmentPath = relSliceFile(base, mid, completedSliceId, "ASSESSMENT");
944
+ const assessmentPath = join(base, relSliceFile(base, mid, completedSliceId, "ASSESSMENT"));
945
+
946
+ // Build deferred captures context for reassess prompt
947
+ let deferredCaptures = "(none)";
948
+ try {
949
+ const { loadDeferredCaptures } = await import("./triage-resolution.js");
950
+ const deferred = loadDeferredCaptures(base);
951
+ if (deferred.length > 0) {
952
+ deferredCaptures = deferred.map(c =>
953
+ `- **${c.id}**: "${c.text}" — ${c.rationale ?? "deferred during triage"}`
954
+ ).join("\n");
955
+ }
956
+ } catch {
957
+ // Non-fatal — captures module may not be available
958
+ }
851
959
 
852
960
  return loadPrompt("reassess-roadmap", {
853
961
  workingDirectory: base,
@@ -858,6 +966,7 @@ export async function buildReassessRoadmapPrompt(
858
966
  completedSliceSummaryPath: summaryRel,
859
967
  assessmentPath,
860
968
  inlinedContext,
969
+ deferredCaptures,
861
970
  });
862
971
  }
863
972
 
@@ -7,8 +7,9 @@
7
7
  */
8
8
 
9
9
  import { existsSync, cpSync, readFileSync, realpathSync, utimesSync } from "node:fs";
10
- import { join, resolve } from "node:path";
11
- import { execSync } from "node:child_process";
10
+ import { isAbsolute, join, resolve } from "node:path";
11
+ import { copyWorktreeDb, reconcileWorktreeDb, isDbAvailable } from "./gsd-db.js";
12
+ import { execSync, execFileSync } from "node:child_process";
12
13
  import {
13
14
  createWorktree,
14
15
  removeWorktree,
@@ -33,6 +34,7 @@ import {
33
34
  nativeAddPaths,
34
35
  nativeRmForce,
35
36
  nativeBranchDelete,
37
+ nativeBranchExists,
36
38
  } from "./native-git-bridge.js";
37
39
 
38
40
  // ─── Module State ──────────────────────────────────────────────────────────
@@ -75,6 +77,48 @@ function nudgeGitBranchCache(previousCwd: string): void {
75
77
  }
76
78
  }
77
79
 
80
+ // ─── Worktree Post-Create Hook (#597) ────────────────────────────────────────
81
+
82
+ /**
83
+ * Run the user-configured post-create hook script after worktree creation.
84
+ * The script receives SOURCE_DIR and WORKTREE_DIR as environment variables.
85
+ * Failure is non-fatal — returns the error message or null on success.
86
+ *
87
+ * Reads the hook path from git.worktree_post_create in preferences.
88
+ * Pass hookPath directly to bypass preference loading (useful for testing).
89
+ */
90
+ export function runWorktreePostCreateHook(sourceDir: string, worktreeDir: string, hookPath?: string): string | null {
91
+ if (hookPath === undefined) {
92
+ const prefs = loadEffectiveGSDPreferences()?.preferences?.git;
93
+ hookPath = prefs?.worktree_post_create;
94
+ }
95
+ if (!hookPath) return null;
96
+
97
+ // Resolve relative paths against the source project root
98
+ const resolved = isAbsolute(hookPath) ? hookPath : join(sourceDir, hookPath);
99
+ if (!existsSync(resolved)) {
100
+ return `Worktree post-create hook not found: ${resolved}`;
101
+ }
102
+
103
+ try {
104
+ execSync(resolved, {
105
+ cwd: worktreeDir,
106
+ env: {
107
+ ...process.env,
108
+ SOURCE_DIR: sourceDir,
109
+ WORKTREE_DIR: worktreeDir,
110
+ },
111
+ stdio: ["ignore", "pipe", "pipe"],
112
+ encoding: "utf-8",
113
+ timeout: 30_000, // 30 second timeout
114
+ });
115
+ return null;
116
+ } catch (err) {
117
+ const msg = err instanceof Error ? err.message : String(err);
118
+ return `Worktree post-create hook failed: ${msg}`;
119
+ }
120
+ }
121
+
78
122
  // ─── Auto-Worktree Branch Naming ───────────────────────────────────────────
79
123
 
80
124
  export function autoWorktreeBranch(milestoneId: string): string {
@@ -93,11 +137,21 @@ export function autoWorktreeBranch(milestoneId: string): string {
93
137
  export function createAutoWorktree(basePath: string, milestoneId: string): string {
94
138
  const branch = autoWorktreeBranch(milestoneId);
95
139
 
96
- // Use the integration branch recorded in META.json as the start point.
97
- // This ensures the worktree branch is created from the branch the user
98
- // was on when they started the milestone (e.g. f-setup-gsd-2), not main.
99
- const integrationBranch = readIntegrationBranch(basePath, milestoneId) ?? undefined;
100
- const info = createWorktree(basePath, milestoneId, { branch, startPoint: integrationBranch });
140
+ // Check if the milestone branch already exists it survives auto-mode
141
+ // stop/pause and contains committed work from prior sessions. If it exists,
142
+ // re-attach the worktree to it WITHOUT resetting. Only create a fresh branch
143
+ // from the integration branch when no prior work exists.
144
+ const branchExists = nativeBranchExists(basePath, branch);
145
+
146
+ let info: { name: string; path: string; branch: string; exists: boolean };
147
+ if (branchExists) {
148
+ // Re-attach worktree to the existing milestone branch (preserving commits)
149
+ info = createWorktree(basePath, milestoneId, { branch, reuseExistingBranch: true });
150
+ } else {
151
+ // Fresh start — create branch from integration branch
152
+ const integrationBranch = readIntegrationBranch(basePath, milestoneId) ?? undefined;
153
+ info = createWorktree(basePath, milestoneId, { branch, startPoint: integrationBranch });
154
+ }
101
155
 
102
156
  // Copy .gsd/ planning artifacts from the source repo into the new worktree.
103
157
  // Worktrees are fresh git checkouts — untracked files don't carry over.
@@ -106,6 +160,13 @@ export function createAutoWorktree(basePath: string, milestoneId: string): strin
106
160
  // on plan-slice because the plan file doesn't exist in the worktree.
107
161
  copyPlanningArtifacts(basePath, info.path);
108
162
 
163
+ // Run user-configured post-create hook (#597) — e.g. copy .env, symlink assets
164
+ const hookError = runWorktreePostCreateHook(basePath, info.path);
165
+ if (hookError) {
166
+ // Non-fatal — log but don't prevent worktree usage
167
+ console.error(`[GSD] ${hookError}`);
168
+ }
169
+
109
170
  const previousCwd = process.cwd();
110
171
 
111
172
  try {
@@ -151,14 +212,28 @@ function copyPlanningArtifacts(srcBase: string, wtPath: string): void {
151
212
  } catch { /* non-fatal */ }
152
213
  }
153
214
  }
215
+
216
+ // Copy gsd.db if present in source
217
+ const srcDb = join(srcGsd, "gsd.db");
218
+ const destDb = join(dstGsd, "gsd.db");
219
+ if (existsSync(srcDb)) {
220
+ try {
221
+ copyWorktreeDb(srcDb, destDb);
222
+ } catch { /* non-fatal */ }
223
+ }
154
224
  }
155
225
 
156
226
  /**
157
227
  * Teardown an auto-worktree: chdir back to original base, then remove
158
228
  * the worktree and its branch.
159
229
  */
160
- export function teardownAutoWorktree(originalBasePath: string, milestoneId: string): void {
230
+ export function teardownAutoWorktree(
231
+ originalBasePath: string,
232
+ milestoneId: string,
233
+ opts: { preserveBranch?: boolean } = {},
234
+ ): void {
161
235
  const branch = autoWorktreeBranch(milestoneId);
236
+ const { preserveBranch = false } = opts;
162
237
  const previousCwd = process.cwd();
163
238
 
164
239
  try {
@@ -171,7 +246,7 @@ export function teardownAutoWorktree(originalBasePath: string, milestoneId: stri
171
246
  }
172
247
 
173
248
  nudgeGitBranchCache(previousCwd);
174
- removeWorktree(originalBasePath, milestoneId, { branch });
249
+ removeWorktree(originalBasePath, milestoneId, { branch, deleteBranch: !preserveBranch });
175
250
  }
176
251
 
177
252
  /**
@@ -299,6 +374,15 @@ export function mergeMilestoneToMain(
299
374
  // 1. Auto-commit dirty state in worktree before leaving
300
375
  autoCommitDirtyState(worktreeCwd);
301
376
 
377
+ // Reconcile worktree DB into main DB before leaving worktree context
378
+ if (isDbAvailable()) {
379
+ try {
380
+ const worktreeDbPath = join(worktreeCwd, ".gsd", "gsd.db");
381
+ const mainDbPath = join(originalBasePath_, ".gsd", "gsd.db");
382
+ reconcileWorktreeDb(mainDbPath, worktreeDbPath);
383
+ } catch { /* non-fatal */ }
384
+ }
385
+
302
386
  // 2. Parse roadmap for slice listing
303
387
  const roadmap = parseRoadmap(roadmapContent);
304
388
  const completedSlices = roadmap.slices.filter(s => s.done);