gsd-pi 2.76.0 → 2.77.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (536) hide show
  1. package/README.md +45 -25
  2. package/dist/claude-cli-check.js +32 -3
  3. package/dist/mcp-server.d.ts +7 -0
  4. package/dist/mcp-server.js +35 -1
  5. package/dist/onboarding.js +45 -0
  6. package/dist/resource-loader.d.ts +1 -1
  7. package/dist/resource-loader.js +2 -8
  8. package/dist/resources/agents/researcher.md +1 -1
  9. package/dist/resources/extensions/claude-code-cli/readiness.js +31 -8
  10. package/dist/resources/extensions/claude-code-cli/stream-adapter.js +77 -17
  11. package/dist/resources/extensions/gsd/auto/loop.js +9 -0
  12. package/dist/resources/extensions/gsd/auto/phases.js +104 -11
  13. package/dist/resources/extensions/gsd/auto/run-unit.js +38 -2
  14. package/dist/resources/extensions/gsd/auto/session.js +22 -1
  15. package/dist/resources/extensions/gsd/auto-dispatch.js +16 -3
  16. package/dist/resources/extensions/gsd/auto-model-selection.js +53 -16
  17. package/dist/resources/extensions/gsd/auto-post-unit.js +25 -2
  18. package/dist/resources/extensions/gsd/auto-prompts.js +14 -0
  19. package/dist/resources/extensions/gsd/auto-recovery.js +32 -1
  20. package/dist/resources/extensions/gsd/auto-start.js +58 -57
  21. package/dist/resources/extensions/gsd/auto-verification.js +33 -0
  22. package/dist/resources/extensions/gsd/auto-worktree.js +51 -53
  23. package/dist/resources/extensions/gsd/auto.js +70 -28
  24. package/dist/resources/extensions/gsd/blocked-models.js +68 -0
  25. package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +93 -1
  26. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +39 -9
  27. package/dist/resources/extensions/gsd/bootstrap/exec-tools.js +93 -0
  28. package/dist/resources/extensions/gsd/bootstrap/memory-tools.js +3 -0
  29. package/dist/resources/extensions/gsd/bootstrap/register-extension.js +12 -0
  30. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +52 -6
  31. package/dist/resources/extensions/gsd/bootstrap/system-context.js +84 -23
  32. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +34 -2
  33. package/dist/resources/extensions/gsd/clean-root-preflight.js +93 -0
  34. package/dist/resources/extensions/gsd/commands-extract-learnings.js +54 -89
  35. package/dist/resources/extensions/gsd/commands-prefs-wizard.js +968 -23
  36. package/dist/resources/extensions/gsd/compaction-snapshot.js +121 -0
  37. package/dist/resources/extensions/gsd/complexity-classifier.js +5 -3
  38. package/dist/resources/extensions/gsd/db-writer.js +88 -16
  39. package/dist/resources/extensions/gsd/doctor-git-checks.js +23 -29
  40. package/dist/resources/extensions/gsd/doctor-providers.js +51 -5
  41. package/dist/resources/extensions/gsd/ecosystem/gsd-extension-api.js +1 -0
  42. package/dist/resources/extensions/gsd/error-classifier.js +31 -3
  43. package/dist/resources/extensions/gsd/exec-history.js +120 -0
  44. package/dist/resources/extensions/gsd/exec-sandbox.js +258 -0
  45. package/dist/resources/extensions/gsd/gitignore.js +1 -0
  46. package/dist/resources/extensions/gsd/gsd-db.js +168 -23
  47. package/dist/resources/extensions/gsd/guided-flow.js +190 -1
  48. package/dist/resources/extensions/gsd/health-widget.js +4 -1
  49. package/dist/resources/extensions/gsd/hook-emitter.js +108 -0
  50. package/dist/resources/extensions/gsd/init-wizard.js +15 -1
  51. package/dist/resources/extensions/gsd/key-manager.js +28 -0
  52. package/dist/resources/extensions/gsd/memory-backfill.js +126 -0
  53. package/dist/resources/extensions/gsd/memory-store.js +19 -0
  54. package/dist/resources/extensions/gsd/model-router.js +36 -3
  55. package/dist/resources/extensions/gsd/pre-execution-checks.js +44 -9
  56. package/dist/resources/extensions/gsd/preferences-types.js +9 -0
  57. package/dist/resources/extensions/gsd/preferences-validation.js +83 -0
  58. package/dist/resources/extensions/gsd/preferences.js +17 -17
  59. package/dist/resources/extensions/gsd/prompt-loader.js +22 -7
  60. package/dist/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
  61. package/dist/resources/extensions/gsd/prompts/complete-slice.md +2 -2
  62. package/dist/resources/extensions/gsd/prompts/debug-diagnose.md +2 -0
  63. package/dist/resources/extensions/gsd/prompts/discuss-headless.md +8 -0
  64. package/dist/resources/extensions/gsd/prompts/discuss.md +29 -2
  65. package/dist/resources/extensions/gsd/prompts/execute-task.md +3 -2
  66. package/dist/resources/extensions/gsd/prompts/parallel-research-slices.md +5 -2
  67. package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -0
  68. package/dist/resources/extensions/gsd/prompts/research-slice.md +1 -0
  69. package/dist/resources/extensions/gsd/safety/evidence-collector.js +96 -0
  70. package/dist/resources/extensions/gsd/safety/file-change-validator.js +13 -5
  71. package/dist/resources/extensions/gsd/safety/safety-harness.js +5 -1
  72. package/dist/resources/extensions/gsd/state.js +43 -4
  73. package/dist/resources/extensions/gsd/token-counter.js +22 -5
  74. package/dist/resources/extensions/gsd/tools/complete-milestone.js +16 -10
  75. package/dist/resources/extensions/gsd/tools/exec-search-tool.js +59 -0
  76. package/dist/resources/extensions/gsd/tools/exec-tool.js +126 -0
  77. package/dist/resources/extensions/gsd/tools/memory-tools.js +26 -1
  78. package/dist/resources/extensions/gsd/tools/resume-tool.js +23 -0
  79. package/dist/resources/extensions/gsd/uok/plan-v2.js +20 -3
  80. package/dist/resources/extensions/gsd/workflow-mcp.js +3 -0
  81. package/dist/resources/extensions/gsd/workflow-templates/spike.md +6 -0
  82. package/dist/resources/extensions/gsd/worktree-resolver.js +50 -10
  83. package/dist/resources/extensions/search-the-web/command-search-provider.js +5 -4
  84. package/dist/resources/extensions/search-the-web/native-search.js +45 -13
  85. package/dist/resources/skills/api-design/SKILL.md +190 -0
  86. package/dist/resources/skills/create-mcp-server/SKILL.md +121 -0
  87. package/dist/resources/skills/decompose-into-slices/SKILL.md +139 -0
  88. package/dist/resources/skills/dependency-upgrade/SKILL.md +158 -0
  89. package/dist/resources/skills/design-an-interface/SKILL.md +102 -0
  90. package/dist/resources/skills/forensics/SKILL.md +153 -0
  91. package/dist/resources/skills/grill-me/SKILL.md +93 -0
  92. package/dist/resources/skills/handoff/SKILL.md +121 -0
  93. package/dist/resources/skills/observability/SKILL.md +174 -0
  94. package/dist/resources/skills/security-review/SKILL.md +181 -0
  95. package/dist/resources/skills/spike-wrap-up/SKILL.md +138 -0
  96. package/dist/resources/skills/tdd/SKILL.md +112 -0
  97. package/dist/resources/skills/verify-before-complete/SKILL.md +98 -0
  98. package/dist/resources/skills/write-docs/SKILL.md +82 -0
  99. package/dist/resources/skills/write-milestone-brief/SKILL.md +135 -0
  100. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  101. package/dist/web/standalone/.next/BUILD_ID +1 -1
  102. package/dist/web/standalone/.next/app-path-routes-manifest.json +10 -10
  103. package/dist/web/standalone/.next/build-manifest.json +2 -2
  104. package/dist/web/standalone/.next/required-server-files.json +1 -1
  105. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  106. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  107. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  108. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  109. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  110. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  111. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  112. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  113. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  114. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  115. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  116. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  117. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  118. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  119. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  120. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  121. package/dist/web/standalone/.next/server/app/index.html +1 -1
  122. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  123. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  124. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  125. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  126. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  127. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  128. package/dist/web/standalone/.next/server/app-paths-manifest.json +10 -10
  129. package/dist/web/standalone/.next/server/chunks/6897.js +2 -2
  130. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  131. package/dist/web/standalone/.next/server/middleware-manifest.json +1 -1
  132. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  133. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  134. package/dist/web/standalone/server.js +1 -1
  135. package/dist/welcome-screen.js +6 -1
  136. package/dist/wizard.js +2 -0
  137. package/package.json +1 -1
  138. package/packages/daemon/package.json +2 -2
  139. package/packages/mcp-server/dist/remote-questions.d.ts +45 -0
  140. package/packages/mcp-server/dist/remote-questions.d.ts.map +1 -0
  141. package/packages/mcp-server/dist/remote-questions.js +732 -0
  142. package/packages/mcp-server/dist/remote-questions.js.map +1 -0
  143. package/packages/mcp-server/dist/server.d.ts +7 -0
  144. package/packages/mcp-server/dist/server.d.ts.map +1 -1
  145. package/packages/mcp-server/dist/server.js +70 -8
  146. package/packages/mcp-server/dist/server.js.map +1 -1
  147. package/packages/mcp-server/dist/session-manager.d.ts +14 -0
  148. package/packages/mcp-server/dist/session-manager.d.ts.map +1 -1
  149. package/packages/mcp-server/dist/session-manager.js +49 -1
  150. package/packages/mcp-server/dist/session-manager.js.map +1 -1
  151. package/packages/mcp-server/dist/workflow-tools.d.ts +1 -1
  152. package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
  153. package/packages/mcp-server/dist/workflow-tools.js +163 -25
  154. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  155. package/packages/mcp-server/package.json +4 -3
  156. package/packages/mcp-server/src/mcp-server.test.ts +67 -0
  157. package/packages/mcp-server/src/remote-questions.test.ts +294 -0
  158. package/packages/mcp-server/src/remote-questions.ts +916 -0
  159. package/packages/mcp-server/src/server.ts +89 -14
  160. package/packages/mcp-server/src/session-manager.ts +43 -1
  161. package/packages/mcp-server/src/workflow-tools.test.ts +146 -1
  162. package/packages/mcp-server/src/workflow-tools.ts +215 -43
  163. package/packages/mcp-server/tsconfig.test.json +19 -0
  164. package/packages/mcp-server/tsconfig.tsbuildinfo +1 -1
  165. package/packages/native/package.json +1 -1
  166. package/packages/pi-agent-core/dist/agent-loop.js +12 -0
  167. package/packages/pi-agent-core/dist/agent-loop.js.map +1 -1
  168. package/packages/pi-agent-core/dist/types.d.ts +30 -0
  169. package/packages/pi-agent-core/dist/types.d.ts.map +1 -1
  170. package/packages/pi-agent-core/dist/types.js.map +1 -1
  171. package/packages/pi-agent-core/package.json +1 -1
  172. package/packages/pi-agent-core/src/agent-loop.ts +14 -0
  173. package/packages/pi-agent-core/src/types.ts +34 -0
  174. package/packages/pi-agent-core/tsconfig.tsbuildinfo +1 -1
  175. package/packages/pi-ai/dist/models/custom.d.ts +38 -0
  176. package/packages/pi-ai/dist/models/custom.d.ts.map +1 -1
  177. package/packages/pi-ai/dist/models/custom.js +41 -0
  178. package/packages/pi-ai/dist/models/custom.js.map +1 -1
  179. package/packages/pi-ai/dist/providers/anthropic-auth.test.js +1 -1
  180. package/packages/pi-ai/dist/providers/anthropic-auth.test.js.map +1 -1
  181. package/packages/pi-ai/dist/providers/anthropic-bearer-auth.test.d.ts +2 -0
  182. package/packages/pi-ai/dist/providers/anthropic-bearer-auth.test.d.ts.map +1 -0
  183. package/packages/pi-ai/dist/providers/anthropic-bearer-auth.test.js +13 -0
  184. package/packages/pi-ai/dist/providers/anthropic-bearer-auth.test.js.map +1 -0
  185. package/packages/pi-ai/dist/providers/anthropic-shared.d.ts.map +1 -1
  186. package/packages/pi-ai/dist/providers/anthropic-shared.js +27 -4
  187. package/packages/pi-ai/dist/providers/anthropic-shared.js.map +1 -1
  188. package/packages/pi-ai/dist/providers/anthropic.d.ts.map +1 -1
  189. package/packages/pi-ai/dist/providers/anthropic.js +13 -4
  190. package/packages/pi-ai/dist/providers/anthropic.js.map +1 -1
  191. package/packages/pi-ai/dist/providers/minimax-tool-name.test.d.ts +2 -0
  192. package/packages/pi-ai/dist/providers/minimax-tool-name.test.d.ts.map +1 -0
  193. package/packages/pi-ai/dist/providers/minimax-tool-name.test.js +80 -0
  194. package/packages/pi-ai/dist/providers/minimax-tool-name.test.js.map +1 -0
  195. package/packages/pi-ai/dist/providers/openai-completions.d.ts.map +1 -1
  196. package/packages/pi-ai/dist/providers/openai-completions.js +60 -15
  197. package/packages/pi-ai/dist/providers/openai-completions.js.map +1 -1
  198. package/packages/pi-ai/dist/providers/simple-options.d.ts +10 -0
  199. package/packages/pi-ai/dist/providers/simple-options.d.ts.map +1 -1
  200. package/packages/pi-ai/dist/providers/simple-options.js +16 -1
  201. package/packages/pi-ai/dist/providers/simple-options.js.map +1 -1
  202. package/packages/pi-ai/dist/providers/think-tag-parser.d.ts +17 -0
  203. package/packages/pi-ai/dist/providers/think-tag-parser.d.ts.map +1 -0
  204. package/packages/pi-ai/dist/providers/think-tag-parser.js +75 -0
  205. package/packages/pi-ai/dist/providers/think-tag-parser.js.map +1 -0
  206. package/packages/pi-ai/dist/providers/think-tag-parser.test.d.ts +2 -0
  207. package/packages/pi-ai/dist/providers/think-tag-parser.test.d.ts.map +1 -0
  208. package/packages/pi-ai/dist/providers/think-tag-parser.test.js +41 -0
  209. package/packages/pi-ai/dist/providers/think-tag-parser.test.js.map +1 -0
  210. package/packages/pi-ai/dist/utils/oauth/github-copilot.d.ts.map +1 -1
  211. package/packages/pi-ai/dist/utils/oauth/github-copilot.js +12 -2
  212. package/packages/pi-ai/dist/utils/oauth/github-copilot.js.map +1 -1
  213. package/packages/pi-ai/dist/utils/oauth/github-copilot.test.js +164 -14
  214. package/packages/pi-ai/dist/utils/oauth/github-copilot.test.js.map +1 -1
  215. package/packages/pi-ai/dist/utils/oauth/google-antigravity.d.ts.map +1 -1
  216. package/packages/pi-ai/dist/utils/oauth/google-antigravity.js +15 -3
  217. package/packages/pi-ai/dist/utils/oauth/google-antigravity.js.map +1 -1
  218. package/packages/pi-ai/dist/utils/oauth/google-antigravity.test.d.ts +2 -0
  219. package/packages/pi-ai/dist/utils/oauth/google-antigravity.test.d.ts.map +1 -0
  220. package/packages/pi-ai/dist/utils/oauth/google-antigravity.test.js +67 -0
  221. package/packages/pi-ai/dist/utils/oauth/google-antigravity.test.js.map +1 -0
  222. package/packages/pi-ai/dist/utils/oauth/google-gemini-cli.d.ts.map +1 -1
  223. package/packages/pi-ai/dist/utils/oauth/google-gemini-cli.js +16 -3
  224. package/packages/pi-ai/dist/utils/oauth/google-gemini-cli.js.map +1 -1
  225. package/packages/pi-ai/dist/utils/oauth/google-gemini-cli.test.d.ts +2 -0
  226. package/packages/pi-ai/dist/utils/oauth/google-gemini-cli.test.d.ts.map +1 -0
  227. package/packages/pi-ai/dist/utils/oauth/google-gemini-cli.test.js +67 -0
  228. package/packages/pi-ai/dist/utils/oauth/google-gemini-cli.test.js.map +1 -0
  229. package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.d.ts +2 -0
  230. package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.d.ts.map +1 -0
  231. package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.js +289 -0
  232. package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.js.map +1 -0
  233. package/packages/pi-ai/package.json +1 -1
  234. package/packages/pi-ai/src/models/custom.ts +42 -0
  235. package/packages/pi-ai/src/providers/anthropic-auth.test.ts +1 -1
  236. package/packages/pi-ai/src/providers/anthropic-bearer-auth.test.ts +26 -0
  237. package/packages/pi-ai/src/providers/anthropic-shared.ts +26 -5
  238. package/packages/pi-ai/src/providers/anthropic.ts +15 -4
  239. package/packages/pi-ai/src/providers/minimax-tool-name.test.ts +98 -0
  240. package/packages/pi-ai/src/providers/openai-completions.ts +57 -16
  241. package/packages/pi-ai/src/providers/simple-options.ts +17 -1
  242. package/packages/pi-ai/src/providers/think-tag-parser.test.ts +44 -0
  243. package/packages/pi-ai/src/providers/think-tag-parser.ts +94 -0
  244. package/packages/pi-ai/src/utils/oauth/github-copilot.test.ts +200 -23
  245. package/packages/pi-ai/src/utils/oauth/github-copilot.ts +12 -2
  246. package/packages/pi-ai/src/utils/oauth/google-antigravity.test.ts +84 -0
  247. package/packages/pi-ai/src/utils/oauth/google-antigravity.ts +15 -5
  248. package/packages/pi-ai/src/utils/oauth/google-gemini-cli.test.ts +84 -0
  249. package/packages/pi-ai/src/utils/oauth/google-gemini-cli.ts +16 -5
  250. package/packages/pi-ai/src/utils/oauth/oauth-providers.test.ts +363 -0
  251. package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
  252. package/packages/pi-coding-agent/dist/core/agent-session-abort-order.test.js +3 -2
  253. package/packages/pi-coding-agent/dist/core/agent-session-abort-order.test.js.map +1 -1
  254. package/packages/pi-coding-agent/dist/core/agent-session.d.ts +2 -0
  255. package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
  256. package/packages/pi-coding-agent/dist/core/agent-session.js +32 -2
  257. package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
  258. package/packages/pi-coding-agent/dist/core/extensions/index.d.ts +1 -1
  259. package/packages/pi-coding-agent/dist/core/extensions/index.d.ts.map +1 -1
  260. package/packages/pi-coding-agent/dist/core/extensions/index.js.map +1 -1
  261. package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts.map +1 -1
  262. package/packages/pi-coding-agent/dist/core/extensions/loader.js +4 -0
  263. package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
  264. package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts +35 -2
  265. package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts.map +1 -1
  266. package/packages/pi-coding-agent/dist/core/extensions/runner.js +233 -0
  267. package/packages/pi-coding-agent/dist/core/extensions/runner.js.map +1 -1
  268. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts +205 -2
  269. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts.map +1 -1
  270. package/packages/pi-coding-agent/dist/core/extensions/types.js.map +1 -1
  271. package/packages/pi-coding-agent/dist/core/hooks-runner.d.ts +53 -0
  272. package/packages/pi-coding-agent/dist/core/hooks-runner.d.ts.map +1 -0
  273. package/packages/pi-coding-agent/dist/core/hooks-runner.js +337 -0
  274. package/packages/pi-coding-agent/dist/core/hooks-runner.js.map +1 -0
  275. package/packages/pi-coding-agent/dist/core/hooks-runner.test.d.ts +2 -0
  276. package/packages/pi-coding-agent/dist/core/hooks-runner.test.d.ts.map +1 -0
  277. package/packages/pi-coding-agent/dist/core/hooks-runner.test.js +234 -0
  278. package/packages/pi-coding-agent/dist/core/hooks-runner.test.js.map +1 -0
  279. package/packages/pi-coding-agent/dist/core/index.d.ts +1 -0
  280. package/packages/pi-coding-agent/dist/core/index.d.ts.map +1 -1
  281. package/packages/pi-coding-agent/dist/core/index.js +1 -0
  282. package/packages/pi-coding-agent/dist/core/index.js.map +1 -1
  283. package/packages/pi-coding-agent/dist/core/model-discovery.d.ts +3 -1
  284. package/packages/pi-coding-agent/dist/core/model-discovery.d.ts.map +1 -1
  285. package/packages/pi-coding-agent/dist/core/model-discovery.js +92 -12
  286. package/packages/pi-coding-agent/dist/core/model-discovery.js.map +1 -1
  287. package/packages/pi-coding-agent/dist/core/model-discovery.test.js +16 -1
  288. package/packages/pi-coding-agent/dist/core/model-discovery.test.js.map +1 -1
  289. package/packages/pi-coding-agent/dist/core/model-registry-auth-header.test.d.ts +2 -0
  290. package/packages/pi-coding-agent/dist/core/model-registry-auth-header.test.d.ts.map +1 -0
  291. package/packages/pi-coding-agent/dist/core/model-registry-auth-header.test.js +40 -0
  292. package/packages/pi-coding-agent/dist/core/model-registry-auth-header.test.js.map +1 -0
  293. package/packages/pi-coding-agent/dist/core/model-registry-custom-caps.test.d.ts +2 -0
  294. package/packages/pi-coding-agent/dist/core/model-registry-custom-caps.test.d.ts.map +1 -0
  295. package/packages/pi-coding-agent/dist/core/model-registry-custom-caps.test.js +203 -0
  296. package/packages/pi-coding-agent/dist/core/model-registry-custom-caps.test.js.map +1 -0
  297. package/packages/pi-coding-agent/dist/core/model-registry-discovery.test.js +61 -1
  298. package/packages/pi-coding-agent/dist/core/model-registry-discovery.test.js.map +1 -1
  299. package/packages/pi-coding-agent/dist/core/model-registry.d.ts +5 -0
  300. package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
  301. package/packages/pi-coding-agent/dist/core/model-registry.js +90 -10
  302. package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
  303. package/packages/pi-coding-agent/dist/core/redact-secrets.d.ts +2 -0
  304. package/packages/pi-coding-agent/dist/core/redact-secrets.d.ts.map +1 -0
  305. package/packages/pi-coding-agent/dist/core/redact-secrets.js +49 -0
  306. package/packages/pi-coding-agent/dist/core/redact-secrets.js.map +1 -0
  307. package/packages/pi-coding-agent/dist/core/redact-secrets.test.d.ts +2 -0
  308. package/packages/pi-coding-agent/dist/core/redact-secrets.test.d.ts.map +1 -0
  309. package/packages/pi-coding-agent/dist/core/redact-secrets.test.js +67 -0
  310. package/packages/pi-coding-agent/dist/core/redact-secrets.test.js.map +1 -0
  311. package/packages/pi-coding-agent/dist/core/session-manager.d.ts.map +1 -1
  312. package/packages/pi-coding-agent/dist/core/session-manager.js +10 -6
  313. package/packages/pi-coding-agent/dist/core/session-manager.js.map +1 -1
  314. package/packages/pi-coding-agent/dist/core/session-manager.test.js +45 -1
  315. package/packages/pi-coding-agent/dist/core/session-manager.test.js.map +1 -1
  316. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +55 -0
  317. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
  318. package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
  319. package/packages/pi-coding-agent/dist/index.d.ts +1 -1
  320. package/packages/pi-coding-agent/dist/index.d.ts.map +1 -1
  321. package/packages/pi-coding-agent/dist/index.js.map +1 -1
  322. package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.d.ts +1 -1
  323. package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.d.ts.map +1 -1
  324. package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.js +5 -4
  325. package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.js.map +1 -1
  326. package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.d.ts.map +1 -1
  327. package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.js +13 -7
  328. package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.js.map +1 -1
  329. package/packages/pi-coding-agent/dist/modes/interactive/components/skill-invocation-message.d.ts +7 -6
  330. package/packages/pi-coding-agent/dist/modes/interactive/components/skill-invocation-message.d.ts.map +1 -1
  331. package/packages/pi-coding-agent/dist/modes/interactive/components/skill-invocation-message.js +29 -21
  332. package/packages/pi-coding-agent/dist/modes/interactive/components/skill-invocation-message.js.map +1 -1
  333. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  334. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +13 -1
  335. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  336. package/packages/pi-coding-agent/package.json +1 -1
  337. package/packages/pi-coding-agent/src/core/agent-session-abort-order.test.ts +3 -2
  338. package/packages/pi-coding-agent/src/core/agent-session.ts +38 -2
  339. package/packages/pi-coding-agent/src/core/extensions/index.ts +16 -0
  340. package/packages/pi-coding-agent/src/core/extensions/loader.ts +5 -0
  341. package/packages/pi-coding-agent/src/core/extensions/runner.ts +351 -0
  342. package/packages/pi-coding-agent/src/core/extensions/types.ts +258 -0
  343. package/packages/pi-coding-agent/src/core/hooks-runner.test.ts +269 -0
  344. package/packages/pi-coding-agent/src/core/hooks-runner.ts +460 -0
  345. package/packages/pi-coding-agent/src/core/index.ts +10 -0
  346. package/packages/pi-coding-agent/src/core/model-discovery.test.ts +19 -0
  347. package/packages/pi-coding-agent/src/core/model-discovery.ts +99 -12
  348. package/packages/pi-coding-agent/src/core/model-registry-auth-header.test.ts +44 -0
  349. package/packages/pi-coding-agent/src/core/model-registry-custom-caps.test.ts +245 -0
  350. package/packages/pi-coding-agent/src/core/model-registry-discovery.test.ts +75 -0
  351. package/packages/pi-coding-agent/src/core/model-registry.ts +102 -10
  352. package/packages/pi-coding-agent/src/core/redact-secrets.test.ts +86 -0
  353. package/packages/pi-coding-agent/src/core/redact-secrets.ts +58 -0
  354. package/packages/pi-coding-agent/src/core/session-manager.test.ts +65 -1
  355. package/packages/pi-coding-agent/src/core/session-manager.ts +10 -6
  356. package/packages/pi-coding-agent/src/core/settings-manager.ts +57 -0
  357. package/packages/pi-coding-agent/src/index.ts +16 -0
  358. package/packages/pi-coding-agent/src/modes/interactive/components/chat-frame.ts +6 -6
  359. package/packages/pi-coding-agent/src/modes/interactive/components/provider-manager.ts +16 -7
  360. package/packages/pi-coding-agent/src/modes/interactive/components/skill-invocation-message.ts +36 -22
  361. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +13 -1
  362. package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
  363. package/packages/pi-tui/package.json +1 -1
  364. package/packages/rpc-client/package.json +1 -1
  365. package/pkg/package.json +1 -1
  366. package/scripts/link-workspace-packages.cjs +1 -0
  367. package/src/resources/agents/researcher.md +1 -1
  368. package/src/resources/extensions/claude-code-cli/readiness.ts +32 -8
  369. package/src/resources/extensions/claude-code-cli/stream-adapter.ts +78 -17
  370. package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +149 -5
  371. package/src/resources/extensions/gsd/auto/loop-deps.ts +14 -0
  372. package/src/resources/extensions/gsd/auto/loop.ts +9 -0
  373. package/src/resources/extensions/gsd/auto/phases.ts +131 -10
  374. package/src/resources/extensions/gsd/auto/run-unit.ts +40 -2
  375. package/src/resources/extensions/gsd/auto/session.ts +35 -2
  376. package/src/resources/extensions/gsd/auto-dispatch.ts +16 -3
  377. package/src/resources/extensions/gsd/auto-model-selection.ts +71 -15
  378. package/src/resources/extensions/gsd/auto-post-unit.ts +29 -3
  379. package/src/resources/extensions/gsd/auto-prompts.ts +28 -1
  380. package/src/resources/extensions/gsd/auto-recovery.ts +26 -1
  381. package/src/resources/extensions/gsd/auto-start.ts +60 -68
  382. package/src/resources/extensions/gsd/auto-verification.ts +33 -0
  383. package/src/resources/extensions/gsd/auto-worktree.ts +62 -63
  384. package/src/resources/extensions/gsd/auto.ts +73 -28
  385. package/src/resources/extensions/gsd/blocked-models.ts +98 -0
  386. package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +120 -1
  387. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +40 -9
  388. package/src/resources/extensions/gsd/bootstrap/exec-tools.ts +109 -0
  389. package/src/resources/extensions/gsd/bootstrap/memory-tools.ts +5 -0
  390. package/src/resources/extensions/gsd/bootstrap/register-extension.ts +15 -0
  391. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +54 -6
  392. package/src/resources/extensions/gsd/bootstrap/system-context.ts +89 -26
  393. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +35 -2
  394. package/src/resources/extensions/gsd/clean-root-preflight.ts +111 -0
  395. package/src/resources/extensions/gsd/commands-extract-learnings.ts +55 -90
  396. package/src/resources/extensions/gsd/commands-prefs-wizard.ts +898 -32
  397. package/src/resources/extensions/gsd/compaction-snapshot.ts +165 -0
  398. package/src/resources/extensions/gsd/complexity-classifier.ts +5 -3
  399. package/src/resources/extensions/gsd/db-writer.ts +88 -17
  400. package/src/resources/extensions/gsd/doctor-git-checks.ts +23 -27
  401. package/src/resources/extensions/gsd/doctor-providers.ts +59 -6
  402. package/src/resources/extensions/gsd/ecosystem/gsd-extension-api.ts +2 -0
  403. package/src/resources/extensions/gsd/error-classifier.ts +36 -3
  404. package/src/resources/extensions/gsd/exec-history.ts +153 -0
  405. package/src/resources/extensions/gsd/exec-sandbox.ts +326 -0
  406. package/src/resources/extensions/gsd/gitignore.ts +1 -1
  407. package/src/resources/extensions/gsd/gsd-db.ts +186 -23
  408. package/src/resources/extensions/gsd/guided-flow.ts +222 -1
  409. package/src/resources/extensions/gsd/health-widget.ts +3 -1
  410. package/src/resources/extensions/gsd/hook-emitter.ts +188 -0
  411. package/src/resources/extensions/gsd/init-wizard.ts +15 -1
  412. package/src/resources/extensions/gsd/journal.ts +2 -1
  413. package/src/resources/extensions/gsd/key-manager.ts +28 -0
  414. package/src/resources/extensions/gsd/memory-backfill.ts +140 -0
  415. package/src/resources/extensions/gsd/memory-store.ts +26 -0
  416. package/src/resources/extensions/gsd/model-router.ts +42 -1
  417. package/src/resources/extensions/gsd/pre-execution-checks.ts +46 -10
  418. package/src/resources/extensions/gsd/preferences-types.ts +46 -0
  419. package/src/resources/extensions/gsd/preferences-validation.ts +79 -0
  420. package/src/resources/extensions/gsd/preferences.ts +17 -17
  421. package/src/resources/extensions/gsd/prompt-loader.ts +30 -7
  422. package/src/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
  423. package/src/resources/extensions/gsd/prompts/complete-slice.md +2 -2
  424. package/src/resources/extensions/gsd/prompts/debug-diagnose.md +2 -0
  425. package/src/resources/extensions/gsd/prompts/discuss-headless.md +8 -0
  426. package/src/resources/extensions/gsd/prompts/discuss.md +29 -2
  427. package/src/resources/extensions/gsd/prompts/execute-task.md +3 -2
  428. package/src/resources/extensions/gsd/prompts/parallel-research-slices.md +5 -2
  429. package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -0
  430. package/src/resources/extensions/gsd/prompts/research-slice.md +1 -0
  431. package/src/resources/extensions/gsd/safety/evidence-collector.ts +119 -0
  432. package/src/resources/extensions/gsd/safety/file-change-validator.ts +17 -4
  433. package/src/resources/extensions/gsd/safety/safety-harness.ts +9 -0
  434. package/src/resources/extensions/gsd/state.ts +45 -4
  435. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +188 -2
  436. package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +95 -1
  437. package/src/resources/extensions/gsd/tests/auto-paused-session-validation.test.ts +12 -0
  438. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +49 -0
  439. package/src/resources/extensions/gsd/tests/auto-start-bootstrap-await-3420.test.ts +141 -0
  440. package/src/resources/extensions/gsd/tests/auto-start-model-capture.test.ts +33 -3
  441. package/src/resources/extensions/gsd/tests/auto-thinking-restore.test.ts +38 -0
  442. package/src/resources/extensions/gsd/tests/auto-wrapup-inflight-guard.test.ts +23 -0
  443. package/src/resources/extensions/gsd/tests/blocked-models.test.ts +98 -0
  444. package/src/resources/extensions/gsd/tests/bundled-skill-triggers.test.ts +54 -0
  445. package/src/resources/extensions/gsd/tests/clean-root-preflight.test.ts +186 -0
  446. package/src/resources/extensions/gsd/tests/commands-extract-learnings.test.ts +68 -66
  447. package/src/resources/extensions/gsd/tests/compaction-snapshot.test.ts +123 -0
  448. package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +61 -1
  449. package/src/resources/extensions/gsd/tests/complete-slice.test.ts +2 -2
  450. package/src/resources/extensions/gsd/tests/complete-task.test.ts +2 -2
  451. package/src/resources/extensions/gsd/tests/complexity-classifier.test.ts +3 -3
  452. package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +2 -0
  453. package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +42 -0
  454. package/src/resources/extensions/gsd/tests/derive-state-helpers.test.ts +8 -4
  455. package/src/resources/extensions/gsd/tests/doctor-providers.test.ts +148 -3
  456. package/src/resources/extensions/gsd/tests/double-merge-guard.test.ts +1 -1
  457. package/src/resources/extensions/gsd/tests/ensure-db-open.test.ts +306 -1
  458. package/src/resources/extensions/gsd/tests/escalation.test.ts +1 -1
  459. package/src/resources/extensions/gsd/tests/exec-history.test.ts +237 -0
  460. package/src/resources/extensions/gsd/tests/exec-sandbox.test.ts +210 -0
  461. package/src/resources/extensions/gsd/tests/file-change-validator.test.ts +58 -0
  462. package/src/resources/extensions/gsd/tests/flat-rate-routing-guard.test.ts +40 -9
  463. package/src/resources/extensions/gsd/tests/freeform-decisions.test.ts +62 -0
  464. package/src/resources/extensions/gsd/tests/gsd-db.test.ts +447 -1
  465. package/src/resources/extensions/gsd/tests/init-wizard.test.ts +27 -0
  466. package/src/resources/extensions/gsd/tests/integration/doctor-git-symlink-cwd.test.ts +11 -0
  467. package/src/resources/extensions/gsd/tests/integration/doctor-git.test.ts +78 -0
  468. package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +1 -0
  469. package/src/resources/extensions/gsd/tests/integration/gitignore-tracked-gsd.test.ts +1 -0
  470. package/src/resources/extensions/gsd/tests/integration/idle-recovery.test.ts +30 -0
  471. package/src/resources/extensions/gsd/tests/interactive-routing-bypass.test.ts +1 -1
  472. package/src/resources/extensions/gsd/tests/isolation-none-branch-guard.test.ts +1 -1
  473. package/src/resources/extensions/gsd/tests/issue-4540-regressions.test.ts +288 -0
  474. package/src/resources/extensions/gsd/tests/journal-integration.test.ts +37 -0
  475. package/src/resources/extensions/gsd/tests/key-manager.test.ts +9 -0
  476. package/src/resources/extensions/gsd/tests/load-memory-block.test.ts +36 -0
  477. package/src/resources/extensions/gsd/tests/md-importer.test.ts +1 -1
  478. package/src/resources/extensions/gsd/tests/memory-pressure-stuck-state.test.ts +12 -0
  479. package/src/resources/extensions/gsd/tests/memory-store.test.ts +2 -2
  480. package/src/resources/extensions/gsd/tests/parallel-research-dispatch.test.ts +19 -0
  481. package/src/resources/extensions/gsd/tests/plan-gate-failed-doctor-heal-hint.test.ts +37 -0
  482. package/src/resources/extensions/gsd/tests/pre-exec-backtick-strip.test.ts +14 -0
  483. package/src/resources/extensions/gsd/tests/pre-exec-gate-loop.test.ts +272 -0
  484. package/src/resources/extensions/gsd/tests/pre-execution-checks.test.ts +356 -0
  485. package/src/resources/extensions/gsd/tests/preferences.test.ts +110 -0
  486. package/src/resources/extensions/gsd/tests/prefs-wizard-coverage.test.ts +44 -0
  487. package/src/resources/extensions/gsd/tests/prompt-loader-extension-dir.test.ts +49 -0
  488. package/src/resources/extensions/gsd/tests/provider-errors.test.ts +103 -4
  489. package/src/resources/extensions/gsd/tests/ready-phrase-no-files-4573.test.ts +388 -0
  490. package/src/resources/extensions/gsd/tests/restore-tools-after-discuss.test.ts +9 -3
  491. package/src/resources/extensions/gsd/tests/resume-dispatch-worktree.test.ts +230 -0
  492. package/src/resources/extensions/gsd/tests/safety-harness-false-positives.test.ts +205 -0
  493. package/src/resources/extensions/gsd/tests/save-gate-result-render.test.ts +95 -0
  494. package/src/resources/extensions/gsd/tests/schema-v21-sequence.test.ts +413 -0
  495. package/src/resources/extensions/gsd/tests/session-start-footer.test.ts +32 -40
  496. package/src/resources/extensions/gsd/tests/stash-queued-context-files.test.ts +56 -0
  497. package/src/resources/extensions/gsd/tests/token-counter.test.ts +105 -1
  498. package/src/resources/extensions/gsd/tests/tool-compatibility.test.ts +107 -0
  499. package/src/resources/extensions/gsd/tests/uok-plan-v2-wiring.test.ts +23 -0
  500. package/src/resources/extensions/gsd/tests/validate-milestone.test.ts +9 -3
  501. package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +65 -2
  502. package/src/resources/extensions/gsd/tests/worktree-db.test.ts +35 -0
  503. package/src/resources/extensions/gsd/tests/worktree-journal-events.test.ts +6 -1
  504. package/src/resources/extensions/gsd/tests/worktree-resolver.test.ts +78 -5
  505. package/src/resources/extensions/gsd/tests/write-gate.test.ts +64 -0
  506. package/src/resources/extensions/gsd/tests/zombie-gsd-state.test.ts +3 -1
  507. package/src/resources/extensions/gsd/token-counter.ts +22 -5
  508. package/src/resources/extensions/gsd/tools/complete-milestone.ts +15 -9
  509. package/src/resources/extensions/gsd/tools/exec-search-tool.ts +81 -0
  510. package/src/resources/extensions/gsd/tools/exec-tool.ts +183 -0
  511. package/src/resources/extensions/gsd/tools/memory-tools.ts +31 -1
  512. package/src/resources/extensions/gsd/tools/resume-tool.ts +40 -0
  513. package/src/resources/extensions/gsd/uok/plan-v2.ts +26 -3
  514. package/src/resources/extensions/gsd/workflow-logger.ts +4 -1
  515. package/src/resources/extensions/gsd/workflow-mcp.ts +3 -0
  516. package/src/resources/extensions/gsd/workflow-templates/spike.md +6 -0
  517. package/src/resources/extensions/gsd/worktree-resolver.ts +54 -9
  518. package/src/resources/extensions/search-the-web/command-search-provider.ts +5 -4
  519. package/src/resources/extensions/search-the-web/native-search.ts +48 -12
  520. package/src/resources/skills/api-design/SKILL.md +190 -0
  521. package/src/resources/skills/create-mcp-server/SKILL.md +121 -0
  522. package/src/resources/skills/decompose-into-slices/SKILL.md +139 -0
  523. package/src/resources/skills/dependency-upgrade/SKILL.md +158 -0
  524. package/src/resources/skills/design-an-interface/SKILL.md +102 -0
  525. package/src/resources/skills/forensics/SKILL.md +153 -0
  526. package/src/resources/skills/grill-me/SKILL.md +93 -0
  527. package/src/resources/skills/handoff/SKILL.md +121 -0
  528. package/src/resources/skills/observability/SKILL.md +174 -0
  529. package/src/resources/skills/security-review/SKILL.md +181 -0
  530. package/src/resources/skills/spike-wrap-up/SKILL.md +138 -0
  531. package/src/resources/skills/tdd/SKILL.md +112 -0
  532. package/src/resources/skills/verify-before-complete/SKILL.md +98 -0
  533. package/src/resources/skills/write-docs/SKILL.md +82 -0
  534. package/src/resources/skills/write-milestone-brief/SKILL.md +135 -0
  535. /package/dist/web/standalone/.next/static/{ssX7BLv3Dw9Fb4CtrCGeR → pV-mPo7rYGb5JBC09C8GG}/_buildManifest.js +0 -0
  536. /package/dist/web/standalone/.next/static/{ssX7BLv3Dw9Fb4CtrCGeR → pV-mPo7rYGb5JBC09C8GG}/_ssgManifest.js +0 -0
