gsd-pi 2.73.1-dev.d987996 → 2.74.0-dev.0306a2e

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 (535) hide show
  1. package/dist/cli-web-branch.d.ts +4 -3
  2. package/dist/cli-web-branch.js +10 -7
  3. package/dist/cli.js +184 -206
  4. package/dist/headless-query.js +4 -1
  5. package/dist/help-text.js +23 -0
  6. package/dist/logo.d.ts +1 -1
  7. package/dist/logo.js +1 -1
  8. package/dist/onboarding.js +59 -53
  9. package/dist/resource-loader.js +2 -2
  10. package/dist/resources/extensions/claude-code-cli/stream-adapter.js +68 -4
  11. package/dist/resources/extensions/gsd/activity-log.js +16 -0
  12. package/dist/resources/extensions/gsd/auto/detect-stuck.js +11 -4
  13. package/dist/resources/extensions/gsd/auto/loop.js +147 -10
  14. package/dist/resources/extensions/gsd/auto/phases.js +173 -13
  15. package/dist/resources/extensions/gsd/auto/session.js +10 -0
  16. package/dist/resources/extensions/gsd/auto-dispatch.js +22 -4
  17. package/dist/resources/extensions/gsd/auto-model-selection.js +105 -16
  18. package/dist/resources/extensions/gsd/auto-post-unit.js +254 -15
  19. package/dist/resources/extensions/gsd/auto-prompts.js +12 -0
  20. package/dist/resources/extensions/gsd/auto-start.js +23 -6
  21. package/dist/resources/extensions/gsd/auto-timeout-recovery.js +13 -0
  22. package/dist/resources/extensions/gsd/auto-unit-closeout.js +18 -0
  23. package/dist/resources/extensions/gsd/auto-verification.js +186 -3
  24. package/dist/resources/extensions/gsd/auto.js +65 -12
  25. package/dist/resources/extensions/gsd/bootstrap/register-extension.js +30 -8
  26. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +41 -2
  27. package/dist/resources/extensions/gsd/commands/catalog.js +26 -1
  28. package/dist/resources/extensions/gsd/commands/handlers/ops.js +25 -0
  29. package/dist/resources/extensions/gsd/commands/handlers/workflow.js +68 -9
  30. package/dist/resources/extensions/gsd/commands-add-tests.js +111 -0
  31. package/dist/resources/extensions/gsd/commands-backlog.js +140 -0
  32. package/dist/resources/extensions/gsd/commands-do.js +79 -0
  33. package/dist/resources/extensions/gsd/commands-extract-learnings.js +225 -0
  34. package/dist/resources/extensions/gsd/commands-handlers.js +8 -2
  35. package/dist/resources/extensions/gsd/commands-maintenance.js +6 -6
  36. package/dist/resources/extensions/gsd/commands-pr-branch.js +180 -0
  37. package/dist/resources/extensions/gsd/commands-prefs-wizard.js +1 -1
  38. package/dist/resources/extensions/gsd/commands-session-report.js +82 -0
  39. package/dist/resources/extensions/gsd/commands-ship.js +187 -0
  40. package/dist/resources/extensions/gsd/db-writer.js +3 -5
  41. package/dist/resources/extensions/gsd/docs/preferences-reference.md +15 -2
  42. package/dist/resources/extensions/gsd/ecosystem/gsd-extension-api.js +144 -0
  43. package/dist/resources/extensions/gsd/ecosystem/loader.js +145 -0
  44. package/dist/resources/extensions/gsd/git-service.js +49 -1
  45. package/dist/resources/extensions/gsd/graph-context.js +157 -0
  46. package/dist/resources/extensions/gsd/gsd-db.js +581 -2
  47. package/dist/resources/extensions/gsd/guided-flow.js +23 -0
  48. package/dist/resources/extensions/gsd/index.js +15 -2
  49. package/dist/resources/extensions/gsd/init-wizard.js +1 -0
  50. package/dist/resources/extensions/gsd/journal.js +27 -0
  51. package/dist/resources/extensions/gsd/md-importer.js +3 -4
  52. package/dist/resources/extensions/gsd/memory-store.js +19 -51
  53. package/dist/resources/extensions/gsd/metrics.js +19 -0
  54. package/dist/resources/extensions/gsd/milestone-validation-gates.js +13 -12
  55. package/dist/resources/extensions/gsd/native-git-bridge.js +7 -4
  56. package/dist/resources/extensions/gsd/notification-widget.js +2 -2
  57. package/dist/resources/extensions/gsd/parallel-orchestrator.js +33 -1
  58. package/dist/resources/extensions/gsd/preferences-models.js +63 -3
  59. package/dist/resources/extensions/gsd/preferences-types.js +2 -0
  60. package/dist/resources/extensions/gsd/preferences-validation.js +130 -2
  61. package/dist/resources/extensions/gsd/preferences.js +26 -0
  62. package/dist/resources/extensions/gsd/prompts/add-tests.md +35 -0
  63. package/dist/resources/extensions/gsd/slice-parallel-orchestrator.js +12 -2
  64. package/dist/resources/extensions/gsd/state.js +66 -15
  65. package/dist/resources/extensions/gsd/templates/PREFERENCES.md +18 -0
  66. package/dist/resources/extensions/gsd/tools/complete-slice.js +20 -0
  67. package/dist/resources/extensions/gsd/tools/validate-milestone.js +39 -4
  68. package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +3 -14
  69. package/dist/resources/extensions/gsd/triage-resolution.js +2 -5
  70. package/dist/resources/extensions/gsd/unit-ownership.js +1 -1
  71. package/dist/resources/extensions/gsd/uok/audit-toggle.js +7 -0
  72. package/dist/resources/extensions/gsd/uok/audit.js +40 -0
  73. package/dist/resources/extensions/gsd/uok/contracts.js +1 -0
  74. package/dist/resources/extensions/gsd/uok/execution-graph.js +179 -0
  75. package/dist/resources/extensions/gsd/uok/flags.js +29 -0
  76. package/dist/resources/extensions/gsd/uok/gate-runner.js +109 -0
  77. package/dist/resources/extensions/gsd/uok/gitops.js +53 -0
  78. package/dist/resources/extensions/gsd/uok/kernel.js +80 -0
  79. package/dist/resources/extensions/gsd/uok/loop-adapter.js +133 -0
  80. package/dist/resources/extensions/gsd/uok/model-policy.js +66 -0
  81. package/dist/resources/extensions/gsd/uok/plan-v2.js +132 -0
  82. package/dist/resources/extensions/gsd/workflow-logger.js +22 -0
  83. package/dist/resources/extensions/gsd/workflow-manifest.js +8 -69
  84. package/dist/resources/extensions/gsd/workflow-migration.js +21 -22
  85. package/dist/resources/extensions/gsd/workflow-projections.js +4 -1
  86. package/dist/resources/extensions/gsd/workflow-reconcile.js +14 -11
  87. package/dist/resources/extensions/ttsr/ttsr-manager.js +3 -1
  88. package/dist/tsconfig.extensions.tsbuildinfo +1 -0
  89. package/dist/update-check.d.ts +1 -0
  90. package/dist/update-check.js +13 -5
  91. package/dist/update-cmd.js +4 -3
  92. package/dist/web/standalone/.next/BUILD_ID +1 -1
  93. package/dist/web/standalone/.next/app-path-routes-manifest.json +13 -13
  94. package/dist/web/standalone/.next/build-manifest.json +2 -2
  95. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  96. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  97. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  98. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  99. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  100. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  101. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  102. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  103. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  104. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  105. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  106. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  107. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  108. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  109. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  110. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  111. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  112. package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
  113. package/dist/web/standalone/.next/server/app/api/terminal/input/route.js +1 -1
  114. package/dist/web/standalone/.next/server/app/api/terminal/resize/route.js +1 -1
  115. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js +1 -1
  116. package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js +1 -1
  117. package/dist/web/standalone/.next/server/app/index.html +1 -1
  118. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  119. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  120. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  121. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  122. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  123. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  124. package/dist/web/standalone/.next/server/app-paths-manifest.json +13 -13
  125. package/dist/web/standalone/.next/server/chunks/6897.js +3 -3
  126. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  127. package/dist/web/standalone/.next/server/middleware-manifest.json +5 -5
  128. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  129. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  130. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  131. package/package.json +3 -3
  132. package/packages/daemon/package.json +2 -2
  133. package/packages/mcp-server/dist/index.d.ts +3 -0
  134. package/packages/mcp-server/dist/index.d.ts.map +1 -1
  135. package/packages/mcp-server/dist/index.js +3 -0
  136. package/packages/mcp-server/dist/index.js.map +1 -1
  137. package/packages/mcp-server/dist/readers/graph.d.ts +87 -0
  138. package/packages/mcp-server/dist/readers/graph.d.ts.map +1 -0
  139. package/packages/mcp-server/dist/readers/graph.js +655 -0
  140. package/packages/mcp-server/dist/readers/graph.js.map +1 -0
  141. package/packages/mcp-server/dist/readers/index.d.ts +2 -0
  142. package/packages/mcp-server/dist/readers/index.d.ts.map +1 -1
  143. package/packages/mcp-server/dist/readers/index.js +1 -0
  144. package/packages/mcp-server/dist/readers/index.js.map +1 -1
  145. package/packages/mcp-server/dist/server.d.ts.map +1 -1
  146. package/packages/mcp-server/dist/server.js +65 -0
  147. package/packages/mcp-server/dist/server.js.map +1 -1
  148. package/packages/mcp-server/package.json +2 -2
  149. package/packages/mcp-server/src/index.ts +15 -0
  150. package/packages/mcp-server/src/readers/graph.test.ts +604 -0
  151. package/packages/mcp-server/src/readers/graph.ts +855 -0
  152. package/packages/mcp-server/src/readers/index.ts +12 -0
  153. package/packages/mcp-server/src/server.ts +83 -0
  154. package/packages/mcp-server/tsconfig.json +1 -0
  155. package/packages/mcp-server/tsconfig.tsbuildinfo +1 -0
  156. package/packages/native/package.json +2 -2
  157. package/packages/native/tsconfig.tsbuildinfo +1 -0
  158. package/packages/pi-agent-core/package.json +1 -1
  159. package/packages/pi-agent-core/tsconfig.json +1 -0
  160. package/packages/pi-agent-core/tsconfig.tsbuildinfo +1 -0
  161. package/packages/pi-ai/dist/index.d.ts +2 -9
  162. package/packages/pi-ai/dist/index.d.ts.map +1 -1
  163. package/packages/pi-ai/dist/index.js +2 -9
  164. package/packages/pi-ai/dist/index.js.map +1 -1
  165. package/packages/pi-ai/dist/models/capability-patches.d.ts +19 -0
  166. package/packages/pi-ai/dist/models/capability-patches.d.ts.map +1 -0
  167. package/packages/pi-ai/dist/models/capability-patches.js +36 -0
  168. package/packages/pi-ai/dist/models/capability-patches.js.map +1 -0
  169. package/packages/pi-ai/dist/{models.custom.d.ts → models/custom.d.ts} +1 -1
  170. package/packages/pi-ai/dist/models/custom.d.ts.map +1 -0
  171. package/packages/pi-ai/dist/{models.custom.js → models/custom.js} +4 -4
  172. package/packages/pi-ai/dist/models/custom.js.map +1 -0
  173. package/packages/pi-ai/dist/models/generated/amazon-bedrock.d.ts +1482 -0
  174. package/packages/pi-ai/dist/models/generated/amazon-bedrock.d.ts.map +1 -0
  175. package/packages/pi-ai/dist/models/generated/amazon-bedrock.js +1484 -0
  176. package/packages/pi-ai/dist/models/generated/amazon-bedrock.js.map +1 -0
  177. package/packages/pi-ai/dist/models/generated/anthropic.d.ts +377 -0
  178. package/packages/pi-ai/dist/models/generated/anthropic.d.ts.map +1 -0
  179. package/packages/pi-ai/dist/models/generated/anthropic.js +379 -0
  180. package/packages/pi-ai/dist/models/generated/anthropic.js.map +1 -0
  181. package/packages/pi-ai/dist/models/generated/azure-openai-responses.d.ts +700 -0
  182. package/packages/pi-ai/dist/models/generated/azure-openai-responses.d.ts.map +1 -0
  183. package/packages/pi-ai/dist/models/generated/azure-openai-responses.js +702 -0
  184. package/packages/pi-ai/dist/models/generated/azure-openai-responses.js.map +1 -0
  185. package/packages/pi-ai/dist/models/generated/cerebras.d.ts +71 -0
  186. package/packages/pi-ai/dist/models/generated/cerebras.d.ts.map +1 -0
  187. package/packages/pi-ai/dist/models/generated/cerebras.js +73 -0
  188. package/packages/pi-ai/dist/models/generated/cerebras.js.map +1 -0
  189. package/packages/pi-ai/dist/models/generated/github-copilot.d.ts +590 -0
  190. package/packages/pi-ai/dist/models/generated/github-copilot.d.ts.map +1 -0
  191. package/packages/pi-ai/dist/models/generated/github-copilot.js +444 -0
  192. package/packages/pi-ai/dist/models/generated/github-copilot.js.map +1 -0
  193. package/packages/pi-ai/dist/models/generated/google-antigravity.d.ts +156 -0
  194. package/packages/pi-ai/dist/models/generated/google-antigravity.d.ts.map +1 -0
  195. package/packages/pi-ai/dist/models/generated/google-antigravity.js +158 -0
  196. package/packages/pi-ai/dist/models/generated/google-antigravity.js.map +1 -0
  197. package/packages/pi-ai/dist/models/generated/google-gemini-cli.d.ts +105 -0
  198. package/packages/pi-ai/dist/models/generated/google-gemini-cli.d.ts.map +1 -0
  199. package/packages/pi-ai/dist/models/generated/google-gemini-cli.js +107 -0
  200. package/packages/pi-ai/dist/models/generated/google-gemini-cli.js.map +1 -0
  201. package/packages/pi-ai/dist/models/generated/google-vertex.d.ts +207 -0
  202. package/packages/pi-ai/dist/models/generated/google-vertex.d.ts.map +1 -0
  203. package/packages/pi-ai/dist/models/generated/google-vertex.js +209 -0
  204. package/packages/pi-ai/dist/models/generated/google-vertex.js.map +1 -0
  205. package/packages/pi-ai/dist/models/generated/google.d.ts +462 -0
  206. package/packages/pi-ai/dist/models/generated/google.d.ts.map +1 -0
  207. package/packages/pi-ai/dist/models/generated/google.js +464 -0
  208. package/packages/pi-ai/dist/models/generated/google.js.map +1 -0
  209. package/packages/pi-ai/dist/models/generated/groq.d.ts +309 -0
  210. package/packages/pi-ai/dist/models/generated/groq.d.ts.map +1 -0
  211. package/packages/pi-ai/dist/models/generated/groq.js +311 -0
  212. package/packages/pi-ai/dist/models/generated/groq.js.map +1 -0
  213. package/packages/pi-ai/dist/models/generated/huggingface.d.ts +383 -0
  214. package/packages/pi-ai/dist/models/generated/huggingface.d.ts.map +1 -0
  215. package/packages/pi-ai/dist/models/generated/huggingface.js +347 -0
  216. package/packages/pi-ai/dist/models/generated/huggingface.js.map +1 -0
  217. package/packages/pi-ai/dist/{models.generated.d.ts → models/generated/index.d.ts} +1 -1
  218. package/packages/pi-ai/dist/{models.generated.d.ts.map → models/generated/index.d.ts.map} +1 -1
  219. package/packages/pi-ai/dist/models/generated/index.js +51 -0
  220. package/packages/pi-ai/dist/models/generated/index.js.map +1 -0
  221. package/packages/pi-ai/dist/models/generated/kimi-coding.d.ts +37 -0
  222. package/packages/pi-ai/dist/models/generated/kimi-coding.d.ts.map +1 -0
  223. package/packages/pi-ai/dist/models/generated/kimi-coding.js +39 -0
  224. package/packages/pi-ai/dist/models/generated/kimi-coding.js.map +1 -0
  225. package/packages/pi-ai/dist/models/generated/minimax-cn.d.ts +105 -0
  226. package/packages/pi-ai/dist/models/generated/minimax-cn.d.ts.map +1 -0
  227. package/packages/pi-ai/dist/models/generated/minimax-cn.js +107 -0
  228. package/packages/pi-ai/dist/models/generated/minimax-cn.js.map +1 -0
  229. package/packages/pi-ai/dist/models/generated/minimax.d.ts +105 -0
  230. package/packages/pi-ai/dist/models/generated/minimax.d.ts.map +1 -0
  231. package/packages/pi-ai/dist/models/generated/minimax.js +107 -0
  232. package/packages/pi-ai/dist/models/generated/minimax.js.map +1 -0
  233. package/packages/pi-ai/dist/models/generated/mistral.d.ts +445 -0
  234. package/packages/pi-ai/dist/models/generated/mistral.d.ts.map +1 -0
  235. package/packages/pi-ai/dist/models/generated/mistral.js +447 -0
  236. package/packages/pi-ai/dist/models/generated/mistral.js.map +1 -0
  237. package/packages/pi-ai/dist/models/generated/openai-codex.d.ts +139 -0
  238. package/packages/pi-ai/dist/models/generated/openai-codex.d.ts.map +1 -0
  239. package/packages/pi-ai/dist/models/generated/openai-codex.js +141 -0
  240. package/packages/pi-ai/dist/models/generated/openai-codex.js.map +1 -0
  241. package/packages/pi-ai/dist/models/generated/openai.d.ts +700 -0
  242. package/packages/pi-ai/dist/models/generated/openai.d.ts.map +1 -0
  243. package/packages/pi-ai/dist/models/generated/openai.js +702 -0
  244. package/packages/pi-ai/dist/models/generated/openai.js.map +1 -0
  245. package/packages/pi-ai/dist/models/generated/opencode-go.d.ts +122 -0
  246. package/packages/pi-ai/dist/models/generated/opencode-go.d.ts.map +1 -0
  247. package/packages/pi-ai/dist/models/generated/opencode-go.js +124 -0
  248. package/packages/pi-ai/dist/models/generated/opencode-go.js.map +1 -0
  249. package/packages/pi-ai/dist/models/generated/opencode.d.ts +530 -0
  250. package/packages/pi-ai/dist/models/generated/opencode.d.ts.map +1 -0
  251. package/packages/pi-ai/dist/models/generated/opencode.js +532 -0
  252. package/packages/pi-ai/dist/models/generated/opencode.js.map +1 -0
  253. package/packages/pi-ai/dist/models/generated/openrouter.d.ts +4270 -0
  254. package/packages/pi-ai/dist/models/generated/openrouter.d.ts.map +1 -0
  255. package/packages/pi-ai/dist/models/generated/openrouter.js +4272 -0
  256. package/packages/pi-ai/dist/models/generated/openrouter.js.map +1 -0
  257. package/packages/pi-ai/dist/models/generated/vercel-ai-gateway.d.ts +2604 -0
  258. package/packages/pi-ai/dist/models/generated/vercel-ai-gateway.d.ts.map +1 -0
  259. package/packages/pi-ai/dist/models/generated/vercel-ai-gateway.js +2606 -0
  260. package/packages/pi-ai/dist/models/generated/vercel-ai-gateway.js.map +1 -0
  261. package/packages/pi-ai/dist/models/generated/xai.d.ts +411 -0
  262. package/packages/pi-ai/dist/models/generated/xai.d.ts.map +1 -0
  263. package/packages/pi-ai/dist/models/generated/xai.js +413 -0
  264. package/packages/pi-ai/dist/models/generated/xai.js.map +1 -0
  265. package/packages/pi-ai/dist/models/generated/zai.d.ts +276 -0
  266. package/packages/pi-ai/dist/models/generated/zai.d.ts.map +1 -0
  267. package/packages/pi-ai/dist/models/generated/zai.js +239 -0
  268. package/packages/pi-ai/dist/models/generated/zai.js.map +1 -0
  269. package/packages/pi-ai/dist/models/index.d.ts +27 -0
  270. package/packages/pi-ai/dist/models/index.d.ts.map +1 -0
  271. package/packages/pi-ai/dist/models/index.js +80 -0
  272. package/packages/pi-ai/dist/models/index.js.map +1 -0
  273. package/packages/pi-ai/dist/models.d.ts +1 -36
  274. package/packages/pi-ai/dist/models.d.ts.map +1 -1
  275. package/packages/pi-ai/dist/models.generated.test.js +1 -2
  276. package/packages/pi-ai/dist/models.generated.test.js.map +1 -1
  277. package/packages/pi-ai/dist/models.js +3 -112
  278. package/packages/pi-ai/dist/models.js.map +1 -1
  279. package/packages/pi-ai/dist/models.test.js +6 -5
  280. package/packages/pi-ai/dist/models.test.js.map +1 -1
  281. package/packages/pi-ai/dist/utils/overflow.d.ts.map +1 -1
  282. package/packages/pi-ai/dist/utils/overflow.js +12 -0
  283. package/packages/pi-ai/dist/utils/overflow.js.map +1 -1
  284. package/packages/pi-ai/dist/utils/tests/overflow.test.d.ts +2 -0
  285. package/packages/pi-ai/dist/utils/tests/overflow.test.d.ts.map +1 -0
  286. package/packages/pi-ai/dist/utils/tests/overflow.test.js +50 -0
  287. package/packages/pi-ai/dist/utils/tests/overflow.test.js.map +1 -0
  288. package/packages/pi-ai/package.json +1 -1
  289. package/packages/pi-ai/scripts/generate-models.ts +74 -40
  290. package/packages/pi-ai/src/index.ts +5 -9
  291. package/packages/pi-ai/src/models/capability-patches.ts +40 -0
  292. package/packages/pi-ai/src/{models.custom.ts → models/custom.ts} +4 -4
  293. package/packages/pi-ai/src/models/generated/amazon-bedrock.ts +1486 -0
  294. package/packages/pi-ai/src/models/generated/anthropic.ts +381 -0
  295. package/packages/pi-ai/src/models/generated/azure-openai-responses.ts +704 -0
  296. package/packages/pi-ai/src/models/generated/cerebras.ts +75 -0
  297. package/packages/pi-ai/src/models/generated/github-copilot.ts +446 -0
  298. package/packages/pi-ai/src/models/generated/google-antigravity.ts +160 -0
  299. package/packages/pi-ai/src/models/generated/google-gemini-cli.ts +109 -0
  300. package/packages/pi-ai/src/models/generated/google-vertex.ts +211 -0
  301. package/packages/pi-ai/src/models/generated/google.ts +466 -0
  302. package/packages/pi-ai/src/models/generated/groq.ts +313 -0
  303. package/packages/pi-ai/src/models/generated/huggingface.ts +349 -0
  304. package/packages/pi-ai/src/models/generated/index.ts +52 -0
  305. package/packages/pi-ai/src/models/generated/kimi-coding.ts +41 -0
  306. package/packages/pi-ai/src/models/generated/minimax-cn.ts +109 -0
  307. package/packages/pi-ai/src/models/generated/minimax.ts +109 -0
  308. package/packages/pi-ai/src/models/generated/mistral.ts +449 -0
  309. package/packages/pi-ai/src/models/generated/openai-codex.ts +143 -0
  310. package/packages/pi-ai/src/models/generated/openai.ts +704 -0
  311. package/packages/pi-ai/src/models/generated/opencode-go.ts +126 -0
  312. package/packages/pi-ai/src/models/generated/opencode.ts +534 -0
  313. package/packages/pi-ai/src/models/generated/openrouter.ts +4274 -0
  314. package/packages/pi-ai/src/models/generated/vercel-ai-gateway.ts +2608 -0
  315. package/packages/pi-ai/src/models/generated/xai.ts +415 -0
  316. package/packages/pi-ai/src/models/generated/zai.ts +241 -0
  317. package/packages/pi-ai/src/models/index.ts +106 -0
  318. package/packages/pi-ai/src/models.generated.test.ts +1 -2
  319. package/packages/pi-ai/src/models.test.ts +6 -5
  320. package/packages/pi-ai/src/models.ts +3 -153
  321. package/packages/pi-ai/src/utils/overflow.ts +14 -1
  322. package/packages/pi-ai/src/utils/tests/overflow.test.ts +58 -0
  323. package/packages/pi-ai/tsconfig.json +1 -0
  324. package/packages/pi-ai/tsconfig.tsbuildinfo +1 -0
  325. package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js +721 -8
  326. package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js.map +1 -1
  327. package/packages/pi-coding-agent/dist/core/compaction/utils.js +5 -5
  328. package/packages/pi-coding-agent/dist/core/compaction/utils.js.map +1 -1
  329. package/packages/pi-coding-agent/dist/core/compaction-utils.test.d.ts +2 -0
  330. package/packages/pi-coding-agent/dist/core/compaction-utils.test.d.ts.map +1 -0
  331. package/packages/pi-coding-agent/dist/core/compaction-utils.test.js +45 -0
  332. package/packages/pi-coding-agent/dist/core/compaction-utils.test.js.map +1 -0
  333. package/packages/pi-coding-agent/dist/core/model-registry-env-fallback.test.d.ts +2 -0
  334. package/packages/pi-coding-agent/dist/core/model-registry-env-fallback.test.d.ts.map +1 -0
  335. package/packages/pi-coding-agent/dist/core/model-registry-env-fallback.test.js +52 -0
  336. package/packages/pi-coding-agent/dist/core/model-registry-env-fallback.test.js.map +1 -0
  337. package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
  338. package/packages/pi-coding-agent/dist/core/model-registry.js +2 -2
  339. package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
  340. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts +12 -2
  341. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  342. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js +65 -28
  343. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js.map +1 -1
  344. package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.d.ts +2 -1
  345. package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.d.ts.map +1 -1
  346. package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.js +9 -3
  347. package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.js.map +1 -1
  348. package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.test.d.ts +2 -0
  349. package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.test.d.ts.map +1 -0
  350. package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.test.js +52 -0
  351. package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.test.js.map +1 -0
  352. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  353. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +305 -20
  354. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  355. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-ordering.test.d.ts +2 -0
  356. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-ordering.test.d.ts.map +1 -0
  357. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-ordering.test.js +38 -0
  358. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-ordering.test.js.map +1 -0
  359. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts +13 -0
  360. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  361. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +59 -6
  362. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  363. package/packages/pi-coding-agent/package.json +1 -1
  364. package/packages/pi-coding-agent/src/core/chat-controller-ordering.test.ts +884 -8
  365. package/packages/pi-coding-agent/src/core/compaction/utils.ts +5 -5
  366. package/packages/pi-coding-agent/src/core/compaction-utils.test.ts +50 -0
  367. package/packages/pi-coding-agent/src/core/model-registry-env-fallback.test.ts +59 -0
  368. package/packages/pi-coding-agent/src/core/model-registry.ts +2 -1
  369. package/packages/pi-coding-agent/src/modes/interactive/components/assistant-message.ts +78 -32
  370. package/packages/pi-coding-agent/src/modes/interactive/components/dynamic-border.test.ts +73 -0
  371. package/packages/pi-coding-agent/src/modes/interactive/components/dynamic-border.ts +9 -3
  372. package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +381 -39
  373. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode-ordering.test.ts +44 -0
  374. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +79 -6
  375. package/packages/pi-coding-agent/src/types/ambient-modules.d.ts +69 -0
  376. package/packages/pi-coding-agent/tsconfig.json +3 -2
  377. package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -0
  378. package/packages/pi-tui/dist/__tests__/tui.test.js +60 -1
  379. package/packages/pi-tui/dist/__tests__/tui.test.js.map +1 -1
  380. package/packages/pi-tui/dist/tui.d.ts +8 -0
  381. package/packages/pi-tui/dist/tui.d.ts.map +1 -1
  382. package/packages/pi-tui/dist/tui.js +32 -3
  383. package/packages/pi-tui/dist/tui.js.map +1 -1
  384. package/packages/pi-tui/package.json +1 -1
  385. package/packages/pi-tui/src/__tests__/tui.test.ts +76 -1
  386. package/packages/pi-tui/src/tui.ts +31 -3
  387. package/packages/pi-tui/tsconfig.json +1 -0
  388. package/packages/pi-tui/tsconfig.tsbuildinfo +1 -0
  389. package/packages/rpc-client/package.json +1 -1
  390. package/packages/rpc-client/tsconfig.json +1 -0
  391. package/packages/rpc-client/tsconfig.tsbuildinfo +1 -0
  392. package/pkg/package.json +1 -1
  393. package/src/resources/extensions/claude-code-cli/stream-adapter.ts +107 -5
  394. package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +111 -2
  395. package/src/resources/extensions/gsd/activity-log.ts +21 -0
  396. package/src/resources/extensions/gsd/auto/detect-stuck.ts +12 -4
  397. package/src/resources/extensions/gsd/auto/loop-deps.ts +10 -0
  398. package/src/resources/extensions/gsd/auto/loop.ts +159 -10
  399. package/src/resources/extensions/gsd/auto/phases.ts +213 -13
  400. package/src/resources/extensions/gsd/auto/session.ts +10 -0
  401. package/src/resources/extensions/gsd/auto-dispatch.ts +26 -10
  402. package/src/resources/extensions/gsd/auto-model-selection.ts +151 -16
  403. package/src/resources/extensions/gsd/auto-post-unit.ts +278 -16
  404. package/src/resources/extensions/gsd/auto-prompts.ts +13 -0
  405. package/src/resources/extensions/gsd/auto-start.ts +30 -6
  406. package/src/resources/extensions/gsd/auto-timeout-recovery.ts +17 -0
  407. package/src/resources/extensions/gsd/auto-unit-closeout.ts +25 -1
  408. package/src/resources/extensions/gsd/auto-verification.ts +225 -3
  409. package/src/resources/extensions/gsd/auto.ts +72 -16
  410. package/src/resources/extensions/gsd/bootstrap/register-extension.ts +38 -8
  411. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +52 -2
  412. package/src/resources/extensions/gsd/commands/catalog.ts +26 -1
  413. package/src/resources/extensions/gsd/commands/handlers/ops.ts +25 -0
  414. package/src/resources/extensions/gsd/commands/handlers/workflow.ts +74 -9
  415. package/src/resources/extensions/gsd/commands-add-tests.ts +137 -0
  416. package/src/resources/extensions/gsd/commands-backlog.ts +182 -0
  417. package/src/resources/extensions/gsd/commands-do.ts +109 -0
  418. package/src/resources/extensions/gsd/commands-extract-learnings.ts +304 -0
  419. package/src/resources/extensions/gsd/commands-handlers.ts +8 -2
  420. package/src/resources/extensions/gsd/commands-maintenance.ts +6 -6
  421. package/src/resources/extensions/gsd/commands-pr-branch.ts +234 -0
  422. package/src/resources/extensions/gsd/commands-prefs-wizard.ts +1 -1
  423. package/src/resources/extensions/gsd/commands-session-report.ts +101 -0
  424. package/src/resources/extensions/gsd/commands-ship.ts +219 -0
  425. package/src/resources/extensions/gsd/db-writer.ts +3 -5
  426. package/src/resources/extensions/gsd/docs/preferences-reference.md +15 -2
  427. package/src/resources/extensions/gsd/ecosystem/gsd-extension-api.ts +228 -0
  428. package/src/resources/extensions/gsd/ecosystem/loader.ts +201 -0
  429. package/src/resources/extensions/gsd/git-service.ts +68 -0
  430. package/src/resources/extensions/gsd/graph-context.ts +212 -0
  431. package/src/resources/extensions/gsd/gsd-db.ts +788 -3
  432. package/src/resources/extensions/gsd/guided-flow.ts +32 -0
  433. package/src/resources/extensions/gsd/index.ts +18 -2
  434. package/src/resources/extensions/gsd/init-wizard.ts +3 -2
  435. package/src/resources/extensions/gsd/journal.ts +30 -0
  436. package/src/resources/extensions/gsd/md-importer.ts +3 -5
  437. package/src/resources/extensions/gsd/memory-store.ts +31 -62
  438. package/src/resources/extensions/gsd/metrics.ts +26 -0
  439. package/src/resources/extensions/gsd/milestone-validation-gates.ts +13 -14
  440. package/src/resources/extensions/gsd/native-git-bridge.ts +11 -12
  441. package/src/resources/extensions/gsd/notification-widget.ts +2 -2
  442. package/src/resources/extensions/gsd/parallel-orchestrator.ts +40 -1
  443. package/src/resources/extensions/gsd/preferences-models.ts +61 -3
  444. package/src/resources/extensions/gsd/preferences-types.ts +44 -0
  445. package/src/resources/extensions/gsd/preferences-validation.ts +130 -2
  446. package/src/resources/extensions/gsd/preferences.ts +28 -0
  447. package/src/resources/extensions/gsd/prompts/add-tests.md +35 -0
  448. package/src/resources/extensions/gsd/session-lock.ts +14 -2
  449. package/src/resources/extensions/gsd/slice-parallel-orchestrator.ts +20 -1
  450. package/src/resources/extensions/gsd/state.ts +80 -17
  451. package/src/resources/extensions/gsd/templates/PREFERENCES.md +18 -0
  452. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +9 -5
  453. package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +20 -0
  454. package/src/resources/extensions/gsd/tests/auto-post-unit-step-message.test.ts +53 -0
  455. package/src/resources/extensions/gsd/tests/auto-project-root-env.test.ts +7 -3
  456. package/src/resources/extensions/gsd/tests/auto-start-model-capture.test.ts +51 -2
  457. package/src/resources/extensions/gsd/tests/cold-resume-db-reopen.test.ts +6 -2
  458. package/src/resources/extensions/gsd/tests/commands-backlog.test.ts +158 -0
  459. package/src/resources/extensions/gsd/tests/commands-do.test.ts +127 -0
  460. package/src/resources/extensions/gsd/tests/commands-extract-learnings.test.ts +340 -0
  461. package/src/resources/extensions/gsd/tests/commands-pr-branch.test.ts +68 -0
  462. package/src/resources/extensions/gsd/tests/commands-session-report.test.ts +82 -0
  463. package/src/resources/extensions/gsd/tests/commands-ship.test.ts +71 -0
  464. package/src/resources/extensions/gsd/tests/commands-workflow-custom.test.ts +14 -0
  465. package/src/resources/extensions/gsd/tests/complete-milestone-false-merge.test.ts +142 -0
  466. package/src/resources/extensions/gsd/tests/complete-slice.test.ts +2 -2
  467. package/src/resources/extensions/gsd/tests/complete-task.test.ts +2 -2
  468. package/src/resources/extensions/gsd/tests/completed-at-reconcile.test.ts +42 -0
  469. package/src/resources/extensions/gsd/tests/derive-state-crossval.test.ts +3 -2
  470. package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +3 -2
  471. package/src/resources/extensions/gsd/tests/derive-state-helpers.test.ts +68 -8
  472. package/src/resources/extensions/gsd/tests/derive-state.test.ts +3 -3
  473. package/src/resources/extensions/gsd/tests/extension-bootstrap-isolation.test.ts +154 -0
  474. package/src/resources/extensions/gsd/tests/finalize-timeout-guard.test.ts +10 -7
  475. package/src/resources/extensions/gsd/tests/flat-rate-routing-guard.test.ts +137 -1
  476. package/src/resources/extensions/gsd/tests/graph-context.test.ts +337 -0
  477. package/src/resources/extensions/gsd/tests/gsd-db.test.ts +1 -1
  478. package/src/resources/extensions/gsd/tests/health-widget.test.ts +1 -1
  479. package/src/resources/extensions/gsd/tests/integration/state-machine-edge-cases.test.ts +4 -2
  480. package/src/resources/extensions/gsd/tests/journal-integration.test.ts +68 -1
  481. package/src/resources/extensions/gsd/tests/md-importer.test.ts +1 -2
  482. package/src/resources/extensions/gsd/tests/memory-store.test.ts +2 -3
  483. package/src/resources/extensions/gsd/tests/model-isolation.test.ts +91 -2
  484. package/src/resources/extensions/gsd/tests/native-git-bridge-exec-fallback.test.ts +140 -0
  485. package/src/resources/extensions/gsd/tests/post-exec-retry-bypass.test.ts +79 -1
  486. package/src/resources/extensions/gsd/tests/post-unit-state-rebuild.test.ts +2 -1
  487. package/src/resources/extensions/gsd/tests/pre-execution-pause-wiring.test.ts +40 -1
  488. package/src/resources/extensions/gsd/tests/preferences.test.ts +47 -0
  489. package/src/resources/extensions/gsd/tests/register-hooks-depth-verification.test.ts +1 -1
  490. package/src/resources/extensions/gsd/tests/single-writer-invariant.test.ts +180 -0
  491. package/src/resources/extensions/gsd/tests/state-machine-full-walkthrough.test.ts +5 -7
  492. package/src/resources/extensions/gsd/tests/token-profile.test.ts +9 -6
  493. package/src/resources/extensions/gsd/tests/uok-audit-unified.test.ts +101 -0
  494. package/src/resources/extensions/gsd/tests/uok-contracts.test.ts +85 -0
  495. package/src/resources/extensions/gsd/tests/uok-execution-graph.test.ts +69 -0
  496. package/src/resources/extensions/gsd/tests/uok-flags.test.ts +39 -0
  497. package/src/resources/extensions/gsd/tests/uok-gate-runner.test.ts +70 -0
  498. package/src/resources/extensions/gsd/tests/uok-gitops-turn-action.test.ts +85 -0
  499. package/src/resources/extensions/gsd/tests/uok-gitops-wiring.test.ts +35 -0
  500. package/src/resources/extensions/gsd/tests/uok-model-policy.test.ts +89 -0
  501. package/src/resources/extensions/gsd/tests/uok-plan-v2-wiring.test.ts +167 -0
  502. package/src/resources/extensions/gsd/tests/uok-preferences.test.ts +42 -0
  503. package/src/resources/extensions/gsd/tests/validate-milestone-stuck-guard.test.ts +179 -0
  504. package/src/resources/extensions/gsd/tests/validate-milestone-write-order.test.ts +39 -0
  505. package/src/resources/extensions/gsd/tests/workflow-logger-wiring.test.ts +223 -0
  506. package/src/resources/extensions/gsd/tools/complete-slice.ts +26 -0
  507. package/src/resources/extensions/gsd/tools/validate-milestone.ts +48 -3
  508. package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +3 -11
  509. package/src/resources/extensions/gsd/triage-resolution.ts +2 -7
  510. package/src/resources/extensions/gsd/types.ts +14 -1
  511. package/src/resources/extensions/gsd/unit-ownership.ts +2 -2
  512. package/src/resources/extensions/gsd/uok/audit-toggle.ts +9 -0
  513. package/src/resources/extensions/gsd/uok/audit.ts +51 -0
  514. package/src/resources/extensions/gsd/uok/contracts.ts +135 -0
  515. package/src/resources/extensions/gsd/uok/execution-graph.ts +241 -0
  516. package/src/resources/extensions/gsd/uok/flags.ts +45 -0
  517. package/src/resources/extensions/gsd/uok/gate-runner.ts +146 -0
  518. package/src/resources/extensions/gsd/uok/gitops.ts +75 -0
  519. package/src/resources/extensions/gsd/uok/kernel.ts +105 -0
  520. package/src/resources/extensions/gsd/uok/loop-adapter.ts +162 -0
  521. package/src/resources/extensions/gsd/uok/model-policy.ts +112 -0
  522. package/src/resources/extensions/gsd/uok/plan-v2.ts +156 -0
  523. package/src/resources/extensions/gsd/workflow-logger.ts +27 -1
  524. package/src/resources/extensions/gsd/workflow-manifest.ts +9 -104
  525. package/src/resources/extensions/gsd/workflow-migration.ts +21 -29
  526. package/src/resources/extensions/gsd/workflow-projections.ts +8 -1
  527. package/src/resources/extensions/gsd/workflow-reconcile.ts +15 -15
  528. package/src/resources/extensions/ttsr/ttsr-manager.ts +10 -5
  529. package/packages/pi-ai/dist/models.custom.d.ts.map +0 -1
  530. package/packages/pi-ai/dist/models.custom.js.map +0 -1
  531. package/packages/pi-ai/dist/models.generated.js +0 -14343
  532. package/packages/pi-ai/dist/models.generated.js.map +0 -1
  533. package/packages/pi-ai/src/models.generated.ts +0 -14345
  534. /package/dist/web/standalone/.next/static/{cGmbVq2su4f9tMpgIkG8u → tqdo0yKKYz6fJXQnIgbdx}/_buildManifest.js +0 -0
  535. /package/dist/web/standalone/.next/static/{cGmbVq2su4f9tMpgIkG8u → tqdo0yKKYz6fJXQnIgbdx}/_ssgManifest.js +0 -0
