gsd-pi 2.78.0-dev.aeeb2ca00 → 2.78.1-dev.84a383f51

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 (383) hide show
  1. package/README.md +7 -7
  2. package/dist/claude-cli-check.js +64 -37
  3. package/dist/cli-policy.d.ts +13 -0
  4. package/dist/cli-policy.js +17 -0
  5. package/dist/cli.js +95 -55
  6. package/dist/headless-query.d.ts +22 -0
  7. package/dist/headless-query.js +24 -4
  8. package/dist/headless.d.ts +10 -0
  9. package/dist/headless.js +16 -1
  10. package/dist/loader.js +7 -10
  11. package/dist/onboarding.d.ts +10 -0
  12. package/dist/onboarding.js +2 -2
  13. package/dist/provider-migrations.d.ts +2 -2
  14. package/dist/provider-migrations.js +5 -2
  15. package/dist/resource-loader.d.ts +5 -2
  16. package/dist/resource-loader.js +28 -5
  17. package/dist/resources/.managed-resources-content-hash +1 -0
  18. package/dist/resources/extensions/claude-code-cli/readiness.js +77 -45
  19. package/dist/resources/extensions/gsd/auto/loop.js +23 -0
  20. package/dist/resources/extensions/gsd/auto/phases.js +2 -2
  21. package/dist/resources/extensions/gsd/auto/run-unit.js +3 -1
  22. package/dist/resources/extensions/gsd/auto/session.js +3 -0
  23. package/dist/resources/extensions/gsd/auto-recovery.js +43 -4
  24. package/dist/resources/extensions/gsd/auto-runtime-state.js +31 -0
  25. package/dist/resources/extensions/gsd/auto-start.js +1 -1
  26. package/dist/resources/extensions/gsd/auto-tool-tracking.js +2 -2
  27. package/dist/resources/extensions/gsd/auto-worktree.js +30 -0
  28. package/dist/resources/extensions/gsd/auto.js +14 -5
  29. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +14 -2
  30. package/dist/resources/extensions/gsd/bootstrap/exec-tools.js +7 -5
  31. package/dist/resources/extensions/gsd/bootstrap/query-tools.js +2 -2
  32. package/dist/resources/extensions/gsd/bootstrap/register-extension.js +5 -4
  33. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +94 -31
  34. package/dist/resources/extensions/gsd/bootstrap/register-shortcuts.js +11 -6
  35. package/dist/resources/extensions/gsd/bootstrap/system-context.js +34 -8
  36. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +38 -2
  37. package/dist/resources/extensions/gsd/commands/catalog.js +69 -5
  38. package/dist/resources/extensions/gsd/commands/handlers/core.js +22 -1
  39. package/dist/resources/extensions/gsd/commands-mcp-status.js +3 -1
  40. package/dist/resources/extensions/gsd/commands-prefs-wizard.js +10 -1
  41. package/dist/resources/extensions/gsd/dashboard-overlay.js +1 -1
  42. package/dist/resources/extensions/gsd/docs/preferences-reference.md +4 -0
  43. package/dist/resources/extensions/gsd/doctor-runtime-checks.js +39 -1
  44. package/dist/resources/extensions/gsd/error-classifier.js +1 -1
  45. package/dist/resources/extensions/gsd/forensics.js +2 -2
  46. package/dist/resources/extensions/gsd/git-service.js +12 -5
  47. package/dist/resources/extensions/gsd/gsd-db.js +11 -2
  48. package/dist/resources/extensions/gsd/guided-flow.js +23 -23
  49. package/dist/resources/extensions/gsd/memory-store.js +66 -31
  50. package/dist/resources/extensions/gsd/milestone-id-reservation.js +36 -0
  51. package/dist/resources/extensions/gsd/model-router.js +114 -9
  52. package/dist/resources/extensions/gsd/native-git-bridge.js +7 -1
  53. package/dist/resources/extensions/gsd/preferences-models.js +91 -15
  54. package/dist/resources/extensions/gsd/preferences-types.js +2 -0
  55. package/dist/resources/extensions/gsd/preferences-validation.js +32 -0
  56. package/dist/resources/extensions/gsd/preferences.js +5 -3
  57. package/dist/resources/extensions/gsd/prompt-loader.js +23 -12
  58. package/dist/resources/extensions/gsd/slice-parallel-orchestrator.js +9 -3
  59. package/dist/resources/extensions/gsd/state.js +42 -0
  60. package/dist/resources/extensions/gsd/templates/PREFERENCES.md +1 -0
  61. package/dist/resources/extensions/gsd/tools/memory-tools.js +18 -1
  62. package/dist/resources/extensions/gsd/visualizer-overlay.js +1 -1
  63. package/dist/resources/extensions/gsd/watch/header-renderer.js +3 -1
  64. package/dist/resources/extensions/gsd/worktree-command.js +26 -46
  65. package/dist/resources/extensions/gsd/worktree-session-state.js +33 -0
  66. package/dist/resources/extensions/mcp-client/index.js +6 -3
  67. package/dist/resources/extensions/slash-commands/create-extension.js +36 -22
  68. package/dist/resources/skills/create-gsd-extension/SKILL.md +9 -5
  69. package/dist/resources/skills/create-gsd-extension/references/custom-commands.md +1 -1
  70. package/dist/resources/skills/create-gsd-extension/references/custom-rendering.md +5 -5
  71. package/dist/resources/skills/create-gsd-extension/references/custom-tools.md +4 -4
  72. package/dist/resources/skills/create-gsd-extension/references/custom-ui.md +6 -6
  73. package/dist/resources/skills/create-gsd-extension/references/events-reference.md +3 -3
  74. package/dist/resources/skills/create-gsd-extension/references/packaging-distribution.md +1 -1
  75. package/dist/resources/skills/create-gsd-extension/references/remote-execution-overrides.md +3 -3
  76. package/dist/resources/skills/create-gsd-extension/workflows/create-extension.md +32 -12
  77. package/dist/rtk-shared.d.ts +3 -0
  78. package/dist/rtk-shared.js +17 -0
  79. package/dist/rtk.d.ts +2 -5
  80. package/dist/rtk.js +3 -20
  81. package/dist/runtime-checks.d.ts +27 -0
  82. package/dist/runtime-checks.js +38 -0
  83. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  84. package/dist/web/standalone/.next/BUILD_ID +1 -1
  85. package/dist/web/standalone/.next/app-path-routes-manifest.json +12 -12
  86. package/dist/web/standalone/.next/build-manifest.json +3 -3
  87. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  88. package/dist/web/standalone/.next/react-loadable-manifest.json +44 -4
  89. package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  90. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  91. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  92. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  93. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  94. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  95. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  96. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  97. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  98. package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  99. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  100. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  101. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  102. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  103. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  104. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  105. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  106. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  107. package/dist/web/standalone/.next/server/app/api/boot/route.js +1 -1
  108. package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
  109. package/dist/web/standalone/.next/server/app/api/session/events/route.js +4 -2
  110. package/dist/web/standalone/.next/server/app/api/shutdown/route.js +1 -1
  111. package/dist/web/standalone/.next/server/app/index.html +1 -1
  112. package/dist/web/standalone/.next/server/app/index.rsc +2 -2
  113. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  114. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +2 -2
  115. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  116. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  117. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  118. package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  119. package/dist/web/standalone/.next/server/app-paths-manifest.json +12 -12
  120. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  121. package/dist/web/standalone/.next/server/middleware-manifest.json +5 -5
  122. package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
  123. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  124. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  125. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  126. package/dist/web/standalone/.next/server/webpack-runtime.js +1 -1
  127. package/dist/web/standalone/.next/static/chunks/2556.0527fea66e123b7f.js +1 -0
  128. package/dist/web/standalone/.next/static/chunks/2824.08296bc2f9654698.js +1 -0
  129. package/dist/web/standalone/.next/static/chunks/3026.3af53b279375f082.js +1 -0
  130. package/dist/web/standalone/.next/static/chunks/315.6f68ae79b67d25cf.js +1 -0
  131. package/dist/web/standalone/.next/static/chunks/3497.4bfc60a3b3dea717.js +1 -0
  132. package/dist/web/standalone/.next/static/chunks/5516.4a07c872b5c3a663.js +1 -0
  133. package/dist/web/standalone/.next/static/chunks/8336.31b019697882acfb.js +10 -0
  134. package/dist/web/standalone/.next/static/chunks/8845.c9702695e8c5a9c5.js +2 -0
  135. package/dist/web/standalone/.next/static/chunks/9058.01ef3a463bda88f1.js +20 -0
  136. package/dist/web/standalone/.next/static/chunks/9441.1081da1125d1764f.js +1 -0
  137. package/dist/web/standalone/.next/static/chunks/app/{page-5b113fd32bc2a1c3.js → page-9bf2e0c50fb2ca05.js} +1 -1
  138. package/dist/web/standalone/.next/static/chunks/webpack-f9f0dc45e4f3ac10.js +1 -0
  139. package/dist/web/standalone/package.json +2 -1
  140. package/dist/worktree-status-banner.d.ts +1 -0
  141. package/dist/worktree-status-banner.js +132 -0
  142. package/package.json +1 -1
  143. package/packages/daemon/package.json +2 -2
  144. package/packages/mcp-server/dist/alias-telemetry.d.ts +8 -0
  145. package/packages/mcp-server/dist/alias-telemetry.d.ts.map +1 -0
  146. package/packages/mcp-server/dist/alias-telemetry.js +30 -0
  147. package/packages/mcp-server/dist/alias-telemetry.js.map +1 -0
  148. package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
  149. package/packages/mcp-server/dist/workflow-tools.js +74 -46
  150. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  151. package/packages/mcp-server/package.json +2 -2
  152. package/packages/mcp-server/src/alias-telemetry.test.ts +78 -0
  153. package/packages/mcp-server/src/alias-telemetry.ts +30 -0
  154. package/packages/mcp-server/src/workflow-tools.test.ts +26 -0
  155. package/packages/mcp-server/src/workflow-tools.ts +93 -58
  156. package/packages/mcp-server/tsconfig.tsbuildinfo +1 -1
  157. package/packages/native/package.json +1 -1
  158. package/packages/pi-agent-core/package.json +1 -1
  159. package/packages/pi-agent-core/tsconfig.tsbuildinfo +1 -1
  160. package/packages/pi-ai/dist/providers/anthropic-shared.cache-breakpoint.test.d.ts +2 -0
  161. package/packages/pi-ai/dist/providers/anthropic-shared.cache-breakpoint.test.d.ts.map +1 -0
  162. package/packages/pi-ai/dist/providers/anthropic-shared.cache-breakpoint.test.js +231 -0
  163. package/packages/pi-ai/dist/providers/anthropic-shared.cache-breakpoint.test.js.map +1 -0
  164. package/packages/pi-ai/dist/providers/anthropic-shared.d.ts.map +1 -1
  165. package/packages/pi-ai/dist/providers/anthropic-shared.js +48 -19
  166. package/packages/pi-ai/dist/providers/anthropic-shared.js.map +1 -1
  167. package/packages/pi-ai/dist/types.d.ts +13 -0
  168. package/packages/pi-ai/dist/types.d.ts.map +1 -1
  169. package/packages/pi-ai/dist/types.js.map +1 -1
  170. package/packages/pi-ai/dist/utils/repair-tool-json.d.ts.map +1 -1
  171. package/packages/pi-ai/dist/utils/repair-tool-json.js +24 -3
  172. package/packages/pi-ai/dist/utils/repair-tool-json.js.map +1 -1
  173. package/packages/pi-ai/dist/utils/tests/repair-tool-json.test.js +26 -0
  174. package/packages/pi-ai/dist/utils/tests/repair-tool-json.test.js.map +1 -1
  175. package/packages/pi-ai/package.json +1 -1
  176. package/packages/pi-ai/src/providers/anthropic-shared.cache-breakpoint.test.ts +289 -0
  177. package/packages/pi-ai/src/providers/anthropic-shared.ts +52 -20
  178. package/packages/pi-ai/src/types.ts +13 -0
  179. package/packages/pi-ai/src/utils/repair-tool-json.ts +24 -3
  180. package/packages/pi-ai/src/utils/tests/repair-tool-json.test.ts +32 -0
  181. package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
  182. package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
  183. package/packages/pi-coding-agent/dist/core/agent-session.js +6 -0
  184. package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
  185. package/packages/pi-coding-agent/dist/core/messages.d.ts.map +1 -1
  186. package/packages/pi-coding-agent/dist/core/messages.js +4 -0
  187. package/packages/pi-coding-agent/dist/core/messages.js.map +1 -1
  188. package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.js +19 -2
  189. package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.js.map +1 -1
  190. package/packages/pi-coding-agent/dist/core/model-registry.d.ts +10 -0
  191. package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
  192. package/packages/pi-coding-agent/dist/core/model-registry.js +18 -0
  193. package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
  194. package/packages/pi-coding-agent/dist/core/system-prompt.d.ts +13 -0
  195. package/packages/pi-coding-agent/dist/core/system-prompt.d.ts.map +1 -1
  196. package/packages/pi-coding-agent/dist/core/system-prompt.js +20 -16
  197. package/packages/pi-coding-agent/dist/core/system-prompt.js.map +1 -1
  198. package/packages/pi-coding-agent/dist/core/token-telemetry.d.ts +37 -0
  199. package/packages/pi-coding-agent/dist/core/token-telemetry.d.ts.map +1 -0
  200. package/packages/pi-coding-agent/dist/core/token-telemetry.js +49 -0
  201. package/packages/pi-coding-agent/dist/core/token-telemetry.js.map +1 -0
  202. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-card-cleanup-and-success-runtime.test.d.ts +2 -0
  203. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-card-cleanup-and-success-runtime.test.d.ts.map +1 -0
  204. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-card-cleanup-and-success-runtime.test.js +133 -0
  205. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-card-cleanup-and-success-runtime.test.js.map +1 -0
  206. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js +1 -1
  207. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js.map +1 -1
  208. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.js +14 -1
  209. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.js.map +1 -1
  210. package/packages/pi-coding-agent/dist/tests/system-prompt-cache-stability.test.d.ts +2 -0
  211. package/packages/pi-coding-agent/dist/tests/system-prompt-cache-stability.test.d.ts.map +1 -0
  212. package/packages/pi-coding-agent/dist/tests/system-prompt-cache-stability.test.js +78 -0
  213. package/packages/pi-coding-agent/dist/tests/system-prompt-cache-stability.test.js.map +1 -0
  214. package/packages/pi-coding-agent/dist/tests/token-telemetry.test.d.ts +2 -0
  215. package/packages/pi-coding-agent/dist/tests/token-telemetry.test.d.ts.map +1 -0
  216. package/packages/pi-coding-agent/dist/tests/token-telemetry.test.js +181 -0
  217. package/packages/pi-coding-agent/dist/tests/token-telemetry.test.js.map +1 -0
  218. package/packages/pi-coding-agent/package.json +1 -1
  219. package/packages/pi-coding-agent/src/core/agent-session.ts +7 -0
  220. package/packages/pi-coding-agent/src/core/messages.ts +4 -0
  221. package/packages/pi-coding-agent/src/core/model-registry-auth-mode.test.ts +32 -2
  222. package/packages/pi-coding-agent/src/core/model-registry.ts +21 -0
  223. package/packages/pi-coding-agent/src/core/system-prompt.ts +33 -15
  224. package/packages/pi-coding-agent/src/core/token-telemetry.ts +77 -0
  225. package/packages/pi-coding-agent/src/modes/interactive/components/tool-card-cleanup-and-success-runtime.test.ts +212 -0
  226. package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.test.ts +17 -1
  227. package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.ts +1 -1
  228. package/packages/pi-coding-agent/src/tests/system-prompt-cache-stability.test.ts +102 -0
  229. package/packages/pi-coding-agent/src/tests/token-telemetry.test.ts +200 -0
  230. package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
  231. package/packages/pi-tui/dist/__tests__/autocomplete.test.js +17 -3
  232. package/packages/pi-tui/dist/__tests__/autocomplete.test.js.map +1 -1
  233. package/packages/pi-tui/dist/components/__tests__/leak-fixes-runtime.test.d.ts +2 -0
  234. package/packages/pi-tui/dist/components/__tests__/leak-fixes-runtime.test.d.ts.map +1 -0
  235. package/packages/pi-tui/dist/components/__tests__/leak-fixes-runtime.test.js +161 -0
  236. package/packages/pi-tui/dist/components/__tests__/leak-fixes-runtime.test.js.map +1 -0
  237. package/packages/pi-tui/package.json +1 -1
  238. package/packages/pi-tui/src/__tests__/autocomplete.test.ts +20 -3
  239. package/packages/pi-tui/src/components/__tests__/leak-fixes-runtime.test.ts +219 -0
  240. package/packages/pi-tui/tsconfig.tsbuildinfo +1 -1
  241. package/packages/rpc-client/package.json +1 -1
  242. package/pkg/package.json +1 -1
  243. package/src/resources/extensions/claude-code-cli/readiness.ts +78 -46
  244. package/src/resources/extensions/gsd/auto/loop.ts +24 -2
  245. package/src/resources/extensions/gsd/auto/phases.ts +3 -3
  246. package/src/resources/extensions/gsd/auto/run-unit.ts +3 -1
  247. package/src/resources/extensions/gsd/auto/session.ts +3 -0
  248. package/src/resources/extensions/gsd/auto/types.ts +1 -0
  249. package/src/resources/extensions/gsd/auto-recovery.ts +46 -8
  250. package/src/resources/extensions/gsd/auto-runtime-state.ts +51 -0
  251. package/src/resources/extensions/gsd/auto-start.ts +1 -1
  252. package/src/resources/extensions/gsd/auto-tool-tracking.ts +2 -4
  253. package/src/resources/extensions/gsd/auto-worktree.ts +38 -0
  254. package/src/resources/extensions/gsd/auto.ts +14 -4
  255. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +15 -13
  256. package/src/resources/extensions/gsd/bootstrap/exec-tools.ts +8 -7
  257. package/src/resources/extensions/gsd/bootstrap/query-tools.ts +2 -2
  258. package/src/resources/extensions/gsd/bootstrap/register-extension.ts +10 -9
  259. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +102 -31
  260. package/src/resources/extensions/gsd/bootstrap/register-shortcuts.ts +12 -6
  261. package/src/resources/extensions/gsd/bootstrap/system-context.ts +39 -8
  262. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +39 -11
  263. package/src/resources/extensions/gsd/commands/catalog.ts +75 -5
  264. package/src/resources/extensions/gsd/commands/handlers/core.ts +22 -1
  265. package/src/resources/extensions/gsd/commands-mcp-status.ts +3 -1
  266. package/src/resources/extensions/gsd/commands-prefs-wizard.ts +15 -1
  267. package/src/resources/extensions/gsd/dashboard-overlay.ts +1 -1
  268. package/src/resources/extensions/gsd/docs/preferences-reference.md +4 -0
  269. package/src/resources/extensions/gsd/doctor-runtime-checks.ts +39 -1
  270. package/src/resources/extensions/gsd/doctor-types.ts +3 -1
  271. package/src/resources/extensions/gsd/error-classifier.ts +1 -1
  272. package/src/resources/extensions/gsd/forensics.ts +2 -2
  273. package/src/resources/extensions/gsd/git-service.ts +13 -5
  274. package/src/resources/extensions/gsd/gsd-db.ts +12 -2
  275. package/src/resources/extensions/gsd/guided-flow.ts +25 -25
  276. package/src/resources/extensions/gsd/memory-store.ts +81 -28
  277. package/src/resources/extensions/gsd/milestone-id-reservation.ts +47 -0
  278. package/src/resources/extensions/gsd/model-router.ts +172 -9
  279. package/src/resources/extensions/gsd/native-git-bridge.ts +7 -1
  280. package/src/resources/extensions/gsd/preferences-models.ts +101 -15
  281. package/src/resources/extensions/gsd/preferences-types.ts +6 -0
  282. package/src/resources/extensions/gsd/preferences-validation.ts +35 -0
  283. package/src/resources/extensions/gsd/preferences.ts +16 -2
  284. package/src/resources/extensions/gsd/prompt-loader.ts +26 -12
  285. package/src/resources/extensions/gsd/slice-parallel-orchestrator.ts +9 -3
  286. package/src/resources/extensions/gsd/state.ts +42 -0
  287. package/src/resources/extensions/gsd/templates/PREFERENCES.md +1 -0
  288. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +178 -1
  289. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +58 -0
  290. package/src/resources/extensions/gsd/tests/auto-session-encapsulation.test.ts +9 -5
  291. package/src/resources/extensions/gsd/tests/auto-supervisor.test.mjs +21 -4
  292. package/src/resources/extensions/gsd/tests/bootstrap-derive-state-db-open.test.ts +1 -1
  293. package/src/resources/extensions/gsd/tests/budget-prediction.test.ts +138 -211
  294. package/src/resources/extensions/gsd/tests/complete-slice-verification-gate.test.ts +142 -59
  295. package/src/resources/extensions/gsd/tests/complete-slice.test.ts +7 -4
  296. package/src/resources/extensions/gsd/tests/completed-at-reconcile.test.ts +89 -32
  297. package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +41 -23
  298. package/src/resources/extensions/gsd/tests/db-path-worktree-symlink.test.ts +3 -43
  299. package/src/resources/extensions/gsd/tests/debug-logger.test.ts +5 -3
  300. package/src/resources/extensions/gsd/tests/deferred-milestone-dir-4996.test.ts +116 -0
  301. package/src/resources/extensions/gsd/tests/discuss-empty-db-fallback.test.ts +22 -87
  302. package/src/resources/extensions/gsd/tests/discuss-queued-milestones.test.ts +7 -118
  303. package/src/resources/extensions/gsd/tests/discuss-tool-scope-leak.test.ts +18 -60
  304. package/src/resources/extensions/gsd/tests/doctor-orphan-milestone-4996.test.ts +100 -0
  305. package/src/resources/extensions/gsd/tests/double-merge-guard.test.ts +14 -76
  306. package/src/resources/extensions/gsd/tests/ensure-preconditions-guard-4996.test.ts +93 -0
  307. package/src/resources/extensions/gsd/tests/false-degraded-mode-warning.test.ts +22 -83
  308. package/src/resources/extensions/gsd/tests/finalize-timeout-guard.test.ts +1 -63
  309. package/src/resources/extensions/gsd/tests/find-missing-summaries-closed-runtime.test.ts +47 -0
  310. package/src/resources/extensions/gsd/tests/forensics-stuck-loops.test.ts +26 -1
  311. package/src/resources/extensions/gsd/tests/gitignore-bg-shell-runtime.test.ts +63 -0
  312. package/src/resources/extensions/gsd/tests/gsd-db.test.ts +30 -0
  313. package/src/resources/extensions/gsd/tests/gsd-no-project-error-runtime.test.ts +81 -0
  314. package/src/resources/extensions/gsd/tests/headless-answers.test.ts +14 -4
  315. package/src/resources/extensions/gsd/tests/health-widget.test.ts +22 -12
  316. package/src/resources/extensions/gsd/tests/help-menu-coverage.test.ts +57 -0
  317. package/src/resources/extensions/gsd/tests/import-done-milestones-runtime.test.ts +145 -0
  318. package/src/resources/extensions/gsd/tests/init-prefs-routing.test.ts +64 -1
  319. package/src/resources/extensions/gsd/tests/integration/auto-worktree.test.ts +22 -0
  320. package/src/resources/extensions/gsd/tests/integration/token-savings.test.ts +0 -23
  321. package/src/resources/extensions/gsd/tests/memory-store.test.ts +128 -0
  322. package/src/resources/extensions/gsd/tests/memory-tools.test.ts +33 -1
  323. package/src/resources/extensions/gsd/tests/merge-self-branch-guard.test.ts +124 -0
  324. package/src/resources/extensions/gsd/tests/milestone-id-gap-reuse-4996.test.ts +152 -0
  325. package/src/resources/extensions/gsd/tests/model-router.test.ts +169 -8
  326. package/src/resources/extensions/gsd/tests/native-git-infra-errors.test.ts +50 -0
  327. package/src/resources/extensions/gsd/tests/orphaned-worktree-audit.test.ts +8 -0
  328. package/src/resources/extensions/gsd/tests/parallel-crash-recovery.test.ts +32 -43
  329. package/src/resources/extensions/gsd/tests/phases-merge-error-stops-auto.test.ts +4 -10
  330. package/src/resources/extensions/gsd/tests/preferences.test.ts +127 -0
  331. package/src/resources/extensions/gsd/tests/prompt-step-ordering.test.ts +16 -0
  332. package/src/resources/extensions/gsd/tests/provider-errors.test.ts +7 -0
  333. package/src/resources/extensions/gsd/tests/quick-turn-end-cleanup.test.ts +6 -6
  334. package/src/resources/extensions/gsd/tests/register-hooks-compaction-checkpoint.test.ts +93 -0
  335. package/src/resources/extensions/gsd/tests/session-start-footer.test.ts +168 -19
  336. package/src/resources/extensions/gsd/tests/slice-parallel-orchestrator.test.ts +7 -1
  337. package/src/resources/extensions/gsd/tests/smart-entry-complete.test.ts +23 -1
  338. package/src/resources/extensions/gsd/tests/system-context-message-routing.test.ts +101 -0
  339. package/src/resources/extensions/gsd/tests/token-profile.test.ts +51 -4
  340. package/src/resources/extensions/gsd/tests/turn-epoch.test.ts +7 -16
  341. package/src/resources/extensions/gsd/tests/unstructured-continue-context-injection.test.ts +5 -7
  342. package/src/resources/extensions/gsd/tests/uok-gitops-turn-action.test.ts +15 -1
  343. package/src/resources/extensions/gsd/tests/visualizer-overlay.test.ts +6 -6
  344. package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +15 -0
  345. package/src/resources/extensions/gsd/tools/memory-tools.ts +17 -1
  346. package/src/resources/extensions/gsd/unit-context-manifest.ts +8 -8
  347. package/src/resources/extensions/gsd/visualizer-overlay.ts +1 -1
  348. package/src/resources/extensions/gsd/watch/header-renderer.ts +3 -1
  349. package/src/resources/extensions/gsd/workflow-logger.ts +1 -0
  350. package/src/resources/extensions/gsd/worktree-command.ts +31 -44
  351. package/src/resources/extensions/gsd/worktree-session-state.ts +35 -0
  352. package/src/resources/extensions/mcp-client/index.ts +6 -3
  353. package/src/resources/extensions/mcp-client/tests/global-config.test.ts +91 -0
  354. package/src/resources/extensions/slash-commands/create-extension.ts +38 -24
  355. package/src/resources/skills/create-gsd-extension/SKILL.md +9 -5
  356. package/src/resources/skills/create-gsd-extension/references/custom-commands.md +1 -1
  357. package/src/resources/skills/create-gsd-extension/references/custom-rendering.md +5 -5
  358. package/src/resources/skills/create-gsd-extension/references/custom-tools.md +4 -4
  359. package/src/resources/skills/create-gsd-extension/references/custom-ui.md +6 -6
  360. package/src/resources/skills/create-gsd-extension/references/events-reference.md +3 -3
  361. package/src/resources/skills/create-gsd-extension/references/packaging-distribution.md +1 -1
  362. package/src/resources/skills/create-gsd-extension/references/remote-execution-overrides.md +3 -3
  363. package/src/resources/skills/create-gsd-extension/templates/extension-skeleton.ts +2 -2
  364. package/src/resources/skills/create-gsd-extension/templates/stateful-tool-skeleton.ts +3 -3
  365. package/src/resources/skills/create-gsd-extension/templates/templates.test.ts +58 -0
  366. package/src/resources/skills/create-gsd-extension/workflows/create-extension.md +32 -12
  367. package/dist/resources/extensions/browser-tools/tests/browser-tools-integration.test.mjs +0 -601
  368. package/dist/resources/extensions/browser-tools/tests/browser-tools-unit.test.cjs +0 -651
  369. package/dist/resources/extensions/browser-tools/tests/capture-sharp-optional.test.cjs +0 -91
  370. package/dist/resources/extensions/gsd/tests/auto-supervisor.test.mjs +0 -53
  371. package/dist/resources/extensions/gsd/tests/dist-redirect.mjs +0 -112
  372. package/dist/resources/extensions/gsd/tests/resolve-ts-hooks.mjs +0 -23
  373. package/dist/resources/extensions/gsd/tests/resolve-ts.mjs +0 -5
  374. package/dist/resources/skills/github-workflows/references/gh/tests/__init__.py +0 -0
  375. package/dist/resources/skills/github-workflows/references/gh/tests/test_github_project_setup.py +0 -608
  376. package/dist/web/standalone/.next/static/chunks/2826.e9f5195e91f9cad2.js +0 -11
  377. package/dist/web/standalone/.next/static/chunks/3621.fc7480022c972438.js +0 -20
  378. package/dist/web/standalone/.next/static/chunks/webpack-2e68521d7c82f7c2.js +0 -1
  379. package/src/resources/extensions/gsd/tests/copy-planning-artifacts-samepath.test.ts +0 -22
  380. package/src/resources/extensions/gsd/tests/discuss-slice-structured-questions.test.ts +0 -47
  381. package/src/resources/extensions/gsd/tests/empty-content-abort-loop.test.ts +0 -75
  382. /package/dist/web/standalone/.next/static/{cAJH99yNS1UPbeSEiNRrV → UF5VF4F1tB0miEtJS7LyX}/_buildManifest.js +0 -0
  383. /package/dist/web/standalone/.next/static/{cAJH99yNS1UPbeSEiNRrV → UF5VF4F1tB0miEtJS7LyX}/_ssgManifest.js +0 -0