@@ -37,8 +37,9 @@ import { getRtkSessionSavings } from "../shared/rtk-session-stats.js";
37
37
  import { deactivateGSD } from "../shared/gsd-phase-state.js";
38
38
  import { initMetrics, resetMetrics, getLedger, getProjectTotals, formatCost, formatTokenCount, } from "./metrics.js";
39
39
  import { setLogBasePath, logWarning } from "./workflow-logger.js";
40
+ import { preflightCleanRoot, postflightPopStash } from "./clean-root-preflight.js";
40
41
  import { homedir } from "node:os";
41
- import { join } from "node:path";
42
+ import { isAbsolute, join } from "node:path";
42
43
  import { pathToFileURL } from "node:url";
43
44
  import { readFileSync, existsSync, mkdirSync, writeFileSync, unlinkSync } from "node:fs";
44
45
  import { atomicWriteSync } from "./atomic-write.js";
@@ -55,7 +56,7 @@ import { getErrorMessage } from "./error-utils.js";
55
56
  import { recoverFailedMigration } from "./migrate-external.js";
56
57
  import { initRegistry, convertDispatchRules } from "./rule-registry.js";
57
58
  import { emitJournalEvent as _emitJournalEvent } from "./journal.js";
58
- import { updateProgressWidget as _updateProgressWidget, updateSliceProgressCache, clearSliceProgressCache, hideFooter, } from "./auto-dashboard.js";
59
+ import { updateProgressWidget as _updateProgressWidget, updateSliceProgressCache, clearSliceProgressCache, } from "./auto-dashboard.js";
59
60
  import { registerSigtermHandler as _registerSigtermHandler, deregisterSigtermHandler as _deregisterSigtermHandler, } from "./auto-supervisor.js";
