gsd-pi 2.76.0-dev.4100bd590 → 2.76.0-dev.479ad0e78

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 (362) hide show
  1. package/dist/claude-cli-check.js +32 -3
  2. package/dist/mcp-server.d.ts +7 -0
  3. package/dist/mcp-server.js +35 -1
  4. package/dist/onboarding.js +45 -0
  5. package/dist/resource-loader.d.ts +1 -1
  6. package/dist/resource-loader.js +2 -8
  7. package/dist/resources/extensions/claude-code-cli/readiness.js +4 -3
  8. package/dist/resources/extensions/claude-code-cli/stream-adapter.js +77 -17
  9. package/dist/resources/extensions/gsd/auto/loop.js +9 -0
  10. package/dist/resources/extensions/gsd/auto/phases.js +58 -5
  11. package/dist/resources/extensions/gsd/auto/run-unit.js +38 -2
  12. package/dist/resources/extensions/gsd/auto/session.js +22 -1
  13. package/dist/resources/extensions/gsd/auto-dispatch.js +16 -3
  14. package/dist/resources/extensions/gsd/auto-model-selection.js +14 -3
  15. package/dist/resources/extensions/gsd/auto-post-unit.js +25 -2
  16. package/dist/resources/extensions/gsd/auto-prompts.js +14 -0
  17. package/dist/resources/extensions/gsd/auto-recovery.js +32 -1
  18. package/dist/resources/extensions/gsd/auto-start.js +58 -57
  19. package/dist/resources/extensions/gsd/auto-worktree.js +51 -53
  20. package/dist/resources/extensions/gsd/auto.js +70 -28
  21. package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +17 -1
  22. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +39 -9
  23. package/dist/resources/extensions/gsd/bootstrap/exec-tools.js +93 -0
  24. package/dist/resources/extensions/gsd/bootstrap/register-extension.js +2 -0
  25. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +52 -6
  26. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +34 -2
  27. package/dist/resources/extensions/gsd/clean-root-preflight.js +93 -0
  28. package/dist/resources/extensions/gsd/commands-prefs-wizard.js +968 -23
  29. package/dist/resources/extensions/gsd/compaction-snapshot.js +121 -0
  30. package/dist/resources/extensions/gsd/complexity-classifier.js +5 -3
  31. package/dist/resources/extensions/gsd/error-classifier.js +10 -3
  32. package/dist/resources/extensions/gsd/exec-history.js +120 -0
  33. package/dist/resources/extensions/gsd/exec-sandbox.js +258 -0
  34. package/dist/resources/extensions/gsd/gitignore.js +1 -0
  35. package/dist/resources/extensions/gsd/gsd-db.js +149 -31
  36. package/dist/resources/extensions/gsd/guided-flow.js +190 -1
  37. package/dist/resources/extensions/gsd/health-widget.js +4 -1
  38. package/dist/resources/extensions/gsd/init-wizard.js +15 -1
  39. package/dist/resources/extensions/gsd/key-manager.js +28 -0
  40. package/dist/resources/extensions/gsd/model-router.js +36 -3
  41. package/dist/resources/extensions/gsd/pre-execution-checks.js +44 -9
  42. package/dist/resources/extensions/gsd/preferences-types.js +9 -0
  43. package/dist/resources/extensions/gsd/preferences-validation.js +83 -0
  44. package/dist/resources/extensions/gsd/preferences.js +17 -17
  45. package/dist/resources/extensions/gsd/prompt-loader.js +22 -7
  46. package/dist/resources/extensions/gsd/prompts/discuss-headless.md +8 -0
  47. package/dist/resources/extensions/gsd/prompts/discuss.md +29 -2
  48. package/dist/resources/extensions/gsd/prompts/parallel-research-slices.md +5 -2
  49. package/dist/resources/extensions/gsd/safety/evidence-collector.js +96 -0
  50. package/dist/resources/extensions/gsd/safety/file-change-validator.js +13 -5
  51. package/dist/resources/extensions/gsd/safety/safety-harness.js +5 -1
  52. package/dist/resources/extensions/gsd/token-counter.js +22 -5
  53. package/dist/resources/extensions/gsd/tools/complete-milestone.js +16 -10
  54. package/dist/resources/extensions/gsd/tools/exec-search-tool.js +59 -0
  55. package/dist/resources/extensions/gsd/tools/exec-tool.js +126 -0
  56. package/dist/resources/extensions/gsd/tools/resume-tool.js +23 -0
  57. package/dist/resources/extensions/gsd/uok/plan-v2.js +20 -3
  58. package/dist/resources/extensions/gsd/workflow-mcp.js +3 -0
  59. package/dist/resources/extensions/gsd/worktree-resolver.js +50 -10
  60. package/dist/resources/skills/verify-before-complete/SKILL.md +2 -1
  61. package/dist/resources/skills/write-docs/SKILL.md +2 -1
  62. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  63. package/dist/web/standalone/.next/BUILD_ID +1 -1
  64. package/dist/web/standalone/.next/app-path-routes-manifest.json +17 -17
  65. package/dist/web/standalone/.next/build-manifest.json +2 -2
  66. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  67. package/dist/web/standalone/.next/required-server-files.json +1 -1
  68. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  69. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  70. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  71. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  72. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  73. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  74. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  75. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  76. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  77. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  78. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  79. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  80. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  81. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  82. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  83. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  84. package/dist/web/standalone/.next/server/app/index.html +1 -1
  85. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  86. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  87. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  88. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  89. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  90. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  91. package/dist/web/standalone/.next/server/app-paths-manifest.json +17 -17
  92. package/dist/web/standalone/.next/server/chunks/6897.js +2 -2
  93. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  94. package/dist/web/standalone/.next/server/middleware-manifest.json +5 -5
  95. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  96. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  97. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  98. package/dist/web/standalone/server.js +1 -1
  99. package/dist/welcome-screen.js +6 -1
  100. package/dist/wizard.js +2 -0
  101. package/package.json +1 -1
  102. package/packages/mcp-server/dist/remote-questions.d.ts +45 -0
  103. package/packages/mcp-server/dist/remote-questions.d.ts.map +1 -0
  104. package/packages/mcp-server/dist/remote-questions.js +732 -0
  105. package/packages/mcp-server/dist/remote-questions.js.map +1 -0
  106. package/packages/mcp-server/dist/server.d.ts +7 -0
  107. package/packages/mcp-server/dist/server.d.ts.map +1 -1
  108. package/packages/mcp-server/dist/server.js +70 -8
  109. package/packages/mcp-server/dist/server.js.map +1 -1
  110. package/packages/mcp-server/dist/session-manager.d.ts +14 -0
  111. package/packages/mcp-server/dist/session-manager.d.ts.map +1 -1
  112. package/packages/mcp-server/dist/session-manager.js +49 -1
  113. package/packages/mcp-server/dist/session-manager.js.map +1 -1
  114. package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
  115. package/packages/mcp-server/dist/workflow-tools.js +64 -25
  116. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  117. package/packages/mcp-server/package.json +2 -1
  118. package/packages/mcp-server/src/mcp-server.test.ts +67 -0
  119. package/packages/mcp-server/src/remote-questions.test.ts +294 -0
  120. package/packages/mcp-server/src/remote-questions.ts +916 -0
  121. package/packages/mcp-server/src/server.ts +89 -14
  122. package/packages/mcp-server/src/session-manager.ts +43 -1
  123. package/packages/mcp-server/src/workflow-tools.test.ts +146 -1
  124. package/packages/mcp-server/src/workflow-tools.ts +84 -43
  125. package/packages/mcp-server/tsconfig.test.json +19 -0
  126. package/packages/mcp-server/tsconfig.tsbuildinfo +1 -1
  127. package/packages/pi-ai/dist/models/custom.d.ts +38 -0
  128. package/packages/pi-ai/dist/models/custom.d.ts.map +1 -1
  129. package/packages/pi-ai/dist/models/custom.js +41 -0
  130. package/packages/pi-ai/dist/models/custom.js.map +1 -1
  131. package/packages/pi-ai/dist/providers/anthropic-auth.test.js +1 -1
  132. package/packages/pi-ai/dist/providers/anthropic-auth.test.js.map +1 -1
  133. package/packages/pi-ai/dist/providers/anthropic-shared.d.ts.map +1 -1
  134. package/packages/pi-ai/dist/providers/anthropic-shared.js +27 -4
  135. package/packages/pi-ai/dist/providers/anthropic-shared.js.map +1 -1
  136. package/packages/pi-ai/dist/providers/anthropic.d.ts.map +1 -1
  137. package/packages/pi-ai/dist/providers/anthropic.js +8 -3
  138. package/packages/pi-ai/dist/providers/anthropic.js.map +1 -1
  139. package/packages/pi-ai/dist/providers/minimax-tool-name.test.d.ts +2 -0
  140. package/packages/pi-ai/dist/providers/minimax-tool-name.test.d.ts.map +1 -0
  141. package/packages/pi-ai/dist/providers/minimax-tool-name.test.js +80 -0
  142. package/packages/pi-ai/dist/providers/minimax-tool-name.test.js.map +1 -0
  143. package/packages/pi-ai/dist/providers/openai-completions.d.ts.map +1 -1
  144. package/packages/pi-ai/dist/providers/openai-completions.js +60 -15
  145. package/packages/pi-ai/dist/providers/openai-completions.js.map +1 -1
  146. package/packages/pi-ai/dist/providers/simple-options.d.ts +10 -0
  147. package/packages/pi-ai/dist/providers/simple-options.d.ts.map +1 -1
  148. package/packages/pi-ai/dist/providers/simple-options.js +16 -1
  149. package/packages/pi-ai/dist/providers/simple-options.js.map +1 -1
  150. package/packages/pi-ai/dist/providers/think-tag-parser.d.ts +17 -0
  151. package/packages/pi-ai/dist/providers/think-tag-parser.d.ts.map +1 -0
  152. package/packages/pi-ai/dist/providers/think-tag-parser.js +75 -0
  153. package/packages/pi-ai/dist/providers/think-tag-parser.js.map +1 -0
  154. package/packages/pi-ai/dist/providers/think-tag-parser.test.d.ts +2 -0
  155. package/packages/pi-ai/dist/providers/think-tag-parser.test.d.ts.map +1 -0
  156. package/packages/pi-ai/dist/providers/think-tag-parser.test.js +41 -0
  157. package/packages/pi-ai/dist/providers/think-tag-parser.test.js.map +1 -0
  158. package/packages/pi-ai/src/models/custom.ts +42 -0
  159. package/packages/pi-ai/src/providers/anthropic-auth.test.ts +1 -1
  160. package/packages/pi-ai/src/providers/anthropic-shared.ts +26 -5
  161. package/packages/pi-ai/src/providers/anthropic.ts +9 -3
  162. package/packages/pi-ai/src/providers/minimax-tool-name.test.ts +98 -0
  163. package/packages/pi-ai/src/providers/openai-completions.ts +57 -16
  164. package/packages/pi-ai/src/providers/simple-options.ts +17 -1
  165. package/packages/pi-ai/src/providers/think-tag-parser.test.ts +44 -0
  166. package/packages/pi-ai/src/providers/think-tag-parser.ts +94 -0
  167. package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
  168. package/packages/pi-coding-agent/dist/core/agent-session-abort-order.test.js +3 -2
  169. package/packages/pi-coding-agent/dist/core/agent-session-abort-order.test.js.map +1 -1
  170. package/packages/pi-coding-agent/dist/core/agent-session.d.ts +2 -0
  171. package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
  172. package/packages/pi-coding-agent/dist/core/agent-session.js +7 -0
  173. package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
  174. package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts +2 -0
  175. package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts.map +1 -1
  176. package/packages/pi-coding-agent/dist/core/extensions/runner.js.map +1 -1
  177. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts +7 -0
  178. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts.map +1 -1
  179. package/packages/pi-coding-agent/dist/core/extensions/types.js.map +1 -1
  180. package/packages/pi-coding-agent/dist/core/model-discovery.d.ts +3 -1
  181. package/packages/pi-coding-agent/dist/core/model-discovery.d.ts.map +1 -1
  182. package/packages/pi-coding-agent/dist/core/model-discovery.js +92 -12
  183. package/packages/pi-coding-agent/dist/core/model-discovery.js.map +1 -1
  184. package/packages/pi-coding-agent/dist/core/model-discovery.test.js +16 -1
  185. package/packages/pi-coding-agent/dist/core/model-discovery.test.js.map +1 -1
  186. package/packages/pi-coding-agent/dist/core/model-registry-custom-caps.test.d.ts +2 -0
  187. package/packages/pi-coding-agent/dist/core/model-registry-custom-caps.test.d.ts.map +1 -0
  188. package/packages/pi-coding-agent/dist/core/model-registry-custom-caps.test.js +203 -0
  189. package/packages/pi-coding-agent/dist/core/model-registry-custom-caps.test.js.map +1 -0
  190. package/packages/pi-coding-agent/dist/core/model-registry-discovery.test.js +61 -1
  191. package/packages/pi-coding-agent/dist/core/model-registry-discovery.test.js.map +1 -1
  192. package/packages/pi-coding-agent/dist/core/model-registry.d.ts +5 -0
  193. package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
  194. package/packages/pi-coding-agent/dist/core/model-registry.js +90 -10
  195. package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
  196. package/packages/pi-coding-agent/dist/core/redact-secrets.d.ts +2 -0
  197. package/packages/pi-coding-agent/dist/core/redact-secrets.d.ts.map +1 -0
  198. package/packages/pi-coding-agent/dist/core/redact-secrets.js +49 -0
  199. package/packages/pi-coding-agent/dist/core/redact-secrets.js.map +1 -0
  200. package/packages/pi-coding-agent/dist/core/redact-secrets.test.d.ts +2 -0
  201. package/packages/pi-coding-agent/dist/core/redact-secrets.test.d.ts.map +1 -0
  202. package/packages/pi-coding-agent/dist/core/redact-secrets.test.js +67 -0
  203. package/packages/pi-coding-agent/dist/core/redact-secrets.test.js.map +1 -0
  204. package/packages/pi-coding-agent/dist/core/session-manager.d.ts.map +1 -1
  205. package/packages/pi-coding-agent/dist/core/session-manager.js +10 -6
  206. package/packages/pi-coding-agent/dist/core/session-manager.js.map +1 -1
  207. package/packages/pi-coding-agent/dist/core/session-manager.test.js +45 -1
  208. package/packages/pi-coding-agent/dist/core/session-manager.test.js.map +1 -1
  209. package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.d.ts +1 -1
  210. package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.d.ts.map +1 -1
  211. package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.js +5 -4
  212. package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.js.map +1 -1
  213. package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.d.ts.map +1 -1
  214. package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.js +13 -7
  215. package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.js.map +1 -1
  216. package/packages/pi-coding-agent/dist/modes/interactive/components/skill-invocation-message.d.ts +7 -6
  217. package/packages/pi-coding-agent/dist/modes/interactive/components/skill-invocation-message.d.ts.map +1 -1
  218. package/packages/pi-coding-agent/dist/modes/interactive/components/skill-invocation-message.js +29 -21
  219. package/packages/pi-coding-agent/dist/modes/interactive/components/skill-invocation-message.js.map +1 -1
  220. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  221. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +13 -1
  222. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  223. package/packages/pi-coding-agent/src/core/agent-session-abort-order.test.ts +3 -2
  224. package/packages/pi-coding-agent/src/core/agent-session.ts +11 -0
  225. package/packages/pi-coding-agent/src/core/extensions/runner.ts +2 -0
  226. package/packages/pi-coding-agent/src/core/extensions/types.ts +7 -0
  227. package/packages/pi-coding-agent/src/core/model-discovery.test.ts +19 -0
  228. package/packages/pi-coding-agent/src/core/model-discovery.ts +99 -12
  229. package/packages/pi-coding-agent/src/core/model-registry-custom-caps.test.ts +245 -0
  230. package/packages/pi-coding-agent/src/core/model-registry-discovery.test.ts +75 -0
  231. package/packages/pi-coding-agent/src/core/model-registry.ts +102 -10
  232. package/packages/pi-coding-agent/src/core/redact-secrets.test.ts +86 -0
  233. package/packages/pi-coding-agent/src/core/redact-secrets.ts +58 -0
  234. package/packages/pi-coding-agent/src/core/session-manager.test.ts +65 -1
  235. package/packages/pi-coding-agent/src/core/session-manager.ts +10 -6
  236. package/packages/pi-coding-agent/src/modes/interactive/components/chat-frame.ts +6 -6
  237. package/packages/pi-coding-agent/src/modes/interactive/components/provider-manager.ts +16 -7
  238. package/packages/pi-coding-agent/src/modes/interactive/components/skill-invocation-message.ts +36 -22
  239. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +13 -1
  240. package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
  241. package/scripts/link-workspace-packages.cjs +1 -0
  242. package/src/resources/extensions/claude-code-cli/readiness.ts +4 -3
  243. package/src/resources/extensions/claude-code-cli/stream-adapter.ts +78 -17
  244. package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +149 -5
  245. package/src/resources/extensions/gsd/auto/loop-deps.ts +14 -0
  246. package/src/resources/extensions/gsd/auto/loop.ts +9 -0
  247. package/src/resources/extensions/gsd/auto/phases.ts +82 -4
  248. package/src/resources/extensions/gsd/auto/run-unit.ts +40 -2
  249. package/src/resources/extensions/gsd/auto/session.ts +35 -2
  250. package/src/resources/extensions/gsd/auto-dispatch.ts +16 -3
  251. package/src/resources/extensions/gsd/auto-model-selection.ts +17 -2
  252. package/src/resources/extensions/gsd/auto-post-unit.ts +29 -3
  253. package/src/resources/extensions/gsd/auto-prompts.ts +28 -1
  254. package/src/resources/extensions/gsd/auto-recovery.ts +26 -1
  255. package/src/resources/extensions/gsd/auto-start.ts +60 -68
  256. package/src/resources/extensions/gsd/auto-worktree.ts +62 -63
  257. package/src/resources/extensions/gsd/auto.ts +73 -28
  258. package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +23 -1
  259. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +40 -9
  260. package/src/resources/extensions/gsd/bootstrap/exec-tools.ts +109 -0
  261. package/src/resources/extensions/gsd/bootstrap/register-extension.ts +2 -0
  262. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +54 -6
  263. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +35 -2
  264. package/src/resources/extensions/gsd/clean-root-preflight.ts +111 -0
  265. package/src/resources/extensions/gsd/commands-prefs-wizard.ts +898 -32
  266. package/src/resources/extensions/gsd/compaction-snapshot.ts +165 -0
  267. package/src/resources/extensions/gsd/complexity-classifier.ts +5 -3
  268. package/src/resources/extensions/gsd/error-classifier.ts +10 -3
  269. package/src/resources/extensions/gsd/exec-history.ts +153 -0
  270. package/src/resources/extensions/gsd/exec-sandbox.ts +326 -0
  271. package/src/resources/extensions/gsd/gitignore.ts +1 -1
  272. package/src/resources/extensions/gsd/gsd-db.ts +157 -33
  273. package/src/resources/extensions/gsd/guided-flow.ts +222 -1
  274. package/src/resources/extensions/gsd/health-widget.ts +3 -1
  275. package/src/resources/extensions/gsd/init-wizard.ts +15 -1
  276. package/src/resources/extensions/gsd/journal.ts +2 -1
  277. package/src/resources/extensions/gsd/key-manager.ts +28 -0
  278. package/src/resources/extensions/gsd/model-router.ts +42 -1
  279. package/src/resources/extensions/gsd/pre-execution-checks.ts +46 -10
  280. package/src/resources/extensions/gsd/preferences-types.ts +46 -0
  281. package/src/resources/extensions/gsd/preferences-validation.ts +79 -0
  282. package/src/resources/extensions/gsd/preferences.ts +17 -17
  283. package/src/resources/extensions/gsd/prompt-loader.ts +30 -7
  284. package/src/resources/extensions/gsd/prompts/discuss-headless.md +8 -0
  285. package/src/resources/extensions/gsd/prompts/discuss.md +29 -2
  286. package/src/resources/extensions/gsd/prompts/parallel-research-slices.md +5 -2
  287. package/src/resources/extensions/gsd/safety/evidence-collector.ts +119 -0
  288. package/src/resources/extensions/gsd/safety/file-change-validator.ts +17 -4
  289. package/src/resources/extensions/gsd/safety/safety-harness.ts +9 -0
  290. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +188 -2
  291. package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +12 -0
  292. package/src/resources/extensions/gsd/tests/auto-paused-session-validation.test.ts +12 -0
  293. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +49 -0
  294. package/src/resources/extensions/gsd/tests/auto-start-bootstrap-await-3420.test.ts +141 -0
  295. package/src/resources/extensions/gsd/tests/auto-start-model-capture.test.ts +33 -3
  296. package/src/resources/extensions/gsd/tests/auto-thinking-restore.test.ts +38 -0
  297. package/src/resources/extensions/gsd/tests/auto-wrapup-inflight-guard.test.ts +23 -0
  298. package/src/resources/extensions/gsd/tests/clean-root-preflight.test.ts +186 -0
  299. package/src/resources/extensions/gsd/tests/compaction-snapshot.test.ts +123 -0
  300. package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +61 -1
  301. package/src/resources/extensions/gsd/tests/complete-slice.test.ts +2 -2
  302. package/src/resources/extensions/gsd/tests/complete-task.test.ts +2 -2
  303. package/src/resources/extensions/gsd/tests/complexity-classifier.test.ts +3 -3
  304. package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +2 -0
  305. package/src/resources/extensions/gsd/tests/doctor-providers.test.ts +31 -0
  306. package/src/resources/extensions/gsd/tests/double-merge-guard.test.ts +1 -1
  307. package/src/resources/extensions/gsd/tests/ensure-db-open.test.ts +1 -1
  308. package/src/resources/extensions/gsd/tests/escalation.test.ts +1 -1
  309. package/src/resources/extensions/gsd/tests/exec-history.test.ts +237 -0
  310. package/src/resources/extensions/gsd/tests/exec-sandbox.test.ts +210 -0
  311. package/src/resources/extensions/gsd/tests/file-change-validator.test.ts +58 -0
  312. package/src/resources/extensions/gsd/tests/gsd-db.test.ts +447 -1
  313. package/src/resources/extensions/gsd/tests/init-wizard.test.ts +27 -0
  314. package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +1 -0
  315. package/src/resources/extensions/gsd/tests/integration/gitignore-tracked-gsd.test.ts +1 -0
  316. package/src/resources/extensions/gsd/tests/integration/idle-recovery.test.ts +30 -0
  317. package/src/resources/extensions/gsd/tests/isolation-none-branch-guard.test.ts +1 -1
  318. package/src/resources/extensions/gsd/tests/issue-4540-regressions.test.ts +288 -0
  319. package/src/resources/extensions/gsd/tests/journal-integration.test.ts +2 -0
  320. package/src/resources/extensions/gsd/tests/key-manager.test.ts +9 -0
  321. package/src/resources/extensions/gsd/tests/md-importer.test.ts +1 -1
  322. package/src/resources/extensions/gsd/tests/memory-pressure-stuck-state.test.ts +12 -0
  323. package/src/resources/extensions/gsd/tests/memory-store.test.ts +2 -2
  324. package/src/resources/extensions/gsd/tests/parallel-research-dispatch.test.ts +19 -0
  325. package/src/resources/extensions/gsd/tests/plan-gate-failed-doctor-heal-hint.test.ts +37 -0
  326. package/src/resources/extensions/gsd/tests/pre-exec-backtick-strip.test.ts +14 -0
  327. package/src/resources/extensions/gsd/tests/pre-exec-gate-loop.test.ts +272 -0
  328. package/src/resources/extensions/gsd/tests/pre-execution-checks.test.ts +356 -0
  329. package/src/resources/extensions/gsd/tests/preferences.test.ts +110 -0
  330. package/src/resources/extensions/gsd/tests/prefs-wizard-coverage.test.ts +44 -0
  331. package/src/resources/extensions/gsd/tests/prompt-loader-extension-dir.test.ts +49 -0
  332. package/src/resources/extensions/gsd/tests/provider-errors.test.ts +48 -0
  333. package/src/resources/extensions/gsd/tests/ready-phrase-no-files-4573.test.ts +388 -0
  334. package/src/resources/extensions/gsd/tests/restore-tools-after-discuss.test.ts +9 -3
  335. package/src/resources/extensions/gsd/tests/resume-dispatch-worktree.test.ts +230 -0
  336. package/src/resources/extensions/gsd/tests/safety-harness-false-positives.test.ts +205 -0
  337. package/src/resources/extensions/gsd/tests/save-gate-result-render.test.ts +95 -0
  338. package/src/resources/extensions/gsd/tests/schema-v21-sequence.test.ts +413 -0
  339. package/src/resources/extensions/gsd/tests/session-start-footer.test.ts +32 -40
  340. package/src/resources/extensions/gsd/tests/stash-queued-context-files.test.ts +56 -0
  341. package/src/resources/extensions/gsd/tests/token-counter.test.ts +105 -1
  342. package/src/resources/extensions/gsd/tests/tool-compatibility.test.ts +107 -0
  343. package/src/resources/extensions/gsd/tests/uok-plan-v2-wiring.test.ts +23 -0
  344. package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +65 -2
  345. package/src/resources/extensions/gsd/tests/worktree-db.test.ts +35 -0
  346. package/src/resources/extensions/gsd/tests/worktree-journal-events.test.ts +6 -1
  347. package/src/resources/extensions/gsd/tests/worktree-resolver.test.ts +78 -5
  348. package/src/resources/extensions/gsd/tests/write-gate.test.ts +64 -0
  349. package/src/resources/extensions/gsd/tests/zombie-gsd-state.test.ts +3 -1
  350. package/src/resources/extensions/gsd/token-counter.ts +22 -5
  351. package/src/resources/extensions/gsd/tools/complete-milestone.ts +15 -9
  352. package/src/resources/extensions/gsd/tools/exec-search-tool.ts +81 -0
  353. package/src/resources/extensions/gsd/tools/exec-tool.ts +183 -0
  354. package/src/resources/extensions/gsd/tools/resume-tool.ts +40 -0
  355. package/src/resources/extensions/gsd/uok/plan-v2.ts +26 -3
  356. package/src/resources/extensions/gsd/workflow-logger.ts +3 -1
  357. package/src/resources/extensions/gsd/workflow-mcp.ts +3 -0
  358. package/src/resources/extensions/gsd/worktree-resolver.ts +54 -9
  359. package/src/resources/skills/verify-before-complete/SKILL.md +2 -1
  360. package/src/resources/skills/write-docs/SKILL.md +2 -1
  361. /package/dist/web/standalone/.next/static/{YnUwu2WWaT0_hyTLUF4nq → JgU2F-5N9mTyB7kUSSk9A}/_buildManifest.js +0 -0
  362. /package/dist/web/standalone/.next/static/{YnUwu2WWaT0_hyTLUF4nq → JgU2F-5N9mTyB7kUSSk9A}/_ssgManifest.js +0 -0
