gsd-pi 2.74.0-dev.2b524c3 → 2.74.0-dev.658744a

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 (506) hide show
  1. package/dist/cli.js +85 -0
  2. package/dist/headless-query.js +4 -1
  3. package/dist/help-text.js +23 -0
  4. package/dist/resources/extensions/gsd/activity-log.js +16 -0
  5. package/dist/resources/extensions/gsd/auto/detect-stuck.js +11 -4
  6. package/dist/resources/extensions/gsd/auto/loop.js +147 -10
  7. package/dist/resources/extensions/gsd/auto/phases.js +209 -10
  8. package/dist/resources/extensions/gsd/auto/session.js +10 -0
  9. package/dist/resources/extensions/gsd/auto-dispatch.js +11 -1
  10. package/dist/resources/extensions/gsd/auto-model-selection.js +54 -8
  11. package/dist/resources/extensions/gsd/auto-post-unit.js +220 -17
  12. package/dist/resources/extensions/gsd/auto-prompts.js +12 -0
  13. package/dist/resources/extensions/gsd/auto-recovery.js +24 -10
  14. package/dist/resources/extensions/gsd/auto-unit-closeout.js +18 -0
  15. package/dist/resources/extensions/gsd/auto-verification.js +100 -2
  16. package/dist/resources/extensions/gsd/auto-worktree.js +2 -0
  17. package/dist/resources/extensions/gsd/auto.js +36 -4
  18. package/dist/resources/extensions/gsd/bootstrap/provider-error-resume.js +5 -3
  19. package/dist/resources/extensions/gsd/bootstrap/register-extension.js +30 -8
  20. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +61 -9
  21. package/dist/resources/extensions/gsd/cache.js +16 -5
  22. package/dist/resources/extensions/gsd/commands/catalog.js +31 -1
  23. package/dist/resources/extensions/gsd/commands/handlers/core.js +5 -1
  24. package/dist/resources/extensions/gsd/commands/handlers/ops.js +25 -0
  25. package/dist/resources/extensions/gsd/commands/handlers/workflow.js +68 -9
  26. package/dist/resources/extensions/gsd/commands-add-tests.js +111 -0
  27. package/dist/resources/extensions/gsd/commands-backlog.js +140 -0
  28. package/dist/resources/extensions/gsd/commands-do.js +79 -0
  29. package/dist/resources/extensions/gsd/commands-extract-learnings.js +225 -0
  30. package/dist/resources/extensions/gsd/commands-maintenance.js +6 -6
  31. package/dist/resources/extensions/gsd/commands-pr-branch.js +180 -0
  32. package/dist/resources/extensions/gsd/commands-prefs-wizard.js +51 -4
  33. package/dist/resources/extensions/gsd/commands-session-report.js +82 -0
  34. package/dist/resources/extensions/gsd/commands-ship.js +187 -0
  35. package/dist/resources/extensions/gsd/db-writer.js +3 -5
  36. package/dist/resources/extensions/gsd/docs/preferences-reference.md +16 -1
  37. package/dist/resources/extensions/gsd/ecosystem/gsd-extension-api.js +144 -0
  38. package/dist/resources/extensions/gsd/ecosystem/loader.js +145 -0
  39. package/dist/resources/extensions/gsd/git-service.js +49 -1
  40. package/dist/resources/extensions/gsd/graph-context.js +157 -0
  41. package/dist/resources/extensions/gsd/gsd-db.js +581 -2
  42. package/dist/resources/extensions/gsd/guided-flow.js +31 -6
  43. package/dist/resources/extensions/gsd/index.js +15 -2
  44. package/dist/resources/extensions/gsd/init-wizard.js +1 -0
  45. package/dist/resources/extensions/gsd/journal.js +27 -0
  46. package/dist/resources/extensions/gsd/md-importer.js +3 -4
  47. package/dist/resources/extensions/gsd/memory-store.js +19 -51
  48. package/dist/resources/extensions/gsd/metrics.js +19 -0
  49. package/dist/resources/extensions/gsd/milestone-validation-gates.js +13 -12
  50. package/dist/resources/extensions/gsd/native-git-bridge.js +7 -4
  51. package/dist/resources/extensions/gsd/parallel-orchestrator.js +33 -1
  52. package/dist/resources/extensions/gsd/preferences-models.js +20 -3
  53. package/dist/resources/extensions/gsd/preferences-types.js +2 -0
  54. package/dist/resources/extensions/gsd/preferences-validation.js +118 -2
  55. package/dist/resources/extensions/gsd/preferences.js +31 -0
  56. package/dist/resources/extensions/gsd/prompts/add-tests.md +35 -0
  57. package/dist/resources/extensions/gsd/safety/evidence-collector.js +15 -30
  58. package/dist/resources/extensions/gsd/slice-parallel-orchestrator.js +12 -2
  59. package/dist/resources/extensions/gsd/state.js +5 -1
  60. package/dist/resources/extensions/gsd/templates/PREFERENCES.md +19 -0
  61. package/dist/resources/extensions/gsd/tools/complete-slice.js +20 -0
  62. package/dist/resources/extensions/gsd/tools/validate-milestone.js +39 -4
  63. package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +3 -14
  64. package/dist/resources/extensions/gsd/triage-resolution.js +2 -5
  65. package/dist/resources/extensions/gsd/unit-ownership.js +1 -1
  66. package/dist/resources/extensions/gsd/uok/audit-toggle.js +7 -0
  67. package/dist/resources/extensions/gsd/uok/audit.js +40 -0
  68. package/dist/resources/extensions/gsd/uok/contracts.js +1 -0
  69. package/dist/resources/extensions/gsd/uok/execution-graph.js +179 -0
  70. package/dist/resources/extensions/gsd/uok/flags.js +29 -0
  71. package/dist/resources/extensions/gsd/uok/gate-runner.js +109 -0
  72. package/dist/resources/extensions/gsd/uok/gitops.js +53 -0
  73. package/dist/resources/extensions/gsd/uok/kernel.js +80 -0
  74. package/dist/resources/extensions/gsd/uok/loop-adapter.js +133 -0
  75. package/dist/resources/extensions/gsd/uok/model-policy.js +66 -0
  76. package/dist/resources/extensions/gsd/uok/plan-v2.js +132 -0
  77. package/dist/resources/extensions/gsd/workflow-logger.js +22 -0
  78. package/dist/resources/extensions/gsd/workflow-manifest.js +8 -69
  79. package/dist/resources/extensions/gsd/workflow-migration.js +21 -22
  80. package/dist/resources/extensions/gsd/workflow-projections.js +4 -1
  81. package/dist/resources/extensions/gsd/workflow-reconcile.js +14 -11
  82. package/dist/resources/extensions/ttsr/ttsr-manager.js +3 -1
  83. package/dist/tsconfig.extensions.tsbuildinfo +1 -0
  84. package/dist/web/standalone/.next/BUILD_ID +1 -1
  85. package/dist/web/standalone/.next/app-path-routes-manifest.json +9 -9
  86. package/dist/web/standalone/.next/build-manifest.json +2 -2
  87. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  88. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  89. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  90. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  91. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  92. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  93. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  94. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  95. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  96. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  97. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  98. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  99. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  100. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  101. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  102. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  103. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  104. package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
  105. package/dist/web/standalone/.next/server/app/api/terminal/input/route.js +1 -1
  106. package/dist/web/standalone/.next/server/app/api/terminal/resize/route.js +1 -1
  107. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js +1 -1
  108. package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js +1 -1
  109. package/dist/web/standalone/.next/server/app/index.html +1 -1
  110. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  111. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  112. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  113. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  114. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  115. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  116. package/dist/web/standalone/.next/server/app-paths-manifest.json +9 -9
  117. package/dist/web/standalone/.next/server/chunks/6897.js +3 -3
  118. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  119. package/dist/web/standalone/.next/server/middleware-manifest.json +5 -5
  120. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  121. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  122. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  123. package/package.json +3 -2
  124. package/packages/daemon/package.json +2 -2
  125. package/packages/mcp-server/dist/index.d.ts +3 -0
  126. package/packages/mcp-server/dist/index.d.ts.map +1 -1
  127. package/packages/mcp-server/dist/index.js +3 -0
  128. package/packages/mcp-server/dist/index.js.map +1 -1
  129. package/packages/mcp-server/dist/readers/graph.d.ts +87 -0
  130. package/packages/mcp-server/dist/readers/graph.d.ts.map +1 -0
  131. package/packages/mcp-server/dist/readers/graph.js +655 -0
  132. package/packages/mcp-server/dist/readers/graph.js.map +1 -0
  133. package/packages/mcp-server/dist/readers/index.d.ts +2 -0
  134. package/packages/mcp-server/dist/readers/index.d.ts.map +1 -1
  135. package/packages/mcp-server/dist/readers/index.js +1 -0
  136. package/packages/mcp-server/dist/readers/index.js.map +1 -1
  137. package/packages/mcp-server/dist/server.d.ts.map +1 -1
  138. package/packages/mcp-server/dist/server.js +65 -0
  139. package/packages/mcp-server/dist/server.js.map +1 -1
  140. package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
  141. package/packages/mcp-server/dist/workflow-tools.js +88 -6
  142. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  143. package/packages/mcp-server/package.json +2 -2
  144. package/packages/mcp-server/src/index.ts +15 -0
  145. package/packages/mcp-server/src/readers/graph.test.ts +604 -0
  146. package/packages/mcp-server/src/readers/graph.ts +855 -0
  147. package/packages/mcp-server/src/readers/index.ts +12 -0
  148. package/packages/mcp-server/src/server.ts +83 -0
  149. package/packages/mcp-server/src/workflow-tools.ts +95 -10
  150. package/packages/mcp-server/tsconfig.json +1 -0
  151. package/packages/mcp-server/tsconfig.tsbuildinfo +1 -0
  152. package/packages/native/package.json +2 -2
  153. package/packages/native/tsconfig.tsbuildinfo +1 -0
  154. package/packages/pi-agent-core/package.json +1 -1
  155. package/packages/pi-agent-core/tsconfig.json +1 -0
  156. package/packages/pi-agent-core/tsconfig.tsbuildinfo +1 -0
  157. package/packages/pi-ai/dist/index.d.ts +1 -9
  158. package/packages/pi-ai/dist/index.d.ts.map +1 -1
  159. package/packages/pi-ai/dist/index.js +1 -9
  160. package/packages/pi-ai/dist/index.js.map +1 -1
  161. package/packages/pi-ai/dist/models/capability-patches.d.ts +19 -0
  162. package/packages/pi-ai/dist/models/capability-patches.d.ts.map +1 -0
  163. package/packages/pi-ai/dist/models/capability-patches.js +36 -0
  164. package/packages/pi-ai/dist/models/capability-patches.js.map +1 -0
  165. package/packages/pi-ai/dist/{models.custom.d.ts → models/custom.d.ts} +1 -1
  166. package/packages/pi-ai/dist/models/custom.d.ts.map +1 -0
  167. package/packages/pi-ai/dist/{models.custom.js → models/custom.js} +4 -4
  168. package/packages/pi-ai/dist/models/custom.js.map +1 -0
  169. package/packages/pi-ai/dist/models/generated/amazon-bedrock.d.ts +1482 -0
  170. package/packages/pi-ai/dist/models/generated/amazon-bedrock.d.ts.map +1 -0
  171. package/packages/pi-ai/dist/models/generated/amazon-bedrock.js +1484 -0
  172. package/packages/pi-ai/dist/models/generated/amazon-bedrock.js.map +1 -0
  173. package/packages/pi-ai/dist/models/generated/anthropic.d.ts +377 -0
  174. package/packages/pi-ai/dist/models/generated/anthropic.d.ts.map +1 -0
  175. package/packages/pi-ai/dist/models/generated/anthropic.js +379 -0
  176. package/packages/pi-ai/dist/models/generated/anthropic.js.map +1 -0
  177. package/packages/pi-ai/dist/models/generated/azure-openai-responses.d.ts +700 -0
  178. package/packages/pi-ai/dist/models/generated/azure-openai-responses.d.ts.map +1 -0
  179. package/packages/pi-ai/dist/models/generated/azure-openai-responses.js +702 -0
  180. package/packages/pi-ai/dist/models/generated/azure-openai-responses.js.map +1 -0
  181. package/packages/pi-ai/dist/models/generated/cerebras.d.ts +71 -0
  182. package/packages/pi-ai/dist/models/generated/cerebras.d.ts.map +1 -0
  183. package/packages/pi-ai/dist/models/generated/cerebras.js +73 -0
  184. package/packages/pi-ai/dist/models/generated/cerebras.js.map +1 -0
  185. package/packages/pi-ai/dist/models/generated/github-copilot.d.ts +590 -0
  186. package/packages/pi-ai/dist/models/generated/github-copilot.d.ts.map +1 -0
  187. package/packages/pi-ai/dist/models/generated/github-copilot.js +444 -0
  188. package/packages/pi-ai/dist/models/generated/github-copilot.js.map +1 -0
  189. package/packages/pi-ai/dist/models/generated/google-antigravity.d.ts +156 -0
  190. package/packages/pi-ai/dist/models/generated/google-antigravity.d.ts.map +1 -0
  191. package/packages/pi-ai/dist/models/generated/google-antigravity.js +158 -0
  192. package/packages/pi-ai/dist/models/generated/google-antigravity.js.map +1 -0
  193. package/packages/pi-ai/dist/models/generated/google-gemini-cli.d.ts +105 -0
  194. package/packages/pi-ai/dist/models/generated/google-gemini-cli.d.ts.map +1 -0
  195. package/packages/pi-ai/dist/models/generated/google-gemini-cli.js +107 -0
  196. package/packages/pi-ai/dist/models/generated/google-gemini-cli.js.map +1 -0
  197. package/packages/pi-ai/dist/models/generated/google-vertex.d.ts +207 -0
  198. package/packages/pi-ai/dist/models/generated/google-vertex.d.ts.map +1 -0
  199. package/packages/pi-ai/dist/models/generated/google-vertex.js +209 -0
  200. package/packages/pi-ai/dist/models/generated/google-vertex.js.map +1 -0
  201. package/packages/pi-ai/dist/models/generated/google.d.ts +462 -0
  202. package/packages/pi-ai/dist/models/generated/google.d.ts.map +1 -0
  203. package/packages/pi-ai/dist/models/generated/google.js +464 -0
  204. package/packages/pi-ai/dist/models/generated/google.js.map +1 -0
  205. package/packages/pi-ai/dist/models/generated/groq.d.ts +309 -0
  206. package/packages/pi-ai/dist/models/generated/groq.d.ts.map +1 -0
  207. package/packages/pi-ai/dist/models/generated/groq.js +311 -0
  208. package/packages/pi-ai/dist/models/generated/groq.js.map +1 -0
  209. package/packages/pi-ai/dist/models/generated/huggingface.d.ts +383 -0
  210. package/packages/pi-ai/dist/models/generated/huggingface.d.ts.map +1 -0
  211. package/packages/pi-ai/dist/models/generated/huggingface.js +347 -0
  212. package/packages/pi-ai/dist/models/generated/huggingface.js.map +1 -0
  213. package/packages/pi-ai/dist/{models.generated.d.ts → models/generated/index.d.ts} +1 -1
  214. package/packages/pi-ai/dist/{models.generated.d.ts.map → models/generated/index.d.ts.map} +1 -1
  215. package/packages/pi-ai/dist/models/generated/index.js +51 -0
  216. package/packages/pi-ai/dist/models/generated/index.js.map +1 -0
  217. package/packages/pi-ai/dist/models/generated/kimi-coding.d.ts +37 -0
  218. package/packages/pi-ai/dist/models/generated/kimi-coding.d.ts.map +1 -0
  219. package/packages/pi-ai/dist/models/generated/kimi-coding.js +39 -0
  220. package/packages/pi-ai/dist/models/generated/kimi-coding.js.map +1 -0
  221. package/packages/pi-ai/dist/models/generated/minimax-cn.d.ts +105 -0
  222. package/packages/pi-ai/dist/models/generated/minimax-cn.d.ts.map +1 -0
  223. package/packages/pi-ai/dist/models/generated/minimax-cn.js +107 -0
  224. package/packages/pi-ai/dist/models/generated/minimax-cn.js.map +1 -0
  225. package/packages/pi-ai/dist/models/generated/minimax.d.ts +105 -0
  226. package/packages/pi-ai/dist/models/generated/minimax.d.ts.map +1 -0
  227. package/packages/pi-ai/dist/models/generated/minimax.js +107 -0
  228. package/packages/pi-ai/dist/models/generated/minimax.js.map +1 -0
  229. package/packages/pi-ai/dist/models/generated/mistral.d.ts +445 -0
  230. package/packages/pi-ai/dist/models/generated/mistral.d.ts.map +1 -0
  231. package/packages/pi-ai/dist/models/generated/mistral.js +447 -0
  232. package/packages/pi-ai/dist/models/generated/mistral.js.map +1 -0
  233. package/packages/pi-ai/dist/models/generated/openai-codex.d.ts +139 -0
  234. package/packages/pi-ai/dist/models/generated/openai-codex.d.ts.map +1 -0
  235. package/packages/pi-ai/dist/models/generated/openai-codex.js +141 -0
  236. package/packages/pi-ai/dist/models/generated/openai-codex.js.map +1 -0
  237. package/packages/pi-ai/dist/models/generated/openai.d.ts +700 -0
  238. package/packages/pi-ai/dist/models/generated/openai.d.ts.map +1 -0
  239. package/packages/pi-ai/dist/models/generated/openai.js +702 -0
  240. package/packages/pi-ai/dist/models/generated/openai.js.map +1 -0
  241. package/packages/pi-ai/dist/models/generated/opencode-go.d.ts +122 -0
  242. package/packages/pi-ai/dist/models/generated/opencode-go.d.ts.map +1 -0
  243. package/packages/pi-ai/dist/models/generated/opencode-go.js +124 -0
  244. package/packages/pi-ai/dist/models/generated/opencode-go.js.map +1 -0
  245. package/packages/pi-ai/dist/models/generated/opencode.d.ts +530 -0
  246. package/packages/pi-ai/dist/models/generated/opencode.d.ts.map +1 -0
  247. package/packages/pi-ai/dist/models/generated/opencode.js +532 -0
  248. package/packages/pi-ai/dist/models/generated/opencode.js.map +1 -0
  249. package/packages/pi-ai/dist/models/generated/openrouter.d.ts +4270 -0
  250. package/packages/pi-ai/dist/models/generated/openrouter.d.ts.map +1 -0
  251. package/packages/pi-ai/dist/models/generated/openrouter.js +4272 -0
  252. package/packages/pi-ai/dist/models/generated/openrouter.js.map +1 -0
  253. package/packages/pi-ai/dist/models/generated/vercel-ai-gateway.d.ts +2604 -0
  254. package/packages/pi-ai/dist/models/generated/vercel-ai-gateway.d.ts.map +1 -0
  255. package/packages/pi-ai/dist/models/generated/vercel-ai-gateway.js +2606 -0
  256. package/packages/pi-ai/dist/models/generated/vercel-ai-gateway.js.map +1 -0
  257. package/packages/pi-ai/dist/models/generated/xai.d.ts +411 -0
  258. package/packages/pi-ai/dist/models/generated/xai.d.ts.map +1 -0
  259. package/packages/pi-ai/dist/models/generated/xai.js +413 -0
  260. package/packages/pi-ai/dist/models/generated/xai.js.map +1 -0
  261. package/packages/pi-ai/dist/models/generated/zai.d.ts +276 -0
  262. package/packages/pi-ai/dist/models/generated/zai.d.ts.map +1 -0
  263. package/packages/pi-ai/dist/models/generated/zai.js +239 -0
  264. package/packages/pi-ai/dist/models/generated/zai.js.map +1 -0
  265. package/packages/pi-ai/dist/models/index.d.ts +27 -0
  266. package/packages/pi-ai/dist/models/index.d.ts.map +1 -0
  267. package/packages/pi-ai/dist/models/index.js +80 -0
  268. package/packages/pi-ai/dist/models/index.js.map +1 -0
  269. package/packages/pi-ai/dist/models.d.ts +1 -36
  270. package/packages/pi-ai/dist/models.d.ts.map +1 -1
  271. package/packages/pi-ai/dist/models.generated.test.js +1 -2
  272. package/packages/pi-ai/dist/models.generated.test.js.map +1 -1
  273. package/packages/pi-ai/dist/models.js +3 -112
  274. package/packages/pi-ai/dist/models.js.map +1 -1
  275. package/packages/pi-ai/dist/models.test.js +6 -5
  276. package/packages/pi-ai/dist/models.test.js.map +1 -1
  277. package/packages/pi-ai/package.json +1 -1
  278. package/packages/pi-ai/scripts/generate-models.ts +74 -40
  279. package/packages/pi-ai/src/index.ts +1 -9
  280. package/packages/pi-ai/src/models/capability-patches.ts +40 -0
  281. package/packages/pi-ai/src/{models.custom.ts → models/custom.ts} +4 -4
  282. package/packages/pi-ai/src/models/generated/amazon-bedrock.ts +1486 -0
  283. package/packages/pi-ai/src/models/generated/anthropic.ts +381 -0
  284. package/packages/pi-ai/src/models/generated/azure-openai-responses.ts +704 -0
  285. package/packages/pi-ai/src/models/generated/cerebras.ts +75 -0
  286. package/packages/pi-ai/src/models/generated/github-copilot.ts +446 -0
  287. package/packages/pi-ai/src/models/generated/google-antigravity.ts +160 -0
  288. package/packages/pi-ai/src/models/generated/google-gemini-cli.ts +109 -0
  289. package/packages/pi-ai/src/models/generated/google-vertex.ts +211 -0
  290. package/packages/pi-ai/src/models/generated/google.ts +466 -0
  291. package/packages/pi-ai/src/models/generated/groq.ts +313 -0
  292. package/packages/pi-ai/src/models/generated/huggingface.ts +349 -0
  293. package/packages/pi-ai/src/models/generated/index.ts +52 -0
  294. package/packages/pi-ai/src/models/generated/kimi-coding.ts +41 -0
  295. package/packages/pi-ai/src/models/generated/minimax-cn.ts +109 -0
  296. package/packages/pi-ai/src/models/generated/minimax.ts +109 -0
  297. package/packages/pi-ai/src/models/generated/mistral.ts +449 -0
  298. package/packages/pi-ai/src/models/generated/openai-codex.ts +143 -0
  299. package/packages/pi-ai/src/models/generated/openai.ts +704 -0
  300. package/packages/pi-ai/src/models/generated/opencode-go.ts +126 -0
  301. package/packages/pi-ai/src/models/generated/opencode.ts +534 -0
  302. package/packages/pi-ai/src/models/generated/openrouter.ts +4274 -0
  303. package/packages/pi-ai/src/models/generated/vercel-ai-gateway.ts +2608 -0
  304. package/packages/pi-ai/src/models/generated/xai.ts +415 -0
  305. package/packages/pi-ai/src/models/generated/zai.ts +241 -0
  306. package/packages/pi-ai/src/models/index.ts +106 -0
  307. package/packages/pi-ai/src/models.generated.test.ts +1 -2
  308. package/packages/pi-ai/src/models.test.ts +6 -5
  309. package/packages/pi-ai/src/models.ts +3 -153
  310. package/packages/pi-ai/tsconfig.json +1 -0
  311. package/packages/pi-ai/tsconfig.tsbuildinfo +1 -0
  312. package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
  313. package/packages/pi-coding-agent/dist/core/agent-session.js +8 -2
  314. package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
  315. package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js +472 -0
  316. package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js.map +1 -1
  317. package/packages/pi-coding-agent/dist/core/model-registry-env-fallback.test.d.ts +2 -0
  318. package/packages/pi-coding-agent/dist/core/model-registry-env-fallback.test.d.ts.map +1 -0
  319. package/packages/pi-coding-agent/dist/core/model-registry-env-fallback.test.js +52 -0
  320. package/packages/pi-coding-agent/dist/core/model-registry-env-fallback.test.js.map +1 -0
  321. package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
  322. package/packages/pi-coding-agent/dist/core/model-registry.js +2 -2
  323. package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
  324. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js +11 -0
  325. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js.map +1 -1
  326. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts +1 -0
  327. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  328. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js +23 -9
  329. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js.map +1 -1
  330. package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.d.ts +11 -0
  331. package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.d.ts.map +1 -0
  332. package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.js +47 -0
  333. package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.js.map +1 -0
  334. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts +8 -0
  335. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  336. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +68 -8
  337. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
  338. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.d.ts.map +1 -1
  339. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.js +22 -22
  340. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.js.map +1 -1
  341. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  342. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +232 -18
  343. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  344. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-ordering.test.d.ts +2 -0
  345. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-ordering.test.d.ts.map +1 -0
  346. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-ordering.test.js +38 -0
  347. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-ordering.test.js.map +1 -0
  348. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts +14 -0
  349. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  350. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +70 -6
  351. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  352. package/packages/pi-coding-agent/src/core/agent-session.ts +12 -6
  353. package/packages/pi-coding-agent/src/core/chat-controller-ordering.test.ts +612 -0
  354. package/packages/pi-coding-agent/src/core/model-registry-env-fallback.test.ts +59 -0
  355. package/packages/pi-coding-agent/src/core/model-registry.ts +2 -1
  356. package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/tool-execution.test.ts +19 -0
  357. package/packages/pi-coding-agent/src/modes/interactive/components/assistant-message.ts +25 -10
  358. package/packages/pi-coding-agent/src/modes/interactive/components/chat-frame.ts +67 -0
  359. package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +83 -7
  360. package/packages/pi-coding-agent/src/modes/interactive/components/user-message.ts +23 -26
  361. package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +298 -41
  362. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode-ordering.test.ts +44 -0
  363. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +92 -6
  364. package/packages/pi-coding-agent/src/types/ambient-modules.d.ts +69 -0
  365. package/packages/pi-coding-agent/tsconfig.json +3 -2
  366. package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -0
  367. package/packages/pi-tui/package.json +1 -1
  368. package/packages/pi-tui/tsconfig.json +1 -0
  369. package/packages/pi-tui/tsconfig.tsbuildinfo +1 -0
  370. package/packages/rpc-client/package.json +1 -1
  371. package/packages/rpc-client/tsconfig.json +1 -0
  372. package/packages/rpc-client/tsconfig.tsbuildinfo +1 -0
  373. package/src/resources/extensions/gsd/activity-log.ts +21 -0
  374. package/src/resources/extensions/gsd/auto/detect-stuck.ts +12 -4
  375. package/src/resources/extensions/gsd/auto/loop-deps.ts +10 -0
  376. package/src/resources/extensions/gsd/auto/loop.ts +159 -10
  377. package/src/resources/extensions/gsd/auto/phases.ts +261 -10
  378. package/src/resources/extensions/gsd/auto/session.ts +10 -0
  379. package/src/resources/extensions/gsd/auto-dispatch.ts +16 -6
  380. package/src/resources/extensions/gsd/auto-model-selection.ts +69 -8
  381. package/src/resources/extensions/gsd/auto-post-unit.ts +238 -18
  382. package/src/resources/extensions/gsd/auto-prompts.ts +13 -0
  383. package/src/resources/extensions/gsd/auto-recovery.ts +29 -9
  384. package/src/resources/extensions/gsd/auto-unit-closeout.ts +25 -1
  385. package/src/resources/extensions/gsd/auto-verification.ts +129 -2
  386. package/src/resources/extensions/gsd/auto-worktree.ts +1 -0
  387. package/src/resources/extensions/gsd/auto.ts +41 -2
  388. package/src/resources/extensions/gsd/bootstrap/provider-error-resume.ts +5 -3
  389. package/src/resources/extensions/gsd/bootstrap/register-extension.ts +38 -8
  390. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +72 -8
  391. package/src/resources/extensions/gsd/cache.ts +16 -5
  392. package/src/resources/extensions/gsd/commands/catalog.ts +31 -1
  393. package/src/resources/extensions/gsd/commands/handlers/core.ts +5 -1
  394. package/src/resources/extensions/gsd/commands/handlers/ops.ts +25 -0
  395. package/src/resources/extensions/gsd/commands/handlers/workflow.ts +74 -9
  396. package/src/resources/extensions/gsd/commands-add-tests.ts +137 -0
  397. package/src/resources/extensions/gsd/commands-backlog.ts +182 -0
  398. package/src/resources/extensions/gsd/commands-do.ts +109 -0
  399. package/src/resources/extensions/gsd/commands-extract-learnings.ts +304 -0
  400. package/src/resources/extensions/gsd/commands-maintenance.ts +6 -6
  401. package/src/resources/extensions/gsd/commands-pr-branch.ts +234 -0
  402. package/src/resources/extensions/gsd/commands-prefs-wizard.ts +58 -4
  403. package/src/resources/extensions/gsd/commands-session-report.ts +101 -0
  404. package/src/resources/extensions/gsd/commands-ship.ts +219 -0
  405. package/src/resources/extensions/gsd/db-writer.ts +3 -5
  406. package/src/resources/extensions/gsd/docs/preferences-reference.md +16 -1
  407. package/src/resources/extensions/gsd/ecosystem/gsd-extension-api.ts +228 -0
  408. package/src/resources/extensions/gsd/ecosystem/loader.ts +201 -0
  409. package/src/resources/extensions/gsd/git-service.ts +68 -0
  410. package/src/resources/extensions/gsd/graph-context.ts +212 -0
  411. package/src/resources/extensions/gsd/gsd-db.ts +788 -3
  412. package/src/resources/extensions/gsd/guided-flow.ts +36 -2
  413. package/src/resources/extensions/gsd/index.ts +18 -2
  414. package/src/resources/extensions/gsd/init-wizard.ts +3 -2
  415. package/src/resources/extensions/gsd/journal.ts +30 -0
  416. package/src/resources/extensions/gsd/md-importer.ts +3 -5
  417. package/src/resources/extensions/gsd/memory-store.ts +31 -62
  418. package/src/resources/extensions/gsd/metrics.ts +26 -0
  419. package/src/resources/extensions/gsd/milestone-validation-gates.ts +13 -14
  420. package/src/resources/extensions/gsd/native-git-bridge.ts +11 -12
  421. package/src/resources/extensions/gsd/parallel-orchestrator.ts +40 -1
  422. package/src/resources/extensions/gsd/preferences-models.ts +20 -3
  423. package/src/resources/extensions/gsd/preferences-types.ts +38 -0
  424. package/src/resources/extensions/gsd/preferences-validation.ts +117 -2
  425. package/src/resources/extensions/gsd/preferences.ts +34 -0
  426. package/src/resources/extensions/gsd/prompts/add-tests.md +35 -0
  427. package/src/resources/extensions/gsd/safety/evidence-collector.ts +15 -31
  428. package/src/resources/extensions/gsd/session-lock.ts +14 -2
  429. package/src/resources/extensions/gsd/slice-parallel-orchestrator.ts +20 -1
  430. package/src/resources/extensions/gsd/state.ts +9 -2
  431. package/src/resources/extensions/gsd/templates/PREFERENCES.md +19 -0
  432. package/src/resources/extensions/gsd/tests/artifacts-table-preserved-on-cache-invalidate.test.ts +177 -0
  433. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +7 -3
  434. package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +20 -0
  435. package/src/resources/extensions/gsd/tests/auto-project-root-env.test.ts +7 -3
  436. package/src/resources/extensions/gsd/tests/auto-retry-mcp-churn-fixes.test.ts +272 -0
  437. package/src/resources/extensions/gsd/tests/auto-warning-noise-regression.test.ts +117 -0
  438. package/src/resources/extensions/gsd/tests/cold-resume-db-reopen.test.ts +6 -2
  439. package/src/resources/extensions/gsd/tests/commands-backlog.test.ts +158 -0
  440. package/src/resources/extensions/gsd/tests/commands-do.test.ts +127 -0
  441. package/src/resources/extensions/gsd/tests/commands-extract-learnings.test.ts +340 -0
  442. package/src/resources/extensions/gsd/tests/commands-pr-branch.test.ts +68 -0
  443. package/src/resources/extensions/gsd/tests/commands-session-report.test.ts +82 -0
  444. package/src/resources/extensions/gsd/tests/commands-ship.test.ts +71 -0
  445. package/src/resources/extensions/gsd/tests/commands-workflow-custom.test.ts +14 -0
  446. package/src/resources/extensions/gsd/tests/complete-slice.test.ts +2 -2
  447. package/src/resources/extensions/gsd/tests/complete-task.test.ts +2 -2
  448. package/src/resources/extensions/gsd/tests/extension-bootstrap-isolation.test.ts +154 -0
  449. package/src/resources/extensions/gsd/tests/finalize-timeout-guard.test.ts +10 -7
  450. package/src/resources/extensions/gsd/tests/graph-context.test.ts +337 -0
  451. package/src/resources/extensions/gsd/tests/gsd-db.test.ts +1 -1
  452. package/src/resources/extensions/gsd/tests/health-widget.test.ts +1 -1
  453. package/src/resources/extensions/gsd/tests/journal-integration.test.ts +71 -4
  454. package/src/resources/extensions/gsd/tests/md-importer.test.ts +1 -2
  455. package/src/resources/extensions/gsd/tests/memory-store.test.ts +2 -3
  456. package/src/resources/extensions/gsd/tests/native-git-bridge-exec-fallback.test.ts +140 -0
  457. package/src/resources/extensions/gsd/tests/post-exec-retry-bypass.test.ts +79 -1
  458. package/src/resources/extensions/gsd/tests/post-unit-state-rebuild.test.ts +2 -1
  459. package/src/resources/extensions/gsd/tests/pre-execution-pause-wiring.test.ts +40 -1
  460. package/src/resources/extensions/gsd/tests/preferences.test.ts +145 -0
  461. package/src/resources/extensions/gsd/tests/provider-errors.test.ts +57 -2
  462. package/src/resources/extensions/gsd/tests/register-hooks-depth-verification.test.ts +1 -1
  463. package/src/resources/extensions/gsd/tests/single-writer-invariant.test.ts +180 -0
  464. package/src/resources/extensions/gsd/tests/token-profile.test.ts +8 -5
  465. package/src/resources/extensions/gsd/tests/uok-audit-unified.test.ts +101 -0
  466. package/src/resources/extensions/gsd/tests/uok-contracts.test.ts +85 -0
  467. package/src/resources/extensions/gsd/tests/uok-execution-graph.test.ts +69 -0
  468. package/src/resources/extensions/gsd/tests/uok-flags.test.ts +39 -0
  469. package/src/resources/extensions/gsd/tests/uok-gate-runner.test.ts +70 -0
  470. package/src/resources/extensions/gsd/tests/uok-gitops-turn-action.test.ts +85 -0
  471. package/src/resources/extensions/gsd/tests/uok-gitops-wiring.test.ts +35 -0
  472. package/src/resources/extensions/gsd/tests/uok-model-policy.test.ts +89 -0
  473. package/src/resources/extensions/gsd/tests/uok-plan-v2-wiring.test.ts +167 -0
  474. package/src/resources/extensions/gsd/tests/uok-preferences.test.ts +42 -0
  475. package/src/resources/extensions/gsd/tests/validate-milestone-write-order.test.ts +39 -0
  476. package/src/resources/extensions/gsd/tests/workflow-logger-wiring.test.ts +223 -0
  477. package/src/resources/extensions/gsd/tools/complete-slice.ts +26 -0
  478. package/src/resources/extensions/gsd/tools/validate-milestone.ts +48 -3
  479. package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +3 -11
  480. package/src/resources/extensions/gsd/triage-resolution.ts +2 -7
  481. package/src/resources/extensions/gsd/types.ts +14 -1
  482. package/src/resources/extensions/gsd/unit-ownership.ts +2 -2
  483. package/src/resources/extensions/gsd/uok/audit-toggle.ts +9 -0
  484. package/src/resources/extensions/gsd/uok/audit.ts +51 -0
  485. package/src/resources/extensions/gsd/uok/contracts.ts +135 -0
  486. package/src/resources/extensions/gsd/uok/execution-graph.ts +241 -0
  487. package/src/resources/extensions/gsd/uok/flags.ts +45 -0
  488. package/src/resources/extensions/gsd/uok/gate-runner.ts +146 -0
  489. package/src/resources/extensions/gsd/uok/gitops.ts +75 -0
  490. package/src/resources/extensions/gsd/uok/kernel.ts +105 -0
  491. package/src/resources/extensions/gsd/uok/loop-adapter.ts +162 -0
  492. package/src/resources/extensions/gsd/uok/model-policy.ts +112 -0
  493. package/src/resources/extensions/gsd/uok/plan-v2.ts +156 -0
  494. package/src/resources/extensions/gsd/workflow-logger.ts +27 -1
  495. package/src/resources/extensions/gsd/workflow-manifest.ts +9 -104
  496. package/src/resources/extensions/gsd/workflow-migration.ts +21 -29
  497. package/src/resources/extensions/gsd/workflow-projections.ts +8 -1
  498. package/src/resources/extensions/gsd/workflow-reconcile.ts +15 -15
  499. package/src/resources/extensions/ttsr/ttsr-manager.ts +10 -5
  500. package/packages/pi-ai/dist/models.custom.d.ts.map +0 -1
  501. package/packages/pi-ai/dist/models.custom.js.map +0 -1
  502. package/packages/pi-ai/dist/models.generated.js +0 -14343
  503. package/packages/pi-ai/dist/models.generated.js.map +0 -1
  504. package/packages/pi-ai/src/models.generated.ts +0 -14345
  505. /package/dist/web/standalone/.next/static/{YzIEI9sxJy4t5xgClF08g → Es_JWCfFZjIvYZShmjyye}/_buildManifest.js +0 -0
  506. /package/dist/web/standalone/.next/static/{YzIEI9sxJy4t5xgClF08g → Es_JWCfFZjIvYZShmjyye}/_ssgManifest.js +0 -0