@@ -441,8 +441,31 @@ export function shouldBlockQueueExecutionInSnapshot(snapshot, toolName, input, q
441
441
  };
442
442
  }
443
443
  // ─── Planning-unit tools-policy enforcement (#4934) ───────────────────────
444
+ //
445
+ // Runtime half of the declarative ToolsPolicy on UnitContextManifest. The
446
+ // manifest assigns each unit type a tools mode; this predicate is what
447
+ // actually rejects a tool call that violates it.
448
+ //
449
+ // Forensics: a discuss-milestone LLM turn used the host Edit tool to modify
450
+ // index.html in test app b23 (~/Github/test-apps/b23). With this predicate
451
+ // wired into the tool_call hook, the same call returns block=true with a
452
+ // HARD BLOCK reason that the model cannot rationalize past.
453
+ //
454
+ // Activation: the hook supplies the policy resolved from the active unit's
455
+ // manifest. When no unit is active (interactive sessions, unknown unit
456
+ // types), the hook passes null and this predicate is a no-op — falling
457
+ // through to the existing pendingGate / queue-execution / context-write
458
+ // guards.
444
459
  const PLANNING_WRITE_TOOLS = new Set(["write", "edit", "multi_edit", "notebook_edit"]);
445
460
  const PLANNING_SUBAGENT_TOOLS = new Set(["subagent", "task"]);
