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
@@ -64,16 +64,21 @@ export function showHelp(ctx: ExtensionCommandContext, args = ""): void {
64
64
  " /gsd pause Pause auto-mode (preserves state, /gsd auto to resume)",
65
65
  " /gsd discuss Start guided milestone/slice discussion",
66
66
  " /gsd new-milestone Create milestone from headless context (used by gsd headless)",
67
+ " /gsd quick Execute a quick task without full planning overhead",
68
+ " /gsd dispatch Dispatch a specific phase directly [research|plan|execute|complete|uat|replan]",
69
+ " /gsd parallel Parallel milestone orchestration [start|status|stop|pause|resume|merge|watch]",
70
+ " /gsd workflow Custom workflow lifecycle [new|run|list|validate|pause|resume]",
67
71
  "",
68
72
  "VISIBILITY",
69
73
  ` /gsd status Show progress dashboard (${formattedShortcutPair("dashboard")})`,
70
74
  ` /gsd parallel watch Open parallel worker monitor (${formattedShortcutPair("parallel")})`,
75
+ " /gsd widget Cycle status widget [full|small|min|off]",
71
76
  " /gsd visualize Interactive 10-tab TUI (progress, timeline, deps, metrics, health, agent, changes, knowledge, captures, export)",
72
77
  " /gsd queue Show queued/dispatched units and execution order",
73
78
  " /gsd history View execution history [--cost] [--phase] [--model] [N]",
74
79
  " /gsd changelog Show categorized release notes [version]",
75
80
  ` /gsd notifications View persistent notification history [clear|tail|filter] (${formattedShortcutPair("notifications")})`,
76
- " /gsd logs Browse activity logs, debug logs, and metrics",
81
+ " /gsd logs Browse activity logs, debug logs, and metrics [debug|tail|clear]",
77
82
  " /gsd debug Create/list/continue persistent debug sessions",
78
83
  "",
79
84
  "COURSE CORRECTION",
@@ -82,6 +87,9 @@ export function showHelp(ctx: ExtensionCommandContext, args = ""): void {
82
87
  " /gsd triage Classify and route pending captures",
83
88
  " /gsd skip <unit> Prevent a unit from auto-mode dispatch",
84
89
  " /gsd undo Revert last completed unit [--force]",
90
+ " /gsd undo-task Reset a specific task's completion state [DB + markdown]",
91
+ " /gsd reset-slice Reset a slice and all its tasks [DB + markdown]",
92
+ " /gsd rate Rate last unit's model tier [over|ok|under]",
85
93
  " /gsd rethink Conversational project reorganization — reorder, park, discard, add milestones",
86
94
  " /gsd park [id] Park a milestone — skip without deleting [reason]",
87
95
  " /gsd unpark [id] Reactivate a parked milestone",
@@ -90,6 +98,15 @@ export function showHelp(ctx: ExtensionCommandContext, args = ""): void {
90
98
  " /gsd knowledge <type> <text> Add rule, pattern, or lesson to KNOWLEDGE.md",
91
99
  " /gsd codebase [generate|update|stats] Manage the CODEBASE.md cache used in prompt context",
92
100
  "",
101
+ "SHIPPING & BACKLOG",
102
+ " /gsd ship Create a PR from milestone artifacts [--dry-run|--draft|--base|--force]",
103
+ " /gsd do <text> Route freeform text to the right GSD command",
104
+ " /gsd session-report Show session cost, tokens, and work summary [--json|--save]",
105
+ " /gsd backlog Manage backlog items [add|promote|remove|list]",
106
+ " /gsd pr-branch Create a clean PR branch filtering .gsd/ commits [--dry-run|--name]",
107
+ " /gsd add-tests Generate tests for completed slices",
108
+ " /gsd scan Rapid codebase assessment [--focus tech|arch|quality|concerns|tech+arch]",
109
+ "",
93
110
  "SETUP & CONFIGURATION",
94
111
  " /gsd onboarding Re-run setup wizard [--resume|--reset|--step <name>]",
95
112
  " /gsd setup Configuration hub [llm|model|search|remote|keys|prefs|onboarding]",
@@ -102,18 +119,22 @@ export function showHelp(ctx: ExtensionCommandContext, args = ""): void {
102
119
  " /gsd config (deprecated) Set tool API keys — use /gsd keys instead",
103
120
  " /gsd show-config Show effective configuration (models, routing, toggles)",
104
121
  " /gsd hooks Show post-unit hook configuration",
122
+ " /gsd run-hook Manually trigger a specific hook",
123
+ " /gsd skill-health Skill lifecycle dashboard",
105
124
  " /gsd extensions Manage extensions [list|enable|disable|info]",
106
125
  " /gsd fast Toggle OpenAI service tier [on|off|flex|status]",
107
126
  " /gsd mcp MCP server status and connectivity [status|check <server>|init [dir]]",
108
127
  "",
109
128
  "MAINTENANCE",
110
129
  " /gsd doctor Diagnose and repair .gsd/ state [audit|fix|heal] [scope]",
130
+ " /gsd forensics Examine execution logs and post-mortem analysis",
111
131
  " /gsd export Export milestone/slice results [--json|--markdown|--html] [--all]",
112
132
  " /gsd cleanup Remove merged branches or snapshots [branches|snapshots]",
113
133
  " /gsd migrate Migrate .planning/ (v1) to .gsd/ (v2) format",
114
134
  " /gsd remote Control remote auto-mode [slack|discord|status|disconnect]",
115
135
  " /gsd inspect Show SQLite DB diagnostics (schema, row counts, recent entries)",
116
136
  " /gsd update Update GSD to the latest version via npm",
137
+ " /gsd language Set or clear the global response language [off|clear|<language>]",
117
138
  ];
118
139
  const full = ["full", "--full", "all"].includes(args.trim().toLowerCase());
119
140
  ctx.ui.notify((full ? fullLines : summaryLines).join("\n"), "info");
@@ -13,6 +13,7 @@
13
13
  import type { ExtensionCommandContext } from "@gsd/pi-coding-agent";
14
14
 
15
15
  import { existsSync, readFileSync } from "node:fs";
16
+ import { homedir } from "node:os";
16
17
  import { join, resolve } from "node:path";
17
18
 
18
19
  import { ensureProjectWorkflowMcpConfig } from "./mcp-project-config.js";
@@ -69,6 +70,7 @@ function readMcpConfigs(): McpServerRawConfig[] {
69
70
  const configPaths = [
70
71
  join(process.cwd(), ".mcp.json"),
71
72
  join(process.cwd(), ".gsd", "mcp.json"),
73
+ join(process.env.GSD_HOME || join(homedir(), ".gsd"), "mcp.json"),
72
74
  ];
73
75
 
74
76
  for (const configPath of configPaths) {
@@ -118,7 +120,7 @@ export function formatMcpStatusReport(servers: McpServerStatus[]): string {
118
120
  return [
119
121
  "No MCP servers configured.",
120
122
  "",
121
- "Add servers to .mcp.json or .gsd/mcp.json to enable MCP integrations.",
123
+ "Add servers to .mcp.json, .gsd/mcp.json, or $GSD_HOME/mcp.json (default: ~/.gsd/mcp.json) to enable MCP integrations.",
122
124
  "Tip: run /gsd mcp init . to write the local GSD workflow MCP config.",
123
125
  "See: https://modelcontextprotocol.io/quickstart",
124
126
  ].join("\n");
@@ -1524,6 +1524,18 @@ async function configureAdvanced(ctx: ExtensionCommandContext, prefs: Record<str
1524
1524
  const tokenCost = await promptBoolean(ctx, "Show token cost in footer", prefs.show_token_cost, false);
1525
1525
  if (tokenCost !== undefined) prefs.show_token_cost = tokenCost;
1526
1526
 
1527
+ const minRequestInterval = await promptInteger(
1528
+ ctx,
1529
+ "Minimum interval between auto-mode LLM requests (ms, 0 to disable)",
1530
+ prefs.min_request_interval_ms,
1531
+ "0",
1532
+ );
1533
+ if (minRequestInterval === "clear") {
1534
+ delete prefs.min_request_interval_ms;
1535
+ } else if (minRequestInterval !== undefined) {
1536
+ prefs.min_request_interval_ms = minRequestInterval;
1537
+ }
1538
+
1527
1539
  const widget = await promptEnum(ctx, "Auto-mode widget display", prefs.widget_mode, ["full", "small", "min", "off"], "full");
1528
1540
  if (widget !== undefined) prefs.widget_mode = widget;
1529
1541
 
@@ -1715,8 +1727,10 @@ export function serializePreferencesToFrontmatter(prefs: Record<string, unknown>
1715
1727
  "budget_ceiling", "budget_enforcement", "context_pause_threshold",
1716
1728
  "notifications", "cmux", "remote_questions", "git",
1717
1729
  "stale_commit_threshold_minutes",
1730
+ "min_request_interval_ms",
1718
1731
  "post_unit_hooks", "pre_dispatch_hooks",
1719
- "dynamic_routing", "uok", "token_profile", "service_tier", "flat_rate_providers",
1732
+ "dynamic_routing", "disabled_model_providers", "uok", "token_profile",
1733
+ "service_tier", "flat_rate_providers",
1720
1734
  "phases", "parallel", "slice_parallel",
1721
1735
  "reactive_execution", "gate_evaluation",
1722
1736
  "auto_visualize", "auto_report",
@@ -21,7 +21,7 @@ import {
21
21
  type UnitMetrics,
22
22
  } from "./metrics.js";
23
23
  import { loadEffectiveGSDPreferences } from "./preferences.js";
24
- import { getActiveWorktreeName } from "./worktree-command.js";
24
+ import { getActiveWorktreeName } from "./worktree-session-state.js";
25
25
  import { getWorkerBatches, hasActiveWorkers, type WorkerEntry } from "../subagent/worker-registry.js";
26
26
  import { formatDuration, padRight, joinColumns, centerLine, fitColumns, STATUS_GLYPH, STATUS_COLOR } from "../shared/mod.js";
27
27
  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`.
@@ -4,7 +4,7 @@ import { basename, dirname, join } from "node:path";
4
4
  import type { DoctorIssue, DoctorIssueCode } from "./doctor-types.js";
5
5
  import { cleanNumberedGsdVariants } from "./repo-identity.js";
6
6
  import { milestonesDir, gsdRoot, resolveGsdRootFile } from "./paths.js";
7
- import { deriveState } from "./state.js";
7
+ import { deriveState, isGhostMilestone, isReusableGhostMilestone } from "./state.js";
8
8
  import { saveFile } from "./files.js";
9
9
  import { nativeIsRepo, nativeForEachRef, nativeUpdateRef } from "./native-git-bridge.js";
10
10
  import { readCrashLock, isLockProcessAlive, clearLock } from "./crash-recovery.js";
@@ -12,6 +12,7 @@ import { ensureGitignore, isGsdGitignored } from "./gitignore.js";
12
12
  import { readAllSessionStatuses, isSessionStale, removeSessionStatus } from "./session-status-io.js";
13
13
  import { recoverFailedMigration } from "./migrate-external.js";
14
14
  import { splitCompletedKey } from "./forensics.js";
15
+ import { findMilestoneIds } from "./milestone-ids.js";
15
16
 
16
17
  export async function checkRuntimeHealth(
17
18
  basePath: string,
@@ -593,6 +594,43 @@ export async function checkRuntimeHealth(
593
594
  } catch {
594
595
  // Non-fatal — snapshot ref check failed
595
596
  }
597
+
598
+ // ── Orphan milestone directories (#4996) ──────────────────────────────
599
+ // Walk every milestone ID on disk. Any dir that has no DB row, no worktree,
600
+ // and no content files is an orphaned stub — it skews nextMilestoneId and
601
+ // was likely created by ensurePreconditions or showHeadlessMilestoneCreation
602
+ // for a phantom forward-reference. Surface as a fixable warning.
603
+ try {
604
+ const milestoneIds = findMilestoneIds(basePath);
605
+ const hasDbFile = existsSync(join(root, "gsd.db"));
606
+ for (const mid of milestoneIds) {
607
+ const isOrphan = isReusableGhostMilestone(basePath, mid)
608
+ || (!hasDbFile && isGhostMilestone(basePath, mid));
609
+ if (isOrphan) {
610
+ issues.push({
611
+ severity: "warning",
612
+ code: "orphan_milestone_dir",
613
+ scope: "milestone",
614
+ unitId: mid,
615
+ 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.`,
616
+ file: `.gsd/milestones/${mid}`,
617
+ fixable: true,
618
+ });
619
+
620
+ if (shouldFix("orphan_milestone_dir")) {
621
+ try {
622
+ const orphanPath = join(milestonesDir(basePath), mid);
623
+ rmSync(orphanPath, { recursive: true, force: true });
624
+ fixesApplied.push(`removed orphan milestone directory: ${mid}`);
625
+ } catch {
626
+ // Non-fatal — leave for manual cleanup
627
+ }
628
+ }
629
+ }
630
+ }
631
+ } catch {
632
+ // Non-fatal — orphan milestone directory check failed
633
+ }
596
634
  }
597
635
 
598
636
  /**
@@ -80,7 +80,9 @@ export type DoctorIssueCode =
80
80
  | "db_done_task_no_summary"
81
81
  | "db_duplicate_id"
82
82
  | "db_unavailable"
83
- | "projection_drift";
83
+ | "projection_drift"
84
+ // Milestone filesystem/DB drift (#4996)
85
+ | "orphan_milestone_dir";
84
86
 
85
87
  /**
86
88
  * Issue codes that represent global or completion-critical state.
@@ -59,7 +59,7 @@ const NETWORK_RE = /network|ECONNRESET|ETIMEDOUT|ECONNREFUSED|socket hang up|fet
59
59
  // Context overflow errors (context window/length exceeded) should be treated as server-class
60
60
  // transient errors so auto-mode can retry with reduced budget or fall back to a larger-context model.
61
61
  // See: https://github.com/gsd-build/gsd-2/issues/4528
62
- const SERVER_RE = /internal server error|500|502|503|overloaded|server_error|api_error|service.?unavailable|context (?:window|length) exceed|context window exceed/i;
62
+ const SERVER_RE = /internal(?: server)?[ _-]?error|500|502|503|overloaded|server_error|api_error|service.?unavailable|context (?:window|length) exceed|context window exceed/i;
63
63
  // ECONNRESET/ECONNREFUSED are in NETWORK_RE (same-model retry first).
64
64
  const CONNECTION_RE = /terminated|connection.?(?:refused|error)|other side closed|EPIPE|network.?(?:is\s+)?unavailable|stream_exhausted(?:_without_result)?/i;
65
65
  // Catch-all for V8 JSON.parse errors: all modern variants end with "in JSON at position \d+".
@@ -804,7 +804,7 @@ function detectMissingArtifacts(completedKeys: string[], basePath: string, activ
804
804
  * the forensics memory-bloat guard in forensics-journal.test.ts — per-event
805
805
  * detail stays in the journal itself where the LLM can query it on demand.
806
806
  */
807
- function detectWorktreeOrphans(
807
+ export function detectWorktreeOrphans(
808
808
  summary: WorktreeTelemetrySummary,
809
809
  anomalies: ForensicAnomaly[],
810
810
  ): void {
@@ -822,7 +822,7 @@ function detectWorktreeOrphans(
822
822
  reason === "in-progress-unmerged"
823
823
  ? "Auto-mode exited without completing a milestone; live work sits on an unmerged milestone branch. Run `/gsd auto` to resume, or merge manually."
824
824
  : reason === "complete-unmerged"
825
- ? "A completed milestone's branch was never merged back to main. Run `/gsd health --fix` to resolve."
825
+ ? "A completed milestone's branch was never merged back to main. Run `/gsd doctor fix` to resolve."
826
826
  : `Reason: ${reason}.`,
827
827
  });
828
828
  }
@@ -38,6 +38,7 @@ import {
38
38
  } from "./native-git-bridge.js";
39
39
  import { GSDError, GSD_MERGE_CONFLICT, GSD_GIT_ERROR } from "./errors.js";
40
40
  import { getErrorMessage } from "./error-utils.js";
41
+ import { isInfrastructureError } from "./auto/infra-errors.js";
41
42
 
42
43
  // ─── Types ─────────────────────────────────────────────────────────────────
43
44
 
@@ -991,6 +992,17 @@ function buildTurnSnapshotLabel(unitType: string, unitId: string): string {
991
992
  .replace(/^[-/]+|[-/]+$/g, "") || "turn";
992
993
  }
993
994
 
995
+ export function handleTurnGitActionError(action: TurnGitActionMode, err: unknown): TurnGitActionResult {
996
+ if (isInfrastructureError(err)) {
997
+ throw err;
998
+ }
999
+ return {
1000
+ action,
1001
+ status: "failed",
1002
+ error: getErrorMessage(err),
1003
+ };
1004
+ }
1005
+
994
1006
  export function runTurnGitAction(args: {
995
1007
  basePath: string;
996
1008
  action: TurnGitActionMode;
@@ -1029,11 +1041,7 @@ export function runTurnGitAction(args: {
1029
1041
  dirty: nativeHasChanges(args.basePath),
1030
1042
  };
1031
1043
  } catch (err) {
1032
- return {
1033
- action: args.action,
1034
- status: "failed",
1035
- error: getErrorMessage(err),
1036
- };
1044
+ return handleTurnGitActionError(args.action, err);
1037
1045
  }
1038
1046
  }
1039
1047
 
@@ -1405,6 +1405,16 @@ export function checkpointDatabase(): void {
1405
1405
 
1406
1406
  let _txDepth = 0;
1407
1407
 
1408
+ /**
1409
+ * Whether the current call is running inside an active SQLite transaction.
1410
+ * Statement-time recovery paths (e.g. VACUUM retry on a malformed memory
1411
+ * store) MUST gate on this — SQLite refuses VACUUM inside a transaction
1412
+ * and would mask the original error with a secondary "cannot VACUUM" throw.
1413
+ */
1414
+ export function isInTransaction(): boolean {
1415
+ return _txDepth > 0;
1416
+ }
1417
+
1408
1418
  export function transaction<T>(fn: () => T): T {
1409
1419
  if (!currentDb) throw new GSDError(GSD_STALE_STATE, "gsd-db: No database open");
1410
1420
 
@@ -1419,8 +1429,8 @@ export function transaction<T>(fn: () => T): T {
1419
1429
  }
1420
1430
  }
1421
1431
 
1422
- _txDepth++;
1423
1432
  currentDb.exec("BEGIN");
1433
+ _txDepth++;
1424
1434
  try {
1425
1435
  const result = fn();
1426
1436
  currentDb.exec("COMMIT");
@@ -1452,8 +1462,8 @@ export function readTransaction<T>(fn: () => T): T {
1452
1462
  }
1453
1463
  }
1454
1464
 
1455
- _txDepth++;
1456
1465
  currentDb.exec("BEGIN DEFERRED");
1466
+ _txDepth++;
1457
1467
  try {
1458
1468
  const result = fn();
1459
1469
  currentDb.exec("COMMIT");
@@ -44,7 +44,9 @@ import { showProjectInit, offerMigration } from "./init-wizard.js";
44
44
  import { validateDirectory } from "./validate-directory.js";
45
45
  import { showConfirm } from "../shared/tui.js";
46
46
  import { debugLog } from "./debug-logger.js";
47
- import { findMilestoneIds, nextMilestoneId, reserveMilestoneId, getReservedMilestoneIds, clearReservedMilestoneIds } from "./milestone-ids.js";
47
+ import { findMilestoneIds, clearReservedMilestoneIds } from "./milestone-ids.js";
48
+ import { nextMilestoneIdReserved } from "./milestone-id-reservation.js";
49
+ export { nextMilestoneIdReserved } from "./milestone-id-reservation.js";
48
50
  import { parkMilestone, discardMilestone } from "./milestone-actions.js";
49
51
  import { selectAndApplyModel } from "./auto-model-selection.js";
50
52
  import { DISCUSS_TOOLS_ALLOWLIST } from "./constants.js";
@@ -72,20 +74,6 @@ export {
72
74
  } from "./guided-flow-queue.js";
73
75
  import { logWarning } from "./workflow-logger.js";
74
76
 
75
- // ─── ID Generation with Reservation ─────────────────────────────────────────
76
-
77
- /**
78
- * Generate the next milestone ID, accounting for reserved IDs, and reserve it.
79
- * Ensures any preview ID shown in the UI matches what `gsd_milestone_generate_id`
80
- * will later return.
81
- */
82
- function nextMilestoneIdReserved(existingIds: string[], uniqueEnabled: boolean): string {
83
- const allIds = [...new Set([...existingIds, ...getReservedMilestoneIds()])];
84
- const id = nextMilestoneId(allIds, uniqueEnabled);
85
- reserveMilestoneId(id);
86
- return id;
87
- }
88
-
89
77
  function needsPlanV2Gate(state: GSDState): boolean {
90
78
  return state.phase === "executing"
91
79
  || state.phase === "summarizing"
@@ -832,14 +820,19 @@ export async function showHeadlessMilestoneCreation(
832
820
  // Ensure .gsd/ is bootstrapped
833
821
  bootstrapGsdProject(basePath);
834
822
 
823
+ const { ensureDbOpen } = await import("./bootstrap/dynamic-tools.js");
824
+ await ensureDbOpen(basePath);
825
+
835
826
  // Generate next milestone ID
836
827
  const existingIds = findMilestoneIds(basePath);
837
828
  const prefs = loadEffectiveGSDPreferences();
838
- const nextId = nextMilestoneIdReserved(existingIds, prefs?.preferences?.unique_milestone_ids ?? false);
829
+ const nextId = nextMilestoneIdReserved(existingIds, prefs?.preferences?.unique_milestone_ids ?? false, basePath);
839
830
 
840
- // Create milestone directory
841
- const milestoneDir = join(gsdRoot(basePath), "milestones", nextId, "slices");
842
- mkdirSync(milestoneDir, { recursive: true });
831
+ // Fix #4996: Do NOT pre-create the milestone directory here.
832
+ // atomicWriteAsync (used by all artifact writers) calls mkdir lazily before
833
+ // each write, so every path through saveArtifactToDb / saveFile is already
834
+ // lazy-mkdir-safe. Pre-creating the dir before the discuss flow runs leaves
835
+ // an orphan stub if discuss is abandoned — that stub later skews nextMilestoneId.
843
836
 
844
837
  // Build and dispatch the headless discuss prompt
845
838
  const prompt = buildHeadlessDiscussPrompt(nextId, seedContext, basePath);
@@ -1054,9 +1047,11 @@ export async function showDiscuss(
1054
1047
  fastPathInstruction: "",
1055
1048
  }), "gsd-discuss", ctx, "discuss-milestone");
1056
1049
  } else if (choice === "skip_milestone") {
1050
+ const { ensureDbOpen } = await import("./bootstrap/dynamic-tools.js");
1051
+ await ensureDbOpen(basePath);
1057
1052
  const milestoneIds = findMilestoneIds(basePath);
1058
1053
  const uniqueMilestoneIds = !!loadEffectiveGSDPreferences()?.preferences?.unique_milestone_ids;
1059
- const nextId = nextMilestoneIdReserved(milestoneIds, uniqueMilestoneIds);
1054
+ const nextId = nextMilestoneIdReserved(milestoneIds, uniqueMilestoneIds, basePath);
1060
1055
  pendingAutoStartMap.set(basePath, { ctx, pi, basePath, milestoneId: nextId, step: false, createdAt: Date.now() });
1061
1056
  await dispatchWorkflow(pi, await prepareAndBuildDiscussPrompt(ctx, pi, nextId, `New milestone ${nextId}.`, basePath), "gsd-run", ctx, "discuss-milestone");
1062
1057
  }
@@ -1461,7 +1456,7 @@ async function handleMilestoneActions(
1461
1456
  if (choice === "skip") {
1462
1457
  const milestoneIds = findMilestoneIds(basePath);
1463
1458
  const uniqueMilestoneIds = !!loadEffectiveGSDPreferences()?.preferences?.unique_milestone_ids;
1464
- const nextId = nextMilestoneIdReserved(milestoneIds, uniqueMilestoneIds);
1459
+ const nextId = nextMilestoneIdReserved(milestoneIds, uniqueMilestoneIds, basePath);
1465
1460
  pendingAutoStartMap.set(basePath, { ctx, pi, basePath, milestoneId: nextId, step: stepMode, createdAt: Date.now() });
1466
1461
  await dispatchWorkflow(pi, await prepareAndBuildDiscussPrompt(ctx, pi, nextId,
1467
1462
  `New milestone ${nextId}.`,
@@ -1546,6 +1541,11 @@ export async function showSmartEntry(
1546
1541
  ensureGitignore(basePath);
1547
1542
  untrackRuntimeFiles(basePath);
1548
1543
 
1544
+ {
1545
+ const { ensureDbOpen } = await import("./bootstrap/dynamic-tools.js");
1546
+ await ensureDbOpen(basePath);
1547
+ }
1548
+
1549
1549
  // ── Self-heal stale runtime records from crashed auto-mode sessions ──
1550
1550
  selfHealRuntimeRecords(basePath, ctx);
1551
1551
 
@@ -1648,7 +1648,7 @@ export async function showSmartEntry(
1648
1648
  }
1649
1649
 
1650
1650
  const uniqueMilestoneIds = !!loadEffectiveGSDPreferences()?.preferences?.unique_milestone_ids;
1651
- const nextId = nextMilestoneIdReserved(milestoneIds, uniqueMilestoneIds);
1651
+ const nextId = nextMilestoneIdReserved(milestoneIds, uniqueMilestoneIds, basePath);
1652
1652
  const isFirst = milestoneIds.length === 0;
1653
1653
 
1654
1654
  if (isFirst) {
@@ -1728,7 +1728,7 @@ export async function showSmartEntry(
1728
1728
  if (choice === "new_milestone") {
1729
1729
  const milestoneIds = findMilestoneIds(basePath);
1730
1730
  const uniqueMilestoneIds = !!loadEffectiveGSDPreferences()?.preferences?.unique_milestone_ids;
1731
- const nextId = nextMilestoneIdReserved(milestoneIds, uniqueMilestoneIds);
1731
+ const nextId = nextMilestoneIdReserved(milestoneIds, uniqueMilestoneIds, basePath);
1732
1732
 
1733
1733
  pendingAutoStartMap.set(basePath, { ctx, pi, basePath, milestoneId: nextId, step: stepMode, createdAt: Date.now() });
1734
1734
  await dispatchWorkflow(pi, await prepareAndBuildDiscussPrompt(ctx, pi, nextId,
@@ -1796,7 +1796,7 @@ export async function showSmartEntry(
1796
1796
  } else if (choice === "skip_milestone") {
1797
1797
  const milestoneIds = findMilestoneIds(basePath);
1798
1798
  const uniqueMilestoneIds = !!loadEffectiveGSDPreferences()?.preferences?.unique_milestone_ids;
1799
- const nextId = nextMilestoneIdReserved(milestoneIds, uniqueMilestoneIds);
1799
+ const nextId = nextMilestoneIdReserved(milestoneIds, uniqueMilestoneIds, basePath);
1800
1800
  pendingAutoStartMap.set(basePath, { ctx, pi, basePath, milestoneId: nextId, step: stepMode, createdAt: Date.now() });
1801
1801
  await dispatchWorkflow(pi, await prepareAndBuildDiscussPrompt(ctx, pi, nextId,
1802
1802
  `New milestone ${nextId}.`,
@@ -1893,7 +1893,7 @@ export async function showSmartEntry(
1893
1893
  } else if (choice === "skip_milestone") {
1894
1894
  const milestoneIds = findMilestoneIds(basePath);
1895
1895
  const uniqueMilestoneIds = !!loadEffectiveGSDPreferences()?.preferences?.unique_milestone_ids;
1896
- const nextId = nextMilestoneIdReserved(milestoneIds, uniqueMilestoneIds);
1896
+ const nextId = nextMilestoneIdReserved(milestoneIds, uniqueMilestoneIds, basePath);
1897
1897
  pendingAutoStartMap.set(basePath, { ctx, pi, basePath, milestoneId: nextId, step: stepMode, createdAt: Date.now() });
1898
1898
  await dispatchWorkflow(pi, await prepareAndBuildDiscussPrompt(ctx, pi, nextId,
1899
1899
  `New milestone ${nextId}.`,
@@ -7,6 +7,7 @@ import {
7
7
  isDbAvailable,
8
8
  _getAdapter,
9
9
  transaction,
10
+ isInTransaction,
10
11
  insertMemoryRow,
11
12
  rewriteMemoryId,
12
13
  updateMemoryContentRow,
@@ -19,6 +20,7 @@ import {
19
20
  deleteMemoryRelationsFor,
20
21
  } from './gsd-db.js';
21
22
  import { createMemoryRelation, isValidRelation } from './memory-relations.js';
23
+ import { logWarning } from './workflow-logger.js';
22
24
 
23
25
  // ─── Types ──────────────────────────────────────────────────────────────────
24
26
 
@@ -487,7 +489,13 @@ export function nextMemoryId(): string {
487
489
  * Insert a new memory with a race-safe auto-assigned ID.
488
490
  * Uses AUTOINCREMENT seq to derive the ID after insert, avoiding
489
491
  * the read-then-write race in concurrent scenarios (e.g. worktrees).
490
- * Returns the assigned ID, or null on failure.
492
+ * Returns the assigned ID, or null when the DB is unavailable.
493
+ *
494
+ * Throws on genuine SQL errors (corruption, missing tables, constraint
495
+ * violations) so callers can surface the underlying message instead of
496
+ * collapsing the failure to a generic "create_failed". See issue #4967 —
497
+ * the previous bare-catch swallowed "database disk image is malformed"
498
+ * errors, leaving the memory subsystem broken without any signal.
491
499
  */
492
500
  export function createMemory(fields: {
493
501
  category: string;
@@ -504,34 +512,70 @@ export function createMemory(fields: {
504
512
  if (!adapter) return null;
505
513
 
506
514
  try {
507
- const now = new Date().toISOString();
508
- // Insert with a temporary placeholder ID — seq is auto-assigned
509
- const placeholder = `_TMP_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
510
- insertMemoryRow({
511
- id: placeholder,
512
- category: fields.category,
513
- content: fields.content,
514
- confidence: fields.confidence ?? 0.8,
515
- sourceUnitType: fields.source_unit_type ?? null,
516
- sourceUnitId: fields.source_unit_id ?? null,
517
- createdAt: now,
518
- updatedAt: now,
519
- scope: fields.scope ?? 'project',
520
- tags: fields.tags ?? [],
521
- structuredFields: fields.structuredFields ?? null,
522
- });
523
- // Derive the real ID from the assigned seq (SELECT is still fine via adapter)
524
- const row = adapter.prepare('SELECT seq FROM memories WHERE id = :id').get({ ':id': placeholder });
525
- if (!row) return placeholder; // fallback — should not happen
526
- const seq = row['seq'] as number;
527
- const realId = `MEM${String(seq).padStart(3, '0')}`;
528
- rewriteMemoryId(placeholder, realId);
529
- return realId;
530
- } catch {
531
- return null;
515
+ return transaction(() => doCreateMemory(adapter, fields));
516
+ } catch (err) {
517
+ const message = err instanceof Error ? err.message : String(err);
518
+
519
+ // Targeted recovery: a malformed memory store can sometimes be rebuilt
520
+ // by VACUUM. Skip when inside a transaction — SQLite refuses VACUUM
521
+ // there and a secondary throw would mask the real fault.
522
+ if (message.toLowerCase().includes('malformed') && !isInTransaction()) {
523
+ try {
524
+ adapter.prepare('VACUUM').run();
525
+ const recoveryMessage = 'recovered malformed memory store via VACUUM';
526
+ process.stderr.write(`memory-store: ${recoveryMessage}\n`);
527
+ logWarning('memory-store', recoveryMessage);
528
+ return transaction(() => doCreateMemory(adapter, fields));
529
+ } catch (retryErr) {
530
+ const retryMsg = retryErr instanceof Error ? retryErr.message : String(retryErr);
531
+ logWarning('memory-store', `VACUUM recovery for memory store failed: ${retryMsg}`);
532
+ // Surface the *original* malformed error it's the actionable signal.
533
+ throw err;
534
+ }
535
+ }
536
+
537
+ throw err;
532
538
  }
533
539
  }
534
540
 
541
+ function doCreateMemory(
542
+ adapter: NonNullable<ReturnType<typeof _getAdapter>>,
543
+ fields: {
544
+ category: string;
545
+ content: string;
546
+ confidence?: number;
547
+ source_unit_type?: string;
548
+ source_unit_id?: string;
549
+ scope?: string;
550
+ tags?: string[];
551
+ structuredFields?: Record<string, unknown> | null;
552
+ },
553
+ ): string {
554
+ const now = new Date().toISOString();
555
+ // Insert with a temporary placeholder ID — seq is auto-assigned
556
+ const placeholder = `_TMP_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
557
+ insertMemoryRow({
558
+ id: placeholder,
559
+ category: fields.category,
560
+ content: fields.content,
561
+ confidence: fields.confidence ?? 0.8,
562
+ sourceUnitType: fields.source_unit_type ?? null,
563
+ sourceUnitId: fields.source_unit_id ?? null,
564
+ createdAt: now,
565
+ updatedAt: now,
566
+ scope: fields.scope ?? 'project',
567
+ tags: fields.tags ?? [],
568
+ structuredFields: fields.structuredFields ?? null,
569
+ });
570
+ // Derive the real ID from the assigned seq (SELECT is still fine via adapter)
571
+ const row = adapter.prepare('SELECT seq FROM memories WHERE id = :id').get({ ':id': placeholder });
572
+ if (!row) return placeholder; // fallback — should not happen
573
+ const seq = row['seq'] as number;
574
+ const realId = `MEM${String(seq).padStart(3, '0')}`;
575
+ rewriteMemoryId(placeholder, realId);
576
+ return realId;
577
+ }
578
+
535
579
  /**
536
580
  * Update a memory's content and optionally its confidence.
537
581
  */
@@ -728,8 +772,17 @@ export function applyMemoryActions(
728
772
  }
729
773
  enforceMemoryCap();
730
774
  });
731
- } catch {
732
- // non-fatal — transaction will have rolled back
775
+ } catch (err) {
776
+ // Non-fatal — the transaction has rolled back. We log a warning so a
777
+ // degraded memory subsystem (e.g. malformed store, missing tables) is
778
+ // visible to forensics instead of silently dropping every CREATE — see
779
+ // issue #4967, where this swallow combined with createMemory's bare
780
+ // catch hid SQLite corruption from the auto-mode flow entirely.
781
+ const message = err instanceof Error ? err.message : String(err);
782
+ logWarning(
783
+ 'memory-store',
784
+ `applyMemoryActions failed (memory subsystem degraded): ${message}`,
785
+ );
733
786
  }
734
787
  }
735
788