@@ -10,11 +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
+ import { logWarning } from "./workflow-logger.js";
19
+ import { resolveUokFlags } from "./uok/flags.js";
20
+ import { applyModelPolicyFilter } from "./uok/model-policy.js";
18
21
 
19
22
  export interface ModelSelectionResult {
20
23
  /** Routing metadata for metrics recording */
@@ -25,9 +28,7 @@ export interface ModelSelectionResult {
25
28
 
26
29
  export function resolvePreferredModelConfig(
27
30
  unitType: string,
28
- autoModeStartModel: { provider: string; id: string } | null,
29
- /** When false, only return explicit per-phase model configs — do not
30
- * synthesize a routing ceiling from dynamic_routing.tier_models (#3962). */
31
+ autoModeStartModel: { provider: string; id: string; flatRateCtx?: FlatRateContext } | null,
31
32
  isAutoMode = true,
32
33
  ) {
33
34
  const explicitConfig = resolveModelWithFallbacksForUnit(unitType);
@@ -41,7 +42,7 @@ export function resolvePreferredModelConfig(
41
42
  if (!routingConfig.enabled || !routingConfig.tier_models) return undefined;
42
43
 
43
44
  // Don't synthesize a routing config for flat-rate providers (#3453).
44
- if (autoModeStartModel && isFlatRateProvider(autoModeStartModel.provider)) return undefined;
45
+ if (autoModeStartModel && isFlatRateProvider(autoModeStartModel.provider, autoModeStartModel.flatRateCtx)) return undefined;
45
46
 
46
47
  const ceilingModel = routingConfig.tier_models.heavy
47
48
  ?? (autoModeStartModel ? `${autoModeStartModel.provider}/${autoModeStartModel.id}` : undefined);
@@ -68,7 +69,7 @@ export async function selectAndApplyModel(
68
69
  basePath: string,
69
70
  prefs: GSDPreferences | undefined,
70
71
  verbose: boolean,
71
- autoModeStartModel: { provider: string; id: string } | null,
72
+ autoModeStartModel: { provider: string; id: string; flatRateCtx?: FlatRateContext } | null,
72
73
  retryContext?: { isRetry: boolean; previousTier?: string },
73
74
  /** When false (interactive/guided-flow), skip dynamic routing and use the session model.
74
75
  * Dynamic routing only applies in auto-mode where cost optimization is expected. (#3962) */
@@ -76,9 +77,21 @@ export async function selectAndApplyModel(
76
77
  /** Explicit /gsd model pin captured at bootstrap for long-running auto loops. */
77
78
  sessionModelOverride?: { provider: string; id: string } | null,
78
79
  ): Promise<ModelSelectionResult> {
80
+ const uokFlags = resolveUokFlags(prefs);
79
81
  const effectiveSessionModelOverride = sessionModelOverride === undefined
80
82
  ? getSessionModelOverride(ctx.sessionManager.getSessionId())
81
83
  : (sessionModelOverride ?? undefined);
84
+ // Enrich the start model with a flat-rate context up front so routing
85
+ // synthesis and the dispatch-time guard see the same signals (built-in
86
+ // list + user `flat_rate_providers` preference + externalCli auto-
87
+ // detection). The dispatch-time primary-model check below builds its
88
+ // own per-provider context when it has a resolved primary model.
89
+ if (autoModeStartModel) {
90
+ autoModeStartModel = {
91
+ ...autoModeStartModel,
92
+ flatRateCtx: buildFlatRateContext(autoModeStartModel.provider, ctx, prefs),
93
+ };
94
+ }
82
95
  const modelConfig = effectiveSessionModelOverride
83
96
  ? undefined
84
97
  : resolvePreferredModelConfig(unitType, autoModeStartModel, isAutoMode);
@@ -87,6 +100,9 @@ export async function selectAndApplyModel(
87
100
 
88
101
  if (modelConfig) {
89
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;
90
106
 
91
107
  // ─── Dynamic Model Routing ─────────────────────────────────────────
92
108
  // Dynamic routing (complexity-based downgrading) only applies in auto-mode.
@@ -96,8 +112,40 @@ export async function selectAndApplyModel(
96
112
  if (!isAutoMode) {
97
113
  routingConfig.enabled = false;
98
114
  }
115
+ // burn-max defaults to quality-first dispatch (no downgrade routing).
116
+ if (prefs?.token_profile === "burn-max") {
117
+ routingConfig.enabled = false;
118
+ }
99
119
  let effectiveModelConfig = modelConfig;
100
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
+ }
101
149
 
102
150
  // Disable routing for flat-rate providers like GitHub Copilot (#3453).
103
151
  // All models cost the same per request, so downgrading to a cheaper
@@ -105,14 +153,18 @@ export async function selectAndApplyModel(
105
153
  // Fail-closed: if primary model can't be resolved, fall back to
106
154
  // provider-level signals rather than allowing unwanted downgrades.
107
155
  if (routingConfig.enabled) {
108
- const primaryModel = resolveModelId(modelConfig.primary, availableModels, ctx.model?.provider);
156
+ const primaryModel = resolveModelId(modelConfig.primary, routingEligibleModels, ctx.model?.provider);
109
157
  if (primaryModel) {
110
- if (isFlatRateProvider(primaryModel.provider)) {
158
+ const primaryFlatRateCtx = buildFlatRateContext(primaryModel.provider, ctx, prefs);
159
+ if (isFlatRateProvider(primaryModel.provider, primaryFlatRateCtx)) {
111
160
  routingConfig.enabled = false;
112
161
  }
113
162
  } else if (
114
- (autoModeStartModel && isFlatRateProvider(autoModeStartModel.provider))
115
- || (ctx.model?.provider && isFlatRateProvider(ctx.model.provider))
163
+ (autoModeStartModel && isFlatRateProvider(autoModeStartModel.provider, autoModeStartModel.flatRateCtx))
164
+ || (ctx.model?.provider && isFlatRateProvider(
165
+ ctx.model.provider,
166
+ buildFlatRateContext(ctx.model.provider, ctx, prefs),
167
+ ))
116
168
  ) {
117
169
  // Primary model unresolvable but provider signals indicate flat-rate —
118
170
  // disable routing to prevent quality degradation.
@@ -135,8 +187,14 @@ export async function selectAndApplyModel(
135
187
  const shouldClassify = !isHook || routingConfig.hooks !== false;
136
188
 
137
189
  if (shouldClassify) {
138
- let classification = classifyUnitComplexity(unitType, unitId, basePath, budgetPct);
139
- 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);
140
198
 
141
199
  // Escalate tier on retry when escalate_on_failure is enabled (default: true)
142
200
  if (
@@ -243,15 +301,28 @@ export async function selectAndApplyModel(
243
301
  }
244
302
 
245
303
  const modelsToTry = [effectiveModelConfig.primary, ...effectiveModelConfig.fallbacks];
304
+ let attemptedPolicyEligible = false;
246
305
 
247
306
  for (const modelId of modelsToTry) {
248
- const model = resolveModelId(modelId, availableModels, ctx.model?.provider);
307
+ const resolutionPool = uokFlags.modelPolicy ? routingEligibleModels : availableModels;
308
+ const model = resolveModelId(modelId, resolutionPool, ctx.model?.provider);
249
309
 
250
310
  if (!model) {
251
311
  if (verbose) ctx.ui.notify(`Model ${modelId} not found, trying fallback.`, "info");
252
312
  continue;
253
313
  }
254
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
+
255
326
  // Warn if the ID is ambiguous across providers
256
327
  if (!modelId.includes("/")) {
257
328
  const providers = availableModels.filter(m => m.id === modelId).map(m => m.provider);
@@ -317,6 +388,10 @@ export async function selectAndApplyModel(
317
388
  }
318
389
  }
319
390
  }
391
+
392
+ if (uokFlags.modelPolicy && policyAllowedModelKeys && !attemptedPolicyEligible) {
393
+ throw new Error(`Model policy denied dispatch for ${unitType}/${unitId} before prompt send`);
394
+ }
320
395
  } else if (autoModeStartModel) {
321
396
  // No model preference for this unit type — re-apply the model captured
322
397
  // at auto-mode start to prevent bleed from shared global settings.json (#650).
@@ -416,8 +491,68 @@ export function resolveModelId<T extends { id: string; provider: string }>(
416
491
  * Uses case-insensitive matching with alias support to prevent fail-open on
417
492
  * provider naming variations (e.g. "copilot" vs "github-copilot").
418
493
  */
419
- const FLAT_RATE_PROVIDERS = new Set(["github-copilot", "copilot", "claude-code"]);
494
+ const BUILTIN_FLAT_RATE = new Set(["github-copilot", "copilot", "claude-code"]);
420
495
 
421
- export function isFlatRateProvider(provider: string): boolean {
422
- return FLAT_RATE_PROVIDERS.has(provider.toLowerCase());
496
+ /**
497
+ * Optional context that lets callers extend flat-rate detection beyond the
498
+ * hard-coded built-in list. Either signal on its own is enough to classify
499
+ * a provider as flat-rate.
500
+ */
501
+ export interface FlatRateContext {
502
+ /**
503
+ * Auth mode for the specific provider being checked, as returned by
504
+ * `ctx.modelRegistry.getProviderAuthMode(provider)`. Any provider that
505
+ * wraps a local CLI (externalCli) is, by definition, a flat-rate
506
+ * subscription wrapper — every request costs the same regardless of
507
+ * model, so dynamic routing only degrades quality.
508
+ */
509
+ authMode?: "apiKey" | "oauth" | "externalCli" | "none";
510
+ /**
511
+ * Case-insensitive list of extra provider IDs the user has declared as
512
+ * flat-rate via `preferences.flat_rate_providers`. Used for private
513
+ * subscription-backed proxies and enterprise-gated deployments that the
514
+ * built-in list doesn't know about.
515
+ */
516
+ userFlatRate?: readonly string[];
517
+ }
518
+
519
+ export function isFlatRateProvider(provider: string, opts?: FlatRateContext): boolean {
520
+ const p = provider.toLowerCase();
521
+ if (BUILTIN_FLAT_RATE.has(p)) return true;
522
+ if (opts?.userFlatRate?.some(id => id.toLowerCase() === p)) return true;
523
+ if (opts?.authMode === "externalCli") return true;
524
+ return false;
525
+ }
526
+
527
+ /**
528
+ * Build a FlatRateContext for a given provider from live runtime state.
529
+ * Safe to call when ctx or prefs are undefined — missing pieces are
530
+ * treated as "no signal".
531
+ */
532
+ export function buildFlatRateContext(
533
+ provider: string,
534
+ ctx?: { modelRegistry?: { getProviderAuthMode?: (p: string) => string } },
535
+ prefs?: { flat_rate_providers?: readonly string[] },
536
+ ): FlatRateContext {
537
+ let authMode: FlatRateContext["authMode"];
538
+ const getAuthMode = ctx?.modelRegistry?.getProviderAuthMode;
539
+ if (typeof getAuthMode === "function") {
540
+ try {
541
+ const mode = getAuthMode(provider);
542
+ if (mode === "apiKey" || mode === "oauth" || mode === "externalCli" || mode === "none") {
543
+ authMode = mode;
544
+ }
545
+ } catch (err) {
546
+ // Registry lookup failure must never break flat-rate detection —
547
+ // fall through with authMode undefined and surface the cause.
548
+ logWarning(
549
+ "dispatch",
550
+ `flat-rate auth-mode lookup failed for ${provider}: ${err instanceof Error ? err.message : String(err)}`,
551
+ );
552
+ }
553
+ }
554
+ return {
555
+ authMode,
556
+ userFlatRate: prefs?.flat_rate_providers,
557
+ };
423
558
  }
@@ -29,9 +29,10 @@ import { rebuildState } from "./doctor.js";
29
29
  import { parseUnitId } from "./unit-id.js";
30
30
  import { closeoutUnit, type CloseoutOptions } from "./auto-unit-closeout.js";
31
31
  import {
32
- autoCommitCurrentBranch,
32
+ runTurnGitAction,
33
33
  type TaskCommitContext,
34
- } from "./worktree.js";
34
+ type TurnGitActionMode,
35
+ } from "./git-service.js";
35
36
  import {
36
37
  verifyExpectedArtifact,
37
38
  resolveExpectedArtifactPath,
@@ -66,6 +67,9 @@ import { getSliceTasks } from "./gsd-db.js";
66
67
  import { runPreExecutionChecks, type PreExecutionResult } from "./pre-execution-checks.js";
67
68
  import { writePreExecutionEvidence } from "./verification-evidence.js";
68
69
  import { ensureCodebaseMapFresh } from "./codebase-generator.js";
70
+ import { resolveUokFlags } from "./uok/flags.js";
71
+ import { UokGateRunner } from "./uok/gate-runner.js";
72
+ import { writeTurnGitTransaction } from "./uok/gitops.js";
69
73
 
70
74
  /** Maximum verification retry attempts before escalating to blocker placeholder (#2653). */
71
75
  const MAX_VERIFICATION_RETRIES = 3;
@@ -104,10 +108,12 @@ import {
104
108
  updateSliceProgressCache,
105
109
  unitVerb,
106
110
  hideFooter,
111
+ describeNextUnit,
107
112
  } from "./auto-dashboard.js";
108
113
  import { existsSync, unlinkSync } from "node:fs";
109
114
  import { join } from "node:path";
110
115
  import { _resetHasChangesCache } from "./native-git-bridge.js";
116
+ import { autoCommitCurrentBranch } from "./worktree.js";
111
117
 
112
118
  // ─── Rogue File Detection ──────────────────────────────────────────────────
113
119
 
@@ -233,6 +239,18 @@ export function detectRogueFileWrites(
233
239
  return rogues;
234
240
  }
235
241
 
242
+ export const STEP_COMPLETE_FALLBACK_MESSAGE =
243
+ "Step complete. Run /clear, then /gsd to continue (or /gsd auto to run continuously).";
244
+
245
+ export function buildStepCompleteMessage(nextState: import("./types.js").GSDState): string {
246
+ if (nextState.phase === "complete") {
247
+ return "Step complete — milestone finished. Run /gsd status to review, or start the next milestone.";
248
+ }
249
+ const next = describeNextUnit(nextState);
250
+ return `Step complete. Next: ${next.label}\n`
251
+ + `Run /clear, then /gsd to continue (or /gsd auto to run continuously).`;
252
+ }
253
+
236
254
  export interface PreVerificationOpts {
237
255
  skipSettleDelay?: boolean;
238
256
  skipWorktreeSync?: boolean;
@@ -249,6 +267,65 @@ export interface PostUnitContext {
249
267
  updateProgressWidget: (ctx: ExtensionContext, unitType: string, unitId: string, state: import("./types.js").GSDState) => void;
250
268
  }
251
269
 
270
+ export async function autoCommitUnit(
271
+ basePath: string,
272
+ unitType: string,
273
+ unitId: string,
274
+ ctx?: ExtensionContext,
275
+ ): Promise<string | null> {
276
+ try {
277
+ let taskContext: TaskCommitContext | undefined;
278
+
279
+ if (unitType === "execute-task") {
280
+ const { milestone: mid, slice: sid, task: tid } = parseUnitId(unitId);
281
+ if (mid && sid && tid) {
282
+ const summaryPath = resolveTaskFile(basePath, mid, sid, tid, "SUMMARY");
283
+ if (summaryPath) {
284
+ try {
285
+ const summaryContent = await loadFile(summaryPath);
286
+ if (summaryContent) {
287
+ const summary = parseSummary(summaryContent);
288
+ let ghIssueNumber: number | undefined;
289
+ try {
290
+ const { getTaskIssueNumberForCommit } = await import("../github-sync/sync.js");
291
+ ghIssueNumber = getTaskIssueNumberForCommit(basePath, mid, sid, tid) ?? undefined;
292
+ } catch (err) {
293
+ logWarning("engine", `GitHub issue lookup failed: ${err instanceof Error ? err.message : String(err)}`);
294
+ }
295
+
296
+ taskContext = {
297
+ taskId: `${sid}/${tid}`,
298
+ taskTitle: summary.title?.replace(/^T\d+:\s*/, "") || tid,
299
+ oneLiner: summary.oneLiner || undefined,
300
+ keyFiles: summary.frontmatter.key_files?.filter(f => !f.includes("{{")) || undefined,
301
+ issueNumber: ghIssueNumber,
302
+ };
303
+ }
304
+ } catch (e) {
305
+ debugLog("postUnit", { phase: "task-summary-parse", error: String(e) });
306
+ }
307
+ }
308
+ }
309
+ }
310
+
311
+ _resetHasChangesCache();
312
+
313
+ if (LIFECYCLE_ONLY_UNITS.has(unitType)) {
314
+ return null;
315
+ }
316
+
317
+ const commitMsg = autoCommitCurrentBranch(basePath, unitType, unitId, taskContext);
318
+ if (commitMsg) {
319
+ ctx?.ui.notify(`Committed: ${commitMsg.split("\n")[0]}`, "info");
320
+ }
321
+ return commitMsg;
322
+ } catch (e) {
323
+ debugLog("postUnit", { phase: "auto-commit", error: String(e) });
324
+ ctx?.ui.notify(`Auto-commit failed: ${String(e).split("\n")[0]}`, "warning");
325
+ return null;
326
+ }
327
+ }
328
+
252
329
  /**
253
330
  * Pre-verification processing: parallel worker signal check, cache invalidation,
254
331
  * auto-commit, doctor run, state rebuild, worktree sync, artifact verification.
@@ -285,13 +362,21 @@ export async function postUnitPreVerification(pctx: PostUnitContext, opts?: PreV
285
362
  await new Promise(r => setTimeout(r, 100));
286
363
  }
287
364
 
288
- // Auto-commit
365
+ const prefs = loadEffectiveGSDPreferences()?.preferences;
366
+ const uokFlags = resolveUokFlags(prefs);
367
+
368
+ // Turn-level git action (commit | snapshot | status-only)
289
369
  if (s.currentUnit) {
290
370
  const unit = s.currentUnit;
371
+ const turnAction: TurnGitActionMode = uokFlags.gitops ? uokFlags.gitopsTurnAction : "commit";
372
+ const traceId = s.currentTraceId ?? `turn:${unit.startedAt}`;
373
+ const turnId = s.currentTurnId ?? `${unit.type}/${unit.id}/${unit.startedAt}`;
374
+ s.lastGitActionFailure = null;
375
+ s.lastGitActionStatus = null;
291
376
  try {
292
377
  let taskContext: TaskCommitContext | undefined;
293
378
 
294
- if (s.currentUnit.type === "execute-task") {
379
+ if (turnAction === "commit" && s.currentUnit.type === "execute-task") {
295
380
  const { milestone: mid, slice: sid, task: tid } = parseUnitId(s.currentUnit.id);
296
381
  if (mid && sid && tid) {
297
382
  const summaryPath = resolveTaskFile(s.basePath, mid, sid, tid, "SUMMARY");
@@ -332,18 +417,105 @@ export async function postUnitPreVerification(pctx: PostUnitContext, opts?: PreV
332
417
  // `git worktree remove --force` during teardown.
333
418
  _resetHasChangesCache();
334
419
 
335
- // Skip auto-commit for lifecycle-only units (#2553) — they only touch
336
- // `.gsd/` internal state files. Those files are picked up by the next
337
- // actual task commit via smartStage().
338
- if (!LIFECYCLE_ONLY_UNITS.has(s.currentUnit.type)) {
339
- const commitMsg = autoCommitCurrentBranch(s.basePath, s.currentUnit.type, s.currentUnit.id, taskContext);
340
- if (commitMsg) {
341
- ctx.ui.notify(`Committed: ${commitMsg.split("\n")[0]}`, "info");
420
+ const skipLifecycleCommit =
421
+ turnAction === "commit" && LIFECYCLE_ONLY_UNITS.has(s.currentUnit.type);
422
+
423
+ if (skipLifecycleCommit) {
424
+ debugLog("postUnit", {
425
+ phase: "git-action-skipped",
426
+ reason: "lifecycle-only-unit",
427
+ unitType: s.currentUnit.type,
428
+ unitId: s.currentUnit.id,
429
+ });
430
+ } else {
431
+ const gitResult = runTurnGitAction({
432
+ basePath: s.basePath,
433
+ action: turnAction,
434
+ unitType: s.currentUnit.type,
435
+ unitId: s.currentUnit.id,
436
+ taskContext,
437
+ });
438
+
439
+ if (uokFlags.gitops) {
440
+ writeTurnGitTransaction({
441
+ basePath: s.basePath,
442
+ traceId,
443
+ turnId,
444
+ unitType: unit.type,
445
+ unitId: unit.id,
446
+ stage: "publish",
447
+ action: turnAction,
448
+ push: uokFlags.gitopsTurnPush,
449
+ status: gitResult.status,
450
+ error: gitResult.error,
451
+ metadata: {
452
+ dirty: gitResult.dirty,
453
+ commitMessage: gitResult.commitMessage,
454
+ snapshotLabel: gitResult.snapshotLabel,
455
+ },
456
+ });
457
+ }
458
+
459
+ if (gitResult.status === "failed") {
460
+ s.lastGitActionFailure = gitResult.error ?? `git ${turnAction} failed`;
461
+ s.lastGitActionStatus = "failed";
462
+ if (uokFlags.gitops && uokFlags.gates) {
463
+ const parsed = parseUnitId(unit.id);
464
+ const gateRunner = new UokGateRunner();
465
+ gateRunner.register({
466
+ id: "closeout-git-action",
467
+ type: "closeout",
468
+ execute: async () => ({
469
+ outcome: "fail",
470
+ failureClass: "git",
471
+ rationale: `turn git action "${turnAction}" failed`,
472
+ findings: gitResult.error ?? "unknown git failure",
473
+ }),
474
+ });
475
+ await gateRunner.run("closeout-git-action", {
476
+ basePath: s.basePath,
477
+ traceId,
478
+ turnId,
479
+ milestoneId: parsed.milestone ?? undefined,
480
+ sliceId: parsed.slice ?? undefined,
481
+ taskId: parsed.task ?? undefined,
482
+ unitType: unit.type,
483
+ unitId: unit.id,
484
+ });
485
+ }
486
+
487
+ const failureMsg = `Git ${turnAction} failed: ${(gitResult.error ?? "unknown error").split("\n")[0]}`;
488
+ if (uokFlags.gitops) {
489
+ ctx.ui.notify(failureMsg, "error");
490
+ await pauseAuto(ctx, pi);
491
+ return "dispatched";
492
+ }
493
+ ctx.ui.notify(failureMsg, "warning");
494
+ debugLog("postUnit", {
495
+ phase: "git-action-failed-nonblocking",
496
+ action: turnAction,
497
+ error: gitResult.error ?? "unknown error",
498
+ });
499
+ }
500
+
501
+ s.lastGitActionStatus = "ok";
502
+
503
+ if (turnAction === "commit" && gitResult.commitMessage) {
504
+ ctx.ui.notify(`Committed: ${gitResult.commitMessage.split("\n")[0]}`, "info");
505
+ } else if (turnAction === "snapshot" && gitResult.snapshotLabel) {
506
+ ctx.ui.notify(`Snapshot recorded: ${gitResult.snapshotLabel}`, "info");
342
507
  }
343
508
  }
344
509
  } catch (e) {
345
- debugLog("postUnit", { phase: "auto-commit", error: String(e) });
346
- ctx.ui.notify(`Auto-commit failed: ${String(e).split("\n")[0]}`, "warning");
510
+ const message = e instanceof Error ? e.message : String(e);
511
+ s.lastGitActionFailure = message;
512
+ s.lastGitActionStatus = "failed";
513
+ debugLog("postUnit", { phase: "git-action", error: message, action: turnAction });
514
+ ctx.ui.notify(`Git ${turnAction} failed: ${message.split("\n")[0]}`, uokFlags.gitops ? "error" : "warning");
515
+ if (uokFlags.gitops) {
516
+ await pauseAuto(ctx, pi);
517
+ return "dispatched";
518
+ }
347
519
  }
348
520
 
349
521
  // GitHub sync (non-blocking, opt-in)
@@ -619,6 +791,30 @@ export async function postUnitPreVerification(pctx: PostUnitContext, opts?: PreV
619
791
  s.verificationRetryCount.set(retryKey, attempt);
620
792
 
621
793
  if (attempt > MAX_VERIFICATION_RETRIES) {
794
+ // #4175: For complete-milestone, a blocker placeholder is harmful —
795
+ // the stub SUMMARY has no recovery value (milestone is terminal),
796
+ // it does not update DB status (so deriveState never advances),
797
+ // and it fools stopAuto's presence check into merging a milestone
798
+ // that was never legitimately completed. Pause auto-mode with a
799
+ // clear single failure signal and preserve the worktree branch.
800
+ if (s.currentUnit.type === "complete-milestone") {
801
+ debugLog("postUnit", {
802
+ phase: "artifact-verify-pause-complete-milestone",
803
+ unitType: s.currentUnit.type,
804
+ unitId: s.currentUnit.id,
805
+ attempt,
806
+ maxRetries: MAX_VERIFICATION_RETRIES,
807
+ });
808
+ s.verificationRetryCount.delete(retryKey);
809
+ s.pendingVerificationRetry = null;
810
+ ctx.ui.notify(
811
+ `Milestone ${s.currentUnit.id} verification failed after ${MAX_VERIFICATION_RETRIES} retries — worktree branch preserved. Re-run /gsd auto once blockers are resolved.`,
812
+ "error",
813
+ );
814
+ await pauseAuto(ctx, pi);
815
+ return "dispatched";
816
+ }
817
+
622
818
  // Retries exhausted — write a blocker placeholder so the pipeline
623
819
  // can advance past this stuck unit (#2653).
624
820
  debugLog("postUnit", {
@@ -829,11 +1025,13 @@ export async function postUnitPostVerification(pctx: PostUnitContext): Promise<"
829
1025
  s.currentUnit &&
830
1026
  s.currentUnit.type === "plan-slice"
831
1027
  ) {
1028
+ const currentUnit = s.currentUnit;
832
1029
  let preExecPauseNeeded = false;
833
1030
  await runSafely("postUnitPostVerification", "pre-execution-checks", async () => {
1031
+ const prefs = loadEffectiveGSDPreferences()?.preferences;
1032
+ const uokFlags = resolveUokFlags(prefs);
834
1033
  try {
835
1034
  // Check preferences — respect enhanced_verification and enhanced_verification_pre
836
- const prefs = loadEffectiveGSDPreferences()?.preferences;
837
1035
  const enhancedEnabled = prefs?.enhanced_verification !== false; // default true
838
1036
  const preEnabled = prefs?.enhanced_verification_pre !== false; // default true
839
1037
 
@@ -847,7 +1045,7 @@ export async function postUnitPostVerification(pctx: PostUnitContext): Promise<"
847
1045
  }
848
1046
 
849
1047
  // Parse the unit ID to get milestone/slice IDs
850
- const { milestone: mid, slice: sid } = parseUnitId(s.currentUnit!.id);
1048
+ const { milestone: mid, slice: sid } = parseUnitId(currentUnit.id);
851
1049
  if (!mid || !sid) {
852
1050
  debugLog("postUnitPostVerification", {
853
1051
  phase: "pre-execution-checks",
@@ -868,6 +1066,8 @@ export async function postUnitPostVerification(pctx: PostUnitContext): Promise<"
868
1066
  return;
869
1067
  }
870
1068
 
1069
+ const strictMode = prefs?.enhanced_verification_strict === true;
1070
+
871
1071
  // Run pre-execution checks
872
1072
  const result: PreExecutionResult = await runPreExecutionChecks(tasks, s.basePath);
873
1073
 
@@ -891,6 +1091,36 @@ export async function postUnitPostVerification(pctx: PostUnitContext): Promise<"
891
1091
  writePreExecutionEvidence(result, slicePath, mid, sid);
892
1092
  }
893
1093
 
1094
+ if (uokFlags.gates) {
1095
+ const failedChecks = result.checks
1096
+ .filter((check) => !check.passed)
1097
+ .map((check) => `[${check.category}] ${check.target}: ${check.message}`);
1098
+ const warnEscalated = result.status === "warn" && strictMode;
1099
+ const blockingFailure = result.status === "fail" || warnEscalated;
1100
+ const gateRunner = new UokGateRunner();
1101
+ gateRunner.register({
1102
+ id: "pre-execution-checks",
1103
+ type: "input",
1104
+ execute: async () => ({
1105
+ outcome: blockingFailure ? "fail" : "pass",
1106
+ failureClass: result.status === "fail" ? "input" : warnEscalated ? "policy" : "none",
1107
+ rationale: blockingFailure
1108
+ ? `pre-execution checks ${result.status}${warnEscalated ? " (strict)" : ""}`
1109
+ : "pre-execution checks passed",
1110
+ findings: failedChecks.join("\n"),
1111
+ }),
1112
+ });
1113
+ await gateRunner.run("pre-execution-checks", {
1114
+ basePath: s.basePath,
1115
+ traceId: `pre-execution:${currentUnit.id}`,
1116
+ turnId: currentUnit.id,
1117
+ milestoneId: mid,
1118
+ sliceId: sid,
1119
+ unitType: currentUnit.type,
1120
+ unitId: currentUnit.id,
1121
+ });
1122
+ }
1123
+
894
1124
  // Notify UI
895
1125
  if (result.status === "fail") {
896
1126
  const blockingCount = result.checks.filter(c => !c.passed && c.blocking).length;
@@ -929,6 +1159,29 @@ export async function postUnitPostVerification(pctx: PostUnitContext): Promise<"
929
1159
  `Pre-execution checks error: ${errorMessage} — pausing for human review`,
930
1160
  "error",
931
1161
  );
1162
+ if (uokFlags.gates && s.currentUnit) {
1163
+ const { milestone: mid, slice: sid } = parseUnitId(s.currentUnit.id);
1164
+ const gateRunner = new UokGateRunner();
1165
+ gateRunner.register({
1166
+ id: "pre-execution-checks",
1167
+ type: "input",
1168
+ execute: async () => ({
1169
+ outcome: "manual-attention",
1170
+ failureClass: "manual-attention",
1171
+ rationale: "pre-execution checks threw before completion",
1172
+ findings: errorMessage,
1173
+ }),
1174
+ });
1175
+ await gateRunner.run("pre-execution-checks", {
1176
+ basePath: s.basePath,
1177
+ traceId: `pre-execution:${s.currentUnit.id}`,
1178
+ turnId: s.currentUnit.id,
1179
+ milestoneId: mid ?? undefined,
1180
+ sliceId: sid ?? undefined,
1181
+ unitType: s.currentUnit.type,
1182
+ unitId: s.currentUnit.id,
1183
+ });
1184
+ }
932
1185
  preExecPauseNeeded = true;
933
1186
  }
934
1187
  });
@@ -1025,8 +1278,17 @@ export async function postUnitPostVerification(pctx: PostUnitContext): Promise<"
1025
1278
  }
1026
1279
  }
1027
1280
 
1028
- // Step mode → show wizard instead of dispatch
1281
+ // Step mode → show wizard instead of dispatch.
1282
+ // Without this notify(), /gsd in step mode finishes a unit and silently
1283
+ // exits the loop, leaving the user with no hint to /clear and /gsd again.
1029
1284
  if (s.stepMode) {
1285
+ try {
1286
+ const nextState = await deriveState(s.basePath);
1287
+ ctx.ui.notify(buildStepCompleteMessage(nextState), "info");
1288
+ } catch (e) {
1289
+ debugLog("postUnit", { phase: "step-wizard-notify", error: String(e) });
1290
+ ctx.ui.notify(STEP_COMPLETE_FALLBACK_MESSAGE, "info");
1291
+ }
1030
1292
  return "step-wizard";
1031
1293
  }
1032
1294