461
+ /**
462
+ * Read-only / planning-safe tools that any non-"all" mode allows. Mirrors
463
+ * QUEUE_SAFE_TOOLS / GATE_SAFE_TOOLS but is the inclusive default for
464
+ * planning units (which need their full discussion + research surface).
465
+ *
466
+ * gsd_* MCP tools are passed through unconditionally — they have their own
467
+ * domain validation (e.g. depth-verification gate, single-writer DB).
468
+ */
446
469
  const PLANNING_SAFE_TOOLS = new Set([
447
470
  "read", "grep", "find", "ls", "glob",
448
471
  "ask_user_questions",
@@ -458,6 +481,7 @@ function matchesAllowedGlob(absPath, basePath, globs) {
458
481
  const rel = relative(basePath, absPath);
459
482
  if (rel.startsWith("..") || isAbsolute(rel))
460
483
  return false;
484
+ // Normalize Windows separators for minimatch.
461
485
  const posix = rel.split(sep).join("/");
462
486
  return globs.some(g => minimatch(posix, g, { dot: false, nocase: false }));
463
487
  }
@@ -480,7 +504,12 @@ function blockReason(unitType, mode, what) {
480
504
  * - "docs" → like "planning" but also allows writes to paths
481
505
  * matching `allowedPathGlobs` relative to basePath.
482
506
  *
483
- * `policy` of null means "no manifest resolved" pass-through.
507
+ * `pathOrCommand` is the file path for write/edit-shaped tools and the
508
+ * shell command for bash. Other tools ignore this argument.
509
+ *
510
+ * `policy` of null means "no manifest resolved" — pass-through. Callers
511
+ * that have no active unit (interactive sessions) pass null and this
512
+ * predicate is a no-op.
484
513
  */
485
514
  export function shouldBlockPlanningUnit(toolName, pathOrCommand, basePath, unitType, policy) {
486
515
  if (!policy)
@@ -488,6 +517,7 @@ export function shouldBlockPlanningUnit(toolName, pathOrCommand, basePath, unitT
488
517
  if (policy.mode === "all")
489
518
  return { block: false };
490
519
  const tool = toolName;
520
+ // Read-only mode: only Read-class tools are permitted.
491
521
  if (policy.mode === "read-only") {
492
522
  if (PLANNING_SAFE_TOOLS.has(tool))
493
523
  return { block: false };
@@ -496,9 +526,10 @@ export function shouldBlockPlanningUnit(toolName, pathOrCommand, basePath, unitT
496
526
  if (PLANNING_WRITE_TOOLS.has(tool) || tool === "bash" || PLANNING_SUBAGENT_TOOLS.has(tool)) {
497
527
  return { block: true, reason: blockReason(unitType, policy.mode, `${tool} is not permitted (read-only)`) };
498
528
  }
529
+ // Unknown tool in read-only mode — block by default.
499
530
  return { block: true, reason: blockReason(unitType, policy.mode, `tool "${tool}" is not on the read-only allowlist`) };
500
531
  }
501
- // planning / docs modes
532
+ // planning / docs modes share the same surface for safe tools, bash, and subagent.
502
533
  if (PLANNING_SAFE_TOOLS.has(tool))
503
534
  return { block: false };
504
535
  if (tool.startsWith("gsd_"))
@@ -519,8 +550,10 @@ export function shouldBlockPlanningUnit(toolName, pathOrCommand, basePath, unitT
519
550
  return { block: true, reason: blockReason(unitType, policy.mode, `${tool} called with empty path`) };
520
551
  }
521
552
  const absPath = isAbsolute(pathOrCommand) ? pathOrCommand : resolve(basePath, pathOrCommand);
553
+ // Always allow .gsd/ writes — that's where planning artifacts live.
522
554
  if (isPathUnderGsd(absPath, basePath))
523
555
  return { block: false };
556
+ // docs mode additionally allows the manifest's allowedPathGlobs.
524
557
  if (policy.mode === "docs" && matchesAllowedGlob(absPath, basePath, policy.allowedPathGlobs)) {
525
558
  return { block: false };
526
559
  }
@@ -529,5 +562,8 @@ export function shouldBlockPlanningUnit(toolName, pathOrCommand, basePath, unitT
529
562
  reason: blockReason(unitType, policy.mode, `cannot ${tool} "${pathOrCommand}" — writes are restricted to .gsd/${policy.mode === "docs" ? " and " + policy.allowedPathGlobs.join(", ") : ""}`),
530
563
  };
531
564
  }
565
+ // Unknown tool name — pass through. Other layers (queue, pending-gate,
566
+ // CONTEXT.md write) catch known mutating shapes; defaulting to allow here
567
+ // avoids breaking gsd_* MCP tools or future safe additions.
532
568
  return { block: false };
533
569
  }
@@ -1,10 +1,9 @@
1
1
  import { existsSync, readFileSync, readdirSync } from "node:fs";
2
2
  import { homedir } from "node:os";
3
- import { join } from "node:path";
3
+ import { join, resolve } from "node:path";
4
4
  import { loadRegistry } from "../workflow-templates.js";
5
- import { resolveProjectRoot } from "../worktree.js";
6
5
  const gsdHome = process.env.GSD_HOME || join(homedir(), ".gsd");
7
- export const GSD_COMMAND_DESCRIPTION = "GSD — Get Shit Done: /gsd help|start|templates|next|auto|stop|pause|status|widget|visualize|queue|quick|discuss|capture|triage|dispatch|history|undo|undo-task|reset-slice|rate|skip|export|cleanup|model|mode|prefs|config|keys|hooks|run-hook|skill-health|doctor|debug|logs|forensics|changelog|migrate|remote|steer|knowledge|new-milestone|parallel|cmux|park|unpark|init|setup|onboarding|inspect|extensions|update|fast|mcp|rethink|codebase|notifications|ship|do|session-report|backlog|pr-branch|add-tests|scan|language";
6
+ export const GSD_COMMAND_DESCRIPTION = "GSD — Get Shit Done: /gsd help|start|templates|next|auto|stop|pause|status|widget|visualize|queue|quick|discuss|capture|triage|dispatch|history|undo|undo-task|reset-slice|rate|skip|export|cleanup|model|mode|prefs|config|keys|hooks|run-hook|skill-health|doctor|debug|logs|forensics|changelog|migrate|remote|steer|knowledge|new-milestone|parallel|cmux|park|unpark|init|setup|onboarding|inspect|extensions|update|fast|mcp|rethink|workflow|codebase|notifications|ship|do|session-report|backlog|pr-branch|add-tests|scan|language";
8
7
  export const TOP_LEVEL_SUBCOMMANDS = [
9
8
  { cmd: "help", desc: "Categorized command reference with descriptions" },
10
9
  { cmd: "next", desc: "Explicit step mode (same as /gsd)" },
@@ -330,6 +329,71 @@ function getExtensionCompletions(prefix, action) {
330
329
  return [];
331
330
  }
332
331
  }
332
+ function normalizePathForCompare(path) {
333
+ return path.replaceAll("\\", "/").replace(/\/+$/, "");
334
+ }
335
+ function findWorktreeSegment(normalizedPath) {
336
+ const directMarker = "/.gsd/worktrees/";
337
+ const directIdx = normalizedPath.indexOf(directMarker);
338
+ if (directIdx !== -1) {
339
+ return { gsdIdx: directIdx, afterWorktrees: directIdx + directMarker.length };
340
+ }
341
+ const symlinkMatch = normalizedPath.match(/\/\.gsd\/projects\/[a-f0-9]+\/worktrees\//);
342
+ if (symlinkMatch?.index !== undefined) {
343
+ return { gsdIdx: symlinkMatch.index, afterWorktrees: symlinkMatch.index + symlinkMatch[0].length };
344
+ }
345
+ return null;
346
+ }
347
+ function resolveProjectRootFromGitFile(worktreePath) {
348
+ try {
349
+ let dir = worktreePath;
350
+ for (let i = 0; i < 30; i++) {
351
+ const gitPath = join(dir, ".git");
352
+ if (existsSync(gitPath)) {
353
+ const content = readFileSync(gitPath, "utf8").trim();
354
+ if (content.startsWith("gitdir: ")) {
355
+ const gitDir = resolve(dir, content.slice(8));
356
+ const dotGitDir = resolve(gitDir, "..", "..");
357
+ if (dotGitDir.endsWith(".git") || dotGitDir.endsWith(".git/") || dotGitDir.endsWith(".git\\")) {
358
+ return resolve(dotGitDir, "..");
359
+ }
360
+ const commonDirPath = join(gitDir, "commondir");
361
+ if (existsSync(commonDirPath)) {
362
+ const commonDir = readFileSync(commonDirPath, "utf8").trim();
363
+ return resolve(resolve(gitDir, commonDir), "..");
364
+ }
365
+ }
366
+ break;
367
+ }
368
+ const parent = resolve(dir, "..");
369
+ if (parent === dir)
370
+ break;
371
+ dir = parent;
372
+ }
373
+ }
374
+ catch {
375
+ // Completion must stay best-effort.
376
+ }
377
+ return null;
378
+ }
379
+ function resolveProjectRootForCompletion(basePath) {
380
+ if (process.env.GSD_PROJECT_ROOT)
381
+ return process.env.GSD_PROJECT_ROOT;
382
+ const normalizedPath = normalizePathForCompare(basePath);
383
+ const segment = findWorktreeSegment(normalizedPath);
384
+ if (!segment)
385
+ return basePath;
386
+ const separator = basePath.includes("\\") ? "\\" : "/";
387
+ const gsdMarker = `${separator}.gsd${separator}`;
388
+ const gsdIdx = basePath.indexOf(gsdMarker);
389
+ const candidate = gsdIdx !== -1 ? basePath.slice(0, gsdIdx) : basePath.slice(0, segment.gsdIdx);
390
+ const normalizedGsdHome = normalizePathForCompare(gsdHome);
391
+ const candidateGsdPath = normalizePathForCompare(join(candidate, ".gsd"));
392
+ if (candidateGsdPath === normalizedGsdHome || candidateGsdPath.startsWith(`${normalizedGsdHome}/`)) {
393
+ return resolveProjectRootFromGitFile(basePath) ?? basePath;
394
+ }
395
+ return candidate;
396
+ }
333
397
  export function getGsdArgumentCompletions(prefix) {
334
398
  const hasTrailingSpace = prefix.endsWith(" ");
335
399
  const parts = prefix.trim().split(/\s+/);
@@ -384,7 +448,7 @@ export function getGsdArgumentCompletions(prefix) {
384
448
  // Workflow definition-name completion for `workflow run <name>` and `workflow validate <name>`
385
449
  if (command === "workflow" && (subcommand === "run" || subcommand === "validate") && parts.length <= 3) {
386
450
  try {
387
- const defsDir = join(resolveProjectRoot(process.cwd()), ".gsd", "workflow-defs");
451
+ const defsDir = join(resolveProjectRootForCompletion(process.cwd()), ".gsd", "workflow-defs");
388
452
  if (existsSync(defsDir)) {
389
453
  return readdirSync(defsDir)
390
454
  .filter((f) => f.endsWith(".yaml") && f.startsWith(third))
@@ -426,7 +490,7 @@ export function getGsdArgumentCompletions(prefix) {
426
490
  catch { /* ignore */ }
427
491
  };
428
492
  try {
429
- const base = resolveProjectRoot(process.cwd());
493
+ const base = resolveProjectRootForCompletion(process.cwd());
430
494
  scanDir(join(base, ".gsd", "workflows"), "project");
431
495
  scanDir(join(base, ".gsd", "workflow-defs"), "project-legacy");
432
496
  scanDir(join(gsdHome, "workflows"), "global");
@@ -58,16 +58,21 @@ export function showHelp(ctx, args = "") {
58
58
  " /gsd pause Pause auto-mode (preserves state, /gsd auto to resume)",
59
59
  " /gsd discuss Start guided milestone/slice discussion",
60
60
  " /gsd new-milestone Create milestone from headless context (used by gsd headless)",
61
+ " /gsd quick Execute a quick task without full planning overhead",
62
+ " /gsd dispatch Dispatch a specific phase directly [research|plan|execute|complete|uat|replan]",
63
+ " /gsd parallel Parallel milestone orchestration [start|status|stop|pause|resume|merge|watch]",
64
+ " /gsd workflow Custom workflow lifecycle [new|run|list|validate|pause|resume]",
61
65
  "",
62
66
  "VISIBILITY",
63
67
  ` /gsd status Show progress dashboard (${formattedShortcutPair("dashboard")})`,
64
68
  ` /gsd parallel watch Open parallel worker monitor (${formattedShortcutPair("parallel")})`,
69
+ " /gsd widget Cycle status widget [full|small|min|off]",
65
70
  " /gsd visualize Interactive 10-tab TUI (progress, timeline, deps, metrics, health, agent, changes, knowledge, captures, export)",
66
71
  " /gsd queue Show queued/dispatched units and execution order",
67
72
  " /gsd history View execution history [--cost] [--phase] [--model] [N]",
68
73
  " /gsd changelog Show categorized release notes [version]",
69
74
  ` /gsd notifications View persistent notification history [clear|tail|filter] (${formattedShortcutPair("notifications")})`,
70
- " /gsd logs Browse activity logs, debug logs, and metrics",
75
+ " /gsd logs Browse activity logs, debug logs, and metrics [debug|tail|clear]",
71
76
  " /gsd debug Create/list/continue persistent debug sessions",
72
77
  "",
73
78
  "COURSE CORRECTION",
@@ -76,6 +81,9 @@ export function showHelp(ctx, args = "") {
76
81
  " /gsd triage Classify and route pending captures",
77
82
  " /gsd skip <unit> Prevent a unit from auto-mode dispatch",
78
83
  " /gsd undo Revert last completed unit [--force]",
84
+ " /gsd undo-task Reset a specific task's completion state [DB + markdown]",
85
+ " /gsd reset-slice Reset a slice and all its tasks [DB + markdown]",
86
+ " /gsd rate Rate last unit's model tier [over|ok|under]",
79
87
  " /gsd rethink Conversational project reorganization — reorder, park, discard, add milestones",
80
88
  " /gsd park [id] Park a milestone — skip without deleting [reason]",
81
89
  " /gsd unpark [id] Reactivate a parked milestone",
@@ -84,6 +92,15 @@ export function showHelp(ctx, args = "") {
84
92
  " /gsd knowledge <type> <text> Add rule, pattern, or lesson to KNOWLEDGE.md",
85
93
  " /gsd codebase [generate|update|stats] Manage the CODEBASE.md cache used in prompt context",
86
94
  "",
95
+ "SHIPPING & BACKLOG",
96
+ " /gsd ship Create a PR from milestone artifacts [--dry-run|--draft|--base|--force]",
97
+ " /gsd do <text> Route freeform text to the right GSD command",
98
+ " /gsd session-report Show session cost, tokens, and work summary [--json|--save]",
99
+ " /gsd backlog Manage backlog items [add|promote|remove|list]",
100
+ " /gsd pr-branch Create a clean PR branch filtering .gsd/ commits [--dry-run|--name]",
101
+ " /gsd add-tests Generate tests for completed slices",
102
+ " /gsd scan Rapid codebase assessment [--focus tech|arch|quality|concerns|tech+arch]",
103
+ "",
87
104
  "SETUP & CONFIGURATION",
88
105
  " /gsd onboarding Re-run setup wizard [--resume|--reset|--step <name>]",
89
106
  " /gsd setup Configuration hub [llm|model|search|remote|keys|prefs|onboarding]",
@@ -96,18 +113,22 @@ export function showHelp(ctx, args = "") {
96
113
  " /gsd config (deprecated) Set tool API keys — use /gsd keys instead",
97
114
  " /gsd show-config Show effective configuration (models, routing, toggles)",
98
115
  " /gsd hooks Show post-unit hook configuration",
116
+ " /gsd run-hook Manually trigger a specific hook",
117
+ " /gsd skill-health Skill lifecycle dashboard",
99
118
  " /gsd extensions Manage extensions [list|enable|disable|info]",
100
119
  " /gsd fast Toggle OpenAI service tier [on|off|flex|status]",
101
120
  " /gsd mcp MCP server status and connectivity [status|check <server>|init [dir]]",
102
121
  "",
103
122
  "MAINTENANCE",
104
123
  " /gsd doctor Diagnose and repair .gsd/ state [audit|fix|heal] [scope]",
124
+ " /gsd forensics Examine execution logs and post-mortem analysis",
105
125
  " /gsd export Export milestone/slice results [--json|--markdown|--html] [--all]",
106
126
  " /gsd cleanup Remove merged branches or snapshots [branches|snapshots]",
107
127
  " /gsd migrate Migrate .planning/ (v1) to .gsd/ (v2) format",
108
128
  " /gsd remote Control remote auto-mode [slack|discord|status|disconnect]",
109
129
  " /gsd inspect Show SQLite DB diagnostics (schema, row counts, recent entries)",
110
130
  " /gsd update Update GSD to the latest version via npm",
131
+ " /gsd language Set or clear the global response language [off|clear|<language>]",
111
132
  ];
112
133
  const full = ["full", "--full", "all"].includes(args.trim().toLowerCase());
113
134
  ctx.ui.notify((full ? fullLines : summaryLines).join("\n"), "info");
@@ -10,6 +10,7 @@
10
10
  * /gsd mcp init [dir] — Write project-local GSD workflow MCP config
11
11
  */
12
12
  import { existsSync, readFileSync } from "node:fs";
13
+ import { homedir } from "node:os";
13
14
  import { join, resolve } from "node:path";
14
15
  import { ensureProjectWorkflowMcpConfig } from "./mcp-project-config.js";
15
16
  export function formatMcpInitResult(status, configPath, targetPath) {
@@ -33,6 +34,7 @@ function readMcpConfigs() {
33
34
  const configPaths = [
34
35
  join(process.cwd(), ".mcp.json"),
35
36
  join(process.cwd(), ".gsd", "mcp.json"),
37
+ join(process.env.GSD_HOME || join(homedir(), ".gsd"), "mcp.json"),
36
38
  ];
37
39
  for (const configPath of configPaths) {
38
40
  try {
@@ -77,7 +79,7 @@ export function formatMcpStatusReport(servers) {
77
79
  return [
78
80
  "No MCP servers configured.",
79
81
  "",
80
- "Add servers to .mcp.json or .gsd/mcp.json to enable MCP integrations.",
82
+ "Add servers to .mcp.json, .gsd/mcp.json, or $GSD_HOME/mcp.json (default: ~/.gsd/mcp.json) to enable MCP integrations.",
81
83
  "Tip: run /gsd mcp init . to write the local GSD workflow MCP config.",
82
84
  "See: https://modelcontextprotocol.io/quickstart",
83
85
  ].join("\n");
@@ -1481,6 +1481,13 @@ async function configureAdvanced(ctx, prefs) {
1481
1481
  const tokenCost = await promptBoolean(ctx, "Show token cost in footer", prefs.show_token_cost, false);
1482
1482
  if (tokenCost !== undefined)
1483
1483
  prefs.show_token_cost = tokenCost;
1484
+ const minRequestInterval = await promptInteger(ctx, "Minimum interval between auto-mode LLM requests (ms, 0 to disable)", prefs.min_request_interval_ms, "0");
1485
+ if (minRequestInterval === "clear") {
1486
+ delete prefs.min_request_interval_ms;
1487
+ }
1488
+ else if (minRequestInterval !== undefined) {
1489
+ prefs.min_request_interval_ms = minRequestInterval;
1490
+ }
1484
1491
  const widget = await promptEnum(ctx, "Auto-mode widget display", prefs.widget_mode, ["full", "small", "min", "off"], "full");
1485
1492
  if (widget !== undefined)
1486
1493
  prefs.widget_mode = widget;
@@ -1668,8 +1675,10 @@ export function serializePreferencesToFrontmatter(prefs) {
1668
1675
  "budget_ceiling", "budget_enforcement", "context_pause_threshold",
1669
1676
  "notifications", "cmux", "remote_questions", "git",
1670
1677
  "stale_commit_threshold_minutes",
1678
+ "min_request_interval_ms",
1671
1679
  "post_unit_hooks", "pre_dispatch_hooks",
1672
- "dynamic_routing", "uok", "token_profile", "service_tier", "flat_rate_providers",
1680
+ "dynamic_routing", "disabled_model_providers", "uok", "token_profile",
1681
+ "service_tier", "flat_rate_providers",
1673
1682
  "phases", "parallel", "slice_parallel",
1674
1683
  "reactive_execution", "gate_evaluation",
1675
1684
  "auto_visualize", "auto_report",
@@ -14,7 +14,7 @@ import { resolveMilestoneFile } from "./paths.js";
14
14
  import { getAutoDashboardData } from "./auto.js";
15
15
  import { getLedger, getProjectTotals, aggregateByPhase, aggregateBySlice, aggregateByModel, aggregateCacheHitRate, formatCost, formatTokenCount, formatCostProjection, } from "./metrics.js";
16
16
  import { loadEffectiveGSDPreferences } from "./preferences.js";
17
- import { getActiveWorktreeName } from "./worktree-command.js";
17
+ import { getActiveWorktreeName } from "./worktree-session-state.js";
18
18
  import { getWorkerBatches, hasActiveWorkers } from "../subagent/worker-registry.js";
19
19
  import { formatDuration, padRight, joinColumns, centerLine, fitColumns, STATUS_GLYPH, STATUS_COLOR } from "../shared/mod.js";
20
20
  import { estimateTimeRemaining } from "./auto-dashboard.js";
@@ -126,6 +126,8 @@ Setting `prefer_skills: []` does **not** disable skill discovery — it just mea
126
126
  - `idle_timeout_minutes`: minutes of inactivity before the supervisor intervenes (default: 10).
127
127
  - `hard_timeout_minutes`: minutes before the supervisor forces termination (default: 30).
128
128
 
129
+ - `min_request_interval_ms`: number — minimum integer milliseconds between auto-mode LLM request dispatches. Non-integer values are rounded down (e.g., `1000.9 → 1000`). Use this to proactively slow auto-mode on rate-limited providers and reduce 429 errors. Set to `0` to disable. Default: `0` (disabled).
130
+
129
131
  - `git`: configures GSD's git behavior. All fields are optional — omit any to use defaults. Keys:
130
132
  - `auto_push`: boolean — automatically push commits to the remote after committing. Default: `false`.
131
133
  - `push_branches`: boolean — push the milestone branch to the remote after commits. Default: `false`.
@@ -193,6 +195,8 @@ Setting `prefer_skills: []` does **not** disable skill discovery — it just mea
193
195
  - `hooks`: boolean — enable routing hooks. Default: `true`.
194
196
  - `capability_routing`: boolean — enable capability-profile scoring for model selection within a tier. Requires `enabled: true`. Default: `false`.
195
197
 
198
+ - `disabled_model_providers`: string[] — provider IDs to hide from model selection and routing (for example `["google-gemini-cli"]`). This only affects model availability (`/model`, auto-model selection, routing); it does not disable tool auth flows like `google_search`.
199
+
196
200
  - `uok`: Unified Orchestration Kernel controls. Keys:
197
201
  - `enabled`: boolean — enable kernel wrappers and contract observers. Default: `true`.
198
202
  - `legacy_fallback.enabled`: boolean — emergency release fallback that forces legacy orchestration behavior even when `uok.enabled` is `true`. Default: `false`.
@@ -2,7 +2,7 @@ import { existsSync, lstatSync, readdirSync, readFileSync, realpathSync, rmSync,
2
2
  import { basename, dirname, join } from "node:path";
3
3
  import { cleanNumberedGsdVariants } from "./repo-identity.js";
4
4
  import { milestonesDir, gsdRoot, resolveGsdRootFile } from "./paths.js";
5
- import { deriveState } from "./state.js";
5
+ import { deriveState, isGhostMilestone, isReusableGhostMilestone } from "./state.js";
6
6
  import { saveFile } from "./files.js";
7
7
  import { nativeIsRepo, nativeForEachRef, nativeUpdateRef } from "./native-git-bridge.js";
8
8
  import { readCrashLock, isLockProcessAlive, clearLock } from "./crash-recovery.js";
@@ -10,6 +10,7 @@ import { ensureGitignore, isGsdGitignored } from "./gitignore.js";
10
10
  import { readAllSessionStatuses, isSessionStale, removeSessionStatus } from "./session-status-io.js";
11
11
  import { recoverFailedMigration } from "./migrate-external.js";
12
12
  import { splitCompletedKey } from "./forensics.js";
13
+ import { findMilestoneIds } from "./milestone-ids.js";
13
14
  export async function checkRuntimeHealth(basePath, issues, fixesApplied, shouldFix) {
14
15
  const root = gsdRoot(basePath);
15
16
  // ── Stale crash lock ──────────────────────────────────────────────────
@@ -570,6 +571,43 @@ export async function checkRuntimeHealth(basePath, issues, fixesApplied, shouldF
570
571
  catch {
571
572
  // Non-fatal — snapshot ref check failed
572
573
  }
574
+ // ── Orphan milestone directories (#4996) ──────────────────────────────
575
+ // Walk every milestone ID on disk. Any dir that has no DB row, no worktree,
576
+ // and no content files is an orphaned stub — it skews nextMilestoneId and
577
+ // was likely created by ensurePreconditions or showHeadlessMilestoneCreation
578
+ // for a phantom forward-reference. Surface as a fixable warning.
579
+ try {
580
+ const milestoneIds = findMilestoneIds(basePath);
581
+ const hasDbFile = existsSync(join(root, "gsd.db"));
582
+ for (const mid of milestoneIds) {
583
+ const isOrphan = isReusableGhostMilestone(basePath, mid)
584
+ || (!hasDbFile && isGhostMilestone(basePath, mid));
585
+ if (isOrphan) {
586
+ issues.push({
587
+ severity: "warning",
588
+ code: "orphan_milestone_dir",
589
+ scope: "milestone",
590
+ unitId: mid,
591
+ message: `Orphan milestone directory: ${mid} — directory exists on disk with no DB row, no worktree, and no content files. This stub skews milestone ID generation and should be removed.`,
592
+ file: `.gsd/milestones/${mid}`,
593
+ fixable: true,
594
+ });
595
+ if (shouldFix("orphan_milestone_dir")) {
596
+ try {
597
+ const orphanPath = join(milestonesDir(basePath), mid);
598
+ rmSync(orphanPath, { recursive: true, force: true });
599
+ fixesApplied.push(`removed orphan milestone directory: ${mid}`);
600
+ }
601
+ catch {
602
+ // Non-fatal — leave for manual cleanup
603
+ }
604
+ }
605
+ }
606
+ }
607
+ }
608
+ catch {
609
+ // Non-fatal — orphan milestone directory check failed
610
+ }
573
611
  }
574
612
  /**
575
613
  * Build STATE.md markdown content from derived state.
@@ -34,7 +34,7 @@ const NETWORK_RE = /network|ECONNRESET|ETIMEDOUT|ECONNREFUSED|socket hang up|fet
34
34
  // Context overflow errors (context window/length exceeded) should be treated as server-class
35
35
  // transient errors so auto-mode can retry with reduced budget or fall back to a larger-context model.
36
36
  // See: https://github.com/gsd-build/gsd-2/issues/4528
37
- const SERVER_RE = /internal server error|500|502|503|overloaded|server_error|api_error|service.?unavailable|context (?:window|length) exceed|context window exceed/i;
37
+ const SERVER_RE = /internal(?: server)?[ _-]?error|500|502|503|overloaded|server_error|api_error|service.?unavailable|context (?:window|length) exceed|context window exceed/i;
38
38
  // ECONNRESET/ECONNREFUSED are in NETWORK_RE (same-model retry first).
39
39
  const CONNECTION_RE = /terminated|connection.?(?:refused|error)|other side closed|EPIPE|network.?(?:is\s+)?unavailable|stream_exhausted(?:_without_result)?/i;
40
40
  // Catch-all for V8 JSON.parse errors: all modern variants end with "in JSON at position \d+".
@@ -649,7 +649,7 @@ function detectMissingArtifacts(completedKeys, basePath, activeMilestone, anomal
649
649
  * the forensics memory-bloat guard in forensics-journal.test.ts — per-event
650
650
  * detail stays in the journal itself where the LLM can query it on demand.
651
651
  */
652
- function detectWorktreeOrphans(summary, anomalies) {
652
+ export function detectWorktreeOrphans(summary, anomalies) {
653
653
  // 1. Orphan aggregate — severity depends on reason. In-progress orphans are
654
654
  // the #4761 consumer-side signal (live work sitting on an unmerged branch).
655
655
  for (const [reason, count] of Object.entries(summary.orphansByReason)) {
@@ -663,7 +663,7 @@ function detectWorktreeOrphans(summary, anomalies) {
663
663
  details: reason === "in-progress-unmerged"
664
664
  ? "Auto-mode exited without completing a milestone; live work sits on an unmerged milestone branch. Run `/gsd auto` to resume, or merge manually."
665
665
  : reason === "complete-unmerged"
666
- ? "A completed milestone's branch was never merged back to main. Run `/gsd health --fix` to resolve."
666
+ ? "A completed milestone's branch was never merged back to main. Run `/gsd doctor fix` to resolve."
667
667
  : `Reason: ${reason}.`,
668
668
  });
669
669
  }
@@ -18,6 +18,7 @@ import { SLICE_BRANCH_RE, QUICK_BRANCH_RE, WORKFLOW_BRANCH_RE } from "./branch-p
18
18
  import { nativeGetCurrentBranch, nativeDetectMainBranch, nativeBranchExists, nativeHasChanges, nativeAddAllWithExclusions, nativeHasStagedChanges, nativeCommit, nativeRmCached, nativeUpdateRef, nativeResetSoft, nativeCommitSubject, _resetHasChangesCache, } from "./native-git-bridge.js";
19
19
  import { GSDError, GSD_MERGE_CONFLICT, GSD_GIT_ERROR } from "./errors.js";
20
20
  import { getErrorMessage } from "./error-utils.js";
21
+ import { isInfrastructureError } from "./auto/infra-errors.js";
21
22
  export const VALID_BRANCH_NAME = /^[a-zA-Z0-9_\-\/.]+$/;
22
23
  /**
23
24
  * Build a meaningful conventional commit message from task execution context.
@@ -775,6 +776,16 @@ function buildTurnSnapshotLabel(unitType, unitId) {
775
776
  .replace(/-{2,}/g, "-")
776
777
  .replace(/^[-/]+|[-/]+$/g, "") || "turn";
777
778
  }
779
+ export function handleTurnGitActionError(action, err) {
780
+ if (isInfrastructureError(err)) {
781
+ throw err;
782
+ }
783
+ return {
784
+ action,
785
+ status: "failed",
786
+ error: getErrorMessage(err),
787
+ };
788
+ }
778
789
  export function runTurnGitAction(args) {
779
790
  try {
780
791
  // Force fresh working-tree status per turn; nativeHasChanges caches briefly.
@@ -806,11 +817,7 @@ export function runTurnGitAction(args) {
806
817
  };
807
818
  }
808
819
  catch (err) {
809
- return {
810
- action: args.action,
811
- status: "failed",
812
- error: getErrorMessage(err),
813
- };
820
+ return handleTurnGitActionError(args.action, err);
814
821
  }
815
822
  }
816
823
  // ─── Commit Type Inference ─────────────────────────────────────────────────
@@ -1321,6 +1321,15 @@ export function checkpointDatabase() {
1321
1321
  }
1322
1322
  }
1323
1323
  let _txDepth = 0;
1324
+ /**
1325
+ * Whether the current call is running inside an active SQLite transaction.
1326
+ * Statement-time recovery paths (e.g. VACUUM retry on a malformed memory
1327
+ * store) MUST gate on this — SQLite refuses VACUUM inside a transaction
1328
+ * and would mask the original error with a secondary "cannot VACUUM" throw.
1329
+ */
1330
+ export function isInTransaction() {
1331
+ return _txDepth > 0;
1332
+ }
1324
1333
  export function transaction(fn) {
1325
1334
  if (!currentDb)
1326
1335
  throw new GSDError(GSD_STALE_STATE, "gsd-db: No database open");
@@ -1335,8 +1344,8 @@ export function transaction(fn) {
1335
1344
  _txDepth--;
1336
1345
  }
1337
1346
  }
1338
- _txDepth++;
1339
1347
  currentDb.exec("BEGIN");
1348
+ _txDepth++;
1340
1349
  try {
1341
1350
  const result = fn();
1342
1351
  currentDb.exec("COMMIT");
@@ -1369,8 +1378,8 @@ export function readTransaction(fn) {
1369
1378
  _txDepth--;
1370
1379
  }
1371
1380
  }
1372
- _txDepth++;
1373
1381
  currentDb.exec("BEGIN DEFERRED");
1382
+ _txDepth++;
1374
1383
  try {
1375
1384
  const result = fn();
1376
1385
  currentDb.exec("COMMIT");
@@ -33,7 +33,9 @@ import { showProjectInit, offerMigration } from "./init-wizard.js";
33
33
  import { validateDirectory } from "./validate-directory.js";
34
34
  import { showConfirm } from "../shared/tui.js";
35
35
  import { debugLog } from "./debug-logger.js";
36
- import { findMilestoneIds, nextMilestoneId, reserveMilestoneId, getReservedMilestoneIds, clearReservedMilestoneIds } from "./milestone-ids.js";
36
+ import { findMilestoneIds, clearReservedMilestoneIds } from "./milestone-ids.js";
37
+ import { nextMilestoneIdReserved } from "./milestone-id-reservation.js";
38
+ export { nextMilestoneIdReserved } from "./milestone-id-reservation.js";
37
39
  import { parkMilestone, discardMilestone } from "./milestone-actions.js";
38
40
  import { selectAndApplyModel } from "./auto-model-selection.js";
39
41
  import { DISCUSS_TOOLS_ALLOWLIST } from "./constants.js";
@@ -43,18 +45,6 @@ import { runPreparation, formatCodebaseBrief, formatPriorContextBrief, } from ".
43
45
  export { MILESTONE_ID_RE, generateMilestoneSuffix, nextMilestoneId, extractMilestoneSeq, parseMilestoneId, milestoneIdSort, maxMilestoneNum, findMilestoneIds, reserveMilestoneId, claimReservedId, getReservedMilestoneIds, clearReservedMilestoneIds, } from "./milestone-ids.js";
44
46
  export { showQueue, handleQueueReorder, showQueueAdd, buildExistingMilestonesContext, } from "./guided-flow-queue.js";
45
47
  import { logWarning } from "./workflow-logger.js";
46
- // ─── ID Generation with Reservation ─────────────────────────────────────────
47
- /**
48
- * Generate the next milestone ID, accounting for reserved IDs, and reserve it.
49
- * Ensures any preview ID shown in the UI matches what `gsd_milestone_generate_id`
50
- * will later return.
51
- */
52
- function nextMilestoneIdReserved(existingIds, uniqueEnabled) {
53
- const allIds = [...new Set([...existingIds, ...getReservedMilestoneIds()])];
54
- const id = nextMilestoneId(allIds, uniqueEnabled);
55
- reserveMilestoneId(id);
56
- return id;
57
- }
58
48
  function needsPlanV2Gate(state) {
59
49
  return state.phase === "executing"
60
50
  || state.phase === "summarizing"
@@ -675,13 +665,17 @@ export async function showHeadlessMilestoneCreation(ctx, pi, basePath, seedConte
675
665
  clearReservedMilestoneIds();
676
666
  // Ensure .gsd/ is bootstrapped
677
667
  bootstrapGsdProject(basePath);
668
+ const { ensureDbOpen } = await import("./bootstrap/dynamic-tools.js");
669
+ await ensureDbOpen(basePath);
678
670
  // Generate next milestone ID
679
671
  const existingIds = findMilestoneIds(basePath);
680
672
  const prefs = loadEffectiveGSDPreferences();
681
- const nextId = nextMilestoneIdReserved(existingIds, prefs?.preferences?.unique_milestone_ids ?? false);
682
- // Create milestone directory
683
- const milestoneDir = join(gsdRoot(basePath), "milestones", nextId, "slices");
684
- mkdirSync(milestoneDir, { recursive: true });
673
+ const nextId = nextMilestoneIdReserved(existingIds, prefs?.preferences?.unique_milestone_ids ?? false, basePath);
674
+ // Fix #4996: Do NOT pre-create the milestone directory here.
675
+ // atomicWriteAsync (used by all artifact writers) calls mkdir lazily before
676
+ // each write, so every path through saveArtifactToDb / saveFile is already
677
+ // lazy-mkdir-safe. Pre-creating the dir before the discuss flow runs leaves
678
+ // an orphan stub if discuss is abandoned — that stub later skews nextMilestoneId.
685
679
  // Build and dispatch the headless discuss prompt
686
680
  const prompt = buildHeadlessDiscussPrompt(nextId, seedContext, basePath);
687
681
  // Set pending auto start (auto-mode triggers on "Milestone X ready." via checkAutoStartAfterDiscuss)
@@ -865,9 +859,11 @@ export async function showDiscuss(ctx, pi, basePath) {
865
859
  }), "gsd-discuss", ctx, "discuss-milestone");
866
860
  }
867
861
  else if (choice === "skip_milestone") {
862
+ const { ensureDbOpen } = await import("./bootstrap/dynamic-tools.js");
863
+ await ensureDbOpen(basePath);
868
864
  const milestoneIds = findMilestoneIds(basePath);
869
865
  const uniqueMilestoneIds = !!loadEffectiveGSDPreferences()?.preferences?.unique_milestone_ids;
870
- const nextId = nextMilestoneIdReserved(milestoneIds, uniqueMilestoneIds);
866
+ const nextId = nextMilestoneIdReserved(milestoneIds, uniqueMilestoneIds, basePath);
871
867
  pendingAutoStartMap.set(basePath, { ctx, pi, basePath, milestoneId: nextId, step: false, createdAt: Date.now() });
872
868
  await dispatchWorkflow(pi, await prepareAndBuildDiscussPrompt(ctx, pi, nextId, `New milestone ${nextId}.`, basePath), "gsd-run", ctx, "discuss-milestone");
873
869
  }
@@ -1223,7 +1219,7 @@ async function handleMilestoneActions(ctx, pi, basePath, milestoneId, milestoneT
1223
1219
  if (choice === "skip") {
1224
1220
  const milestoneIds = findMilestoneIds(basePath);
1225
1221
  const uniqueMilestoneIds = !!loadEffectiveGSDPreferences()?.preferences?.unique_milestone_ids;
1226
- const nextId = nextMilestoneIdReserved(milestoneIds, uniqueMilestoneIds);
1222
+ const nextId = nextMilestoneIdReserved(milestoneIds, uniqueMilestoneIds, basePath);
1227
1223
  pendingAutoStartMap.set(basePath, { ctx, pi, basePath, milestoneId: nextId, step: stepMode, createdAt: Date.now() });
1228
1224
  await dispatchWorkflow(pi, await prepareAndBuildDiscussPrompt(ctx, pi, nextId, `New milestone ${nextId}.`, basePath), "gsd-run", ctx, "discuss-milestone");
1229
1225
  return true;
@@ -1291,6 +1287,10 @@ export async function showSmartEntry(ctx, pi, basePath, options) {
1291
1287
  // ── Ensure .gitignore has baseline patterns ──────────────────────────
1292
1288
  ensureGitignore(basePath);
1293
1289
  untrackRuntimeFiles(basePath);
1290
+ {
1291
+ const { ensureDbOpen } = await import("./bootstrap/dynamic-tools.js");
1292
+ await ensureDbOpen(basePath);
1293
+ }
1294
1294
  // ── Self-heal stale runtime records from crashed auto-mode sessions ──
1295
1295
  selfHealRuntimeRecords(basePath, ctx);
1296
1296
  const interrupted = await assessInterruptedSession(basePath);
@@ -1388,7 +1388,7 @@ export async function showSmartEntry(ctx, pi, basePath, options) {
1388
1388
  }
1389
1389
  }
1390
1390
  const uniqueMilestoneIds = !!loadEffectiveGSDPreferences()?.preferences?.unique_milestone_ids;
1391
- const nextId = nextMilestoneIdReserved(milestoneIds, uniqueMilestoneIds);
1391
+ const nextId = nextMilestoneIdReserved(milestoneIds, uniqueMilestoneIds, basePath);
1392
1392
  const isFirst = milestoneIds.length === 0;
1393
1393
  if (isFirst) {
1394
1394
  // First ever — skip wizard, just ask directly
@@ -1446,7 +1446,7 @@ export async function showSmartEntry(ctx, pi, basePath, options) {
1446
1446
  if (choice === "new_milestone") {
1447
1447
  const milestoneIds = findMilestoneIds(basePath);
1448
1448
  const uniqueMilestoneIds = !!loadEffectiveGSDPreferences()?.preferences?.unique_milestone_ids;
1449
- const nextId = nextMilestoneIdReserved(milestoneIds, uniqueMilestoneIds);
1449
+ const nextId = nextMilestoneIdReserved(milestoneIds, uniqueMilestoneIds, basePath);
1450
1450
  pendingAutoStartMap.set(basePath, { ctx, pi, basePath, milestoneId: nextId, step: stepMode, createdAt: Date.now() });
1451
1451
  await dispatchWorkflow(pi, await prepareAndBuildDiscussPrompt(ctx, pi, nextId, `New milestone ${nextId}.`, basePath), "gsd-run", ctx, "discuss-milestone");
1452
1452
  }
@@ -1510,7 +1510,7 @@ export async function showSmartEntry(ctx, pi, basePath, options) {
1510
1510
  else if (choice === "skip_milestone") {
1511
1511
  const milestoneIds = findMilestoneIds(basePath);
1512
1512
  const uniqueMilestoneIds = !!loadEffectiveGSDPreferences()?.preferences?.unique_milestone_ids;
1513
- const nextId = nextMilestoneIdReserved(milestoneIds, uniqueMilestoneIds);
1513
+ const nextId = nextMilestoneIdReserved(milestoneIds, uniqueMilestoneIds, basePath);
1514
1514
  pendingAutoStartMap.set(basePath, { ctx, pi, basePath, milestoneId: nextId, step: stepMode, createdAt: Date.now() });
1515
1515
  await dispatchWorkflow(pi, await prepareAndBuildDiscussPrompt(ctx, pi, nextId, `New milestone ${nextId}.`, basePath), "gsd-run", ctx, "discuss-milestone");
1516
1516
  }
@@ -1600,7 +1600,7 @@ export async function showSmartEntry(ctx, pi, basePath, options) {
1600
1600
  else if (choice === "skip_milestone") {
1601
1601
  const milestoneIds = findMilestoneIds(basePath);
1602
1602
  const uniqueMilestoneIds = !!loadEffectiveGSDPreferences()?.preferences?.unique_milestone_ids;
1603
- const nextId = nextMilestoneIdReserved(milestoneIds, uniqueMilestoneIds);
1603
+ const nextId = nextMilestoneIdReserved(milestoneIds, uniqueMilestoneIds, basePath);
1604
1604
  pendingAutoStartMap.set(basePath, { ctx, pi, basePath, milestoneId: nextId, step: stepMode, createdAt: Date.now() });
1605
1605
  await dispatchWorkflow(pi, await prepareAndBuildDiscussPrompt(ctx, pi, nextId, `New milestone ${nextId}.`, basePath), "gsd-run", ctx, "discuss-milestone");
1606
1606
  }