gsd-pi 2.76.0 → 2.77.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (536) hide show
  1. package/README.md +45 -25
  2. package/dist/claude-cli-check.js +32 -3
  3. package/dist/mcp-server.d.ts +7 -0
  4. package/dist/mcp-server.js +35 -1
  5. package/dist/onboarding.js +45 -0
  6. package/dist/resource-loader.d.ts +1 -1
  7. package/dist/resource-loader.js +2 -8
  8. package/dist/resources/agents/researcher.md +1 -1
  9. package/dist/resources/extensions/claude-code-cli/readiness.js +31 -8
  10. package/dist/resources/extensions/claude-code-cli/stream-adapter.js +77 -17
  11. package/dist/resources/extensions/gsd/auto/loop.js +9 -0
  12. package/dist/resources/extensions/gsd/auto/phases.js +104 -11
  13. package/dist/resources/extensions/gsd/auto/run-unit.js +38 -2
  14. package/dist/resources/extensions/gsd/auto/session.js +22 -1
  15. package/dist/resources/extensions/gsd/auto-dispatch.js +16 -3
  16. package/dist/resources/extensions/gsd/auto-model-selection.js +53 -16
  17. package/dist/resources/extensions/gsd/auto-post-unit.js +25 -2
  18. package/dist/resources/extensions/gsd/auto-prompts.js +14 -0
  19. package/dist/resources/extensions/gsd/auto-recovery.js +32 -1
  20. package/dist/resources/extensions/gsd/auto-start.js +58 -57
  21. package/dist/resources/extensions/gsd/auto-verification.js +33 -0
  22. package/dist/resources/extensions/gsd/auto-worktree.js +51 -53
  23. package/dist/resources/extensions/gsd/auto.js +70 -28
  24. package/dist/resources/extensions/gsd/blocked-models.js +68 -0
  25. package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +93 -1
  26. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +39 -9
  27. package/dist/resources/extensions/gsd/bootstrap/exec-tools.js +93 -0
  28. package/dist/resources/extensions/gsd/bootstrap/memory-tools.js +3 -0
  29. package/dist/resources/extensions/gsd/bootstrap/register-extension.js +12 -0
  30. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +52 -6
  31. package/dist/resources/extensions/gsd/bootstrap/system-context.js +84 -23
  32. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +34 -2
  33. package/dist/resources/extensions/gsd/clean-root-preflight.js +93 -0
  34. package/dist/resources/extensions/gsd/commands-extract-learnings.js +54 -89
  35. package/dist/resources/extensions/gsd/commands-prefs-wizard.js +968 -23
  36. package/dist/resources/extensions/gsd/compaction-snapshot.js +121 -0
  37. package/dist/resources/extensions/gsd/complexity-classifier.js +5 -3
  38. package/dist/resources/extensions/gsd/db-writer.js +88 -16
  39. package/dist/resources/extensions/gsd/doctor-git-checks.js +23 -29
  40. package/dist/resources/extensions/gsd/doctor-providers.js +51 -5
  41. package/dist/resources/extensions/gsd/ecosystem/gsd-extension-api.js +1 -0
  42. package/dist/resources/extensions/gsd/error-classifier.js +31 -3
  43. package/dist/resources/extensions/gsd/exec-history.js +120 -0
  44. package/dist/resources/extensions/gsd/exec-sandbox.js +258 -0
  45. package/dist/resources/extensions/gsd/gitignore.js +1 -0
  46. package/dist/resources/extensions/gsd/gsd-db.js +168 -23
  47. package/dist/resources/extensions/gsd/guided-flow.js +190 -1
  48. package/dist/resources/extensions/gsd/health-widget.js +4 -1
  49. package/dist/resources/extensions/gsd/hook-emitter.js +108 -0
  50. package/dist/resources/extensions/gsd/init-wizard.js +15 -1
  51. package/dist/resources/extensions/gsd/key-manager.js +28 -0
  52. package/dist/resources/extensions/gsd/memory-backfill.js +126 -0
  53. package/dist/resources/extensions/gsd/memory-store.js +19 -0
  54. package/dist/resources/extensions/gsd/model-router.js +36 -3
  55. package/dist/resources/extensions/gsd/pre-execution-checks.js +44 -9
  56. package/dist/resources/extensions/gsd/preferences-types.js +9 -0
  57. package/dist/resources/extensions/gsd/preferences-validation.js +83 -0
  58. package/dist/resources/extensions/gsd/preferences.js +17 -17
  59. package/dist/resources/extensions/gsd/prompt-loader.js +22 -7
  60. package/dist/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
  61. package/dist/resources/extensions/gsd/prompts/complete-slice.md +2 -2
  62. package/dist/resources/extensions/gsd/prompts/debug-diagnose.md +2 -0
  63. package/dist/resources/extensions/gsd/prompts/discuss-headless.md +8 -0
  64. package/dist/resources/extensions/gsd/prompts/discuss.md +29 -2
  65. package/dist/resources/extensions/gsd/prompts/execute-task.md +3 -2
  66. package/dist/resources/extensions/gsd/prompts/parallel-research-slices.md +5 -2
  67. package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -0
  68. package/dist/resources/extensions/gsd/prompts/research-slice.md +1 -0
  69. package/dist/resources/extensions/gsd/safety/evidence-collector.js +96 -0
  70. package/dist/resources/extensions/gsd/safety/file-change-validator.js +13 -5
  71. package/dist/resources/extensions/gsd/safety/safety-harness.js +5 -1
  72. package/dist/resources/extensions/gsd/state.js +43 -4
  73. package/dist/resources/extensions/gsd/token-counter.js +22 -5
  74. package/dist/resources/extensions/gsd/tools/complete-milestone.js +16 -10
  75. package/dist/resources/extensions/gsd/tools/exec-search-tool.js +59 -0
  76. package/dist/resources/extensions/gsd/tools/exec-tool.js +126 -0
  77. package/dist/resources/extensions/gsd/tools/memory-tools.js +26 -1
  78. package/dist/resources/extensions/gsd/tools/resume-tool.js +23 -0
  79. package/dist/resources/extensions/gsd/uok/plan-v2.js +20 -3
  80. package/dist/resources/extensions/gsd/workflow-mcp.js +3 -0
  81. package/dist/resources/extensions/gsd/workflow-templates/spike.md +6 -0
  82. package/dist/resources/extensions/gsd/worktree-resolver.js +50 -10
  83. package/dist/resources/extensions/search-the-web/command-search-provider.js +5 -4
  84. package/dist/resources/extensions/search-the-web/native-search.js +45 -13
  85. package/dist/resources/skills/api-design/SKILL.md +190 -0
  86. package/dist/resources/skills/create-mcp-server/SKILL.md +121 -0
  87. package/dist/resources/skills/decompose-into-slices/SKILL.md +139 -0
  88. package/dist/resources/skills/dependency-upgrade/SKILL.md +158 -0
  89. package/dist/resources/skills/design-an-interface/SKILL.md +102 -0
  90. package/dist/resources/skills/forensics/SKILL.md +153 -0
  91. package/dist/resources/skills/grill-me/SKILL.md +93 -0
  92. package/dist/resources/skills/handoff/SKILL.md +121 -0
  93. package/dist/resources/skills/observability/SKILL.md +174 -0
  94. package/dist/resources/skills/security-review/SKILL.md +181 -0
  95. package/dist/resources/skills/spike-wrap-up/SKILL.md +138 -0
  96. package/dist/resources/skills/tdd/SKILL.md +112 -0
  97. package/dist/resources/skills/verify-before-complete/SKILL.md +98 -0
  98. package/dist/resources/skills/write-docs/SKILL.md +82 -0
  99. package/dist/resources/skills/write-milestone-brief/SKILL.md +135 -0
  100. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  101. package/dist/web/standalone/.next/BUILD_ID +1 -1
  102. package/dist/web/standalone/.next/app-path-routes-manifest.json +10 -10
  103. package/dist/web/standalone/.next/build-manifest.json +2 -2
  104. package/dist/web/standalone/.next/required-server-files.json +1 -1
  105. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  106. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  107. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  108. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  109. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  110. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  111. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  112. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  113. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  114. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  115. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  116. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  117. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  118. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  119. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  120. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  121. package/dist/web/standalone/.next/server/app/index.html +1 -1
  122. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  123. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  124. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  125. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  126. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  127. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  128. package/dist/web/standalone/.next/server/app-paths-manifest.json +10 -10
  129. package/dist/web/standalone/.next/server/chunks/6897.js +2 -2
  130. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  131. package/dist/web/standalone/.next/server/middleware-manifest.json +1 -1
  132. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  133. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  134. package/dist/web/standalone/server.js +1 -1
  135. package/dist/welcome-screen.js +6 -1
  136. package/dist/wizard.js +2 -0
  137. package/package.json +1 -1
  138. package/packages/daemon/package.json +2 -2
  139. package/packages/mcp-server/dist/remote-questions.d.ts +45 -0
  140. package/packages/mcp-server/dist/remote-questions.d.ts.map +1 -0
  141. package/packages/mcp-server/dist/remote-questions.js +732 -0
  142. package/packages/mcp-server/dist/remote-questions.js.map +1 -0
  143. package/packages/mcp-server/dist/server.d.ts +7 -0
  144. package/packages/mcp-server/dist/server.d.ts.map +1 -1
  145. package/packages/mcp-server/dist/server.js +70 -8
  146. package/packages/mcp-server/dist/server.js.map +1 -1
  147. package/packages/mcp-server/dist/session-manager.d.ts +14 -0
  148. package/packages/mcp-server/dist/session-manager.d.ts.map +1 -1
  149. package/packages/mcp-server/dist/session-manager.js +49 -1
  150. package/packages/mcp-server/dist/session-manager.js.map +1 -1
  151. package/packages/mcp-server/dist/workflow-tools.d.ts +1 -1
  152. package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
  153. package/packages/mcp-server/dist/workflow-tools.js +163 -25
  154. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  155. package/packages/mcp-server/package.json +4 -3
  156. package/packages/mcp-server/src/mcp-server.test.ts +67 -0
  157. package/packages/mcp-server/src/remote-questions.test.ts +294 -0
  158. package/packages/mcp-server/src/remote-questions.ts +916 -0
  159. package/packages/mcp-server/src/server.ts +89 -14
  160. package/packages/mcp-server/src/session-manager.ts +43 -1
  161. package/packages/mcp-server/src/workflow-tools.test.ts +146 -1
  162. package/packages/mcp-server/src/workflow-tools.ts +215 -43
  163. package/packages/mcp-server/tsconfig.test.json +19 -0
  164. package/packages/mcp-server/tsconfig.tsbuildinfo +1 -1
  165. package/packages/native/package.json +1 -1
  166. package/packages/pi-agent-core/dist/agent-loop.js +12 -0
  167. package/packages/pi-agent-core/dist/agent-loop.js.map +1 -1
  168. package/packages/pi-agent-core/dist/types.d.ts +30 -0
  169. package/packages/pi-agent-core/dist/types.d.ts.map +1 -1
  170. package/packages/pi-agent-core/dist/types.js.map +1 -1
  171. package/packages/pi-agent-core/package.json +1 -1
  172. package/packages/pi-agent-core/src/agent-loop.ts +14 -0
  173. package/packages/pi-agent-core/src/types.ts +34 -0
  174. package/packages/pi-agent-core/tsconfig.tsbuildinfo +1 -1
  175. package/packages/pi-ai/dist/models/custom.d.ts +38 -0
  176. package/packages/pi-ai/dist/models/custom.d.ts.map +1 -1
  177. package/packages/pi-ai/dist/models/custom.js +41 -0
  178. package/packages/pi-ai/dist/models/custom.js.map +1 -1
  179. package/packages/pi-ai/dist/providers/anthropic-auth.test.js +1 -1
  180. package/packages/pi-ai/dist/providers/anthropic-auth.test.js.map +1 -1
  181. package/packages/pi-ai/dist/providers/anthropic-bearer-auth.test.d.ts +2 -0
  182. package/packages/pi-ai/dist/providers/anthropic-bearer-auth.test.d.ts.map +1 -0
  183. package/packages/pi-ai/dist/providers/anthropic-bearer-auth.test.js +13 -0
  184. package/packages/pi-ai/dist/providers/anthropic-bearer-auth.test.js.map +1 -0
  185. package/packages/pi-ai/dist/providers/anthropic-shared.d.ts.map +1 -1
  186. package/packages/pi-ai/dist/providers/anthropic-shared.js +27 -4
  187. package/packages/pi-ai/dist/providers/anthropic-shared.js.map +1 -1
  188. package/packages/pi-ai/dist/providers/anthropic.d.ts.map +1 -1
  189. package/packages/pi-ai/dist/providers/anthropic.js +13 -4
  190. package/packages/pi-ai/dist/providers/anthropic.js.map +1 -1
  191. package/packages/pi-ai/dist/providers/minimax-tool-name.test.d.ts +2 -0
  192. package/packages/pi-ai/dist/providers/minimax-tool-name.test.d.ts.map +1 -0
  193. package/packages/pi-ai/dist/providers/minimax-tool-name.test.js +80 -0
  194. package/packages/pi-ai/dist/providers/minimax-tool-name.test.js.map +1 -0
  195. package/packages/pi-ai/dist/providers/openai-completions.d.ts.map +1 -1
  196. package/packages/pi-ai/dist/providers/openai-completions.js +60 -15
  197. package/packages/pi-ai/dist/providers/openai-completions.js.map +1 -1
  198. package/packages/pi-ai/dist/providers/simple-options.d.ts +10 -0
  199. package/packages/pi-ai/dist/providers/simple-options.d.ts.map +1 -1
  200. package/packages/pi-ai/dist/providers/simple-options.js +16 -1
  201. package/packages/pi-ai/dist/providers/simple-options.js.map +1 -1
  202. package/packages/pi-ai/dist/providers/think-tag-parser.d.ts +17 -0
  203. package/packages/pi-ai/dist/providers/think-tag-parser.d.ts.map +1 -0
  204. package/packages/pi-ai/dist/providers/think-tag-parser.js +75 -0
  205. package/packages/pi-ai/dist/providers/think-tag-parser.js.map +1 -0
  206. package/packages/pi-ai/dist/providers/think-tag-parser.test.d.ts +2 -0
  207. package/packages/pi-ai/dist/providers/think-tag-parser.test.d.ts.map +1 -0
  208. package/packages/pi-ai/dist/providers/think-tag-parser.test.js +41 -0
  209. package/packages/pi-ai/dist/providers/think-tag-parser.test.js.map +1 -0
  210. package/packages/pi-ai/dist/utils/oauth/github-copilot.d.ts.map +1 -1
  211. package/packages/pi-ai/dist/utils/oauth/github-copilot.js +12 -2
  212. package/packages/pi-ai/dist/utils/oauth/github-copilot.js.map +1 -1
  213. package/packages/pi-ai/dist/utils/oauth/github-copilot.test.js +164 -14
  214. package/packages/pi-ai/dist/utils/oauth/github-copilot.test.js.map +1 -1
  215. package/packages/pi-ai/dist/utils/oauth/google-antigravity.d.ts.map +1 -1
  216. package/packages/pi-ai/dist/utils/oauth/google-antigravity.js +15 -3
  217. package/packages/pi-ai/dist/utils/oauth/google-antigravity.js.map +1 -1
  218. package/packages/pi-ai/dist/utils/oauth/google-antigravity.test.d.ts +2 -0
  219. package/packages/pi-ai/dist/utils/oauth/google-antigravity.test.d.ts.map +1 -0
  220. package/packages/pi-ai/dist/utils/oauth/google-antigravity.test.js +67 -0
  221. package/packages/pi-ai/dist/utils/oauth/google-antigravity.test.js.map +1 -0
  222. package/packages/pi-ai/dist/utils/oauth/google-gemini-cli.d.ts.map +1 -1
  223. package/packages/pi-ai/dist/utils/oauth/google-gemini-cli.js +16 -3
  224. package/packages/pi-ai/dist/utils/oauth/google-gemini-cli.js.map +1 -1
  225. package/packages/pi-ai/dist/utils/oauth/google-gemini-cli.test.d.ts +2 -0
  226. package/packages/pi-ai/dist/utils/oauth/google-gemini-cli.test.d.ts.map +1 -0
  227. package/packages/pi-ai/dist/utils/oauth/google-gemini-cli.test.js +67 -0
  228. package/packages/pi-ai/dist/utils/oauth/google-gemini-cli.test.js.map +1 -0
  229. package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.d.ts +2 -0
  230. package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.d.ts.map +1 -0
  231. package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.js +289 -0
  232. package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.js.map +1 -0
  233. package/packages/pi-ai/package.json +1 -1
  234. package/packages/pi-ai/src/models/custom.ts +42 -0
  235. package/packages/pi-ai/src/providers/anthropic-auth.test.ts +1 -1
  236. package/packages/pi-ai/src/providers/anthropic-bearer-auth.test.ts +26 -0
  237. package/packages/pi-ai/src/providers/anthropic-shared.ts +26 -5
  238. package/packages/pi-ai/src/providers/anthropic.ts +15 -4
  239. package/packages/pi-ai/src/providers/minimax-tool-name.test.ts +98 -0
  240. package/packages/pi-ai/src/providers/openai-completions.ts +57 -16
  241. package/packages/pi-ai/src/providers/simple-options.ts +17 -1
  242. package/packages/pi-ai/src/providers/think-tag-parser.test.ts +44 -0
  243. package/packages/pi-ai/src/providers/think-tag-parser.ts +94 -0
  244. package/packages/pi-ai/src/utils/oauth/github-copilot.test.ts +200 -23
  245. package/packages/pi-ai/src/utils/oauth/github-copilot.ts +12 -2
  246. package/packages/pi-ai/src/utils/oauth/google-antigravity.test.ts +84 -0
  247. package/packages/pi-ai/src/utils/oauth/google-antigravity.ts +15 -5
  248. package/packages/pi-ai/src/utils/oauth/google-gemini-cli.test.ts +84 -0
  249. package/packages/pi-ai/src/utils/oauth/google-gemini-cli.ts +16 -5
  250. package/packages/pi-ai/src/utils/oauth/oauth-providers.test.ts +363 -0
  251. package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
  252. package/packages/pi-coding-agent/dist/core/agent-session-abort-order.test.js +3 -2
  253. package/packages/pi-coding-agent/dist/core/agent-session-abort-order.test.js.map +1 -1
  254. package/packages/pi-coding-agent/dist/core/agent-session.d.ts +2 -0
  255. package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
  256. package/packages/pi-coding-agent/dist/core/agent-session.js +32 -2
  257. package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
  258. package/packages/pi-coding-agent/dist/core/extensions/index.d.ts +1 -1
  259. package/packages/pi-coding-agent/dist/core/extensions/index.d.ts.map +1 -1
  260. package/packages/pi-coding-agent/dist/core/extensions/index.js.map +1 -1
  261. package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts.map +1 -1
  262. package/packages/pi-coding-agent/dist/core/extensions/loader.js +4 -0
  263. package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
  264. package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts +35 -2
  265. package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts.map +1 -1
  266. package/packages/pi-coding-agent/dist/core/extensions/runner.js +233 -0
  267. package/packages/pi-coding-agent/dist/core/extensions/runner.js.map +1 -1
  268. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts +205 -2
  269. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts.map +1 -1
  270. package/packages/pi-coding-agent/dist/core/extensions/types.js.map +1 -1
  271. package/packages/pi-coding-agent/dist/core/hooks-runner.d.ts +53 -0
  272. package/packages/pi-coding-agent/dist/core/hooks-runner.d.ts.map +1 -0
  273. package/packages/pi-coding-agent/dist/core/hooks-runner.js +337 -0
  274. package/packages/pi-coding-agent/dist/core/hooks-runner.js.map +1 -0
  275. package/packages/pi-coding-agent/dist/core/hooks-runner.test.d.ts +2 -0
  276. package/packages/pi-coding-agent/dist/core/hooks-runner.test.d.ts.map +1 -0
  277. package/packages/pi-coding-agent/dist/core/hooks-runner.test.js +234 -0
  278. package/packages/pi-coding-agent/dist/core/hooks-runner.test.js.map +1 -0
  279. package/packages/pi-coding-agent/dist/core/index.d.ts +1 -0
  280. package/packages/pi-coding-agent/dist/core/index.d.ts.map +1 -1
  281. package/packages/pi-coding-agent/dist/core/index.js +1 -0
  282. package/packages/pi-coding-agent/dist/core/index.js.map +1 -1
  283. package/packages/pi-coding-agent/dist/core/model-discovery.d.ts +3 -1
  284. package/packages/pi-coding-agent/dist/core/model-discovery.d.ts.map +1 -1
  285. package/packages/pi-coding-agent/dist/core/model-discovery.js +92 -12
  286. package/packages/pi-coding-agent/dist/core/model-discovery.js.map +1 -1
  287. package/packages/pi-coding-agent/dist/core/model-discovery.test.js +16 -1
  288. package/packages/pi-coding-agent/dist/core/model-discovery.test.js.map +1 -1
  289. package/packages/pi-coding-agent/dist/core/model-registry-auth-header.test.d.ts +2 -0
  290. package/packages/pi-coding-agent/dist/core/model-registry-auth-header.test.d.ts.map +1 -0
  291. package/packages/pi-coding-agent/dist/core/model-registry-auth-header.test.js +40 -0
  292. package/packages/pi-coding-agent/dist/core/model-registry-auth-header.test.js.map +1 -0
  293. package/packages/pi-coding-agent/dist/core/model-registry-custom-caps.test.d.ts +2 -0
  294. package/packages/pi-coding-agent/dist/core/model-registry-custom-caps.test.d.ts.map +1 -0
  295. package/packages/pi-coding-agent/dist/core/model-registry-custom-caps.test.js +203 -0
  296. package/packages/pi-coding-agent/dist/core/model-registry-custom-caps.test.js.map +1 -0
  297. package/packages/pi-coding-agent/dist/core/model-registry-discovery.test.js +61 -1
  298. package/packages/pi-coding-agent/dist/core/model-registry-discovery.test.js.map +1 -1
  299. package/packages/pi-coding-agent/dist/core/model-registry.d.ts +5 -0
  300. package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
  301. package/packages/pi-coding-agent/dist/core/model-registry.js +90 -10
  302. package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
  303. package/packages/pi-coding-agent/dist/core/redact-secrets.d.ts +2 -0
  304. package/packages/pi-coding-agent/dist/core/redact-secrets.d.ts.map +1 -0
  305. package/packages/pi-coding-agent/dist/core/redact-secrets.js +49 -0
  306. package/packages/pi-coding-agent/dist/core/redact-secrets.js.map +1 -0
  307. package/packages/pi-coding-agent/dist/core/redact-secrets.test.d.ts +2 -0
  308. package/packages/pi-coding-agent/dist/core/redact-secrets.test.d.ts.map +1 -0
  309. package/packages/pi-coding-agent/dist/core/redact-secrets.test.js +67 -0
  310. package/packages/pi-coding-agent/dist/core/redact-secrets.test.js.map +1 -0
  311. package/packages/pi-coding-agent/dist/core/session-manager.d.ts.map +1 -1
  312. package/packages/pi-coding-agent/dist/core/session-manager.js +10 -6
  313. package/packages/pi-coding-agent/dist/core/session-manager.js.map +1 -1
  314. package/packages/pi-coding-agent/dist/core/session-manager.test.js +45 -1
  315. package/packages/pi-coding-agent/dist/core/session-manager.test.js.map +1 -1
  316. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +55 -0
  317. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
  318. package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
  319. package/packages/pi-coding-agent/dist/index.d.ts +1 -1
  320. package/packages/pi-coding-agent/dist/index.d.ts.map +1 -1
  321. package/packages/pi-coding-agent/dist/index.js.map +1 -1
  322. package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.d.ts +1 -1
  323. package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.d.ts.map +1 -1
  324. package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.js +5 -4
  325. package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.js.map +1 -1
  326. package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.d.ts.map +1 -1
  327. package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.js +13 -7
  328. package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.js.map +1 -1
  329. package/packages/pi-coding-agent/dist/modes/interactive/components/skill-invocation-message.d.ts +7 -6
  330. package/packages/pi-coding-agent/dist/modes/interactive/components/skill-invocation-message.d.ts.map +1 -1
  331. package/packages/pi-coding-agent/dist/modes/interactive/components/skill-invocation-message.js +29 -21
  332. package/packages/pi-coding-agent/dist/modes/interactive/components/skill-invocation-message.js.map +1 -1
  333. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  334. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +13 -1
  335. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  336. package/packages/pi-coding-agent/package.json +1 -1
  337. package/packages/pi-coding-agent/src/core/agent-session-abort-order.test.ts +3 -2
  338. package/packages/pi-coding-agent/src/core/agent-session.ts +38 -2
  339. package/packages/pi-coding-agent/src/core/extensions/index.ts +16 -0
  340. package/packages/pi-coding-agent/src/core/extensions/loader.ts +5 -0
  341. package/packages/pi-coding-agent/src/core/extensions/runner.ts +351 -0
  342. package/packages/pi-coding-agent/src/core/extensions/types.ts +258 -0
  343. package/packages/pi-coding-agent/src/core/hooks-runner.test.ts +269 -0
  344. package/packages/pi-coding-agent/src/core/hooks-runner.ts +460 -0
  345. package/packages/pi-coding-agent/src/core/index.ts +10 -0
  346. package/packages/pi-coding-agent/src/core/model-discovery.test.ts +19 -0
  347. package/packages/pi-coding-agent/src/core/model-discovery.ts +99 -12
  348. package/packages/pi-coding-agent/src/core/model-registry-auth-header.test.ts +44 -0
  349. package/packages/pi-coding-agent/src/core/model-registry-custom-caps.test.ts +245 -0
  350. package/packages/pi-coding-agent/src/core/model-registry-discovery.test.ts +75 -0
  351. package/packages/pi-coding-agent/src/core/model-registry.ts +102 -10
  352. package/packages/pi-coding-agent/src/core/redact-secrets.test.ts +86 -0
  353. package/packages/pi-coding-agent/src/core/redact-secrets.ts +58 -0
  354. package/packages/pi-coding-agent/src/core/session-manager.test.ts +65 -1
  355. package/packages/pi-coding-agent/src/core/session-manager.ts +10 -6
  356. package/packages/pi-coding-agent/src/core/settings-manager.ts +57 -0
  357. package/packages/pi-coding-agent/src/index.ts +16 -0
  358. package/packages/pi-coding-agent/src/modes/interactive/components/chat-frame.ts +6 -6
  359. package/packages/pi-coding-agent/src/modes/interactive/components/provider-manager.ts +16 -7
  360. package/packages/pi-coding-agent/src/modes/interactive/components/skill-invocation-message.ts +36 -22
  361. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +13 -1
  362. package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
  363. package/packages/pi-tui/package.json +1 -1
  364. package/packages/rpc-client/package.json +1 -1
  365. package/pkg/package.json +1 -1
  366. package/scripts/link-workspace-packages.cjs +1 -0
  367. package/src/resources/agents/researcher.md +1 -1
  368. package/src/resources/extensions/claude-code-cli/readiness.ts +32 -8
  369. package/src/resources/extensions/claude-code-cli/stream-adapter.ts +78 -17
  370. package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +149 -5
  371. package/src/resources/extensions/gsd/auto/loop-deps.ts +14 -0
  372. package/src/resources/extensions/gsd/auto/loop.ts +9 -0
  373. package/src/resources/extensions/gsd/auto/phases.ts +131 -10
  374. package/src/resources/extensions/gsd/auto/run-unit.ts +40 -2
  375. package/src/resources/extensions/gsd/auto/session.ts +35 -2
  376. package/src/resources/extensions/gsd/auto-dispatch.ts +16 -3
  377. package/src/resources/extensions/gsd/auto-model-selection.ts +71 -15
  378. package/src/resources/extensions/gsd/auto-post-unit.ts +29 -3
  379. package/src/resources/extensions/gsd/auto-prompts.ts +28 -1
  380. package/src/resources/extensions/gsd/auto-recovery.ts +26 -1
  381. package/src/resources/extensions/gsd/auto-start.ts +60 -68
  382. package/src/resources/extensions/gsd/auto-verification.ts +33 -0
  383. package/src/resources/extensions/gsd/auto-worktree.ts +62 -63
  384. package/src/resources/extensions/gsd/auto.ts +73 -28
  385. package/src/resources/extensions/gsd/blocked-models.ts +98 -0
  386. package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +120 -1
  387. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +40 -9
  388. package/src/resources/extensions/gsd/bootstrap/exec-tools.ts +109 -0
  389. package/src/resources/extensions/gsd/bootstrap/memory-tools.ts +5 -0
  390. package/src/resources/extensions/gsd/bootstrap/register-extension.ts +15 -0
  391. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +54 -6
  392. package/src/resources/extensions/gsd/bootstrap/system-context.ts +89 -26
  393. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +35 -2
  394. package/src/resources/extensions/gsd/clean-root-preflight.ts +111 -0
  395. package/src/resources/extensions/gsd/commands-extract-learnings.ts +55 -90
  396. package/src/resources/extensions/gsd/commands-prefs-wizard.ts +898 -32
  397. package/src/resources/extensions/gsd/compaction-snapshot.ts +165 -0
  398. package/src/resources/extensions/gsd/complexity-classifier.ts +5 -3
  399. package/src/resources/extensions/gsd/db-writer.ts +88 -17
  400. package/src/resources/extensions/gsd/doctor-git-checks.ts +23 -27
  401. package/src/resources/extensions/gsd/doctor-providers.ts +59 -6
  402. package/src/resources/extensions/gsd/ecosystem/gsd-extension-api.ts +2 -0
  403. package/src/resources/extensions/gsd/error-classifier.ts +36 -3
  404. package/src/resources/extensions/gsd/exec-history.ts +153 -0
  405. package/src/resources/extensions/gsd/exec-sandbox.ts +326 -0
  406. package/src/resources/extensions/gsd/gitignore.ts +1 -1
  407. package/src/resources/extensions/gsd/gsd-db.ts +186 -23
  408. package/src/resources/extensions/gsd/guided-flow.ts +222 -1
  409. package/src/resources/extensions/gsd/health-widget.ts +3 -1
  410. package/src/resources/extensions/gsd/hook-emitter.ts +188 -0
  411. package/src/resources/extensions/gsd/init-wizard.ts +15 -1
  412. package/src/resources/extensions/gsd/journal.ts +2 -1
  413. package/src/resources/extensions/gsd/key-manager.ts +28 -0
  414. package/src/resources/extensions/gsd/memory-backfill.ts +140 -0
  415. package/src/resources/extensions/gsd/memory-store.ts +26 -0
  416. package/src/resources/extensions/gsd/model-router.ts +42 -1
  417. package/src/resources/extensions/gsd/pre-execution-checks.ts +46 -10
  418. package/src/resources/extensions/gsd/preferences-types.ts +46 -0
  419. package/src/resources/extensions/gsd/preferences-validation.ts +79 -0
  420. package/src/resources/extensions/gsd/preferences.ts +17 -17
  421. package/src/resources/extensions/gsd/prompt-loader.ts +30 -7
  422. package/src/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
  423. package/src/resources/extensions/gsd/prompts/complete-slice.md +2 -2
  424. package/src/resources/extensions/gsd/prompts/debug-diagnose.md +2 -0
  425. package/src/resources/extensions/gsd/prompts/discuss-headless.md +8 -0
  426. package/src/resources/extensions/gsd/prompts/discuss.md +29 -2
  427. package/src/resources/extensions/gsd/prompts/execute-task.md +3 -2
  428. package/src/resources/extensions/gsd/prompts/parallel-research-slices.md +5 -2
  429. package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -0
  430. package/src/resources/extensions/gsd/prompts/research-slice.md +1 -0
  431. package/src/resources/extensions/gsd/safety/evidence-collector.ts +119 -0
  432. package/src/resources/extensions/gsd/safety/file-change-validator.ts +17 -4
  433. package/src/resources/extensions/gsd/safety/safety-harness.ts +9 -0
  434. package/src/resources/extensions/gsd/state.ts +45 -4
  435. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +188 -2
  436. package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +95 -1
  437. package/src/resources/extensions/gsd/tests/auto-paused-session-validation.test.ts +12 -0
  438. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +49 -0
  439. package/src/resources/extensions/gsd/tests/auto-start-bootstrap-await-3420.test.ts +141 -0
  440. package/src/resources/extensions/gsd/tests/auto-start-model-capture.test.ts +33 -3
  441. package/src/resources/extensions/gsd/tests/auto-thinking-restore.test.ts +38 -0
  442. package/src/resources/extensions/gsd/tests/auto-wrapup-inflight-guard.test.ts +23 -0
  443. package/src/resources/extensions/gsd/tests/blocked-models.test.ts +98 -0
  444. package/src/resources/extensions/gsd/tests/bundled-skill-triggers.test.ts +54 -0
  445. package/src/resources/extensions/gsd/tests/clean-root-preflight.test.ts +186 -0
  446. package/src/resources/extensions/gsd/tests/commands-extract-learnings.test.ts +68 -66
  447. package/src/resources/extensions/gsd/tests/compaction-snapshot.test.ts +123 -0
  448. package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +61 -1
  449. package/src/resources/extensions/gsd/tests/complete-slice.test.ts +2 -2
  450. package/src/resources/extensions/gsd/tests/complete-task.test.ts +2 -2
  451. package/src/resources/extensions/gsd/tests/complexity-classifier.test.ts +3 -3
  452. package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +2 -0
  453. package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +42 -0
  454. package/src/resources/extensions/gsd/tests/derive-state-helpers.test.ts +8 -4
  455. package/src/resources/extensions/gsd/tests/doctor-providers.test.ts +148 -3
  456. package/src/resources/extensions/gsd/tests/double-merge-guard.test.ts +1 -1
  457. package/src/resources/extensions/gsd/tests/ensure-db-open.test.ts +306 -1
  458. package/src/resources/extensions/gsd/tests/escalation.test.ts +1 -1
  459. package/src/resources/extensions/gsd/tests/exec-history.test.ts +237 -0
  460. package/src/resources/extensions/gsd/tests/exec-sandbox.test.ts +210 -0
  461. package/src/resources/extensions/gsd/tests/file-change-validator.test.ts +58 -0
  462. package/src/resources/extensions/gsd/tests/flat-rate-routing-guard.test.ts +40 -9
  463. package/src/resources/extensions/gsd/tests/freeform-decisions.test.ts +62 -0
  464. package/src/resources/extensions/gsd/tests/gsd-db.test.ts +447 -1
  465. package/src/resources/extensions/gsd/tests/init-wizard.test.ts +27 -0
  466. package/src/resources/extensions/gsd/tests/integration/doctor-git-symlink-cwd.test.ts +11 -0
  467. package/src/resources/extensions/gsd/tests/integration/doctor-git.test.ts +78 -0
  468. package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +1 -0
  469. package/src/resources/extensions/gsd/tests/integration/gitignore-tracked-gsd.test.ts +1 -0
  470. package/src/resources/extensions/gsd/tests/integration/idle-recovery.test.ts +30 -0
  471. package/src/resources/extensions/gsd/tests/interactive-routing-bypass.test.ts +1 -1
  472. package/src/resources/extensions/gsd/tests/isolation-none-branch-guard.test.ts +1 -1
  473. package/src/resources/extensions/gsd/tests/issue-4540-regressions.test.ts +288 -0
  474. package/src/resources/extensions/gsd/tests/journal-integration.test.ts +37 -0
  475. package/src/resources/extensions/gsd/tests/key-manager.test.ts +9 -0
  476. package/src/resources/extensions/gsd/tests/load-memory-block.test.ts +36 -0
  477. package/src/resources/extensions/gsd/tests/md-importer.test.ts +1 -1
  478. package/src/resources/extensions/gsd/tests/memory-pressure-stuck-state.test.ts +12 -0
  479. package/src/resources/extensions/gsd/tests/memory-store.test.ts +2 -2
  480. package/src/resources/extensions/gsd/tests/parallel-research-dispatch.test.ts +19 -0
  481. package/src/resources/extensions/gsd/tests/plan-gate-failed-doctor-heal-hint.test.ts +37 -0
  482. package/src/resources/extensions/gsd/tests/pre-exec-backtick-strip.test.ts +14 -0
  483. package/src/resources/extensions/gsd/tests/pre-exec-gate-loop.test.ts +272 -0
  484. package/src/resources/extensions/gsd/tests/pre-execution-checks.test.ts +356 -0
  485. package/src/resources/extensions/gsd/tests/preferences.test.ts +110 -0
  486. package/src/resources/extensions/gsd/tests/prefs-wizard-coverage.test.ts +44 -0
  487. package/src/resources/extensions/gsd/tests/prompt-loader-extension-dir.test.ts +49 -0
  488. package/src/resources/extensions/gsd/tests/provider-errors.test.ts +103 -4
  489. package/src/resources/extensions/gsd/tests/ready-phrase-no-files-4573.test.ts +388 -0
  490. package/src/resources/extensions/gsd/tests/restore-tools-after-discuss.test.ts +9 -3
  491. package/src/resources/extensions/gsd/tests/resume-dispatch-worktree.test.ts +230 -0
  492. package/src/resources/extensions/gsd/tests/safety-harness-false-positives.test.ts +205 -0
  493. package/src/resources/extensions/gsd/tests/save-gate-result-render.test.ts +95 -0
  494. package/src/resources/extensions/gsd/tests/schema-v21-sequence.test.ts +413 -0
  495. package/src/resources/extensions/gsd/tests/session-start-footer.test.ts +32 -40
  496. package/src/resources/extensions/gsd/tests/stash-queued-context-files.test.ts +56 -0
  497. package/src/resources/extensions/gsd/tests/token-counter.test.ts +105 -1
  498. package/src/resources/extensions/gsd/tests/tool-compatibility.test.ts +107 -0
  499. package/src/resources/extensions/gsd/tests/uok-plan-v2-wiring.test.ts +23 -0
  500. package/src/resources/extensions/gsd/tests/validate-milestone.test.ts +9 -3
  501. package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +65 -2
  502. package/src/resources/extensions/gsd/tests/worktree-db.test.ts +35 -0
  503. package/src/resources/extensions/gsd/tests/worktree-journal-events.test.ts +6 -1
  504. package/src/resources/extensions/gsd/tests/worktree-resolver.test.ts +78 -5
  505. package/src/resources/extensions/gsd/tests/write-gate.test.ts +64 -0
  506. package/src/resources/extensions/gsd/tests/zombie-gsd-state.test.ts +3 -1
  507. package/src/resources/extensions/gsd/token-counter.ts +22 -5
  508. package/src/resources/extensions/gsd/tools/complete-milestone.ts +15 -9
  509. package/src/resources/extensions/gsd/tools/exec-search-tool.ts +81 -0
  510. package/src/resources/extensions/gsd/tools/exec-tool.ts +183 -0
  511. package/src/resources/extensions/gsd/tools/memory-tools.ts +31 -1
  512. package/src/resources/extensions/gsd/tools/resume-tool.ts +40 -0
  513. package/src/resources/extensions/gsd/uok/plan-v2.ts +26 -3
  514. package/src/resources/extensions/gsd/workflow-logger.ts +4 -1
  515. package/src/resources/extensions/gsd/workflow-mcp.ts +3 -0
  516. package/src/resources/extensions/gsd/workflow-templates/spike.md +6 -0
  517. package/src/resources/extensions/gsd/worktree-resolver.ts +54 -9
  518. package/src/resources/extensions/search-the-web/command-search-provider.ts +5 -4
  519. package/src/resources/extensions/search-the-web/native-search.ts +48 -12
  520. package/src/resources/skills/api-design/SKILL.md +190 -0
  521. package/src/resources/skills/create-mcp-server/SKILL.md +121 -0
  522. package/src/resources/skills/decompose-into-slices/SKILL.md +139 -0
  523. package/src/resources/skills/dependency-upgrade/SKILL.md +158 -0
  524. package/src/resources/skills/design-an-interface/SKILL.md +102 -0
  525. package/src/resources/skills/forensics/SKILL.md +153 -0
  526. package/src/resources/skills/grill-me/SKILL.md +93 -0
  527. package/src/resources/skills/handoff/SKILL.md +121 -0
  528. package/src/resources/skills/observability/SKILL.md +174 -0
  529. package/src/resources/skills/security-review/SKILL.md +181 -0
  530. package/src/resources/skills/spike-wrap-up/SKILL.md +138 -0
  531. package/src/resources/skills/tdd/SKILL.md +112 -0
  532. package/src/resources/skills/verify-before-complete/SKILL.md +98 -0
  533. package/src/resources/skills/write-docs/SKILL.md +82 -0
  534. package/src/resources/skills/write-milestone-brief/SKILL.md +135 -0
  535. /package/dist/web/standalone/.next/static/{ssX7BLv3Dw9Fb4CtrCGeR → pV-mPo7rYGb5JBC09C8GG}/_buildManifest.js +0 -0
  536. /package/dist/web/standalone/.next/static/{ssX7BLv3Dw9Fb4CtrCGeR → pV-mPo7rYGb5JBC09C8GG}/_ssgManifest.js +0 -0