@@ -65,6 +65,8 @@ export class AutoSession {
65
65
  currentDispatchedModelId = null;
66
66
  originalModelId = null;
67
67
  originalModelProvider = null;
68
+ autoModeStartThinkingLevel = null;
69
+ originalThinkingLevel = null;
68
70
  lastBudgetAlertLevel = 0;
69
71
  // ── Recovery ─────────────────────────────────────────────────────────────
70
72
  pendingCrashRecovery = null;
@@ -77,6 +79,17 @@ export class AutoSession {
77
79
  lastStateRebuildAt = 0;
78
80
  // ── Sidecar queue ─────────────────────────────────────────────────────
79
81
  sidecarQueue = [];
82
+ // ── Pre-exec gate failure context (#4551) ───────────────────────────
83
+ /**
84
+ * Persisted when a pre-execution gate fails on a plan-slice or refine-slice
85
+ * unit. The planning → plan-slice dispatch rule reads this field and injects
86
+ * the failure details into the next re-dispatch prompt so the LLM can fix the
87
+ * specific issues instead of producing an identical plan.
88
+ *
89
+ * Cleared after it has been consumed (injected into the prompt) to avoid
90
+ * stale context bleeding into unrelated slices.
91
+ */
92
+ lastPreExecFailure = null;
80
93
  // ── Tool invocation errors (#2883) ──────────────────────────────────
81
94
  /** Set when a GSD tool execution ends with isError due to malformed/truncated
82
95
  * JSON arguments. Checked by postUnitPreVerification to break retry loops. */
@@ -137,7 +150,12 @@ export class AutoSession {
137
150
  this.unitLifetimeDispatches.clear();
138
151
  }
139
152
  get lockBasePath() {
140
- return this.originalBasePath || this.basePath;
153
+ // Prefer originalBasePath (project root); fall back to basePath.
154
+ // Strip /.gsd/worktrees/ suffix if basePath is itself a worktree path
155
+ // to avoid reading/writing the lock inside the worktree (#3729).
156
+ const resolved = this.originalBasePath || this.basePath;
157
+ const markerIdx = resolved.indexOf("/.gsd/worktrees/");
158
+ return markerIdx !== -1 ? resolved.slice(0, markerIdx) : resolved;
141
159
  }
142
160
  reset() {
143
161
  this.clearTimers();
@@ -177,6 +195,8 @@ export class AutoSession {
177
195
  this.currentDispatchedModelId = null;
178
196
  this.originalModelId = null;
179
197
  this.originalModelProvider = null;
198
+ this.autoModeStartThinkingLevel = null;
199
+ this.originalThinkingLevel = null;
180
200
  this.lastBudgetAlertLevel = 0;
181
201
  // Recovery
182
202
  this.pendingCrashRecovery = null;
@@ -195,6 +215,7 @@ export class AutoSession {
195
215
  this.sidecarQueue = [];
196
216
  this.rewriteAttemptCount = 0;
197
217
  this.consecutiveCompleteBootstraps = 0;
218
+ this.lastPreExecFailure = null;
198
219
  this.lastToolInvocationError = null;
199
220
  this.lastGitActionFailure = null;
200
221
  this.lastGitActionStatus = null;
@@ -451,18 +451,31 @@ export const DISPATCH_RULES = [
451
451
  },
452
452
  {
453
453
  name: "planning → plan-slice",
454
- match: async ({ state, mid, midTitle, basePath, sessionContextWindow, modelRegistry }) => {
454
+ match: async ({ state, mid, midTitle, basePath, sessionContextWindow, modelRegistry, session }) => {
455
455
  if (state.phase !== "planning")
456
456
  return null;
457
457
  if (!state.activeSlice)
458
458
  return missingSliceStop(mid, state.phase);
459
459
  const sid = state.activeSlice.id;
460
460
  const sTitle = state.activeSlice.title;
461
+ // #4551: Consume any persisted pre-exec failure for this slice so the
462
+ // re-dispatched prompt includes the exact blocked references. Clear the
463
+ // field immediately after reading to prevent stale context leaking into
464
+ // a later, unrelated plan-slice run.
465
+ const unitId = `${mid}/${sid}`;
466
+ let priorPreExecFailure;
467
+ if (session?.lastPreExecFailure?.unitId === unitId) {
468
+ priorPreExecFailure = {
469
+ blockingFindings: session.lastPreExecFailure.blockingFindings,
470
+ verdictExcerpt: session.lastPreExecFailure.verdictExcerpt,
471
+ };
472
+ session.lastPreExecFailure = null;
473
+ }
461
474
  return {
462
475
  action: "dispatch",
463
476
  unitType: "plan-slice",
464
- unitId: `${mid}/${sid}`,
465
- prompt: await buildPlanSlicePrompt(mid, midTitle, sid, sTitle, basePath, undefined, { sessionContextWindow, modelRegistry }),
477
+ unitId,
478
+ prompt: await buildPlanSlicePrompt(mid, midTitle, sid, sTitle, basePath, undefined, { sessionContextWindow, modelRegistry, priorPreExecFailure }),
466
479
  };
467
480
  },
468
481
  },
@@ -13,6 +13,11 @@ import { logWarning } from "./workflow-logger.js";
13
13
  import { resolveUokFlags } from "./uok/flags.js";
14
14
  import { applyModelPolicyFilter } from "./uok/model-policy.js";
15
15
  import { isModelBlocked } from "./blocked-models.js";
16
+ function reapplyThinkingLevel(pi, level) {
17
+ if (!level)
18
+ return;
19
+ pi.setThinkingLevel(level);
20
+ }
16
21
  export function resolvePreferredModelConfig(unitType, autoModeStartModel, isAutoMode = true) {
17
22
  const explicitConfig = resolveModelWithFallbacksForUnit(unitType);
18
23
  if (explicitConfig) {
@@ -58,7 +63,9 @@ export async function selectAndApplyModel(ctx, pi, unitType, unitId, basePath, p
58
63
  * Dynamic routing only applies in auto-mode where cost optimization is expected. (#3962) */
59
64
  isAutoMode = true,
60
65
  /** Explicit /gsd model pin captured at bootstrap for long-running auto loops. */
61
- sessionModelOverride) {
66
+ sessionModelOverride,
67
+ /** Thinking level captured at auto-mode start and re-applied after model swaps. */
68
+ autoModeStartThinkingLevel) {
62
69
  const uokFlags = resolveUokFlags(prefs);
63
70
  const effectiveSessionModelOverride = sessionModelOverride === undefined
64
71
  ? getSessionModelOverride(ctx.sessionManager.getSessionId())
@@ -280,10 +287,11 @@ sessionModelOverride) {
280
287
  const ok = await pi.setModel(model, { persist: false });
281
288
  if (ok) {
282
289
  appliedModel = model;
290
+ reapplyThinkingLevel(pi, autoModeStartThinkingLevel);
283
291
  // ADR-005: Adjust active tool set for the selected model's provider capabilities.
284
292
  // Hard-filter incompatible tools, then let extensions override via adjust_tool_set hook.
285
293
  const activeToolNames = pi.getActiveTools();
286
- const { toolNames: compatibleTools, removedTools } = adjustToolSet(activeToolNames, model.api);
294
+ const { toolNames: compatibleTools, removedTools } = adjustToolSet(activeToolNames, model.api, model.provider);
287
295
  let finalToolNames = compatibleTools;
288
296
  // Fire adjust_tool_set hook — extensions can override the filtered tool set
289
297
  if (routingConfig.hooks !== false) {
@@ -346,12 +354,15 @@ sessionModelOverride) {
346
354
  const byId = availableModels.find(m => m.id === autoModeStartModel.id && !isModelBlocked(basePath, m.provider, m.id));
347
355
  if (byId) {
348
356
  const fallbackOk = await pi.setModel(byId, { persist: false });
349
- if (fallbackOk)
357
+ if (fallbackOk) {
350
358
  appliedModel = byId;
359
+ reapplyThinkingLevel(pi, autoModeStartThinkingLevel);
360
+ }
351
361
  }
352
362
  }
353
363
  else {
354
364
  appliedModel = startModel;
365
+ reapplyThinkingLevel(pi, autoModeStartThinkingLevel);
355
366
  }
356
367
  }
357
368
  }
@@ -30,7 +30,7 @@ import { checkPostUnitHooks, isRetryPending, consumeRetryTrigger, persistHookSta
30
30
  import { hasPendingCaptures, loadPendingCaptures, revertExecutorResolvedCaptures } from "./captures.js";
31
31
  import { debugLog } from "./debug-logger.js";
32
32
  import { runSafely } from "./auto-utils.js";
33
- import { getEvidence } from "./safety/evidence-collector.js";
33
+ import { getEvidence, clearEvidenceFromDisk } from "./safety/evidence-collector.js";
34
34
  import { validateFileChanges } from "./safety/file-change-validator.js";
35
35
  // crossReferenceEvidence available for future use when verification_evidence is stored in DB
36
36
  // import { crossReferenceEvidence, type ClaimedEvidence } from "./safety/evidence-cross-ref.js";
@@ -535,7 +535,7 @@ export async function postUnitPreVerification(pctx, opts) {
535
535
  if (taskRow) {
536
536
  const expectedOutput = taskRow.expected_output ?? [];
537
537
  const plannedFiles = taskRow.files ?? [];
538
- const audit = validateFileChanges(s.basePath, expectedOutput, plannedFiles);
538
+ const audit = validateFileChanges(s.basePath, expectedOutput, plannedFiles, safetyConfig.file_change_allowlist);
539
539
  if (audit && audit.violations.length > 0) {
540
540
  const warnings = audit.violations.filter(v => v.severity === "warning");
541
541
  for (const v of warnings) {
@@ -588,6 +588,16 @@ export async function postUnitPreVerification(pctx, opts) {
588
588
  debugLog("postUnit", { phase: "safety-content-validation", error: String(e) });
589
589
  }
590
590
  }
591
+ // Clear persisted evidence file now that post-unit processing is complete
592
+ // (Bug #4385 — prevents stale evidence from affecting retries of same unit ID).
593
+ if (safetyConfig.evidence_collection && s.currentUnit.type === "execute-task" && sMid && sSid && sTid) {
594
+ try {
595
+ clearEvidenceFromDisk(s.basePath, sMid, sSid, sTid);
596
+ }
597
+ catch (e) {
598
+ debugLog("postUnit", { phase: "safety-evidence-clear", error: String(e) });
599
+ }
600
+ }
591
601
  }
592
602
  }
593
603
  catch (e) {
@@ -950,12 +960,25 @@ export async function postUnitPostVerification(pctx) {
950
960
  const suffix = blockingChecks.length > 3 ? `\n \u2022 ...and ${blockingChecks.length - 3} more` : "";
951
961
  const evidenceNote = `\nSee ${sid}-PRE-EXEC-VERIFY.json for full details.`;
952
962
  ctx.ui.notify(`Pre-execution checks failed: ${blockingCount} blocking issue${blockingCount === 1 ? "" : "s"} found\n${details}${suffix}${evidenceNote}`, "error");
963
+ // Persist failure context so the next plan-slice re-dispatch can inject
964
+ // it into the prompt and break the infinite loop (#4551).
965
+ s.lastPreExecFailure = {
966
+ unitId: currentUnit.id,
967
+ blockingFindings: blockingChecks.map(c => `[${c.category}] ${c.target}: ${c.message}`),
968
+ verdictExcerpt: `status=${result.status}; ${blockingCount} blocking issue${blockingCount === 1 ? "" : "s"} detected`,
969
+ };
953
970
  preExecPauseNeeded = true;
954
971
  }
955
972
  else if (result.status === "warn") {
956
973
  ctx.ui.notify(`Pre-execution checks passed with warnings`, "warning");
957
974
  // Strict mode: treat warnings as blocking
958
975
  if (prefs?.enhanced_verification_strict === true) {
976
+ const warnChecks = result.checks.filter(c => !c.passed);
977
+ s.lastPreExecFailure = {
978
+ unitId: currentUnit.id,
979
+ blockingFindings: warnChecks.map(c => `[${c.category}] ${c.target}: ${c.message}`),
980
+ verdictExcerpt: `status=${result.status} (strict mode); ${warnChecks.length} warning${warnChecks.length === 1 ? "" : "s"} treated as blocking`,
981
+ };
959
982
  preExecPauseNeeded = true;
960
983
  }
961
984
  }
@@ -1223,6 +1223,20 @@ export async function buildPlanSlicePrompt(mid, _midTitle, sid, sTitle, base, le
1223
1223
  prependBlocks.push(`## Prior Sketch Scope (soft hint — non-binding)\n\n${options.softScopeHint.trim()}\n\n` +
1224
1224
  `This scope was captured during an earlier progressive-planning pass that was later disabled. Treat it as context only — you may plan beyond it if the work genuinely requires more scope. Do NOT treat this as a hard boundary.`);
1225
1225
  }
1226
+ // #4551: inject pre-exec failure context so the re-dispatched plan-slice
1227
+ // addresses the exact blocked references rather than reproducing the same plan.
1228
+ if (options?.priorPreExecFailure) {
1229
+ const { blockingFindings, verdictExcerpt } = options.priorPreExecFailure;
1230
+ const findingsList = blockingFindings.length > 0
1231
+ ? blockingFindings.map(f => `- ${f}`).join("\n")
1232
+ : "- (no specific findings recorded)";
1233
+ prependBlocks.push(`## Fix these specific issues from the prior pre-exec check\n\n` +
1234
+ `The previous plan-slice attempt was blocked by pre-execution validation.\n` +
1235
+ `Gate verdict: ${verdictExcerpt}\n\n` +
1236
+ `Blocked references that must be resolved in this plan:\n${findingsList}\n\n` +
1237
+ `Revise the plan so that every reference listed above is satisfied before execution begins. ` +
1238
+ `Do not reproduce the same file paths, package names, or task ordering that caused these failures.`);
1239
+ }
1226
1240
  return renderSlicePrompt({
1227
1241
  mid, sid, sTitle, base,
1228
1242
  level: level ?? resolveInlineLevel(),
@@ -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