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
@@ -17,7 +17,7 @@
17
17
  */
18
18
 
19
19
  import type { Api, Model } from "@gsd/pi-ai";
20
- import type { ExtensionCommandContext } from "@gsd/pi-coding-agent";
20
+ import type { ExtensionAPI, ExtensionCommandContext } from "@gsd/pi-coding-agent";
21
21
  import type { GitServiceImpl } from "../git-service.js";
22
22
  import type { CaptureEntry } from "../captures.js";
23
23
  import type { BudgetAlertLevel } from "../auto-budget.js";
@@ -40,6 +40,8 @@ export interface StartModel {
40
40
  id: string;
41
41
  }
42
42
 
43
+ export type ThinkingLevelSnapshot = ReturnType<ExtensionAPI["getThinkingLevel"]>;
44
+
43
45
  export interface PendingVerificationRetry {
44
46
  unitId: string;
45
47
  failureContext: string;
@@ -62,6 +64,15 @@ export interface SidecarItem {
62
64
  captureId?: string;
63
65
  }
64
66
 
67
+ export interface PreExecFailure {
68
+ /** Milestone/slice that failed (e.g. "M001/S02"). */
69
+ unitId: string;
70
+ /** Verbatim blocking check strings from the failed gate run. */
71
+ blockingFindings: string[];
72
+ /** Condensed gate verdict excerpt for context (status + rationale). */
73
+ verdictExcerpt: string;
74
+ }
75
+
65
76
  // ─── Constants ───────────────────────────────────────────────────────────────
66
77
 
67
78
  export const MAX_UNIT_DISPATCHES = 3;
@@ -120,6 +131,8 @@ export class AutoSession {
120
131
  currentDispatchedModelId: string | null = null;
121
132
  originalModelId: string | null = null;
122
133
  originalModelProvider: string | null = null;
134
+ autoModeStartThinkingLevel: ThinkingLevelSnapshot | null = null;
135
+ originalThinkingLevel: ThinkingLevelSnapshot | null = null;
123
136
  lastBudgetAlertLevel: BudgetAlertLevel = 0;
124
137
 
125
138
  // ── Recovery ─────────────────────────────────────────────────────────────
@@ -135,6 +148,18 @@ export class AutoSession {
135
148
  // ── Sidecar queue ─────────────────────────────────────────────────────
136
149
  sidecarQueue: SidecarItem[] = [];
137
150
 
151
+ // ── Pre-exec gate failure context (#4551) ───────────────────────────
152
+ /**
153
+ * Persisted when a pre-execution gate fails on a plan-slice or refine-slice
154
+ * unit. The planning → plan-slice dispatch rule reads this field and injects
155
+ * the failure details into the next re-dispatch prompt so the LLM can fix the
156
+ * specific issues instead of producing an identical plan.
157
+ *
158
+ * Cleared after it has been consumed (injected into the prompt) to avoid
159
+ * stale context bleeding into unrelated slices.
160
+ */
161
+ lastPreExecFailure: PreExecFailure | null = null;
162
+
138
163
  // ── Tool invocation errors (#2883) ──────────────────────────────────
139
164
  /** Set when a GSD tool execution ends with isError due to malformed/truncated
140
165
  * JSON arguments. Checked by postUnitPreVerification to break retry loops. */
@@ -195,7 +220,12 @@ export class AutoSession {
195
220
  }
196
221
 
197
222
  get lockBasePath(): string {
198
- return this.originalBasePath || this.basePath;
223
+ // Prefer originalBasePath (project root); fall back to basePath.
224
+ // Strip /.gsd/worktrees/ suffix if basePath is itself a worktree path
225
+ // to avoid reading/writing the lock inside the worktree (#3729).
226
+ const resolved = this.originalBasePath || this.basePath;
227
+ const markerIdx = resolved.indexOf("/.gsd/worktrees/");
228
+ return markerIdx !== -1 ? resolved.slice(0, markerIdx) : resolved;
199
229
  }
200
230
 
201
231
  reset(): void {
@@ -241,6 +271,8 @@ export class AutoSession {
241
271
  this.currentDispatchedModelId = null;
242
272
  this.originalModelId = null;
243
273
  this.originalModelProvider = null;
274
+ this.autoModeStartThinkingLevel = null;
275
+ this.originalThinkingLevel = null;
244
276
  this.lastBudgetAlertLevel = 0;
245
277
 
246
278
  // Recovery
@@ -261,6 +293,7 @@ export class AutoSession {
261
293
  this.sidecarQueue = [];
262
294
  this.rewriteAttemptCount = 0;
263
295
  this.consecutiveCompleteBootstraps = 0;
296
+ this.lastPreExecFailure = null;
264
297
  this.lastToolInvocationError = null;
265
298
  this.lastGitActionFailure = null;
266
299
  this.lastGitActionStatus = null;
@@ -568,15 +568,28 @@ export const DISPATCH_RULES: DispatchRule[] = [
568
568
  },
569
569
  {
570
570
  name: "planning → plan-slice",
571
- match: async ({ state, mid, midTitle, basePath, sessionContextWindow, modelRegistry }) => {
571
+ match: async ({ state, mid, midTitle, basePath, sessionContextWindow, modelRegistry, session }) => {
572
572
  if (state.phase !== "planning") return null;
573
573
  if (!state.activeSlice) return missingSliceStop(mid, state.phase);
574
574
  const sid = state.activeSlice!.id;
575
575
  const sTitle = state.activeSlice!.title;
576
+ // #4551: Consume any persisted pre-exec failure for this slice so the
577
+ // re-dispatched prompt includes the exact blocked references. Clear the
578
+ // field immediately after reading to prevent stale context leaking into
579
+ // a later, unrelated plan-slice run.
580
+ const unitId = `${mid}/${sid}`;
581
+ let priorPreExecFailure: { blockingFindings: string[]; verdictExcerpt: string } | undefined;
582
+ if (session?.lastPreExecFailure?.unitId === unitId) {
583
+ priorPreExecFailure = {
584
+ blockingFindings: session.lastPreExecFailure.blockingFindings,
585
+ verdictExcerpt: session.lastPreExecFailure.verdictExcerpt,
586
+ };
587
+ session.lastPreExecFailure = null;
588
+ }
576
589
  return {
577
590
  action: "dispatch",
578
591
  unitType: "plan-slice",
579
- unitId: `${mid}/${sid}`,
592
+ unitId,
580
593
  prompt: await buildPlanSlicePrompt(
581
594
  mid,
582
595
  midTitle,
@@ -584,7 +597,7 @@ export const DISPATCH_RULES: DispatchRule[] = [
584
597
  sTitle,
585
598
  basePath,
586
599
  undefined,
587
- { sessionContextWindow, modelRegistry },
600
+ { sessionContextWindow, modelRegistry, priorPreExecFailure },
588
601
  ),
589
602
  };
590
603
  },
@@ -33,6 +33,14 @@ export interface PreferredModelConfig {
33
33
  source: "explicit" | "synthesized";
34
34
  }
35
35
 
36
+ function reapplyThinkingLevel(
37
+ pi: ExtensionAPI,
38
+ level: ReturnType<ExtensionAPI["getThinkingLevel"]> | null | undefined,
39
+ ): void {
40
+ if (!level) return;
41
+ pi.setThinkingLevel(level);
42
+ }
43
+
36
44
  export function resolvePreferredModelConfig(
37
45
  unitType: string,
38
46
  autoModeStartModel: { provider: string; id: string; flatRateCtx?: FlatRateContext } | null,
@@ -97,6 +105,8 @@ export async function selectAndApplyModel(
97
105
  isAutoMode = true,
98
106
  /** Explicit /gsd model pin captured at bootstrap for long-running auto loops. */
99
107
  sessionModelOverride?: { provider: string; id: string } | null,
108
+ /** Thinking level captured at auto-mode start and re-applied after model swaps. */
109
+ autoModeStartThinkingLevel?: ReturnType<ExtensionAPI["getThinkingLevel"]> | null,
100
110
  ): Promise<ModelSelectionResult> {
101
111
  const uokFlags = resolveUokFlags(prefs);
102
112
  const effectiveSessionModelOverride = sessionModelOverride === undefined
@@ -380,11 +390,12 @@ export async function selectAndApplyModel(
380
390
  const ok = await pi.setModel(model, { persist: false });
381
391
  if (ok) {
382
392
  appliedModel = model;
393
+ reapplyThinkingLevel(pi, autoModeStartThinkingLevel);
383
394
 
384
395
  // ADR-005: Adjust active tool set for the selected model's provider capabilities.
385
396
  // Hard-filter incompatible tools, then let extensions override via adjust_tool_set hook.
386
397
  const activeToolNames = pi.getActiveTools();
387
- const { toolNames: compatibleTools, removedTools } = adjustToolSet(activeToolNames, model.api);
398
+ const { toolNames: compatibleTools, removedTools } = adjustToolSet(activeToolNames, model.api, model.provider);
388
399
  let finalToolNames = compatibleTools;
389
400
 
390
401
  // Fire adjust_tool_set hook — extensions can override the filtered tool set
@@ -456,10 +467,14 @@ export async function selectAndApplyModel(
456
467
  );
457
468
  if (byId) {
458
469
  const fallbackOk = await pi.setModel(byId, { persist: false });
459
- if (fallbackOk) appliedModel = byId;
470
+ if (fallbackOk) {
471
+ appliedModel = byId;
472
+ reapplyThinkingLevel(pi, autoModeStartThinkingLevel);
473
+ }
460
474
  }
461
475
  } else {
462
476
  appliedModel = startModel;
477
+ reapplyThinkingLevel(pi, autoModeStartThinkingLevel);
463
478
  }
464
479
  }
465
480
  }
@@ -55,7 +55,7 @@ import { hasPendingCaptures, loadPendingCaptures, revertExecutorResolvedCaptures
55
55
  import { debugLog } from "./debug-logger.js";
56
56
  import { runSafely } from "./auto-utils.js";
57
57
  import type { AutoSession, SidecarItem } from "./auto/session.js";
58
- import { getEvidence } from "./safety/evidence-collector.js";
58
+ import { getEvidence, clearEvidenceFromDisk } from "./safety/evidence-collector.js";
59
59
  import { validateFileChanges } from "./safety/file-change-validator.js";
60
60
  // crossReferenceEvidence available for future use when verification_evidence is stored in DB
61
61
  // import { crossReferenceEvidence, type ClaimedEvidence } from "./safety/evidence-cross-ref.js";
@@ -107,7 +107,6 @@ import {
107
107
  updateProgressWidget as _updateProgressWidget,
108
108
  updateSliceProgressCache,
109
109
  unitVerb,
110
- hideFooter,
111
110
  describeNextUnit,
112
111
  } from "./auto-dashboard.js";
113
112
  import { existsSync, unlinkSync } from "node:fs";
@@ -654,7 +653,7 @@ export async function postUnitPreVerification(pctx: PostUnitContext, opts?: PreV
654
653
  if (taskRow) {
655
654
  const expectedOutput = taskRow.expected_output ?? [];
656
655
  const plannedFiles = taskRow.files ?? [];
657
- const audit = validateFileChanges(s.basePath, expectedOutput, plannedFiles);
656
+ const audit = validateFileChanges(s.basePath, expectedOutput, plannedFiles, safetyConfig.file_change_allowlist);
658
657
  if (audit && audit.violations.length > 0) {
659
658
  const warnings = audit.violations.filter(v => v.severity === "warning");
660
659
  for (const v of warnings) {
@@ -712,6 +711,16 @@ export async function postUnitPreVerification(pctx: PostUnitContext, opts?: PreV
712
711
  debugLog("postUnit", { phase: "safety-content-validation", error: String(e) });
713
712
  }
714
713
  }
714
+
715
+ // Clear persisted evidence file now that post-unit processing is complete
716
+ // (Bug #4385 — prevents stale evidence from affecting retries of same unit ID).
717
+ if (safetyConfig.evidence_collection && s.currentUnit.type === "execute-task" && sMid && sSid && sTid) {
718
+ try {
719
+ clearEvidenceFromDisk(s.basePath, sMid, sSid, sTid);
720
+ } catch (e) {
721
+ debugLog("postUnit", { phase: "safety-evidence-clear", error: String(e) });
722
+ }
723
+ }
715
724
  }
716
725
  } catch (e) {
717
726
  debugLog("postUnit", { phase: "safety-harness", error: String(e) });
@@ -1134,6 +1143,15 @@ export async function postUnitPostVerification(pctx: PostUnitContext): Promise<"
1134
1143
  `Pre-execution checks failed: ${blockingCount} blocking issue${blockingCount === 1 ? "" : "s"} found\n${details}${suffix}${evidenceNote}`,
1135
1144
  "error",
1136
1145
  );
1146
+ // Persist failure context so the next plan-slice re-dispatch can inject
1147
+ // it into the prompt and break the infinite loop (#4551).
1148
+ s.lastPreExecFailure = {
1149
+ unitId: currentUnit.id,
1150
+ blockingFindings: blockingChecks.map(
1151
+ c => `[${c.category}] ${c.target}: ${c.message}`,
1152
+ ),
1153
+ verdictExcerpt: `status=${result.status}; ${blockingCount} blocking issue${blockingCount === 1 ? "" : "s"} detected`,
1154
+ };
1137
1155
  preExecPauseNeeded = true;
1138
1156
  } else if (result.status === "warn") {
1139
1157
  ctx.ui.notify(
@@ -1142,6 +1160,14 @@ export async function postUnitPostVerification(pctx: PostUnitContext): Promise<"
1142
1160
  );
1143
1161
  // Strict mode: treat warnings as blocking
1144
1162
  if (prefs?.enhanced_verification_strict === true) {
1163
+ const warnChecks = result.checks.filter(c => !c.passed);
1164
+ s.lastPreExecFailure = {
1165
+ unitId: currentUnit.id,
1166
+ blockingFindings: warnChecks.map(
1167
+ c => `[${c.category}] ${c.target}: ${c.message}`,
1168
+ ),
1169
+ verdictExcerpt: `status=${result.status} (strict mode); ${warnChecks.length} warning${warnChecks.length === 1 ? "" : "s"} treated as blocking`,
1170
+ };
1145
1171
  preExecPauseNeeded = true;
1146
1172
  }
1147
1173
  }
@@ -1380,7 +1380,18 @@ async function renderSlicePrompt(options: {
1380
1380
 
1381
1381
  export async function buildPlanSlicePrompt(
1382
1382
  mid: string, _midTitle: string, sid: string, sTitle: string, base: string, level?: InlineLevel,
1383
- options?: { softScopeHint?: string; sessionContextWindow?: number; modelRegistry?: MinimalModelRegistry },
1383
+ options?: {
1384
+ softScopeHint?: string;
1385
+ sessionContextWindow?: number;
1386
+ modelRegistry?: MinimalModelRegistry;
1387
+ /** Failure context from a prior pre-exec gate run (#4551). When present, a
1388
+ * "Fix these specific issues" section is appended so the LLM addresses the
1389
+ * exact problems instead of producing an identical plan that fails again. */
1390
+ priorPreExecFailure?: {
1391
+ blockingFindings: string[];
1392
+ verdictExcerpt: string;
1393
+ };
1394
+ },
1384
1395
  ): Promise<string> {
1385
1396
  const prependBlocks: string[] = [];
1386
1397
  // ADR-011: when the refining-phase dispatch rule gracefully downgrades to
@@ -1393,6 +1404,22 @@ export async function buildPlanSlicePrompt(
1393
1404
  `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.`,
1394
1405
  );
1395
1406
  }
1407
+ // #4551: inject pre-exec failure context so the re-dispatched plan-slice
1408
+ // addresses the exact blocked references rather than reproducing the same plan.
1409
+ if (options?.priorPreExecFailure) {
1410
+ const { blockingFindings, verdictExcerpt } = options.priorPreExecFailure;
1411
+ const findingsList = blockingFindings.length > 0
1412
+ ? blockingFindings.map(f => `- ${f}`).join("\n")
1413
+ : "- (no specific findings recorded)";
1414
+ prependBlocks.push(
1415
+ `## Fix these specific issues from the prior pre-exec check\n\n` +
1416
+ `The previous plan-slice attempt was blocked by pre-execution validation.\n` +
1417
+ `Gate verdict: ${verdictExcerpt}\n\n` +
1418
+ `Blocked references that must be resolved in this plan:\n${findingsList}\n\n` +
1419
+ `Revise the plan so that every reference listed above is satisfied before execution begins. ` +
1420
+ `Do not reproduce the same file paths, package names, or task ordering that caused these failures.`,
1421
+ );
1422
+ }
1396
1423
  return renderSlicePrompt({
1397
1424
  mid, sid, sTitle, base,
1398
1425
  level: level ?? resolveInlineLevel(),
@@ -13,7 +13,7 @@ import { appendEvent } from "./workflow-events.js";
13
13
  import { atomicWriteSync } from "./atomic-write.js";
14
14
  import { clearParseCache } from "./files.js";
15
15
  import { parseRoadmap as parseLegacyRoadmap, parsePlan as parseLegacyPlan } from "./parsers-legacy.js";
16
- import { isDbAvailable, getTask, getSlice, getSliceTasks, getPendingGates, updateTaskStatus, updateSliceStatus } from "./gsd-db.js";
16
+ import { isDbAvailable, getTask, getSlice, getSliceTasks, getPendingGates, updateTaskStatus, updateSliceStatus, insertSlice } from "./gsd-db.js";
17
17
  import { isValidationTerminal } from "./state.js";
18
18
  import { getErrorMessage } from "./error-utils.js";
19
19
  import { logWarning, logError } from "./workflow-logger.js";
@@ -268,11 +268,26 @@ export function verifyExpectedArtifact(
268
268
  // RESEARCH file. Without this, resolveExpectedArtifactPath returns null and
269
269
  // the retry/escalation machinery silently re-dispatches forever.
270
270
  //
271
+ // #4068: Also treat a PARALLEL-BLOCKER placeholder as a terminal completion
272
+ // so that timeout-recovery can write the blocker, have verifyExpectedArtifact
273
+ // return true, and let the dispatch loop advance past this unit. Without
274
+ // this, the blocker is written but verification still returns false, the unit
275
+ // is never cleared from unitDispatchCount, and on the next iteration the
276
+ // dispatch rule (which correctly skips parallel-research when PARALLEL-BLOCKER
277
+ // exists) returns null — leaving the loop stuck re-deriving indefinitely.
278
+ //
271
279
  // NOTE: this predicate mirrors the dispatch rule at
272
280
  // auto-dispatch.ts parallel-research-slices — keep the two in sync.
273
281
  if (unitType === "research-slice" && unitId.endsWith("/parallel-research")) {
274
282
  const { milestone: mid } = parseUnitId(unitId);
275
283
  if (!mid) return false;
284
+
285
+ // #4068: PARALLEL-BLOCKER written by timeout-recovery is a terminal state.
286
+ const blockerPath = resolveExpectedArtifactPath(unitType, unitId, base);
287
+ if (blockerPath && existsSync(blockerPath)) {
288
+ return true;
289
+ }
290
+
276
291
  const roadmapFile = resolveMilestoneFile(base, mid, "ROADMAP");
277
292
  if (!roadmapFile || !existsSync(roadmapFile)) {
278
293
  logWarning("recovery", `verify-fail ${unitType} ${unitId}: roadmap missing`);
@@ -532,6 +547,16 @@ export function writeBlockerPlaceholder(
532
547
  try { updateSliceStatus(mid, sid, "complete", ts); } catch (e) { logWarning("recovery", `updateSliceStatus failed during context exhaustion: ${e instanceof Error ? e.message : String(e)}`); }
533
548
  try { appendEvent(base, { cmd: "complete-slice", params: { milestoneId: mid, sliceId: sid }, ts, actor: "system", trigger_reason: "blocker-placeholder-recovery" }); } catch (e) { logWarning("recovery", `appendEvent failed for slice recovery: ${e instanceof Error ? e.message : String(e)}`); }
534
549
  }
550
+ // Insert a placeholder complete slice so deriveState sees activeMilestoneSlices.length > 0
551
+ // and exits the pre-planning phase. Without this, activeMilestoneSlices stays empty
552
+ // after the blocker ROADMAP.md is written, causing deriveState to return phase:'pre-planning'
553
+ // indefinitely and re-dispatching plan-milestone in an infinite loop (#4378).
554
+ if (unitType === "plan-milestone" && mid) {
555
+ try {
556
+ insertSlice({ id: "S00-blocker", milestoneId: mid, title: "Blocker placeholder — planning failed", status: "complete", sequence: 0 });
557
+ } catch (e) { logWarning("recovery", `insertSlice placeholder failed for plan-milestone recovery: ${e instanceof Error ? e.message : String(e)}`); }
558
+ try { appendEvent(base, { cmd: "plan-milestone", params: { milestoneId: mid }, ts, actor: "system", trigger_reason: "blocker-placeholder-recovery" }); } catch (e) { logWarning("recovery", `appendEvent failed for plan-milestone recovery: ${e instanceof Error ? e.message : String(e)}`); }
559
+ }
535
560
  }
536
561
 
537
562
  return diagnoseExpectedArtifact(unitType, unitId, base);
@@ -60,8 +60,8 @@ import { initRoutingHistory } from "./routing-history.js";
60
60
  import { restoreHookState, resetHookState } from "./post-unit-hooks.js";
61
61
  import { resetProactiveHealing, setLevelChangeCallback } from "./doctor-proactive.js";
62
62
  import { snapshotSkills } from "./skill-discovery.js";
63
- import { isDbAvailable, getMilestone, openDatabase } from "./gsd-db.js";
64
- import { hideFooter } from "./auto-dashboard.js";
63
+ import { isDbAvailable, getMilestone, openDatabase, getDbStatus } from "./gsd-db.js";
64
+
65
65
  import {
66
66
  debugLog,
67
67
  enableDebug,
@@ -92,7 +92,7 @@ import type { WorktreeResolver } from "./worktree-resolver.js";
92
92
  import { getSessionModelOverride } from "./session-model-override.js";
93
93
 
94
94
  export interface BootstrapDeps {
95
- shouldUseWorktreeIsolation: () => boolean;
95
+ shouldUseWorktreeIsolation: (basePath?: string) => boolean;
96
96
  registerSigtermHandler: (basePath: string) => void;
97
97
  lockBase: () => string;
98
98
  buildResolver: () => WorktreeResolver;
@@ -273,8 +273,8 @@ export async function bootstrapAutoSession(
273
273
  //
274
274
  // Precedence:
275
275
  // 1) Explicit session override via /gsd model (this session)
276
- // 2) GSD model preferences from PREFERENCES.md (validated against live auth)
277
- // 3) Current session model from settings/session restore (if provider ready)
276
+ // 2) Current session model from settings/session restore (if provider ready)
277
+ // 3) GSD model preferences from PREFERENCES.md (validated against live auth)
278
278
  //
279
279
  // This preserves #3517 defaults while honoring explicit runtime model
280
280
  // selection for subsequent /gsd runs in the same session.
@@ -314,11 +314,14 @@ export async function bootstrapAutoSession(
314
314
  }
315
315
  const sessionModelReady =
316
316
  ctx.model && ctx.modelRegistry.isProviderRequestReady(ctx.model.provider);
317
+ const currentSessionModel = (sessionModelReady && ctx.model)
318
+ ? { provider: ctx.model.provider, id: ctx.model.id }
319
+ : null;
320
+ const startThinkingSnapshot = pi.getThinkingLevel();
317
321
  const startModelSnapshot = manualSessionOverride
322
+ ?? currentSessionModel
318
323
  ?? validatedPreferredModel
319
- ?? (sessionModelReady && ctx.model
320
- ? { provider: ctx.model.provider, id: ctx.model.id }
321
- : null);
324
+ ?? null;
322
325
 
323
326
  try {
324
327
  // Validate GSD_PROJECT_ID early so the user gets immediate feedback
@@ -340,7 +343,7 @@ export async function bootstrapAutoSession(
340
343
  const hasLocalGit = existsSync(join(base, ".git"));
341
344
  if (!hasLocalGit || isInheritedRepo(base)) {
342
345
  const mainBranch =
343
- loadEffectiveGSDPreferences()?.preferences?.git?.main_branch || "main";
346
+ loadEffectiveGSDPreferences(base)?.preferences?.git?.main_branch || "main";
344
347
  nativeInit(base, mainBranch);
345
348
  }
346
349
 
@@ -358,7 +361,7 @@ export async function bootstrapAutoSession(
358
361
  // Ensure .gitignore has baseline patterns.
359
362
  // ensureGitignore checks for git-tracked .gsd/ files and skips the
360
363
  // ".gsd" pattern if the project intentionally tracks .gsd/ in git.
361
- const gitPrefs = loadEffectiveGSDPreferences()?.preferences?.git;
364
+ const gitPrefs = loadEffectiveGSDPreferences(base)?.preferences?.git;
362
365
  const manageGitignore = gitPrefs?.manage_gitignore;
363
366
  ensureGitignore(base, { manageGitignore });
364
367
  if (manageGitignore !== false) untrackRuntimeFiles(base);
@@ -387,7 +390,7 @@ export async function bootstrapAutoSession(
387
390
  // Initialize GitServiceImpl
388
391
  s.gitService = new GitServiceImpl(
389
392
  s.basePath,
390
- loadEffectiveGSDPreferences()?.preferences?.git ?? {},
393
+ loadEffectiveGSDPreferences(base)?.preferences?.git ?? {},
391
394
  );
392
395
 
393
396
  // ── Debug mode ──
@@ -431,7 +434,7 @@ export async function bootstrapAutoSession(
431
434
  // was lost due to session ending between completion and teardown.
432
435
  // Must run after DB open and before worktree entry.
433
436
  try {
434
- const auditResult = auditOrphanedMilestoneBranches(base, getIsolationMode());
437
+ const auditResult = auditOrphanedMilestoneBranches(base, getIsolationMode(base));
435
438
  for (const msg of auditResult.recovered) {
436
439
  ctx.ui.notify(`Orphan audit: ${msg}`, "info");
437
440
  }
@@ -451,7 +454,7 @@ export async function bootstrapAutoSession(
451
454
  // Stale worktree state recovery (#654)
452
455
  if (
453
456
  state.activeMilestone &&
454
- shouldUseWorktreeIsolation() &&
457
+ shouldUseWorktreeIsolation(base) &&
455
458
  !detectWorktreeName(base)
456
459
  ) {
457
460
  const wtPath = getAutoWorktreePath(base, state.activeMilestone.id);
@@ -469,7 +472,7 @@ export async function bootstrapAutoSession(
469
472
  if (
470
473
  state.activeMilestone &&
471
474
  (state.phase === "pre-planning" || state.phase === "complete") &&
472
- getIsolationMode() !== "none" &&
475
+ getIsolationMode(base) !== "none" &&
473
476
  !detectWorktreeName(base) &&
474
477
  !base.includes(`${pathSep}.gsd${pathSep}worktrees${pathSep}`)
475
478
  ) {
@@ -550,37 +553,15 @@ export async function bootstrapAutoSession(
550
553
  const { showSmartEntry } = await import("./guided-flow.js");
551
554
  await showSmartEntry(ctx, pi, base, { step: requestedStepMode });
552
555
 
553
- invalidateAllCaches();
554
- const postState = await deriveState(base);
555
- if (
556
- postState.activeMilestone &&
557
- postState.phase !== "complete" &&
558
- postState.phase !== "pre-planning"
559
- ) {
560
- s.consecutiveCompleteBootstraps = 0; // Successfully advanced past "complete"
561
- state = postState;
562
- } else if (
563
- postState.activeMilestone &&
564
- postState.phase === "pre-planning"
565
- ) {
566
- const contextFile = resolveMilestoneFile(
567
- base,
568
- postState.activeMilestone.id,
569
- "CONTEXT",
570
- );
571
- const hasContext = !!(contextFile && (await loadFile(contextFile)));
572
- if (hasContext) {
573
- state = postState;
574
- } else {
575
- ctx.ui.notify(
576
- "Discussion completed but no milestone context was written. Run /gsd to try the discussion again, or /gsd auto after creating the milestone manually.",
577
- "warning",
578
- );
579
- return releaseLockAndReturn();
580
- }
581
- } else {
582
- return releaseLockAndReturn();
583
- }
556
+ // showSmartEntry dispatches via pi.sendMessage() which is fire-and-forget:
557
+ // it queues the message and returns immediately, before the LLM turn runs.
558
+ // Checking postState here would always see the pre-dispatch state, causing
559
+ // the premature "Discussion completed but..." warning (#3420).
560
+ //
561
+ // checkAutoStartAfterDiscuss (in guided-flow.ts) already handles re-entering
562
+ // auto-mode by calling startAutoDetached after the discussion completes.
563
+ // Release the lock and let the async dispatch proceed.
564
+ return releaseLockAndReturn();
584
565
  }
585
566
 
586
567
  // Active milestone exists but has no roadmap
@@ -592,17 +573,16 @@ export async function bootstrapAutoSession(
592
573
  const { showSmartEntry } = await import("./guided-flow.js");
593
574
  await showSmartEntry(ctx, pi, base, { step: requestedStepMode });
594
575
 
595
- invalidateAllCaches();
596
- const postState = await deriveState(base);
597
- if (postState.activeMilestone && postState.phase !== "pre-planning") {
598
- state = postState;
599
- } else {
600
- ctx.ui.notify(
601
- "Discussion completed but milestone context is still missing. Run /gsd to try again.",
602
- "warning",
603
- );
604
- return releaseLockAndReturn();
605
- }
576
+ // showSmartEntry dispatches via pi.sendMessage() which is fire-and-forget:
577
+ // it queues the message and returns immediately, before the LLM turn runs.
578
+ // Checking postState here fires before the LLM has had a turn, so the
579
+ // pre-planning phase would still appear unchanged and a premature warning
580
+ // would be emitted (#3420).
581
+ //
582
+ // checkAutoStartAfterDiscuss (in guided-flow.ts) already handles re-entering
583
+ // auto-mode by calling startAutoDetached after the discussion completes.
584
+ // Release the lock and let the async dispatch proceed.
585
+ return releaseLockAndReturn();
606
586
  }
607
587
  }
608
588
 
@@ -664,15 +644,16 @@ export async function bootstrapAutoSession(
664
644
  s.pendingQuickTasks = [];
665
645
  s.currentUnit = null;
666
646
  s.currentMilestoneId = state.activeMilestone?.id ?? null;
667
- s.originalModelId = ctx.model?.id ?? null;
668
- s.originalModelProvider = ctx.model?.provider ?? null;
647
+ s.originalModelId = startModelSnapshot?.id ?? ctx.model?.id ?? null;
648
+ s.originalModelProvider = startModelSnapshot?.provider ?? ctx.model?.provider ?? null;
649
+ s.originalThinkingLevel = startThinkingSnapshot ?? null;
669
650
 
670
651
  // Register SIGTERM handler
671
652
  registerSigtermHandler(base);
672
653
 
673
654
  // Capture integration branch
674
655
  if (s.currentMilestoneId) {
675
- if (getIsolationMode() !== "none") {
656
+ if (getIsolationMode(base) !== "none") {
676
657
  captureIntegrationBranch(base, s.currentMilestoneId);
677
658
  }
678
659
  setActiveMilestoneId(base, s.currentMilestoneId);
@@ -681,7 +662,7 @@ export async function bootstrapAutoSession(
681
662
  // Guard against stale milestone branch when isolation:none (#3613).
682
663
  // A prior session with isolation:branch/worktree may have left HEAD on
683
664
  // milestone/<MID>. Auto-checkout back to the integration branch.
684
- if (getIsolationMode() === "none" && nativeIsRepo(base)) {
665
+ if (getIsolationMode(base) === "none" && nativeIsRepo(base)) {
685
666
  try {
686
667
  const currentBranch = nativeGetCurrentBranch(base);
687
668
  if (currentBranch.startsWith("milestone/")) {
@@ -712,7 +693,7 @@ export async function bootstrapAutoSession(
712
693
 
713
694
  if (
714
695
  s.currentMilestoneId &&
715
- getIsolationMode() !== "none" &&
696
+ getIsolationMode(base) !== "none" &&
716
697
  !detectWorktreeName(base) &&
717
698
  !isUnderGsdWorktrees(base)
718
699
  ) {
@@ -758,9 +739,22 @@ export async function bootstrapAutoSession(
758
739
  // call returns "db_unavailable", triggering artifact-retry which
759
740
  // re-dispatches the same task — producing an infinite loop (#2419).
760
741
  if (existsSync(gsdDbPath) && !isDbAvailable()) {
742
+ const dbStatus = getDbStatus();
743
+ const phaseHint = dbStatus.lastPhase === "open"
744
+ ? "The database file could not be opened"
745
+ : dbStatus.lastPhase === "initSchema"
746
+ ? "The database schema could not be initialized"
747
+ : dbStatus.lastPhase === "vacuum-recovery"
748
+ ? "Corruption recovery (VACUUM) failed"
749
+ : dbStatus.attempted
750
+ ? "The database could not be opened (phase unknown)"
751
+ : "The database provider could not be loaded";
752
+ const errorDetail = dbStatus.lastError ? ` (${dbStatus.lastError.message})` : "";
753
+ const providerHint = dbStatus.provider
754
+ ? ` Provider: ${dbStatus.provider}.`
755
+ : " No SQLite provider available — check Node >= 22 or install better-sqlite3.";
761
756
  ctx.ui.notify(
762
- "SQLite database exists but failed to open. Auto-mode cannot proceed without a working database provider. " +
763
- "Check for corrupt gsd.db or missing native SQLite bindings.",
757
+ `SQLite database exists but failed to open: ${gsdDbPath}. ${phaseHint}${errorDetail}.${providerHint}`,
764
758
  "error",
765
759
  );
766
760
  return releaseLockAndReturn();
@@ -779,6 +773,7 @@ export async function bootstrapAutoSession(
779
773
  id: startModelSnapshot.id,
780
774
  };
781
775
  }
776
+ s.autoModeStartThinkingLevel = startThinkingSnapshot ?? null;
782
777
  s.manualSessionModelOverride = manualSessionOverride ?? null;
783
778
 
784
779
  // Apply worker model override from parallel orchestrator (#worker-model).
@@ -801,14 +796,11 @@ export async function bootstrapAutoSession(
801
796
  }
802
797
 
803
798
  // Snapshot installed skills
804
- if (resolveSkillDiscoveryMode() !== "off") {
799
+ if (resolveSkillDiscoveryMode(base) !== "off") {
805
800
  snapshotSkills();
806
801
  }
807
802
 
808
803
  ctx.ui.setStatus("gsd-auto", s.stepMode ? "next" : "auto");
809
- ctx.ui.setFooter(hideFooter);
810
- // Hide gsd-health during AUTO — gsd-progress is the single source of truth
811
- // for last-commit / cost / health signal while auto is running.
812
804
  ctx.ui.setWidget("gsd-health", undefined);
813
805
  const modeLabel = s.stepMode ? "Step-mode" : "Auto-mode";
814
806
  const pendingCount = (state.registry ?? []).filter(
@@ -835,7 +827,7 @@ export async function bootstrapAutoSession(
835
827
  // FlatRateContext used by selectAndApplyModel so user-declared
836
828
  // flat-rate providers and externalCli auto-detection are respected.
837
829
  const { isFlatRateProvider, buildFlatRateContext } = await import("./auto-model-selection.js");
838
- const bannerPrefs = loadEffectiveGSDPreferences()?.preferences;
830
+ const bannerPrefs = loadEffectiveGSDPreferences(base)?.preferences;
839
831
  const effectiveProvider = s.autoModeStartModel?.provider ?? ctx.model?.provider;
840
832
  const effectivelyEnabled = routingConfig.enabled
841
833
  && (routingConfig.allow_flat_rate_providers