@@ -11,7 +11,7 @@ import { appendEvent } from "./workflow-events.js";
11
11
  import { atomicWriteSync } from "./atomic-write.js";
12
12
  import { clearParseCache } from "./files.js";
13
13
  import { parseRoadmap as parseLegacyRoadmap, parsePlan as parseLegacyPlan } from "./parsers-legacy.js";
14
- import { isDbAvailable, getTask, getSlice, getSliceTasks, getPendingGates, updateTaskStatus, updateSliceStatus } from "./gsd-db.js";
14
+ import { isDbAvailable, getTask, getSlice, getSliceTasks, getPendingGates, updateTaskStatus, updateSliceStatus, insertSlice } from "./gsd-db.js";
15
15
  import { isValidationTerminal } from "./state.js";
16
16
  import { getErrorMessage } from "./error-utils.js";
17
17
  import { logWarning, logError } from "./workflow-logger.js";
@@ -220,12 +220,25 @@ export function verifyExpectedArtifact(unitType, unitId, base) {
220
220
  // RESEARCH file. Without this, resolveExpectedArtifactPath returns null and
221
221
  // the retry/escalation machinery silently re-dispatches forever.
222
222
  //
223
+ // #4068: Also treat a PARALLEL-BLOCKER placeholder as a terminal completion
224
+ // so that timeout-recovery can write the blocker, have verifyExpectedArtifact
225
+ // return true, and let the dispatch loop advance past this unit. Without
226
+ // this, the blocker is written but verification still returns false, the unit
227
+ // is never cleared from unitDispatchCount, and on the next iteration the
228
+ // dispatch rule (which correctly skips parallel-research when PARALLEL-BLOCKER
229
+ // exists) returns null — leaving the loop stuck re-deriving indefinitely.
230
+ //
223
231
  // NOTE: this predicate mirrors the dispatch rule at
224
232
  // auto-dispatch.ts parallel-research-slices — keep the two in sync.
225
233
  if (unitType === "research-slice" && unitId.endsWith("/parallel-research")) {
226
234
  const { milestone: mid } = parseUnitId(unitId);
227
235
  if (!mid)
228
236
  return false;
237
+ // #4068: PARALLEL-BLOCKER written by timeout-recovery is a terminal state.
238
+ const blockerPath = resolveExpectedArtifactPath(unitType, unitId, base);
239
+ if (blockerPath && existsSync(blockerPath)) {
240
+ return true;
241
+ }
229
242
  const roadmapFile = resolveMilestoneFile(base, mid, "ROADMAP");
230
243
  if (!roadmapFile || !existsSync(roadmapFile)) {
231
244
  logWarning("recovery", `verify-fail ${unitType} ${unitId}: roadmap missing`);
@@ -497,6 +510,24 @@ export function writeBlockerPlaceholder(unitType, unitId, base, reason) {
497
510
  logWarning("recovery", `appendEvent failed for slice recovery: ${e instanceof Error ? e.message : String(e)}`);
498
511
  }
499
512
  }
513
+ // Insert a placeholder complete slice so deriveState sees activeMilestoneSlices.length > 0
514
+ // and exits the pre-planning phase. Without this, activeMilestoneSlices stays empty
515
+ // after the blocker ROADMAP.md is written, causing deriveState to return phase:'pre-planning'
516
+ // indefinitely and re-dispatching plan-milestone in an infinite loop (#4378).
517
+ if (unitType === "plan-milestone" && mid) {
518
+ try {
519
+ insertSlice({ id: "S00-blocker", milestoneId: mid, title: "Blocker placeholder — planning failed", status: "complete", sequence: 0 });
520
+ }
521
+ catch (e) {
522
+ logWarning("recovery", `insertSlice placeholder failed for plan-milestone recovery: ${e instanceof Error ? e.message : String(e)}`);
523
+ }
524
+ try {
525
+ appendEvent(base, { cmd: "plan-milestone", params: { milestoneId: mid }, ts, actor: "system", trigger_reason: "blocker-placeholder-recovery" });
526
+ }
527
+ catch (e) {
528
+ logWarning("recovery", `appendEvent failed for plan-milestone recovery: ${e instanceof Error ? e.message : String(e)}`);
529
+ }
530
+ }
500
531
  }
501
532
  return diagnoseExpectedArtifact(unitType, unitId, base);
502
533
  }