60
61
  import { isDbAvailable, getMilestone } from "./gsd-db.js";
61
62
  import { countPendingCaptures } from "./captures.js";
@@ -136,6 +137,24 @@ function restoreMilestoneLockEnv() {
136
137
  s.hadMilestoneLockEnv = false;
137
138
  s.milestoneLockEnvCaptured = false;
138
139
  }
140
+ function normalizeSessionFilePath(raw) {
141
+ if (typeof raw !== "string")
142
+ return null;
143
+ const trimmed = raw.trim();
144
+ if (!trimmed)
145
+ return null;
146
+ const firstLine = trimmed.split(/\r?\n/, 1)[0]?.trim() ?? "";
147
+ if (!firstLine)
148
+ return null;
149
+ // Guard against accidental message concatenation by trimming to .jsonl.
150
+ const jsonlIndex = firstLine.toLowerCase().indexOf(".jsonl");
151
+ const candidate = jsonlIndex >= 0 ? firstLine.slice(0, jsonlIndex + ".jsonl".length) : firstLine;
152
+ if (!isAbsolute(candidate))
153
+ return null;
154
+ if (!candidate.toLowerCase().endsWith(".jsonl"))
155
+ return null;
156
+ return candidate;
157
+ }
139
158
  export function startAutoDetached(ctx, pi, base, verboseMode, options) {
140
159
  void startAuto(ctx, pi, base, verboseMode, options).catch((err) => {
141
160
  const message = getErrorMessage(err);
@@ -145,8 +164,8 @@ export function startAutoDetached(ctx, pi, base, verboseMode, options) {
145
164
  });
146
165
  }
147
166
  /** Returns true if the project is configured for `isolation:worktree` mode. */
148
- export function shouldUseWorktreeIsolation() {
149
- const prefs = loadEffectiveGSDPreferences()?.preferences?.git;
167
+ export function shouldUseWorktreeIsolation(basePath) {
168
+ const prefs = loadEffectiveGSDPreferences(basePath)?.preferences?.git;
150
169
  if (prefs?.isolation === "worktree")
151
170
  return true;
152
171
  // Default is false — worktree isolation requires explicit opt-in
@@ -215,7 +234,7 @@ export function getAutoDashboardData() {
215
234
  const rtkSavings = sessionId && s.basePath
216
235
  ? getRtkSessionSavings(s.basePath, sessionId)
217
236
  : null;
218
- const rtkEnabled = loadEffectiveGSDPreferences()?.preferences.experimental?.rtk === true;
237
+ const rtkEnabled = loadEffectiveGSDPreferences(s.basePath || undefined)?.preferences.experimental?.rtk === true;
219
238
  // Pending capture count — lazy check, non-fatal
220
239
  let pendingCaptureCount = 0;
221
240
  try {
@@ -393,7 +412,7 @@ function clearUnitTimeout() {
393
412
  }
394
413
  /** Build snapshot metric opts. */
395
414
  function buildSnapshotOpts(_unitType, _unitId) {
396
- const prefs = loadEffectiveGSDPreferences()?.preferences;
415
+ const prefs = loadEffectiveGSDPreferences(s.basePath || undefined)?.preferences;
397
416
  const uokFlags = resolveUokFlags(prefs);
398
417
  return {
399
418
  ...(s.autoStartTime > 0 ? { autoSessionKey: String(s.autoStartTime) } : {}),
@@ -427,7 +446,7 @@ function handleLostSessionLock(ctx, lockStatus) {
427
446
  restoreProjectRootEnv();
428
447
  restoreMilestoneLockEnv();
429
448
  deregisterSigtermHandler();
430
- clearCmuxSidebar(loadEffectiveGSDPreferences()?.preferences);
449
+ clearCmuxSidebar(loadEffectiveGSDPreferences(s.basePath || undefined)?.preferences);
431
450
  const base = lockBase();
432
451
  const lockFilePath = base ? join(gsdRoot(base), "auto.lock") : "unknown";
433
452
  const recoverySuggestion = "\nTo recover, run: gsd doctor --fix";
@@ -443,7 +462,6 @@ function handleLostSessionLock(ctx, lockStatus) {
443
462
  ctx?.ui.notify(message, "error");
444
463
  ctx?.ui.setStatus("gsd-auto", undefined);
445
464
  ctx?.ui.setWidget("gsd-progress", undefined);
446
- ctx?.ui.setFooter(undefined);
447
465
  if (ctx)
448
466
  initHealthWidget(ctx);
449
467
  }
@@ -480,7 +498,6 @@ function cleanupAfterLoopExit(ctx) {
480
498
  if (!s.paused) {
481
499
  ctx.ui.setStatus("gsd-auto", undefined);
482
500
  ctx.ui.setWidget("gsd-progress", undefined);
483
- ctx.ui.setFooter(undefined);
484
501
  initHealthWidget(ctx);
485
502
  }
486
503
  // Restore CWD out of worktree back to original project root
@@ -498,7 +515,7 @@ function cleanupAfterLoopExit(ctx) {
498
515
  export async function stopAuto(ctx, pi, reason) {
499
516
  if (!s.active && !s.paused)
500
517
  return;
501
- const loadedPreferences = loadEffectiveGSDPreferences()?.preferences;
518
+ const loadedPreferences = loadEffectiveGSDPreferences(s.basePath || undefined)?.preferences;
502
519
  const reasonSuffix = reason ? ` — ${reason}` : "";
503
520
  try {
504
521
  // ── Step 1: Timers and locks ──
@@ -695,13 +712,16 @@ export async function stopAuto(ctx, pi, reason) {
695
712
  catch (err) { /* non-fatal */
696
713
  logWarning("engine", `file unlink failed: ${err instanceof Error ? err.message : String(err)}`, { file: "auto.ts" });
697
714
  }
698
- // ── Step 13: Restore original model (before reset clears IDs) ──
715
+ // ── Step 13: Restore original model + thinking (before reset clears IDs) ──
699
716
  try {
700
717
  if (pi && ctx && s.originalModelId && s.originalModelProvider) {
701
718
  const original = ctx.modelRegistry.find(s.originalModelProvider, s.originalModelId);
702
719
  if (original)
703
720
  await pi.setModel(original);
704
721
  }
722
+ if (pi && s.originalThinkingLevel) {
723
+ pi.setThinkingLevel(s.originalThinkingLevel);
724
+ }
705
725
  }
706
726
  catch (e) {
707
727
  debugLog("stop-cleanup-model", { error: e instanceof Error ? e.message : String(e) });
@@ -740,7 +760,6 @@ export async function stopAuto(ctx, pi, reason) {
740
760
  // UI cleanup
741
761
  ctx?.ui.setStatus("gsd-auto", undefined);
742
762
  ctx?.ui.setWidget("gsd-progress", undefined);
743
- ctx?.ui.setFooter(undefined);
744
763
  if (ctx)
745
764
  initHealthWidget(ctx);
746
765
  restoreProjectRootEnv();
@@ -775,7 +794,7 @@ export async function pauseAuto(ctx, _pi, _errorContext) {
775
794
  // Pass errorContext so runUnitPhase can distinguish user-initiated pause
776
795
  // from provider-error pause and avoid hard-stopping (#2762).
777
796
  resolveAgentEndCancelled(_errorContext);
778
- s.pausedSessionFile = ctx?.sessionManager?.getSessionFile() ?? null;
797
+ s.pausedSessionFile = normalizeSessionFilePath(ctx?.sessionManager?.getSessionFile() ?? null);
779
798
  // Persist paused-session metadata so resume survives /exit (#1383).
780
799
  // The fresh-start bootstrap checks for this file and restores worktree context.
781
800
  try {
@@ -829,7 +848,6 @@ export async function pauseAuto(ctx, _pi, _errorContext) {
829
848
  s.verificationRetryCount.clear();
830
849
  ctx?.ui.setStatus("gsd-auto", "paused");
831
850
  ctx?.ui.setWidget("gsd-progress", undefined);
832
- ctx?.ui.setFooter(undefined);
833
851
  if (ctx)
834
852
  initHealthWidget(ctx);
835
853
  const resumeCmd = s.stepMode ? "/gsd next" : "/gsd auto";
@@ -975,6 +993,9 @@ function buildLoopDeps() {
975
993
  },
976
994
  // Journal
977
995
  emitJournalEvent: (entry) => _emitJournalEvent(s.basePath, entry),
996
+ // Clean-root preflight gate (#2909)
997
+ preflightCleanRoot,
998
+ postflightPopStash,
978
999
  };
979
1000
  }
980
1001
  /**
@@ -1031,7 +1052,9 @@ export async function startAuto(ctx, pi, base, verboseMode, options) {
1031
1052
  unlinkSync(pausedPath);
1032
1053
  }
1033
1054
  catch (e) {
1034
- logWarning("session", `pause file cleanup failed: ${e instanceof Error ? e.message : String(e)}`, { file: "auto.ts" });
1055
+ if (e.code !== "ENOENT") {
1056
+ logWarning("session", `pause file cleanup failed: ${e instanceof Error ? e.message : String(e)}`, { file: "auto.ts" });
1057
+ }
1035
1058
  }
1036
1059
  ctx.ui.notify(`Resuming paused custom workflow${meta.activeRunDir ? ` (${meta.activeRunDir})` : ""}.`, "info");
1037
1060
  }
@@ -1049,7 +1072,9 @@ export async function startAuto(ctx, pi, base, verboseMode, options) {
1049
1072
  unlinkSync(pausedPath);
1050
1073
  }
1051
1074
  catch (err) {
1052
- logWarning("session", `pause file cleanup failed: ${err instanceof Error ? err.message : String(err)}`, { file: "auto.ts" });
1075
+ if (err.code !== "ENOENT") {
1076
+ logWarning("session", `pause file cleanup failed: ${err instanceof Error ? err.message : String(err)}`, { file: "auto.ts" });
1077
+ }
1053
1078
  }
1054
1079
  ctx.ui.notify(`Paused milestone ${meta.milestoneId} is ${!mDir ? "missing" : "already complete"}. Starting fresh.`, "info");
1055
1080
  }
@@ -1057,7 +1082,7 @@ export async function startAuto(ctx, pi, base, verboseMode, options) {
1057
1082
  s.currentMilestoneId = meta.milestoneId;
1058
1083
  s.originalBasePath = meta.originalBasePath || base;
1059
1084
  s.stepMode = meta.stepMode ?? requestedStepMode;
1060
- s.pausedSessionFile = meta.sessionFile ?? null;
1085
+ s.pausedSessionFile = normalizeSessionFilePath(meta.sessionFile ?? null);
1061
1086
  s.pausedUnitType = meta.unitType ?? null;
1062
1087
  s.pausedUnitId = meta.unitId ?? null;
1063
1088
  s.autoStartTime = meta.autoStartTime || Date.now();
@@ -1067,7 +1092,9 @@ export async function startAuto(ctx, pi, base, verboseMode, options) {
1067
1092
  unlinkSync(pausedPath);
1068
1093
  }
1069
1094
  catch (e) {
1070
- logWarning("session", `pause file cleanup failed: ${e instanceof Error ? e.message : String(e)}`, { file: "auto.ts" });
1095
+ if (e.code !== "ENOENT") {
1096
+ logWarning("session", `pause file cleanup failed: ${e instanceof Error ? e.message : String(e)}`, { file: "auto.ts" });
1097
+ }
1071
1098
  }
1072
1099
  ctx.ui.notify(`Resuming paused session for ${meta.milestoneId}${meta.worktreePath && existsSync(meta.worktreePath) ? ` (worktree)` : ""}.`, "info");
1073
1100
  }
@@ -1077,7 +1104,9 @@ export async function startAuto(ctx, pi, base, verboseMode, options) {
1077
1104
  unlinkSync(pausedPath);
1078
1105
  }
1079
1106
  catch (e) {
1080
- logWarning("session", `stale pause file cleanup failed: ${e instanceof Error ? e.message : String(e)}`, { file: "auto.ts" });
1107
+ if (e.code !== "ENOENT") {
1108
+ logWarning("session", `stale pause file cleanup failed: ${e instanceof Error ? e.message : String(e)}`, { file: "auto.ts" });
1109
+ }
1081
1110
  }
1082
1111
  }
1083
1112
  }
@@ -1133,7 +1162,9 @@ export async function startAuto(ctx, pi, base, verboseMode, options) {
1133
1162
  unlinkSync(s.pausedSessionFile);
1134
1163
  }
1135
1164
  catch (err) {
1136
- logWarning("session", `pause file cleanup failed: ${err instanceof Error ? err.message : String(err)}`, { file: "auto.ts" });
1165
+ if (err.code !== "ENOENT") {
1166
+ logWarning("session", `pause file cleanup failed: ${err instanceof Error ? err.message : String(err)}`, { file: "auto.ts" });
1167
+ }
1137
1168
  }
1138
1169
  s.pausedSessionFile = null;
1139
1170
  }
@@ -1143,6 +1174,17 @@ export async function startAuto(ctx, pi, base, verboseMode, options) {
1143
1174
  s.stepMode = requestedStepMode;
1144
1175
  s.cmdCtx = ctx;
1145
1176
  s.basePath = base;
1177
+ // ── Resume worktree: if the paused session was inside a milestone worktree,
1178
+ // apply that path as the dispatch basePath immediately (#3723).
1179
+ // This ensures the dispatch loop runs from the worktree directory even when
1180
+ // enterMilestone guard conditions differ between the original and resumed
1181
+ // session (e.g. isolation mode changed, detectWorktreeName differs across
1182
+ // process restarts). We guard with existsSync so a stale or deleted
1183
+ // worktree directory safely falls back to the project root.
1184
+ const resumeWorktreePath = freshStartAssessment.pausedSession?.worktreePath;
1185
+ if (resumeWorktreePath && existsSync(resumeWorktreePath)) {
1186
+ s.basePath = resumeWorktreePath;
1187
+ }
1146
1188
  // Ensure the workflow-logger audit log is pinned to the project root
1147
1189
  // even when auto-mode is entered via a path that bypasses the
1148
1190
  // bootstrap/dynamic-tools ensureDbOpen() → setLogBasePath() chain
@@ -1161,7 +1203,7 @@ export async function startAuto(ctx, pi, base, verboseMode, options) {
1161
1203
  });
1162
1204
  // ── Auto-worktree / branch-mode: re-enter on resume ──
1163
1205
  if (s.currentMilestoneId &&
1164
- getIsolationMode() !== "none" &&
1206
+ getIsolationMode(s.originalBasePath || s.basePath) !== "none" &&
1165
1207
  s.originalBasePath &&
1166
1208
  !isInAutoWorktree(s.basePath) &&
1167
1209
  !detectWorktreeName(s.basePath) &&
@@ -1172,7 +1214,7 @@ export async function startAuto(ctx, pi, base, verboseMode, options) {
1172
1214
  }
1173
1215
  registerSigtermHandler(lockBase());
1174
1216
  ctx.ui.setStatus("gsd-auto", s.stepMode ? "next" : "auto");
1175
- ctx.ui.setFooter(hideFooter);
1217
+ ctx.ui.setWidget("gsd-health", undefined);
1176
1218
  ctx.ui.notify(s.stepMode ? "Step-mode resumed." : "Auto-mode resumed.", "info");
1177
1219
  restoreHookState(s.basePath);
1178
1220
  // Re-sync managed resources on resume so long-lived auto sessions pick up
@@ -1194,7 +1236,7 @@ export async function startAuto(ctx, pi, base, verboseMode, options) {
1194
1236
  await openProjectDbIfPresent(s.basePath);
1195
1237
  try {
1196
1238
  await rebuildState(s.basePath);
1197
- syncCmuxSidebar(loadEffectiveGSDPreferences()?.preferences, await deriveState(s.basePath));
1239
+ syncCmuxSidebar(loadEffectiveGSDPreferences(s.basePath || undefined)?.preferences, await deriveState(s.basePath));
1198
1240
  }
1199
1241
  catch (e) {
1200
1242
  debugLog("resume-rebuild-state-failed", {
@@ -1224,7 +1266,7 @@ export async function startAuto(ctx, pi, base, verboseMode, options) {
1224
1266
  }
1225
1267
  updateSessionLock(lockBase(), "resuming", s.currentMilestoneId ?? "unknown");
1226
1268
  writeLock(lockBase(), "resuming", s.currentMilestoneId ?? "unknown");
1227
- logCmuxEvent(loadEffectiveGSDPreferences()?.preferences, s.stepMode ? "Step-mode resumed." : "Auto-mode resumed.", "progress");
1269
+ logCmuxEvent(loadEffectiveGSDPreferences(s.basePath || undefined)?.preferences, s.stepMode ? "Step-mode resumed." : "Auto-mode resumed.", "progress");
1228
1270
  captureProjectRootEnv(s.originalBasePath || s.basePath);
1229
1271
  startAutoCommandPolling(s.basePath);
1230
1272
  await runAutoLoopWithUok({
@@ -1250,13 +1292,13 @@ export async function startAuto(ctx, pi, base, verboseMode, options) {
1250
1292
  return;
1251
1293
  captureProjectRootEnv(s.originalBasePath || s.basePath);
1252
1294
  try {
1253
- syncCmuxSidebar(loadEffectiveGSDPreferences()?.preferences, await deriveState(s.basePath));
1295
+ syncCmuxSidebar(loadEffectiveGSDPreferences(s.basePath || undefined)?.preferences, await deriveState(s.basePath));
1254
1296
  }
1255
1297
  catch (err) {
1256
1298
  // Best-effort only — sidebar sync must never block auto-mode startup
1257
1299
  logWarning("engine", `cmux sync failed: ${err instanceof Error ? err.message : String(err)}`, { file: "auto.ts" });
1258
1300
  }
1259
- logCmuxEvent(loadEffectiveGSDPreferences()?.preferences, requestedStepMode ? "Step-mode started." : "Auto-mode started.", "progress");
1301
+ logCmuxEvent(loadEffectiveGSDPreferences(s.basePath || undefined)?.preferences, requestedStepMode ? "Step-mode started." : "Auto-mode started.", "progress");
1260
1302
  startAutoCommandPolling(s.basePath);
1261
1303
  // Dispatch the first unit
1262
1304
  await runAutoLoopWithUok({
@@ -1361,8 +1403,8 @@ export async function dispatchHookUnit(ctx, pi, hookName, triggerUnitType, trigg
1361
1403
  `Ensure the model is defined in models.json and has auth configured.`, "warning");
1362
1404
  }
1363
1405
  }
1364
- const sessionFile = ctx.sessionManager.getSessionFile();
1365
- writeLock(lockBase(), hookUnitType, triggerUnitId, sessionFile);
1406
+ const sessionFile = normalizeSessionFilePath(ctx.sessionManager.getSessionFile());
1407
+ writeLock(lockBase(), hookUnitType, triggerUnitId, sessionFile ?? undefined);
1366
1408
  clearUnitTimeout();
1367
1409
  const supervisor = resolveAutoSupervisorConfig();
1368
1410
  const hookHardTimeoutMs = (supervisor.hard_timeout_minutes ?? 30) * 60 * 1000;
@@ -0,0 +1,68 @@
1
+ // GSD — Persistent per-project blocklist of provider/model pairs that the
2
+ // provider has rejected at request time for account entitlement reasons.
3
+ //
4
+ // Lives at `.gsd/runtime/blocked-models.json` so the block survives /gsd auto
5
+ // restarts. Auto-mode model selection skips blocked entries; agent-end
6
+ // recovery adds entries when a runtime rejection is classified as
7
+ // `unsupported-model`. See issue #4513.
8
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
9
+ import { dirname, join } from "node:path";
10
+ import { gsdRoot } from "./paths.js";
11
+ import { withFileLockSync } from "./file-lock.js";
12
+ function blockedModelsPath(basePath) {
13
+ return join(gsdRoot(basePath), "runtime", "blocked-models.json");
14
+ }
15
+ function modelKey(provider, id) {
16
+ return `${provider.toLowerCase()}/${id.toLowerCase()}`;
17
+ }
18
+ function readFileSafe(path) {
19
+ if (!existsSync(path))
20
+ return { version: 1, blocked: [] };
21
+ try {
22
+ const raw = readFileSync(path, "utf-8");
23
+ const parsed = JSON.parse(raw);
24
+ if (!parsed || !Array.isArray(parsed.blocked)) {
25
+ return { version: 1, blocked: [] };
26
+ }
27
+ const blocked = parsed.blocked.filter((e) => !!e && typeof e.provider === "string" && typeof e.id === "string");
28
+ return { version: 1, blocked };
29
+ }
30
+ catch {
31
+ // Corrupted JSON: treat as empty so a bad file never blocks dispatch.
32
+ return { version: 1, blocked: [] };
33
+ }
34
+ }
35
+ export function loadBlockedModels(basePath) {
36
+ return readFileSafe(blockedModelsPath(basePath)).blocked;
37
+ }
38
+ export function isModelBlocked(basePath, provider, id) {
39
+ if (!provider || !id)
40
+ return false;
41
+ const target = modelKey(provider, id);
42
+ return loadBlockedModels(basePath).some((e) => modelKey(e.provider, e.id) === target);
43
+ }
44
+ export function blockModel(basePath, provider, id, reason) {
45
+ const path = blockedModelsPath(basePath);
46
+ mkdirSync(dirname(path), { recursive: true });
47
+ // Ensure the file exists before we try to lock it — proper-lockfile requires
48
+ // the target path to exist (file-lock.ts falls through to an unlocked call
49
+ // otherwise).
50
+ if (!existsSync(path)) {
51
+ writeFileSync(path, JSON.stringify({ version: 1, blocked: [] }, null, 2) + "\n", "utf-8");
52
+ }
53
+ withFileLockSync(path, () => {
54
+ const current = readFileSafe(path);
55
+ const target = modelKey(provider, id);
56
+ if (current.blocked.some((e) => modelKey(e.provider, e.id) === target)) {
57
+ return;
58
+ }
59
+ const next = {
60
+ version: 1,
61
+ blocked: [
62
+ ...current.blocked,
63
+ { provider, id, reason, blockedAt: Date.now() },
64
+ ],
65
+ };
66
+ writeFileSync(path, JSON.stringify(next, null, 2) + "\n", "utf-8");
67
+ });
68
+ }
@@ -1,5 +1,5 @@
1
1
  import { logWarning } from "../workflow-logger.js";
2
- import { checkAutoStartAfterDiscuss } from "../guided-flow.js";
2
+ import { checkAutoStartAfterDiscuss, maybeHandleReadyPhraseWithoutFiles, maybeHandleEmptyIntentTurn, resetEmptyTurnCounter, } from "../guided-flow.js";
3
3
  import { getAutoDashboardData, getAutoModeStartModel, isAutoActive, pauseAuto, setCurrentDispatchedModelId } from "../auto.js";
4
4
  import { getNextFallbackModel, resolveModelWithFallbacksForUnit } from "../preferences.js";
5
5
  import { pauseAutoForProviderError } from "../provider-error-pause.js";
@@ -8,6 +8,7 @@ import { resolveModelId } from "../auto-model-selection.js";
8
8
  import { clearDiscussionFlowState } from "./write-gate.js";
9
9
  import { resumeAutoAfterProviderDelay } from "./provider-error-resume.js";
10
10
  import { classifyError, createRetryState, resetRetryState, isTransient, } from "../error-classifier.js";
11
+ import { blockModel, isModelBlocked } from "../blocked-models.js";
11
12
  const retryState = createRetryState();
12
13
  const MAX_NETWORK_RETRIES = 2;
13
14
  const MAX_TRANSIENT_AUTO_RESUMES = 8;
@@ -52,6 +53,19 @@ export async function handleAgentEnd(pi, event, ctx) {
52
53
  clearDiscussionFlowState();
53
54
  return;
54
55
  }
56
+ // #4573 — When the LLM emits "Milestone X ready." but the required files
57
+ // are missing, `checkAutoStartAfterDiscuss` returns false silently. Surface
58
+ // that and nudge the LLM to complete the writes before the user hits the
59
+ // downstream "All milestones complete" warning loop.
60
+ if (maybeHandleReadyPhraseWithoutFiles(event))
61
+ return;
62
+ // #4573 — Empty-turn recovery: if the LLM announced intent in prose but
63
+ // emitted no tool calls, nudge it to execute. Fires only when auto-mode is
64
+ // active or a discussion autostart is pending (non-auto interactive discuss
65
+ // is user-driven). Runs before `isAutoActive` early return so pending
66
+ // discussions (where isAutoActive may be false) still get recovered.
67
+ if (maybeHandleEmptyIntentTurn(event, isAutoActive()))
68
+ return;
55
69
  if (!isAutoActive())
56
70
  return;
57
71
  if (isSessionSwitchInFlight())
@@ -106,6 +120,81 @@ export async function handleAgentEnd(pi, event, ctx) {
106
120
  const explicitRetryAfterMs = ("retryAfterMs" in lastMsg && typeof lastMsg.retryAfterMs === "number") ? lastMsg.retryAfterMs : undefined;
107
121
  // ── 1. Classify using rawErrorMsg to avoid prose false-positives ────
108
122
  const cls = classifyError(rawErrorMsg, explicitRetryAfterMs);
123
+ // ── 1a. Unsupported-model: provider rejected this model for the current
124
+ // account/plan at request time (#4513). Persist a block so the
125
+ // same dead model isn't reselected on the next /gsd auto restart,
126
+ // then try a fallback before pausing.
127
+ if (cls.kind === "unsupported-model") {
128
+ const dash = getAutoDashboardData();
129
+ const rejectedProvider = ctx.model?.provider;
130
+ const rejectedId = ctx.model?.id;
131
+ if (dash.basePath && rejectedProvider && rejectedId) {
132
+ try {
133
+ blockModel(dash.basePath, rejectedProvider, rejectedId, rawErrorMsg || "unsupported for account");
134
+ ctx.ui.notify(`Blocked ${rejectedProvider}/${rejectedId} for this project — provider rejected it for the current account.`, "warning");
135
+ }
136
+ catch (err) {
137
+ const m = err instanceof Error ? err.message : String(err);
138
+ logWarning("bootstrap", `Failed to persist blocked model: ${m}`);
139
+ }
140
+ }
141
+ // Try configured fallback chain, skipping anything already blocked.
142
+ if (dash.currentUnit && dash.basePath) {
143
+ const modelConfig = resolveModelWithFallbacksForUnit(dash.currentUnit.type);
144
+ if (modelConfig && modelConfig.fallbacks.length > 0) {
145
+ const availableModels = ctx.modelRegistry.getAvailable();
146
+ let cursorModelId = ctx.model?.id;
147
+ while (true) {
148
+ const nextModelId = getNextFallbackModel(cursorModelId, modelConfig);
149
+ if (!nextModelId)
150
+ break;
151
+ const candidate = resolveModelId(nextModelId, availableModels, ctx.model?.provider);
152
+ if (candidate && !isModelBlocked(dash.basePath, candidate.provider, candidate.id)) {
153
+ const ok = await pi.setModel(candidate, { persist: false });
154
+ if (ok) {
155
+ setCurrentDispatchedModelId({ provider: candidate.provider, id: candidate.id });
156
+ ctx.ui.notify(`Switched to fallback ${candidate.provider}/${candidate.id} after account entitlement rejection.`, "warning");
157
+ pi.sendMessage({ customType: "gsd-auto-timeout-recovery", content: "Continue execution.", display: false }, { triggerTurn: true });
158
+ return;
159
+ }
160
+ }
161
+ cursorModelId = nextModelId;
162
+ }
163
+ }
164
+ // Fallback chain exhausted — try the auto-mode start model if it isn't
165
+ // the same one we just blocked and isn't itself blocked.
166
+ const sessionModel = getAutoModeStartModel();
167
+ if (sessionModel &&
168
+ !(sessionModel.provider === rejectedProvider && sessionModel.id === rejectedId) &&
169
+ !isModelBlocked(dash.basePath, sessionModel.provider, sessionModel.id)) {
170
+ const startModel = ctx.modelRegistry
171
+ .getAvailable()
172
+ .find((m) => m.provider === sessionModel.provider && m.id === sessionModel.id);
173
+ if (startModel) {
174
+ const ok = await pi.setModel(startModel, { persist: false });
175
+ if (ok) {
176
+ setCurrentDispatchedModelId({ provider: startModel.provider, id: startModel.id });
177
+ ctx.ui.notify(`Restored auto-mode start model ${startModel.provider}/${startModel.id} after entitlement rejection.`, "warning");
178
+ pi.sendMessage({ customType: "gsd-auto-timeout-recovery", content: "Continue execution.", display: false }, { triggerTurn: true });
179
+ return;
180
+ }
181
+ }
182
+ }
183
+ }
184
+ // No usable fallback — pause with a clearly named message.
185
+ const blockedLabel = rejectedProvider && rejectedId ? `${rejectedProvider}/${rejectedId}` : "current model";
186
+ const pauseDetail = `Model ${blockedLabel} blocked for this account${errorDetail}. Configure a different model and restart /gsd auto.`;
187
+ await pauseAutoForProviderError(ctx.ui, pauseDetail, () => pauseAuto(ctx, pi, {
188
+ message: pauseDetail,
189
+ category: "provider",
190
+ isTransient: false,
191
+ }), {
192
+ isRateLimit: false,
193
+ isTransient: false,
194
+ retryAfterMs: 0,
195
+ });
196
+ return;
197
+ }
109
198
  // ── 1b. Defer to Core RetryHandler for most transient errors ────────
110
199
  // Core retries transient failures in-session after this handler.
111
200
  // Keep that behavior for non-rate-limit classes to avoid pause/retry races,
@@ -210,6 +299,9 @@ export async function handleAgentEnd(pi, event, ctx) {
210
299
  // ── Success path ─────────────────────────────────────────────────────────
211
300
  try {
212
301
  resetRetryState(retryState);
302
+ // #4573 — Reset the empty-turn counter on any successful agent turn so
303
+ // transient stalls don't accumulate across independent units.
304
+ resetEmptyTurnCounter();
213
305
  resolveAgentEnd(event);
214
306
  }
215
307
  catch (err) {
@@ -19,6 +19,18 @@ function registerAlias(pi, toolDef, aliasName, canonicalName) {
19
19
  promptGuidelines: [`Alias for ${canonicalName} — prefer the canonical name.`],
20
20
  });
21
21
  }
22
+ /**
23
+ * Read a tool result's structured payload, accommodating MCP's `details` →
24
+ * `structuredContent` rename (#4472, #4477). In-process executions still
25
+ * deliver the payload on `result.details`; MCP-routed executions deliver it
26
+ * on `result.structuredContent` (post `adaptExecutorResult` transform). All
27
+ * `renderResult` callbacks in this file route through this helper so a future
28
+ * field rename only needs to be applied in one place.
29
+ */
30
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any -- result shape varies by tool
31
+ function readDetails(result) {
32
+ return result?.details ?? result?.structuredContent;
33
+ }
22
34
  export function registerDbTools(pi) {
23
35
  // ─── gsd_decision_save (formerly gsd_save_decision) ─────────────────────
24
36
  const decisionSaveExecute = async (_toolCallId, params, _signal, _onUpdate, _ctx) => {
@@ -92,7 +104,7 @@ export function registerDbTools(pi) {
92
104
  return new Text(text, 0, 0);
93
105
  },
94
106
  renderResult(result, _options, theme) {
95
- const d = result.details;
107
+ const d = readDetails(result);
96
108
  if (result.isError || d?.error) {
97
109
  return new Text(theme.fg("error", `Error: ${d?.error ?? "unknown"}`), 0, 0);
98
110
  }
@@ -175,7 +187,7 @@ export function registerDbTools(pi) {
175
187
  return new Text(text, 0, 0);
176
188
  },
177
189
  renderResult(result, _options, theme) {
178
- const d = result.details;
190
+ const d = readDetails(result);
179
191
  if (result.isError || d?.error) {
180
192
  return new Text(theme.fg("error", `Error: ${d?.error ?? "unknown"}`), 0, 0);
181
193
  }
@@ -255,7 +267,7 @@ export function registerDbTools(pi) {
255
267
  return new Text(text, 0, 0);
256
268
  },
257
269
  renderResult(result, _options, theme) {
258
- const d = result.details;
270
+ const d = readDetails(result);
259
271
  if (result.isError || d?.error) {
260
272
  return new Text(theme.fg("error", `Error: ${d?.error ?? "unknown"}`), 0, 0);
261
273
  }
@@ -301,7 +313,7 @@ export function registerDbTools(pi) {
301
313
  return new Text(text, 0, 0);
302
314
  },
303
315
  renderResult(result, _options, theme) {
304
- const d = result.details;
316
+ const d = readDetails(result);
305
317
  if (result.isError || d?.error) {
306
318
  return new Text(theme.fg("error", `Error: ${d?.error ?? "unknown"}`), 0, 0);
307
319
  }
@@ -382,7 +394,7 @@ export function registerDbTools(pi) {
382
394
  return new Text(theme.fg("toolTitle", theme.bold("milestone_generate_id")), 0, 0);
383
395
  },
384
396
  renderResult(result, _options, theme) {
385
- const d = result.details;
397
+ const d = readDetails(result);
386
398
  if (result.isError || d?.error) {
387
399
  return new Text(theme.fg("error", `Error: ${d?.error ?? "unknown"}`), 0, 0);
388
400
  }
@@ -967,13 +979,31 @@ export function registerDbTools(pi) {
967
979
  text += theme.fg("dim", ` → ${args.verdict ?? ""}`);
968
980
  return new Text(text, 0, 0);
969
981
  },
982
+ /**
983
+ * Render the save_gate_result tool output for the TUI.
984
+ *
985
+ * Prefers structured fields, but falls back to `content[0].text` when the
986
+ * structured payload is empty. Defensive: the structural fix on this
987
+ * branch plumbs `details` through MCP via `structuredContent`, but older
988
+ * hosts, a future handler that forgets `structuredContent`, or any drop
989
+ * of non-standard return fields would otherwise render as
990
+ * "undefined: undefined". Same fallback applies to error rendering, and
991
+ * we strip a leading `Error:` from the fallback text to avoid producing
992
+ * `Error: Error: ...`.
993
+ */
970
994
  renderResult(result, _options, theme) {
971
- const d = result.details;
995
+ const d = readDetails(result);
972
996
  if (result.isError || d?.error) {
973
- return new Text(theme.fg("error", `Error: ${d?.error ?? "unknown"}`), 0, 0);
997
+ const rawMsg = d?.error ?? result.content?.[0]?.text ?? "unknown";
998
+ const msg = rawMsg.replace(/^\s*Error:\s*/i, "");
999
+ return new Text(theme.fg("error", `Error: ${msg}`), 0, 0);
1000
+ }
1001
+ if (!d?.gateId || !d?.verdict) {
1002
+ const text = result.content?.[0]?.text ?? "Gate result saved";
1003
+ return new Text(theme.fg("success", text), 0, 0);
974
1004
  }
975
- const color = d?.verdict === "flag" ? "warning" : "success";
976
- return new Text(theme.fg(color, `${d?.gateId}: ${d?.verdict}`), 0, 0);
1005
+ const color = d.verdict === "flag" ? "warning" : "success";
1006
+ return new Text(theme.fg(color, `${d.gateId}: ${d.verdict}`), 0, 0);
977
1007
  },
978
1008
  };
979
1009
  pi.registerTool(saveGateResultTool);