@@ -12,6 +12,7 @@ import { importExtensionModule, type ExtensionAPI, type ExtensionContext } from
12
12
  import type { AutoSession, SidecarItem } from "./session.js";
13
13
  import type { LoopDeps } from "./loop-deps.js";
14
14
  import type { PostUnitContext, PreVerificationOpts } from "../auto-post-unit.js";
15
+ import type { Phase } from "../types.js";
15
16
  import {
16
17
  MAX_RECOVERY_CHARS,
17
18
  BUDGET_THRESHOLDS,
@@ -28,9 +29,19 @@ import { debugLog } from "../debug-logger.js";
28
29
  import { PROJECT_FILES } from "../detection.js";
29
30
  import { MergeConflictError } from "../git-service.js";
30
31
  import { setCurrentPhase, clearCurrentPhase } from "../../shared/gsd-phase-state.js";
32
+ import { pauseAutoForProviderError } from "../provider-error-pause.js";
33
+ import { resumeAutoAfterProviderDelay } from "../bootstrap/provider-error-resume.js";
31
34
  import { join, basename, dirname, parse as parsePath } from "node:path";
32
35
  import { existsSync, cpSync, readdirSync } from "node:fs";
33
- import { logWarning, logError } from "../workflow-logger.js";
36
+ import {
37
+ logWarning,
38
+ logError,
39
+ _resetLogs,
40
+ drainLogs,
41
+ drainAndSummarize,
42
+ formatForNotification,
43
+ hasAnyIssues,
44
+ } from "../workflow-logger.js";
34
45
  import { gsdRoot } from "../paths.js";
35
46
  import { atomicWriteSync } from "../atomic-write.js";
36
47
  import { verifyExpectedArtifact, diagnoseExpectedArtifact, buildLoopRemediationSteps } from "../auto-recovery.js";
@@ -39,6 +50,9 @@ import { withTimeout, FINALIZE_PRE_TIMEOUT_MS, FINALIZE_POST_TIMEOUT_MS } from "
39
50
  import { getEligibleSlices } from "../slice-parallel-eligibility.js";
40
51
  import { startSliceParallel } from "../slice-parallel-orchestrator.js";
41
52
  import { isDbAvailable, getMilestoneSlices } from "../gsd-db.js";
53
+ import { ensurePlanV2Graph } from "../uok/plan-v2.js";
54
+ import { resolveUokFlags } from "../uok/flags.js";
55
+ import { UokGateRunner } from "../uok/gate-runner.js";
42
56
  import { resetEvidence } from "../safety/evidence-collector.js";
43
57
  import { createCheckpoint, cleanupCheckpoint, rollbackToCheckpoint } from "../safety/git-checkpoint.js";
44
58
  import { resolveSafetyHarnessConfig } from "../safety/safety-harness.js";
@@ -47,6 +61,15 @@ import {
47
61
  getRequiredWorkflowToolsForAutoUnit,
48
62
  } from "../workflow-mcp.js";
49
63
 
64
+ // ─── Session timeout auto-resume state ────────────────────────────────────────
65
+
66
+ let consecutiveSessionTimeouts = 0;
67
+ const MAX_SESSION_TIMEOUT_AUTO_RESUMES = 3;
68
+
69
+ export function resetSessionTimeoutState(): void {
70
+ consecutiveSessionTimeouts = 0;
71
+ }
72
+
50
73
  // ─── generateMilestoneReport ──────────────────────────────────────────────────
51
74
 
52
75
  /**
@@ -69,6 +92,17 @@ export function _resolveDispatchGuardBasePath(
69
92
  return s.originalBasePath || s.basePath;
70
93
  }
71
94
 
95
+ const PLAN_V2_GATE_PHASES: ReadonlySet<Phase> = new Set([
96
+ "executing",
97
+ "summarizing",
98
+ "validating-milestone",
99
+ "completing-milestone",
100
+ ]);
101
+
102
+ function shouldRunPlanV2Gate(phase: Phase): boolean {
103
+ return PLAN_V2_GATE_PHASES.has(phase);
104
+ }
105
+
72
106
  /**
73
107
  * Generate and write an HTML milestone report snapshot.
74
108
  * Extracted from the milestone-transition block in autoLoop.
@@ -159,6 +193,29 @@ async function closeoutAndStop(
159
193
  await deps.stopAuto(ctx, pi, reason);
160
194
  }
161
195
 
196
+ async function emitCancelledUnitEnd(
197
+ ic: IterationContext,
198
+ unitType: string,
199
+ unitId: string,
200
+ unitStartSeq: number,
201
+ errorContext?: { message: string; category: string; stopReason?: string; isTransient?: boolean; retryAfterMs?: number },
202
+ ): Promise<void> {
203
+ ic.deps.emitJournalEvent({
204
+ ts: new Date().toISOString(),
205
+ flowId: ic.flowId,
206
+ seq: ic.nextSeq(),
207
+ eventType: "unit-end",
208
+ data: {
209
+ unitType,
210
+ unitId,
211
+ status: "cancelled",
212
+ artifactVerified: false,
213
+ ...(errorContext ? { errorContext } : {}),
214
+ },
215
+ causedBy: { flowId: ic.flowId, seq: unitStartSeq },
216
+ });
217
+ }
218
+
162
219
  // ─── runPreDispatch ───────────────────────────────────────────────────────────
163
220
 
164
221
  /**
@@ -171,14 +228,60 @@ export async function runPreDispatch(
171
228
  loopState: LoopState,
172
229
  ): Promise<PhaseResult<PreDispatchData>> {
173
230
  const { ctx, pi, s, deps, prefs } = ic;
231
+ const uokFlags = resolveUokFlags(prefs);
232
+ const runPreDispatchGate = async (input: {
233
+ gateId: string;
234
+ gateType: string;
235
+ outcome: "pass" | "fail" | "retry" | "manual-attention";
236
+ failureClass: "none" | "policy" | "input" | "execution" | "artifact" | "verification" | "closeout" | "git" | "timeout" | "manual-attention" | "unknown";
237
+ rationale: string;
238
+ findings?: string;
239
+ milestoneId?: string;
240
+ }): Promise<void> => {
241
+ if (!uokFlags.gates) return;
242
+ const gateRunner = new UokGateRunner();
243
+ gateRunner.register({
244
+ id: input.gateId,
245
+ type: input.gateType,
246
+ execute: async () => ({
247
+ outcome: input.outcome,
248
+ failureClass: input.failureClass,
249
+ rationale: input.rationale,
250
+ findings: input.findings ?? "",
251
+ }),
252
+ });
253
+ await gateRunner.run(input.gateId, {
254
+ basePath: s.basePath,
255
+ traceId: `pre-dispatch:${ic.flowId}`,
256
+ turnId: `iter-${ic.iteration}`,
257
+ milestoneId: input.milestoneId ?? s.currentMilestoneId ?? undefined,
258
+ unitType: "pre-dispatch",
259
+ unitId: `iter-${ic.iteration}`,
260
+ });
261
+ };
174
262
 
175
263
  // Resource version guard
176
264
  const staleMsg = deps.checkResourcesStale(s.resourceVersionOnStart);
177
265
  if (staleMsg) {
266
+ await runPreDispatchGate({
267
+ gateId: "resource-version-guard",
268
+ gateType: "policy",
269
+ outcome: "fail",
270
+ failureClass: "policy",
271
+ rationale: "resource version guard blocked dispatch",
272
+ findings: staleMsg,
273
+ });
178
274
  await deps.stopAuto(ctx, pi, staleMsg);
179
275
  debugLog("autoLoop", { phase: "exit", reason: "resources-stale" });
180
276
  return { action: "break", reason: "resources-stale" };
181
277
  }
278
+ await runPreDispatchGate({
279
+ gateId: "resource-version-guard",
280
+ gateType: "policy",
281
+ outcome: "pass",
282
+ failureClass: "none",
283
+ rationale: "resource version guard passed",
284
+ });
182
285
 
183
286
  deps.invalidateAllCaches();
184
287
  s.lastPromptCharCount = undefined;
@@ -194,6 +297,14 @@ export async function runPreDispatch(
194
297
  );
195
298
  }
196
299
  if (!healthGate.proceed) {
300
+ await runPreDispatchGate({
301
+ gateId: "pre-dispatch-health-gate",
302
+ gateType: "execution",
303
+ outcome: "manual-attention",
304
+ failureClass: "manual-attention",
305
+ rationale: "pre-dispatch health gate blocked dispatch",
306
+ findings: healthGate.reason,
307
+ });
197
308
  ctx.ui.notify(
198
309
  healthGate.reason || "Pre-dispatch health check failed — run /gsd doctor for details.",
199
310
  "error",
@@ -202,7 +313,23 @@ export async function runPreDispatch(
202
313
  debugLog("autoLoop", { phase: "exit", reason: "health-gate-failed" });
203
314
  return { action: "break", reason: "health-gate-failed" };
204
315
  }
316
+ await runPreDispatchGate({
317
+ gateId: "pre-dispatch-health-gate",
318
+ gateType: "execution",
319
+ outcome: "pass",
320
+ failureClass: "none",
321
+ rationale: "pre-dispatch health gate passed",
322
+ findings: healthGate.fixesApplied.length > 0 ? healthGate.fixesApplied.join(", ") : "",
323
+ });
205
324
  } catch (e) {
325
+ await runPreDispatchGate({
326
+ gateId: "pre-dispatch-health-gate",
327
+ gateType: "execution",
328
+ outcome: "manual-attention",
329
+ failureClass: "manual-attention",
330
+ rationale: "pre-dispatch health gate threw unexpectedly",
331
+ findings: String(e),
332
+ });
206
333
  logWarning("engine", "Pre-dispatch health gate threw unexpectedly", { error: String(e) });
207
334
  }
208
335
 
@@ -221,6 +348,32 @@ export async function runPreDispatch(
221
348
 
222
349
  // Derive state
223
350
  let state = await deps.deriveState(s.basePath);
351
+ if (prefs?.uok?.plan_v2?.enabled && shouldRunPlanV2Gate(state.phase)) {
352
+ const compiled = ensurePlanV2Graph(s.basePath, state);
353
+ if (!compiled.ok) {
354
+ const reason = compiled.reason ?? "Plan v2 compilation failed";
355
+ await runPreDispatchGate({
356
+ gateId: "plan-v2-gate",
357
+ gateType: "policy",
358
+ outcome: "manual-attention",
359
+ failureClass: "manual-attention",
360
+ rationale: "plan v2 compile gate failed",
361
+ findings: reason,
362
+ milestoneId: state.activeMilestone?.id ?? undefined,
363
+ });
364
+ ctx.ui.notify(`Plan gate failed-closed: ${reason}`, "error");
365
+ await deps.pauseAuto(ctx, pi);
366
+ return { action: "break", reason: "plan-v2-gate-failed" };
367
+ }
368
+ await runPreDispatchGate({
369
+ gateId: "plan-v2-gate",
370
+ gateType: "policy",
371
+ outcome: "pass",
372
+ failureClass: "none",
373
+ rationale: "plan v2 compile gate passed",
374
+ milestoneId: state.activeMilestone?.id ?? undefined,
375
+ });
376
+ }
224
377
  deps.syncCmuxSidebar(prefs, state);
225
378
  let mid = state.activeMilestone?.id;
226
379
  let midTitle = state.activeMilestone?.title;
@@ -266,7 +419,10 @@ export async function runPreDispatch(
266
419
  s.basePath,
267
420
  mid,
268
421
  eligible,
269
- { maxWorkers: prefs.slice_parallel.max_workers ?? 2 },
422
+ {
423
+ maxWorkers: prefs.slice_parallel.max_workers ?? 2,
424
+ useExecutionGraph: uokFlags.executionGraph,
425
+ },
270
426
  );
271
427
  if (result.started.length > 0) {
272
428
  ctx.ui.notify(
@@ -1081,7 +1237,13 @@ export async function runUnitPhase(
1081
1237
  );
1082
1238
  const previousTier = s.currentUnitRouting?.tier;
1083
1239
 
1240
+ // Scope workflow-logger buffer to this unit so post-finalize drains are
1241
+ // per-unit. Without this, the module-level _buffer accumulates across every
1242
+ // unit in the same Node process (see workflow-logger.ts module header).
1243
+ _resetLogs();
1084
1244
  s.currentUnit = { type: unitType, id: unitId, startedAt: Date.now() };
1245
+ s.lastGitActionFailure = null;
1246
+ s.lastGitActionStatus = null;
1085
1247
  setCurrentPhase(unitType);
1086
1248
  s.lastToolInvocationError = null; // #2883: clear stale error from previous unit
1087
1249
  const unitStartSeq = ic.nextSeq();
@@ -1347,27 +1509,93 @@ export async function runUnitPhase(
1347
1509
  // Provider-error pause: pauseAuto already handled cleanup and scheduled
1348
1510
  // recovery. Don't hard-stop — just break out of the loop (#2762).
1349
1511
  if (unitResult.errorContext?.category === "provider") {
1512
+ await emitCancelledUnitEnd(ic, unitType, unitId, unitStartSeq, unitResult.errorContext);
1350
1513
  debugLog("autoLoop", { phase: "exit", reason: "provider-pause", isTransient: unitResult.errorContext.isTransient });
1351
1514
  return { action: "break", reason: "provider-pause" };
1352
1515
  }
1353
- // Session creation timeout (not a structural error): pause auto-mode
1354
- // and let the provider-error-resume timer handle recovery (#3767). This
1355
- // matches the provider-pause pathbreak out cleanly, don't hard-stop.
1516
+ // Timeout category covers two distinct scenarios:
1517
+ // 1. Session creation timeout (120s) transient, auto-resume with backoff
1518
+ // 2. Unit hard timeout (30min+)stuck agent, pause for manual review
1356
1519
  // Structural errors (TypeError, is not a function) are NOT transient
1357
1520
  // and must hard-stop to avoid infinite retry loops.
1358
1521
  if (
1359
1522
  unitResult.errorContext?.isTransient &&
1360
1523
  unitResult.errorContext?.category === "timeout"
1361
1524
  ) {
1525
+ const isSessionCreationTimeout = unitResult.errorContext.message?.includes("Session creation timed out");
1526
+
1527
+ if (isSessionCreationTimeout) {
1528
+ consecutiveSessionTimeouts += 1;
1529
+ const baseRetryAfterMs = 30_000;
1530
+ const retryAfterMs = baseRetryAfterMs * 2 ** Math.max(0, consecutiveSessionTimeouts - 1);
1531
+ const allowAutoResume = consecutiveSessionTimeouts <= MAX_SESSION_TIMEOUT_AUTO_RESUMES;
1532
+
1533
+ if (!allowAutoResume) {
1534
+ ctx.ui.notify(
1535
+ `Session creation timed out ${consecutiveSessionTimeouts} consecutive times for ${unitType} ${unitId}. Pausing for manual review.`,
1536
+ "warning",
1537
+ );
1538
+ }
1539
+
1540
+ debugLog("autoLoop", {
1541
+ phase: "session-timeout-pause",
1542
+ unitType, unitId,
1543
+ consecutiveSessionTimeouts,
1544
+ retryAfterMs,
1545
+ allowAutoResume,
1546
+ });
1547
+
1548
+ const errorDetail = ` for ${unitType} ${unitId}`;
1549
+ await pauseAutoForProviderError(
1550
+ ctx.ui,
1551
+ errorDetail,
1552
+ () => deps.pauseAuto(ctx, pi),
1553
+ {
1554
+ isRateLimit: false,
1555
+ isTransient: allowAutoResume,
1556
+ retryAfterMs,
1557
+ resume: allowAutoResume
1558
+ ? () => {
1559
+ void resumeAutoAfterProviderDelay(pi, ctx).catch((err) => {
1560
+ const message = err instanceof Error ? err.message : String(err);
1561
+ ctx.ui.notify(
1562
+ `Session timeout recovery failed: ${message}`,
1563
+ "error",
1564
+ );
1565
+ });
1566
+ }
1567
+ : undefined,
1568
+ },
1569
+ );
1570
+ await deps.autoCommitUnit?.(s.basePath, unitType, unitId, ctx);
1571
+ await emitCancelledUnitEnd(ic, unitType, unitId, unitStartSeq, unitResult.errorContext);
1572
+ return { action: "break", reason: "session-timeout" };
1573
+ }
1574
+
1575
+ // Unit hard timeout (30min+): pause without auto-resume — stuck agent
1362
1576
  ctx.ui.notify(
1363
- `Session creation timed out for ${unitType} ${unitId}. Pausing auto-mode (recoverable).`,
1577
+ `Unit timed out for ${unitType} ${unitId} (supervision may have failed). Pausing auto-mode.`,
1364
1578
  "warning",
1365
1579
  );
1366
- debugLog("autoLoop", { phase: "session-timeout-pause", unitType, unitId });
1580
+ debugLog("autoLoop", { phase: "unit-hard-timeout-pause", unitType, unitId });
1367
1581
  await deps.pauseAuto(ctx, pi);
1368
- return { action: "break", reason: "session-timeout" };
1582
+ await deps.autoCommitUnit?.(s.basePath, unitType, unitId, ctx);
1583
+ await emitCancelledUnitEnd(ic, unitType, unitId, unitStartSeq, unitResult.errorContext);
1584
+ return { action: "break", reason: "unit-hard-timeout" };
1369
1585
  }
1370
1586
  // All other cancelled states (structural errors, non-transient failures): hard stop
1587
+ if (s.currentUnit) {
1588
+ await deps.closeoutUnit(
1589
+ ctx,
1590
+ s.basePath,
1591
+ unitType,
1592
+ unitId,
1593
+ s.currentUnit.startedAt,
1594
+ deps.buildSnapshotOpts(unitType, unitId),
1595
+ );
1596
+ }
1597
+ await deps.autoCommitUnit?.(s.basePath, unitType, unitId, ctx);
1598
+ await emitCancelledUnitEnd(ic, unitType, unitId, unitStartSeq, unitResult.errorContext);
1371
1599
  ctx.ui.notify(
1372
1600
  `Session creation failed for ${unitType} ${unitId}: ${unitResult.errorContext?.message ?? "unknown"}. Stopping auto-mode.`,
1373
1601
  "warning",
@@ -1383,6 +1611,8 @@ export async function runUnitPhase(
1383
1611
  // Guard: stopAuto() may have nulled s.currentUnit via s.reset() while
1384
1612
  // this coroutine was suspended at `await runUnit(...)` (#2939).
1385
1613
  if (s.currentUnit) {
1614
+ // Reset session timeout counter — any successful unit clears the slate
1615
+ consecutiveSessionTimeouts = 0;
1386
1616
  await deps.closeoutUnit(
1387
1617
  ctx,
1388
1618
  s.basePath,
@@ -1545,6 +1775,9 @@ export async function runFinalize(
1545
1775
  // cannot mutate state for the next unit (#3757).
1546
1776
  s.currentUnit = null;
1547
1777
  clearCurrentPhase();
1778
+ // Drop any logger entries from the timed-out unit so they don't bleed
1779
+ // into the next iteration's drain.
1780
+ drainLogs();
1548
1781
  loopState.consecutiveFinalizeTimeouts++;
1549
1782
  debugLog("autoLoop", {
1550
1783
  phase: "pre-verification-timeout",
@@ -1572,11 +1805,15 @@ export async function runFinalize(
1572
1805
 
1573
1806
  const preResult = preResultGuard.value;
1574
1807
  if (preResult === "dispatched") {
1808
+ const dispatchedReason = s.lastGitActionFailure
1809
+ ? "git-closeout-failure"
1810
+ : "pre-verification-dispatched";
1575
1811
  debugLog("autoLoop", {
1576
1812
  phase: "exit",
1577
- reason: "pre-verification-dispatched",
1813
+ reason: dispatchedReason,
1814
+ gitError: s.lastGitActionFailure ?? undefined,
1578
1815
  });
1579
- return { action: "break", reason: "pre-verification-dispatched" };
1816
+ return { action: "break", reason: dispatchedReason };
1580
1817
  }
1581
1818
  if (preResult === "retry") {
1582
1819
  if (sidecarItem) {
@@ -1643,6 +1880,9 @@ export async function runFinalize(
1643
1880
  // cannot mutate state for the next unit (#3757).
1644
1881
  s.currentUnit = null;
1645
1882
  clearCurrentPhase();
1883
+ // Drop any logger entries from the timed-out unit so they don't bleed
1884
+ // into the next iteration's drain.
1885
+ drainLogs();
1646
1886
  loopState.consecutiveFinalizeTimeouts++;
1647
1887
  debugLog("autoLoop", {
1648
1888
  phase: "post-verification-timeout",
@@ -1687,5 +1927,16 @@ export async function runFinalize(
1687
1927
  // Both pre and post verification completed without timeout — reset counter
1688
1928
  loopState.consecutiveFinalizeTimeouts = 0;
1689
1929
 
1930
+ // Surface accumulated workflow-logger issues for this unit to the user.
1931
+ // Warnings/errors logged during the unit are buffered in the logger and
1932
+ // drained here so the user sees a single consolidated post-unit alert.
1933
+ if (hasAnyIssues()) {
1934
+ const { logs } = drainAndSummarize();
1935
+ if (logs.length > 0) {
1936
+ const severity = logs.some((e) => e.severity === "error") ? "error" : "warning";
1937
+ ctx.ui.notify(formatForNotification(logs), severity);
1938
+ }
1939
+ }
1940
+
1690
1941
  return { action: "next", data: undefined as void };
1691
1942
  }
@@ -106,6 +106,8 @@ export class AutoSession {
106
106
 
107
107
  // ── Current unit ─────────────────────────────────────────────────────────
108
108
  currentUnit: CurrentUnit | null = null;
109
+ currentTraceId: string | null = null;
110
+ currentTurnId: string | null = null;
109
111
  currentUnitRouting: UnitRouting | null = null;
110
112
  currentMilestoneId: string | null = null;
111
113
 
@@ -137,6 +139,10 @@ export class AutoSession {
137
139
  /** Set when a GSD tool execution ends with isError due to malformed/truncated
138
140
  * JSON arguments. Checked by postUnitPreVerification to break retry loops. */
139
141
  lastToolInvocationError: string | null = null;
142
+ /** Set when turn-level git action fails during closeout. */
143
+ lastGitActionFailure: string | null = null;
144
+ /** Last turn-level git action status captured during finalize. */
145
+ lastGitActionStatus: "ok" | "failed" | null = null;
140
146
 
141
147
  // ── Isolation degradation ────────────────────────────────────────────
142
148
  /** Set to true when worktree creation fails; prevents merge of nonexistent branch. */
@@ -219,6 +225,8 @@ export class AutoSession {
219
225
 
220
226
  // Unit
221
227
  this.currentUnit = null;
228
+ this.currentTraceId = null;
229
+ this.currentTurnId = null;
222
230
  this.currentUnitRouting = null;
223
231
  this.currentMilestoneId = null;
224
232
 
@@ -250,6 +258,8 @@ export class AutoSession {
250
258
  this.rewriteAttemptCount = 0;
251
259
  this.consecutiveCompleteBootstraps = 0;
252
260
  this.lastToolInvocationError = null;
261
+ this.lastGitActionFailure = null;
262
+ this.lastGitActionStatus = null;
253
263
  this.isolationDegraded = false;
254
264
  this.milestoneMergedInPhases = false;
255
265
  this.checkpointSha = null;
@@ -53,6 +53,8 @@ import {
53
53
  checkNeedsRunUat,
54
54
  } from "./auto-prompts.js";
55
55
  import { resolveModelWithFallbacksForUnit } from "./preferences-models.js";
56
+ import { resolveUokFlags } from "./uok/flags.js";
57
+ import { selectReactiveDispatchBatch } from "./uok/execution-graph.js";
56
58
 
57
59
  // ─── Types ────────────────────────────────────────────────────────────────
58
60
 
@@ -584,12 +586,20 @@ export const DISPATCH_RULES: DispatchRule[] = [
584
586
  // Only activate reactive dispatch when >1 task is ready
585
587
  if (readyIds.length <= 1) return null;
586
588
 
587
- const selected = chooseNonConflictingSubset(
588
- readyIds,
589
- graph,
590
- maxParallel,
591
- new Set(),
592
- );
589
+ const uokFlags = resolveUokFlags(prefs);
590
+ const selected = uokFlags.executionGraph
591
+ ? selectReactiveDispatchBatch({
592
+ graph,
593
+ readyIds,
594
+ maxParallel,
595
+ inFlightOutputs: new Set(),
596
+ }).selected
597
+ : chooseNonConflictingSubset(
598
+ readyIds,
599
+ graph,
600
+ maxParallel,
601
+ new Set(),
602
+ );
593
603
  if (selected.length <= 1) return null;
594
604
 
595
605
  // Log graph metrics for observability
@@ -10,12 +10,14 @@ import type { ExtensionAPI, ExtensionContext } from "@gsd/pi-coding-agent";
10
10
  import type { GSDPreferences } from "./preferences.js";
11
11
  import { resolveModelWithFallbacksForUnit, resolveDynamicRoutingConfig } from "./preferences.js";
12
12
  import type { ComplexityTier } from "./complexity-classifier.js";
13
- import { classifyUnitComplexity, tierLabel } from "./complexity-classifier.js";
13
+ import { classifyUnitComplexity, extractTaskMetadata, tierLabel } from "./complexity-classifier.js";
14
14
  import { resolveModelForComplexity, escalateTier, getEligibleModels, loadCapabilityOverrides, adjustToolSet, filterToolsForProvider } from "./model-router.js";
15
15
  import { getLedger, getProjectTotals } from "./metrics.js";
16
16
  import { unitPhaseLabel } from "./auto-dashboard.js";
17
17
  import { getSessionModelOverride } from "./session-model-override.js";
18
18
  import { logWarning } from "./workflow-logger.js";
19
+ import { resolveUokFlags } from "./uok/flags.js";
20
+ import { applyModelPolicyFilter } from "./uok/model-policy.js";
19
21
 
20
22
  export interface ModelSelectionResult {
21
23
  /** Routing metadata for metrics recording */
@@ -75,6 +77,7 @@ export async function selectAndApplyModel(
75
77
  /** Explicit /gsd model pin captured at bootstrap for long-running auto loops. */
76
78
  sessionModelOverride?: { provider: string; id: string } | null,
77
79
  ): Promise<ModelSelectionResult> {
80
+ const uokFlags = resolveUokFlags(prefs);
78
81
  const effectiveSessionModelOverride = sessionModelOverride === undefined
79
82
  ? getSessionModelOverride(ctx.sessionManager.getSessionId())
80
83
  : (sessionModelOverride ?? undefined);
@@ -97,6 +100,9 @@ export async function selectAndApplyModel(
97
100
 
98
101
  if (modelConfig) {
99
102
  const availableModels = ctx.modelRegistry.getAvailable();
103
+ const modelPolicyTraceId = `model:${ctx.sessionManager.getSessionId()}:${Date.now()}`;
104
+ const modelPolicyTurnId = `${unitType}:${unitId}`;
105
+ let policyAllowedModelKeys: Set<string> | null = null;
100
106
 
101
107
  // ─── Dynamic Model Routing ─────────────────────────────────────────
102
108
  // Dynamic routing (complexity-based downgrading) only applies in auto-mode.
@@ -106,8 +112,40 @@ export async function selectAndApplyModel(
106
112
  if (!isAutoMode) {
107
113
  routingConfig.enabled = false;
108
114
  }
115
+ // burn-max defaults to quality-first dispatch (no downgrade routing).
116
+ if (prefs?.token_profile === "burn-max") {
117
+ routingConfig.enabled = false;
118
+ }
109
119
  let effectiveModelConfig = modelConfig;
110
120
  let routingTierLabel = "";
121
+ let routingEligibleModels = availableModels;
122
+
123
+ const taskMetadataForPolicy = unitType === "execute-task"
124
+ ? extractTaskMetadata(unitId, basePath)
125
+ : undefined;
126
+
127
+ if (uokFlags.modelPolicy) {
128
+ const policy = applyModelPolicyFilter(
129
+ availableModels,
130
+ {
131
+ basePath,
132
+ traceId: modelPolicyTraceId,
133
+ turnId: modelPolicyTurnId,
134
+ unitType,
135
+ taskMetadata: taskMetadataForPolicy,
136
+ currentProvider: ctx.model?.provider,
137
+ allowCrossProvider: routingConfig.cross_provider !== false,
138
+ requiredTools: pi.getActiveTools(),
139
+ },
140
+ );
141
+ routingEligibleModels = policy.eligible;
142
+ policyAllowedModelKeys = new Set(
143
+ policy.eligible.map((m) => `${m.provider.toLowerCase()}/${m.id.toLowerCase()}`),
144
+ );
145
+ if (routingEligibleModels.length === 0) {
146
+ throw new Error(`Model policy denied all candidate models for ${unitType}/${unitId}`);
147
+ }
148
+ }
111
149
 
112
150
  // Disable routing for flat-rate providers like GitHub Copilot (#3453).
113
151
  // All models cost the same per request, so downgrading to a cheaper
@@ -115,7 +153,7 @@ export async function selectAndApplyModel(
115
153
  // Fail-closed: if primary model can't be resolved, fall back to
116
154
  // provider-level signals rather than allowing unwanted downgrades.
117
155
  if (routingConfig.enabled) {
118
- const primaryModel = resolveModelId(modelConfig.primary, availableModels, ctx.model?.provider);
156
+ const primaryModel = resolveModelId(modelConfig.primary, routingEligibleModels, ctx.model?.provider);
119
157
  if (primaryModel) {
120
158
  const primaryFlatRateCtx = buildFlatRateContext(primaryModel.provider, ctx, prefs);
121
159
  if (isFlatRateProvider(primaryModel.provider, primaryFlatRateCtx)) {
@@ -149,8 +187,14 @@ export async function selectAndApplyModel(
149
187
  const shouldClassify = !isHook || routingConfig.hooks !== false;
150
188
 
151
189
  if (shouldClassify) {
152
- let classification = classifyUnitComplexity(unitType, unitId, basePath, budgetPct);
153
- const availableModelIds = availableModels.map(m => m.id);
190
+ let classification = classifyUnitComplexity(
191
+ unitType,
192
+ unitId,
193
+ basePath,
194
+ budgetPct,
195
+ taskMetadataForPolicy,
196
+ );
197
+ const availableModelIds = routingEligibleModels.map(m => m.id);
154
198
 
155
199
  // Escalate tier on retry when escalate_on_failure is enabled (default: true)
156
200
  if (
@@ -257,15 +301,28 @@ export async function selectAndApplyModel(
257
301
  }
258
302
 
259
303
  const modelsToTry = [effectiveModelConfig.primary, ...effectiveModelConfig.fallbacks];
304
+ let attemptedPolicyEligible = false;
260
305
 
261
306
  for (const modelId of modelsToTry) {
262
- const model = resolveModelId(modelId, availableModels, ctx.model?.provider);
307
+ const resolutionPool = uokFlags.modelPolicy ? routingEligibleModels : availableModels;
308
+ const model = resolveModelId(modelId, resolutionPool, ctx.model?.provider);
263
309
 
264
310
  if (!model) {
265
311
  if (verbose) ctx.ui.notify(`Model ${modelId} not found, trying fallback.`, "info");
266
312
  continue;
267
313
  }
268
314
 
315
+ if (policyAllowedModelKeys) {
316
+ const key = `${model.provider.toLowerCase()}/${model.id.toLowerCase()}`;
317
+ if (!policyAllowedModelKeys.has(key)) {
318
+ if (verbose) {
319
+ ctx.ui.notify(`Model policy denied ${model.provider}/${model.id}; trying fallback.`, "warning");
320
+ }
321
+ continue;
322
+ }
323
+ attemptedPolicyEligible = true;
324
+ }
325
+
269
326
  // Warn if the ID is ambiguous across providers
270
327
  if (!modelId.includes("/")) {
271
328
  const providers = availableModels.filter(m => m.id === modelId).map(m => m.provider);
@@ -331,6 +388,10 @@ export async function selectAndApplyModel(
331
388
  }
332
389
  }
333
390
  }
391
+
392
+ if (uokFlags.modelPolicy && policyAllowedModelKeys && !attemptedPolicyEligible) {
393
+ throw new Error(`Model policy denied dispatch for ${unitType}/${unitId} before prompt send`);
394
+ }
334
395
  } else if (autoModeStartModel) {
335
396
  // No model preference for this unit type — re-apply the model captured
336
397
  // at auto-mode start to prevent bleed from shared global settings.json (#650).
@@ -474,10 +535,10 @@ export function buildFlatRateContext(
474
535
  prefs?: { flat_rate_providers?: readonly string[] },
475
536
  ): FlatRateContext {
476
537
  let authMode: FlatRateContext["authMode"];
477
- const getAuthMode = ctx?.modelRegistry?.getProviderAuthMode;
478
- if (typeof getAuthMode === "function") {
538
+ const registry = ctx?.modelRegistry;
539
+ if (registry && typeof registry.getProviderAuthMode === "function") {
479
540
  try {
480
- const mode = getAuthMode(provider);
541
+ const mode = registry.getProviderAuthMode(provider);
481
542
  if (mode === "apiKey" || mode === "oauth" || mode === "externalCli" || mode === "none") {
482
543
  authMode = mode;
483
544
  }