@@ -30,8 +30,7 @@ import { initRoutingHistory } from "./routing-history.js";
30
30
  import { restoreHookState, resetHookState } from "./post-unit-hooks.js";
31
31
  import { resetProactiveHealing, setLevelChangeCallback } from "./doctor-proactive.js";
32
32
  import { snapshotSkills } from "./skill-discovery.js";
33
- import { isDbAvailable, getMilestone, openDatabase } from "./gsd-db.js";
34
- import { hideFooter } from "./auto-dashboard.js";
33
+ import { isDbAvailable, getMilestone, openDatabase, getDbStatus } from "./gsd-db.js";
35
34
  import { debugLog, enableDebug, isDebugEnabled, getDebugLogPath, } from "./debug-logger.js";
36
35
  import { logWarning, logError } from "./workflow-logger.js";
37
36
  import { existsSync, mkdirSync, readdirSync, rmSync, statSync, unlinkSync, } from "node:fs";
@@ -190,8 +189,8 @@ export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, reques
190
189
  //
191
190
  // Precedence:
192
191
  // 1) Explicit session override via /gsd model (this session)
193
- // 2) GSD model preferences from PREFERENCES.md (validated against live auth)
194
- // 3) Current session model from settings/session restore (if provider ready)
192
+ // 2) Current session model from settings/session restore (if provider ready)
193
+ // 3) GSD model preferences from PREFERENCES.md (validated against live auth)
195
194
  //
196
195
  // This preserves #3517 defaults while honoring explicit runtime model
197
196
  // selection for subsequent /gsd runs in the same session.
@@ -224,11 +223,14 @@ export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, reques
224
223
  }
225
224
  }
226
225
  const sessionModelReady = ctx.model && ctx.modelRegistry.isProviderRequestReady(ctx.model.provider);
226
+ const currentSessionModel = (sessionModelReady && ctx.model)
227
+ ? { provider: ctx.model.provider, id: ctx.model.id }
228
+ : null;
229
+ const startThinkingSnapshot = pi.getThinkingLevel();
227
230
  const startModelSnapshot = manualSessionOverride
231
+ ?? currentSessionModel
228
232
  ?? validatedPreferredModel
229
- ?? (sessionModelReady && ctx.model
230
- ? { provider: ctx.model.provider, id: ctx.model.id }
231
- : null);
233
+ ?? null;
232
234
  try {
233
235
  // Validate GSD_PROJECT_ID early so the user gets immediate feedback
234
236
  const customProjectId = process.env.GSD_PROJECT_ID;
@@ -244,7 +246,7 @@ export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, reques
244
246
  // the parent git root). See #2393 and related issue.
245
247
  const hasLocalGit = existsSync(join(base, ".git"));
246
248
  if (!hasLocalGit || isInheritedRepo(base)) {
247
- const mainBranch = loadEffectiveGSDPreferences()?.preferences?.git?.main_branch || "main";
249
+ const mainBranch = loadEffectiveGSDPreferences(base)?.preferences?.git?.main_branch || "main";
248
250
  nativeInit(base, mainBranch);
249
251
  }
250
252
  // Migrate legacy in-project .gsd/ to external state directory.
@@ -260,7 +262,7 @@ export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, reques
260
262
  // Ensure .gitignore has baseline patterns.
261
263
  // ensureGitignore checks for git-tracked .gsd/ files and skips the
262
264
  // ".gsd" pattern if the project intentionally tracks .gsd/ in git.
263
- const gitPrefs = loadEffectiveGSDPreferences()?.preferences?.git;
265
+ const gitPrefs = loadEffectiveGSDPreferences(base)?.preferences?.git;
264
266
  const manageGitignore = gitPrefs?.manage_gitignore;
265
267
  ensureGitignore(base, { manageGitignore });
266
268
  if (manageGitignore !== false)
@@ -286,7 +288,7 @@ export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, reques
286
288
  prepareWorkflowMcpForProject(ctx, base);
287
289
  }
288
290
  // Initialize GitServiceImpl
289
- s.gitService = new GitServiceImpl(s.basePath, loadEffectiveGSDPreferences()?.preferences?.git ?? {});
291
+ s.gitService = new GitServiceImpl(s.basePath, loadEffectiveGSDPreferences(base)?.preferences?.git ?? {});
290
292
  // ── Debug mode ──
291
293
  if (!isDebugEnabled() && process.env.GSD_DEBUG === "1") {
292
294
  enableDebug(base);
@@ -319,7 +321,7 @@ export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, reques
319
321
  // was lost due to session ending between completion and teardown.
320
322
  // Must run after DB open and before worktree entry.
321
323
  try {
322
- const auditResult = auditOrphanedMilestoneBranches(base, getIsolationMode());
324
+ const auditResult = auditOrphanedMilestoneBranches(base, getIsolationMode(base));
323
325
  for (const msg of auditResult.recovered) {
324
326
  ctx.ui.notify(`Orphan audit: ${msg}`, "info");
325
327
  }
@@ -337,7 +339,7 @@ export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, reques
337
339
  let state = await deriveState(base);
338
340
  // Stale worktree state recovery (#654)
339
341
  if (state.activeMilestone &&
340
- shouldUseWorktreeIsolation() &&
342
+ shouldUseWorktreeIsolation(base) &&
341
343
  !detectWorktreeName(base)) {
342
344
  const wtPath = getAutoWorktreePath(base, state.activeMilestone.id);
343
345
  if (wtPath) {
@@ -352,7 +354,7 @@ export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, reques
352
354
  let hasSurvivorBranch = false;
353
355
  if (state.activeMilestone &&
354
356
  (state.phase === "pre-planning" || state.phase === "complete") &&
355
- getIsolationMode() !== "none" &&
357
+ getIsolationMode(base) !== "none" &&
356
358
  !detectWorktreeName(base) &&
357
359
  !base.includes(`${pathSep}.gsd${pathSep}worktrees${pathSep}`)) {
358
360
  const milestoneBranch = `milestone/${state.activeMilestone.id}`;
@@ -413,29 +415,15 @@ export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, reques
413
415
  }
414
416
  const { showSmartEntry } = await import("./guided-flow.js");
415
417
  await showSmartEntry(ctx, pi, base, { step: requestedStepMode });
416
- invalidateAllCaches();
417
- const postState = await deriveState(base);
418
- if (postState.activeMilestone &&
419
- postState.phase !== "complete" &&
420
- postState.phase !== "pre-planning") {
421
- s.consecutiveCompleteBootstraps = 0; // Successfully advanced past "complete"
422
- state = postState;
423
- }
424
- else if (postState.activeMilestone &&
425
- postState.phase === "pre-planning") {
426
- const contextFile = resolveMilestoneFile(base, postState.activeMilestone.id, "CONTEXT");
427
- const hasContext = !!(contextFile && (await loadFile(contextFile)));
428
- if (hasContext) {
429
- state = postState;
430
- }
431
- else {
432
- ctx.ui.notify("Discussion completed but no milestone context was written. Run /gsd to try the discussion again, or /gsd auto after creating the milestone manually.", "warning");
433
- return releaseLockAndReturn();
434
- }
435
- }
436
- else {
437
- return releaseLockAndReturn();
438
- }
418
+ // showSmartEntry dispatches via pi.sendMessage() which is fire-and-forget:
419
+ // it queues the message and returns immediately, before the LLM turn runs.
420
+ // Checking postState here would always see the pre-dispatch state, causing
421
+ // the premature "Discussion completed but..." warning (#3420).
422
+ //
423
+ // checkAutoStartAfterDiscuss (in guided-flow.ts) already handles re-entering
424
+ // auto-mode by calling startAutoDetached after the discussion completes.
425
+ // Release the lock and let the async dispatch proceed.
426
+ return releaseLockAndReturn();
439
427
  }
440
428
  // Active milestone exists but has no roadmap
441
429
  if (state.phase === "pre-planning") {
@@ -445,15 +433,16 @@ export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, reques
445
433
  if (!hasContext) {
446
434
  const { showSmartEntry } = await import("./guided-flow.js");
447
435
  await showSmartEntry(ctx, pi, base, { step: requestedStepMode });
448
- invalidateAllCaches();
449
- const postState = await deriveState(base);
450
- if (postState.activeMilestone && postState.phase !== "pre-planning") {
451
- state = postState;
452
- }
453
- else {
454
- ctx.ui.notify("Discussion completed but milestone context is still missing. Run /gsd to try again.", "warning");
455
- return releaseLockAndReturn();
456
- }
436
+ // showSmartEntry dispatches via pi.sendMessage() which is fire-and-forget:
437
+ // it queues the message and returns immediately, before the LLM turn runs.
438
+ // Checking postState here fires before the LLM has had a turn, so the
439
+ // pre-planning phase would still appear unchanged and a premature warning
440
+ // would be emitted (#3420).
441
+ //
442
+ // checkAutoStartAfterDiscuss (in guided-flow.ts) already handles re-entering
443
+ // auto-mode by calling startAutoDetached after the discussion completes.
444
+ // Release the lock and let the async dispatch proceed.
445
+ return releaseLockAndReturn();
457
446
  }
458
447
  }
459
448
  // Active milestone has CONTEXT-DRAFT but no full context — needs discussion
@@ -506,13 +495,14 @@ export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, reques
506
495
  s.pendingQuickTasks = [];
507
496
  s.currentUnit = null;
508
497
  s.currentMilestoneId = state.activeMilestone?.id ?? null;
509
- s.originalModelId = ctx.model?.id ?? null;
510
- s.originalModelProvider = ctx.model?.provider ?? null;
498
+ s.originalModelId = startModelSnapshot?.id ?? ctx.model?.id ?? null;
499
+ s.originalModelProvider = startModelSnapshot?.provider ?? ctx.model?.provider ?? null;
500
+ s.originalThinkingLevel = startThinkingSnapshot ?? null;
511
501
  // Register SIGTERM handler
512
502
  registerSigtermHandler(base);
513
503
  // Capture integration branch
514
504
  if (s.currentMilestoneId) {
515
- if (getIsolationMode() !== "none") {
505
+ if (getIsolationMode(base) !== "none") {
516
506
  captureIntegrationBranch(base, s.currentMilestoneId);
517
507
  }
518
508
  setActiveMilestoneId(base, s.currentMilestoneId);
@@ -520,7 +510,7 @@ export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, reques
520
510
  // Guard against stale milestone branch when isolation:none (#3613).
521
511
  // A prior session with isolation:branch/worktree may have left HEAD on
522
512
  // milestone/<MID>. Auto-checkout back to the integration branch.
523
- if (getIsolationMode() === "none" && nativeIsRepo(base)) {
513
+ if (getIsolationMode(base) === "none" && nativeIsRepo(base)) {
524
514
  try {
525
515
  const currentBranch = nativeGetCurrentBranch(base);
526
516
  if (currentBranch.startsWith("milestone/")) {
@@ -548,7 +538,7 @@ export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, reques
548
538
  return symlinkRe.test(p);
549
539
  };
550
540
  if (s.currentMilestoneId &&
551
- getIsolationMode() !== "none" &&
541
+ getIsolationMode(base) !== "none" &&
552
542
  !detectWorktreeName(base) &&
553
543
  !isUnderGsdWorktrees(base)) {
554
544
  buildResolver().enterMilestone(s.currentMilestoneId, {
@@ -593,8 +583,21 @@ export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, reques
593
583
  // call returns "db_unavailable", triggering artifact-retry which
594
584
  // re-dispatches the same task — producing an infinite loop (#2419).
595
585
  if (existsSync(gsdDbPath) && !isDbAvailable()) {
596
- ctx.ui.notify("SQLite database exists but failed to open. Auto-mode cannot proceed without a working database provider. " +
597
- "Check for corrupt gsd.db or missing native SQLite bindings.", "error");
586
+ const dbStatus = getDbStatus();
587
+ const phaseHint = dbStatus.lastPhase === "open"
588
+ ? "The database file could not be opened"
589
+ : dbStatus.lastPhase === "initSchema"
590
+ ? "The database schema could not be initialized"
591
+ : dbStatus.lastPhase === "vacuum-recovery"
592
+ ? "Corruption recovery (VACUUM) failed"
593
+ : dbStatus.attempted
594
+ ? "The database could not be opened (phase unknown)"
595
+ : "The database provider could not be loaded";
596
+ const errorDetail = dbStatus.lastError ? ` (${dbStatus.lastError.message})` : "";
597
+ const providerHint = dbStatus.provider
598
+ ? ` Provider: ${dbStatus.provider}.`
599
+ : " No SQLite provider available — check Node >= 22 or install better-sqlite3.";
600
+ ctx.ui.notify(`SQLite database exists but failed to open: ${gsdDbPath}. ${phaseHint}${errorDetail}.${providerHint}`, "error");
598
601
  return releaseLockAndReturn();
599
602
  }
600
603
  // Initialize metrics
@@ -608,6 +611,7 @@ export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, reques
608
611
  id: startModelSnapshot.id,
609
612
  };
610
613
  }
614
+ s.autoModeStartThinkingLevel = startThinkingSnapshot ?? null;
611
615
  s.manualSessionModelOverride = manualSessionOverride ?? null;
612
616
  // Apply worker model override from parallel orchestrator (#worker-model).
613
617
  // GSD_WORKER_MODEL is injected by the coordinator when parallel.worker_model
@@ -628,13 +632,10 @@ export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, reques
628
632
  }
629
633
  }
630
634
  // Snapshot installed skills
631
- if (resolveSkillDiscoveryMode() !== "off") {
635
+ if (resolveSkillDiscoveryMode(base) !== "off") {
632
636
  snapshotSkills();
633
637
  }
634
638
  ctx.ui.setStatus("gsd-auto", s.stepMode ? "next" : "auto");
635
- ctx.ui.setFooter(hideFooter);
636
- // Hide gsd-health during AUTO — gsd-progress is the single source of truth
637
- // for last-commit / cost / health signal while auto is running.
638
639
  ctx.ui.setWidget("gsd-health", undefined);
639
640
  const modeLabel = s.stepMode ? "Step-mode" : "Auto-mode";
640
641
  const pendingCount = (state.registry ?? []).filter((m) => m.status !== "complete" && m.status !== "parked").length;
@@ -656,7 +657,7 @@ export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, reques
656
657
  // FlatRateContext used by selectAndApplyModel so user-declared
657
658
  // flat-rate providers and externalCli auto-detection are respected.
658
659
  const { isFlatRateProvider, buildFlatRateContext } = await import("./auto-model-selection.js");
659
- const bannerPrefs = loadEffectiveGSDPreferences()?.preferences;
660
+ const bannerPrefs = loadEffectiveGSDPreferences(base)?.preferences;
660
661
  const effectiveProvider = s.autoModeStartModel?.provider ?? ctx.model?.provider;
661
662
  const effectivelyEnabled = routingConfig.enabled
662
663
  && (routingConfig.allow_flat_rate_providers
@@ -396,6 +396,39 @@ export async function runPostUnitVerification(vctx, pauseAuto) {
396
396
  if (postExecBlockingFailure) {
397
397
  result.passed = false;
398
398
  }
399
+ // Emit Layer 2 verify_result event with the final, post-exec verdict so hooks
400
+ // see the authoritative pass/fail and the complete set of failures.
401
+ try {
402
+ const { emitVerifyResult } = await import("./hook-emitter.js");
403
+ const checkFailures = result.checks
404
+ .filter((c) => c.exitCode !== 0)
405
+ .map((c) => ({
406
+ kind: "gate",
407
+ message: `${c.command} exited ${c.exitCode}${c.stderr ? `: ${c.stderr.slice(0, 200)}` : ""}`,
408
+ }));
409
+ const runtimeFailures = (result.runtimeErrors ?? [])
410
+ .filter((e) => e.blocking)
411
+ .map((e) => ({
412
+ kind: "other",
413
+ message: `[${e.source}] ${e.message.slice(0, 200)}`,
414
+ }));
415
+ const postExecFailures = (postExecChecks ?? [])
416
+ .filter((c) => !c.passed)
417
+ .map((c) => ({
418
+ kind: "other",
419
+ message: `[${c.category}] ${c.target}: ${c.message}`,
420
+ }));
421
+ await emitVerifyResult({
422
+ passed: result.passed,
423
+ failures: [...checkFailures, ...runtimeFailures, ...postExecFailures],
424
+ unitType: s.currentUnit.type,
425
+ unitId: s.currentUnit.id,
426
+ cwd: s.basePath,
427
+ });
428
+ }
429
+ catch (hookErr) {
430
+ logWarning("engine", `verify_result hook emission failed: ${hookErr.message}`);
431
+ }
399
432
  // ── Auto-fix retry logic ──
400
433
  if (result.passed) {
401
434
  s.verificationRetryCount.delete(s.currentUnit.id);
@@ -180,14 +180,6 @@ function clearProjectRootStateFiles(basePath, milestoneId) {
180
180
  }
181
181
  }
182
182
  }
183
- function isProjectGsdSymlink(basePath) {
184
- try {
185
- return lstatSyncFn(join(basePath, ".gsd")).isSymbolicLink();
186
- }
187
- catch {
188
- return false;
189
- }
190
- }
191
183
  // ─── Build Artifact Auto-Resolve ─────────────────────────────────────────────
192
184
  /** Patterns for machine-generated build artifacts that can be safely
193
185
  * auto-resolved by accepting --theirs during merge. These files are
@@ -1429,50 +1421,15 @@ export function mergeMilestoneToMain(originalBasePath_, milestoneId, roadmapCont
1429
1421
  });
1430
1422
  }
1431
1423
  }
1432
- // 7. Stash any pre-existing dirty files so the squash merge is not
1433
- // blocked by unrelated local changes (#2151). clearProjectRootStateFiles
1434
- // only removes untracked .gsd/ files; tracked dirty files elsewhere (e.g.
1435
- // .planning/work-state.json with stash conflict markers) are invisible to
1436
- // that cleanup but will cause `git merge --squash` to reject.
1437
- let stashed = false;
1438
- try {
1439
- const status = execFileSync("git", ["status", "--porcelain"], {
1440
- cwd: originalBasePath_,
1441
- stdio: ["ignore", "pipe", "pipe"],
1442
- encoding: "utf-8",
1443
- }).trim();
1444
- if (status) {
1445
- // Use --include-untracked to stash untracked files that would block
1446
- // the squash merge, but EXCLUDE .gsd/milestones/ (#2505).
1447
- // --include-untracked without exclusion sweeps queued milestone
1448
- // CONTEXT files into the stash. If stash pop later fails, those files
1449
- // are permanently trapped in the stash entry and lost on the next
1450
- // stash push or drop.
1451
- //
1452
- // When `.gsd` itself is a symlink, Git rejects pathspecs below it
1453
- // ("beyond a symbolic link"). In that layout, exclude the whole symlink
1454
- // and keep stashing real project files that could block the merge.
1455
- const stashPathspecs = isProjectGsdSymlink(originalBasePath_)
1456
- ? [".", ":(exclude).gsd"]
1457
- : [":(exclude).gsd/milestones"];
1458
- execFileSync("git", [
1459
- "stash", "push", "--include-untracked",
1460
- "-m", `gsd: pre-merge stash for ${milestoneId}`,
1461
- "--", ...stashPathspecs,
1462
- ], { cwd: originalBasePath_, stdio: ["ignore", "pipe", "pipe"], encoding: "utf-8" });
1463
- stashed = true;
1464
- }
1465
- }
1466
- catch (err) {
1467
- // Stash failure is non-fatal — proceed without stash and let the merge
1468
- // report the dirty tree if it fails.
1469
- logWarning("worktree", `git stash failed: ${err instanceof Error ? err.message : String(err)}`);
1470
- }
1471
- // 7a. Shelter queued milestone directories before the squash merge (#2505).
1424
+ // 7. Shelter queued milestone directories before the squash merge (#2505).
1472
1425
  // The milestone branch may contain copies of queued milestone dirs (via
1473
1426
  // copyPlanningArtifacts), so `git merge --squash` rejects when those same
1474
1427
  // files exist as untracked in the working tree. Temporarily move them to
1475
1428
  // a backup location, then restore after the merge+commit.
1429
+ //
1430
+ // MUST run BEFORE the pre-merge stash (step 7a) so `--include-untracked`
1431
+ // does not sweep queued CONTEXT files into the stash. If stash pop later
1432
+ // fails, files trapped inside the stash are permanently lost (#2505).
1476
1433
  const milestonesDir = join(gsdRoot(originalBasePath_), "milestones");
1477
1434
  const shelterDir = join(gsdRoot(originalBasePath_), ".milestone-shelter");
1478
1435
  const shelteredDirs = [];
@@ -1526,6 +1483,31 @@ export function mergeMilestoneToMain(originalBasePath_, milestoneId, roadmapCont
1526
1483
  // Non-fatal — proceed with merge; untracked files may block it
1527
1484
  logWarning("worktree", `milestone shelter operation failed: ${err instanceof Error ? err.message : String(err)}`);
1528
1485
  }
1486
+ // 7a. Stash pre-existing dirty files so the squash merge is not blocked by
1487
+ // unrelated local changes (#2151). Includes untracked files to handle
1488
+ // locally-added files that conflict with tracked files on the milestone
1489
+ // branch. Passing NO pathspec lets git skip gitignored paths silently;
1490
+ // adding an explicit pathspec trips a `git add`-style fatal on ignored
1491
+ // entries (e.g. a gitignored `.gsd` symlink under ADR-002) (#4573).
1492
+ // Queued CONTEXT files under `.gsd/milestones/*` are already sheltered
1493
+ // in step 7 above, so they won't be swept into the stash.
1494
+ let stashed = false;
1495
+ try {
1496
+ const status = execFileSync("git", ["status", "--porcelain"], {
1497
+ cwd: originalBasePath_,
1498
+ stdio: ["ignore", "pipe", "pipe"],
1499
+ encoding: "utf-8",
1500
+ }).trim();
1501
+ if (status) {
1502
+ execFileSync("git", ["stash", "push", "--include-untracked", "-m", `gsd: pre-merge stash for ${milestoneId}`], { cwd: originalBasePath_, stdio: ["ignore", "pipe", "pipe"], encoding: "utf-8" });
1503
+ stashed = true;
1504
+ }
1505
+ }
1506
+ catch (err) {
1507
+ // Stash failure is non-fatal — proceed without stash and let the merge
1508
+ // report the dirty tree if it fails.
1509
+ logWarning("worktree", `git stash failed: ${err instanceof Error ? err.message : String(err)}`);
1510
+ }
1529
1511
  // 7b. Clean up stale merge state before attempting squash merge (#2912).
1530
1512
  // A leftover MERGE_HEAD (from a previous failed merge, libgit2 native path,
1531
1513
  // or interrupted operation) causes `git merge --squash` to refuse with
@@ -1761,16 +1743,32 @@ export function mergeMilestoneToMain(originalBasePath_, milestoneId, roadmapCont
1761
1743
  // When a milestone only produced .gsd/ metadata (summaries, roadmaps) but no
1762
1744
  // real code, the user sees "milestone complete" but nothing changed in their
1763
1745
  // codebase. Surface this so the caller can warn the user.
1746
+ //
1747
+ // Bug #4385 fix: use `git diff-tree --root` instead of `git diff HEAD~1 HEAD`.
1748
+ // `HEAD~1` does not exist on initial commits and is unreliable on shallow clones
1749
+ // and merge commits. `diff-tree --root` handles all three cases correctly.
1750
+ // The empty-tree hash (4b825dc…) is the universal fallback for refs that don't exist.
1751
+ const GIT_EMPTY_TREE = "4b825dc642cb6eb9a060e54bf8d69288fbee4904";
1764
1752
  let codeFilesChanged = false;
1765
1753
  if (!nothingToCommit) {
1766
1754
  try {
1767
- const mergedFiles = nativeDiffNumstat(originalBasePath_, "HEAD~1", "HEAD");
1768
- codeFilesChanged = mergedFiles.some((entry) => !entry.path.startsWith(".gsd/"));
1755
+ const diffTreeOutput = execFileSync("git", ["diff-tree", "--root", "--no-commit-id", "-r", "--name-only", "HEAD"], { cwd: originalBasePath_, stdio: ["ignore", "pipe", "pipe"], encoding: "utf-8" }).trim();
1756
+ const mergedFiles = diffTreeOutput ? diffTreeOutput.split("\n").filter(Boolean) : [];
1757
+ codeFilesChanged = mergedFiles.some((f) => !f.startsWith(".gsd/"));
1769
1758
  }
1770
1759
  catch (e) {
1771
- // If HEAD~1 doesn't exist (first commit), assume code was changed
1772
- logWarning("worktree", `diff numstat failed (assuming code changed): ${e.message}`);
1773
- codeFilesChanged = true;
1760
+ // diff-tree failed (e.g. unborn HEAD in a brand-new repo) fall back to
1761
+ // comparing against the empty tree so initial-commit repos still report changes.
1762
+ try {
1763
+ const fallbackOutput = execFileSync("git", ["diff", "--name-only", GIT_EMPTY_TREE, "HEAD"], { cwd: originalBasePath_, stdio: ["ignore", "pipe", "pipe"], encoding: "utf-8" }).trim();
1764
+ const fallbackFiles = fallbackOutput ? fallbackOutput.split("\n").filter(Boolean) : [];
1765
+ codeFilesChanged = fallbackFiles.some((f) => !f.startsWith(".gsd/"));
1766
+ }
1767
+ catch {
1768
+ // Truly unable to determine — assume code was changed to avoid silent data loss
1769
+ logWarning("worktree", `diff-tree and empty-tree fallback both failed (assuming code changed): ${e.message}`);
1770
+ codeFilesChanged = true;
1771
+ }
1774
1772
  }
1775
1773
  }
1776
1774
  // 10. Auto-push if enabled