muonroi-cli 1.8.4 → 1.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (562) hide show
  1. package/LICENSE +17 -5
  2. package/dist/packages/agent-harness-core/src/driver.d.ts +27 -1
  3. package/dist/packages/agent-harness-core/src/driver.js +46 -0
  4. package/dist/packages/agent-harness-core/src/event-filter.js +11 -0
  5. package/dist/packages/agent-harness-core/src/event-redact.js +7 -0
  6. package/dist/packages/agent-harness-core/src/event-tee.d.ts +64 -0
  7. package/dist/packages/agent-harness-core/src/event-tee.js +104 -0
  8. package/dist/packages/agent-harness-core/src/mcp-server.d.ts +25 -0
  9. package/dist/packages/agent-harness-core/src/mcp-server.js +169 -21
  10. package/dist/packages/agent-harness-core/src/predicate.d.ts +1 -1
  11. package/dist/packages/agent-harness-core/src/protocol.d.ts +90 -4
  12. package/dist/packages/agent-harness-core/src/protocol.js +15 -0
  13. package/dist/packages/agent-harness-core/src/visual-quality.d.ts +58 -0
  14. package/dist/packages/agent-harness-core/src/visual-quality.js +141 -0
  15. package/dist/packages/agent-harness-opentui/src/agent-mode.d.ts +6 -0
  16. package/dist/packages/agent-harness-opentui/src/agent-mode.js +14 -1
  17. package/dist/packages/agent-harness-opentui/src/input-bridge.d.ts +2 -10
  18. package/dist/packages/agent-harness-opentui/src/input-bridge.js +103 -16
  19. package/dist/packages/agent-harness-opentui/src/install.d.ts +8 -0
  20. package/dist/packages/agent-harness-opentui/src/install.js +10 -0
  21. package/dist/packages/agent-harness-opentui/src/semantic.js +12 -10
  22. package/dist/packages/agent-harness-opentui/src/visual-capture.d.ts +56 -0
  23. package/dist/packages/agent-harness-opentui/src/visual-capture.js +103 -0
  24. package/dist/src/agent-harness/mock-model.d.ts +38 -0
  25. package/dist/src/agent-harness/mock-model.js +69 -3
  26. package/dist/src/agent-harness/test-spawn.js +31 -0
  27. package/dist/src/chat/chat-keychain.d.ts +7 -12
  28. package/dist/src/chat/chat-keychain.js +19 -86
  29. package/dist/src/cli/config/screen-providers.js +1 -1
  30. package/dist/src/cli/cost-forensics.d.ts +10 -0
  31. package/dist/src/cli/cost-forensics.js +18 -3
  32. package/dist/src/cli/keys-bundle.d.ts +1 -1
  33. package/dist/src/cli/keys-bundle.js +1 -1
  34. package/dist/src/cli/keys.d.ts +10 -47
  35. package/dist/src/cli/keys.js +31 -399
  36. package/dist/src/council/clarifier.d.ts +31 -3
  37. package/dist/src/council/clarifier.js +220 -32
  38. package/dist/src/council/context.js +49 -15
  39. package/dist/src/council/debate-checkpoint.d.ts +129 -0
  40. package/dist/src/council/debate-checkpoint.js +176 -0
  41. package/dist/src/council/debate-planner.js +54 -5
  42. package/dist/src/council/debate-summary.d.ts +25 -0
  43. package/dist/src/council/debate-summary.js +85 -0
  44. package/dist/src/council/debate.d.ts +169 -2
  45. package/dist/src/council/debate.js +1265 -135
  46. package/dist/src/council/index.d.ts +108 -1
  47. package/dist/src/council/index.js +670 -197
  48. package/dist/src/council/leader.d.ts +26 -0
  49. package/dist/src/council/leader.js +150 -9
  50. package/dist/src/council/llm.d.ts +94 -0
  51. package/dist/src/council/llm.js +348 -55
  52. package/dist/src/council/panel-select.d.ts +30 -0
  53. package/dist/src/council/panel-select.js +82 -0
  54. package/dist/src/council/planner.js +40 -0
  55. package/dist/src/council/preflight.d.ts +17 -0
  56. package/dist/src/council/preflight.js +50 -2
  57. package/dist/src/council/prompts.d.ts +39 -4
  58. package/dist/src/council/prompts.js +256 -69
  59. package/dist/src/council/stance-recall.d.ts +42 -0
  60. package/dist/src/council/stance-recall.js +57 -0
  61. package/dist/src/council/strip-think.d.ts +17 -0
  62. package/dist/src/council/strip-think.js +33 -0
  63. package/dist/src/council/types.d.ts +138 -0
  64. package/dist/src/ee/artifact-cache.d.ts +16 -0
  65. package/dist/src/ee/artifact-cache.js +32 -0
  66. package/dist/src/ee/auth.d.ts +20 -0
  67. package/dist/src/ee/auth.js +54 -2
  68. package/dist/src/ee/bridge.d.ts +10 -0
  69. package/dist/src/ee/bridge.js +58 -0
  70. package/dist/src/ee/client.js +109 -21
  71. package/dist/src/ee/ee-onboarding.js +6 -26
  72. package/dist/src/ee/export-transcripts.d.ts +1 -0
  73. package/dist/src/ee/export-transcripts.js +8 -10
  74. package/dist/src/ee/extract-session.js +29 -0
  75. package/dist/src/ee/extract-style.d.ts +58 -0
  76. package/dist/src/ee/extract-style.js +270 -0
  77. package/dist/src/ee/recall-ledger.d.ts +9 -0
  78. package/dist/src/ee/recall-ledger.js +3 -0
  79. package/dist/src/ee/scope.d.ts +1 -0
  80. package/dist/src/ee/scope.js +26 -1
  81. package/dist/src/ee/search.d.ts +7 -0
  82. package/dist/src/ee/search.js +24 -0
  83. package/dist/src/ee/transcript-emit.js +2 -0
  84. package/dist/src/ee/types.d.ts +22 -0
  85. package/dist/src/ee/who-am-i-brain.d.ts +35 -0
  86. package/dist/src/ee/who-am-i-brain.js +220 -0
  87. package/dist/src/ee/who-am-i.d.ts +10 -3
  88. package/dist/src/ee/who-am-i.js +12 -0
  89. package/dist/src/ee/workflow-event.d.ts +48 -0
  90. package/dist/src/ee/workflow-event.js +81 -0
  91. package/dist/src/flow/compaction/compress.d.ts +3 -3
  92. package/dist/src/flow/compaction/compress.js +58 -8
  93. package/dist/src/flow/compaction/extract.d.ts +4 -7
  94. package/dist/src/flow/compaction/extract.js +50 -10
  95. package/dist/src/flow/compaction/index.d.ts +14 -1
  96. package/dist/src/flow/compaction/index.js +96 -3
  97. package/dist/src/flow/compaction/input-guard.d.ts +24 -0
  98. package/dist/src/flow/compaction/input-guard.js +43 -0
  99. package/dist/src/flow/compaction/progress.d.ts +35 -0
  100. package/dist/src/flow/compaction/progress.js +35 -0
  101. package/dist/src/flow/fold-planning.d.ts +36 -0
  102. package/dist/src/flow/fold-planning.js +83 -0
  103. package/dist/src/flow/hierarchy.d.ts +146 -0
  104. package/dist/src/flow/hierarchy.js +427 -0
  105. package/dist/src/flow/index.d.ts +1 -0
  106. package/dist/src/flow/index.js +2 -0
  107. package/dist/src/flow/run-artifacts.d.ts +102 -0
  108. package/dist/src/flow/run-artifacts.js +208 -0
  109. package/dist/src/generated/version.d.ts +1 -1
  110. package/dist/src/generated/version.js +1 -1
  111. package/dist/src/gsd/assessment-schema.d.ts +44 -0
  112. package/dist/src/gsd/assessment-schema.js +134 -0
  113. package/dist/src/gsd/capability-registry.d.ts +45 -0
  114. package/dist/src/gsd/capability-registry.js +337 -0
  115. package/dist/src/gsd/complexity-assessor.d.ts +39 -0
  116. package/dist/src/gsd/complexity-assessor.js +152 -0
  117. package/dist/src/gsd/config-bridge.d.ts +7 -0
  118. package/dist/src/gsd/config-bridge.js +114 -0
  119. package/dist/src/gsd/config-loader.d.ts +27 -0
  120. package/dist/src/gsd/config-loader.js +50 -0
  121. package/dist/src/gsd/council-context.d.ts +44 -0
  122. package/dist/src/gsd/council-context.js +114 -0
  123. package/dist/src/gsd/ee-closure.d.ts +28 -0
  124. package/dist/src/gsd/ee-closure.js +49 -0
  125. package/dist/src/gsd/flags.d.ts +66 -0
  126. package/dist/src/gsd/flags.js +102 -0
  127. package/dist/src/gsd/gsd-dispatch.d.ts +58 -0
  128. package/dist/src/gsd/gsd-dispatch.js +131 -0
  129. package/dist/src/gsd/gsd-runtime.d.ts +22 -0
  130. package/dist/src/gsd/gsd-runtime.js +37 -0
  131. package/dist/src/gsd/host-adapter.d.ts +11 -0
  132. package/dist/src/gsd/host-adapter.js +29 -0
  133. package/dist/src/gsd/index.d.ts +24 -1
  134. package/dist/src/gsd/index.js +27 -0
  135. package/dist/src/gsd/loop-host-contract.d.ts +21 -0
  136. package/dist/src/gsd/loop-host-contract.js +39 -0
  137. package/dist/src/gsd/loop-host.d.ts +69 -0
  138. package/dist/src/gsd/loop-host.js +245 -0
  139. package/dist/src/gsd/loop-resolver.d.ts +36 -0
  140. package/dist/src/gsd/loop-resolver.js +79 -0
  141. package/dist/src/gsd/model-tier.d.ts +13 -0
  142. package/dist/src/gsd/model-tier.js +45 -0
  143. package/dist/src/gsd/mutation-gate.d.ts +16 -0
  144. package/dist/src/gsd/mutation-gate.js +41 -0
  145. package/dist/src/gsd/native-roadmap.d.ts +89 -0
  146. package/dist/src/gsd/native-roadmap.js +343 -0
  147. package/dist/src/gsd/native-state.d.ts +47 -0
  148. package/dist/src/gsd/native-state.js +220 -0
  149. package/dist/src/gsd/paths.d.ts +23 -0
  150. package/dist/src/gsd/paths.js +66 -0
  151. package/dist/src/gsd/phase-dag.d.ts +12 -0
  152. package/dist/src/gsd/phase-dag.js +94 -0
  153. package/dist/src/gsd/phase-sync.d.ts +42 -0
  154. package/dist/src/gsd/phase-sync.js +321 -0
  155. package/dist/src/gsd/pil-gate-context.d.ts +13 -0
  156. package/dist/src/gsd/pil-gate-context.js +64 -0
  157. package/dist/src/gsd/pil-gate-critic.d.ts +19 -0
  158. package/dist/src/gsd/pil-gate-critic.js +74 -0
  159. package/dist/src/gsd/plan-council-prompts.d.ts +25 -0
  160. package/dist/src/gsd/plan-council-prompts.js +79 -0
  161. package/dist/src/gsd/plan-council.d.ts +44 -0
  162. package/dist/src/gsd/plan-council.js +283 -0
  163. package/dist/src/gsd/plan-gate-vocabulary.d.ts +40 -0
  164. package/dist/src/gsd/plan-gate-vocabulary.js +64 -0
  165. package/dist/src/gsd/product-workspace.d.ts +13 -0
  166. package/dist/src/gsd/product-workspace.js +124 -0
  167. package/dist/src/gsd/ship-bridge.d.ts +25 -0
  168. package/dist/src/gsd/ship-bridge.js +65 -0
  169. package/dist/src/gsd/state-document.d.ts +40 -0
  170. package/dist/src/gsd/state-document.js +163 -0
  171. package/dist/src/gsd/verdict-schema.d.ts +39 -0
  172. package/dist/src/gsd/verdict-schema.js +144 -0
  173. package/dist/src/gsd/verify-context.d.ts +22 -0
  174. package/dist/src/gsd/verify-context.js +27 -0
  175. package/dist/src/gsd/verify-council-prompts.d.ts +19 -0
  176. package/dist/src/gsd/verify-council-prompts.js +85 -0
  177. package/dist/src/gsd/verify-council.d.ts +25 -0
  178. package/dist/src/gsd/verify-council.js +119 -0
  179. package/dist/src/gsd/verify-gate-vocabulary.d.ts +25 -0
  180. package/dist/src/gsd/verify-gate-vocabulary.js +46 -0
  181. package/dist/src/gsd/workflow-engine.d.ts +60 -0
  182. package/dist/src/gsd/workflow-engine.js +207 -0
  183. package/dist/src/gsd/workflow-tools.d.ts +13 -0
  184. package/dist/src/gsd/workflow-tools.js +277 -0
  185. package/dist/src/headless/council-answers.js +4 -0
  186. package/dist/src/hooks/index.js +1 -1
  187. package/dist/src/index.js +172 -270
  188. package/dist/src/lsp/builtins.js +3 -1
  189. package/dist/src/lsp/manager.d.ts +5 -1
  190. package/dist/src/lsp/manager.js +249 -3
  191. package/dist/src/lsp/npm-cache.d.ts +11 -1
  192. package/dist/src/lsp/npm-cache.js +17 -1
  193. package/dist/src/lsp/runtime.d.ts +6 -1
  194. package/dist/src/lsp/runtime.js +17 -1
  195. package/dist/src/lsp/types.d.ts +83 -1
  196. package/dist/src/lsp/types.js +10 -0
  197. package/dist/src/maintain/pr-builder.js +23 -13
  198. package/dist/src/mcp/auto-setup.js +57 -32
  199. package/dist/src/mcp/client-pool.js +44 -16
  200. package/dist/src/mcp/lsp-tools.d.ts +5 -1
  201. package/dist/src/mcp/lsp-tools.js +93 -2
  202. package/dist/src/mcp/mcp-keychain.d.ts +3 -5
  203. package/dist/src/mcp/mcp-keychain.js +9 -49
  204. package/dist/src/mcp/research-onboarding.js +8 -7
  205. package/dist/src/mcp/runtime.js +34 -2
  206. package/dist/src/mcp/setup-guide-text.d.ts +1 -1
  207. package/dist/src/mcp/setup-guide-text.js +22 -2
  208. package/dist/src/mcp/tools-server.d.ts +10 -0
  209. package/dist/src/mcp/tools-server.js +10 -2
  210. package/dist/src/models/catalog-client.d.ts +87 -0
  211. package/dist/src/models/catalog-client.js +105 -38
  212. package/dist/src/models/catalog.json +528 -265
  213. package/dist/src/models/registry.d.ts +22 -7
  214. package/dist/src/models/registry.js +73 -10
  215. package/dist/src/ops/doctor.js +1 -1
  216. package/dist/src/orchestrator/ask-user.d.ts +61 -0
  217. package/dist/src/orchestrator/ask-user.js +65 -0
  218. package/dist/src/orchestrator/auto-commit.js +1 -1
  219. package/dist/src/orchestrator/batch-turn-runner.js +2 -2
  220. package/dist/src/orchestrator/cache-prefix.d.ts +67 -0
  221. package/dist/src/orchestrator/cache-prefix.js +83 -0
  222. package/dist/src/orchestrator/compact-request.d.ts +32 -0
  223. package/dist/src/orchestrator/compact-request.js +41 -0
  224. package/dist/src/orchestrator/compaction.d.ts +12 -3
  225. package/dist/src/orchestrator/compaction.js +35 -15
  226. package/dist/src/orchestrator/council-manager.d.ts +12 -3
  227. package/dist/src/orchestrator/council-manager.js +74 -32
  228. package/dist/src/orchestrator/council-request.d.ts +49 -0
  229. package/dist/src/orchestrator/council-request.js +62 -0
  230. package/dist/src/orchestrator/cross-turn-dedup.d.ts +6 -0
  231. package/dist/src/orchestrator/cross-turn-dedup.js +22 -1
  232. package/dist/src/orchestrator/error-utils.d.ts +29 -0
  233. package/dist/src/orchestrator/error-utils.js +132 -24
  234. package/dist/src/orchestrator/grounding-check.js +39 -1
  235. package/dist/src/orchestrator/interactive-pause.d.ts +26 -0
  236. package/dist/src/orchestrator/interactive-pause.js +36 -0
  237. package/dist/src/orchestrator/message-processor.d.ts +4 -0
  238. package/dist/src/orchestrator/message-processor.js +268 -41
  239. package/dist/src/orchestrator/orchestrator.d.ts +64 -3
  240. package/dist/src/orchestrator/orchestrator.js +823 -120
  241. package/dist/src/orchestrator/preprocessor.js +3 -3
  242. package/dist/src/orchestrator/proactive-compact-detector.d.ts +26 -0
  243. package/dist/src/orchestrator/proactive-compact-detector.js +36 -0
  244. package/dist/src/orchestrator/prompts.js +17 -17
  245. package/dist/src/orchestrator/reactive-delegation.d.ts +39 -0
  246. package/dist/src/orchestrator/reactive-delegation.js +59 -0
  247. package/dist/src/orchestrator/retry-classifier.d.ts +2 -1
  248. package/dist/src/orchestrator/retry-classifier.js +46 -2
  249. package/dist/src/orchestrator/safety-askcard.d.ts +1 -1
  250. package/dist/src/orchestrator/safety-askcard.js +5 -2
  251. package/dist/src/orchestrator/safety-intercept.d.ts +50 -0
  252. package/dist/src/orchestrator/safety-intercept.js +62 -0
  253. package/dist/src/orchestrator/scope-reminder.js +1 -1
  254. package/dist/src/orchestrator/session-experience.d.ts +2 -1
  255. package/dist/src/orchestrator/session-experience.js +2 -1
  256. package/dist/src/orchestrator/should-run-gate.d.ts +5 -0
  257. package/dist/src/orchestrator/should-run-gate.js +18 -0
  258. package/dist/src/orchestrator/stall-watchdog.d.ts +31 -3
  259. package/dist/src/orchestrator/stall-watchdog.js +65 -10
  260. package/dist/src/orchestrator/stream-runner.d.ts +13 -3
  261. package/dist/src/orchestrator/stream-runner.js +115 -49
  262. package/dist/src/orchestrator/sub-agent-cap.d.ts +13 -1
  263. package/dist/src/orchestrator/sub-agent-cap.js +16 -1
  264. package/dist/src/orchestrator/sub-agent-model-tier.d.ts +13 -1
  265. package/dist/src/orchestrator/sub-agent-model-tier.js +16 -2
  266. package/dist/src/orchestrator/subagent-compactor.d.ts +53 -1
  267. package/dist/src/orchestrator/subagent-compactor.js +126 -15
  268. package/dist/src/orchestrator/tool-engine.d.ts +41 -0
  269. package/dist/src/orchestrator/tool-engine.js +846 -66
  270. package/dist/src/orchestrator/tool-limit-auto-recover.d.ts +22 -0
  271. package/dist/src/orchestrator/tool-limit-auto-recover.js +30 -0
  272. package/dist/src/orchestrator/turn-runner-deps.d.ts +19 -0
  273. package/dist/src/orchestrator/turn-watchdog.d.ts +44 -0
  274. package/dist/src/orchestrator/turn-watchdog.js +84 -0
  275. package/dist/src/pil/agent-operating-contract.d.ts +1 -1
  276. package/dist/src/pil/agent-operating-contract.js +6 -4
  277. package/dist/src/pil/cheap-model-playbook.d.ts +1 -1
  278. package/dist/src/pil/cheap-model-playbook.js +5 -1
  279. package/dist/src/pil/cheap-model-workbooks.d.ts +1 -1
  280. package/dist/src/pil/cheap-model-workbooks.js +1 -1
  281. package/dist/src/pil/discovery-types.d.ts +1 -0
  282. package/dist/src/pil/discovery.d.ts +1 -1
  283. package/dist/src/pil/discovery.js +18 -13
  284. package/dist/src/pil/layer1-intent.d.ts +18 -6
  285. package/dist/src/pil/layer1-intent.js +66 -757
  286. package/dist/src/pil/layer15-context-scan.js +15 -1
  287. package/dist/src/pil/layer1_5-complexity-size.d.ts +7 -0
  288. package/dist/src/pil/layer1_5-complexity-size.js +31 -5
  289. package/dist/src/pil/layer3-ee-injection.js +23 -8
  290. package/dist/src/pil/layer4-gsd.js +69 -16
  291. package/dist/src/pil/layer5-context.js +7 -3
  292. package/dist/src/pil/layer6-output.d.ts +23 -0
  293. package/dist/src/pil/layer6-output.js +5 -1
  294. package/dist/src/pil/llm-classify.d.ts +111 -5
  295. package/dist/src/pil/llm-classify.js +421 -189
  296. package/dist/src/pil/native-capabilities-workbook.d.ts +1 -1
  297. package/dist/src/pil/native-capabilities-workbook.js +8 -0
  298. package/dist/src/pil/pipeline.js +36 -2
  299. package/dist/src/pil/repo-grounding-probe.d.ts +15 -0
  300. package/dist/src/pil/repo-grounding-probe.js +136 -0
  301. package/dist/src/pil/repo-structure-hints.d.ts +7 -0
  302. package/dist/src/pil/repo-structure-hints.js +45 -0
  303. package/dist/src/pil/response-tools.js +5 -3
  304. package/dist/src/pil/schema.d.ts +1 -0
  305. package/dist/src/pil/schema.js +2 -0
  306. package/dist/src/pil/types.d.ts +18 -0
  307. package/dist/src/playbook/directives.d.ts +4 -0
  308. package/dist/src/playbook/directives.js +17 -5
  309. package/dist/src/product-loop/artifact-io.js +4 -0
  310. package/dist/src/product-loop/backlog-builder.d.ts +14 -1
  311. package/dist/src/product-loop/backlog-builder.js +30 -6
  312. package/dist/src/product-loop/criteria-seed.d.ts +51 -0
  313. package/dist/src/product-loop/criteria-seed.js +200 -0
  314. package/dist/src/product-loop/discovery-context-format.js +3 -1
  315. package/dist/src/product-loop/discovery-ecosystem.js +4 -1
  316. package/dist/src/product-loop/discovery-interview.d.ts +9 -0
  317. package/dist/src/product-loop/discovery-interview.js +60 -12
  318. package/dist/src/product-loop/discovery-recommender.js +2 -1
  319. package/dist/src/product-loop/discovery-schema.js +19 -2
  320. package/dist/src/product-loop/discovery-triage.d.ts +23 -0
  321. package/dist/src/product-loop/discovery-triage.js +109 -0
  322. package/dist/src/product-loop/gather.js +150 -2
  323. package/dist/src/product-loop/ideal-trace.d.ts +7 -0
  324. package/dist/src/product-loop/ideal-trace.js +64 -0
  325. package/dist/src/product-loop/index.d.ts +13 -1
  326. package/dist/src/product-loop/index.js +340 -52
  327. package/dist/src/product-loop/loop-driver.d.ts +7 -0
  328. package/dist/src/product-loop/loop-driver.js +330 -106
  329. package/dist/src/product-loop/phase-plan.d.ts +21 -0
  330. package/dist/src/product-loop/phase-plan.js +81 -6
  331. package/dist/src/product-loop/phase-rituals.d.ts +3 -0
  332. package/dist/src/product-loop/phase-rituals.js +8 -3
  333. package/dist/src/product-loop/phase-runner.js +39 -12
  334. package/dist/src/product-loop/plan-adherence-review.d.ts +26 -0
  335. package/dist/src/product-loop/plan-adherence-review.js +144 -0
  336. package/dist/src/product-loop/sprint-runner.d.ts +173 -0
  337. package/dist/src/product-loop/sprint-runner.js +863 -19
  338. package/dist/src/product-loop/types.d.ts +61 -5
  339. package/dist/src/providers/adapter.d.ts +1 -1
  340. package/dist/src/providers/adapter.js +3 -4
  341. package/dist/src/providers/anthropic.d.ts +9 -8
  342. package/dist/src/providers/anthropic.js +13 -47
  343. package/dist/src/providers/auth/browser-flow.d.ts +1 -1
  344. package/dist/src/providers/auth/browser-flow.js +1 -1
  345. package/dist/src/providers/auth/grok-oauth.d.ts +1 -0
  346. package/dist/src/providers/auth/grok-oauth.js +30 -5
  347. package/dist/src/providers/auth/openai-oauth.d.ts +1 -0
  348. package/dist/src/providers/auth/openai-oauth.js +15 -1
  349. package/dist/src/providers/auth/registry.js +0 -34
  350. package/dist/src/providers/auth/token-store.d.ts +9 -9
  351. package/dist/src/providers/auth/token-store.js +8 -67
  352. package/dist/src/providers/auth/types.d.ts +9 -1
  353. package/dist/src/providers/auth/types.js +1 -1
  354. package/dist/src/providers/capabilities.d.ts +24 -5
  355. package/dist/src/providers/capabilities.js +42 -24
  356. package/dist/src/providers/endpoints.d.ts +2 -2
  357. package/dist/src/providers/endpoints.js +11 -10
  358. package/dist/src/providers/env-store.d.ts +17 -0
  359. package/dist/src/providers/env-store.js +228 -0
  360. package/dist/src/providers/keychain.d.ts +22 -18
  361. package/dist/src/providers/keychain.js +127 -140
  362. package/dist/src/providers/mcp-vision-bridge.js +56 -146
  363. package/dist/src/providers/openai-compatible.js +8 -1
  364. package/dist/src/providers/pricing.d.ts +2 -2
  365. package/dist/src/providers/pricing.js +3 -13
  366. package/dist/src/providers/runtime.d.ts +43 -3
  367. package/dist/src/providers/runtime.js +88 -14
  368. package/dist/src/providers/strategies/base.strategy.d.ts +16 -0
  369. package/dist/src/providers/strategies/base.strategy.js +24 -1
  370. package/dist/src/providers/strategies/{siliconflow.strategy.d.ts → opencode-go.strategy.d.ts} +3 -3
  371. package/dist/src/providers/strategies/opencode-go.strategy.js +83 -0
  372. package/dist/src/providers/strategies/registry.js +4 -4
  373. package/dist/src/providers/strategies/thinking-mode.d.ts +109 -0
  374. package/dist/src/providers/strategies/thinking-mode.js +288 -1
  375. package/dist/src/providers/strategies/xai.strategy.js +27 -0
  376. package/dist/src/providers/strategies/zai.strategy.d.ts +14 -0
  377. package/dist/src/providers/strategies/zai.strategy.js +44 -0
  378. package/dist/src/providers/types.d.ts +5 -6
  379. package/dist/src/providers/types.js +2 -2
  380. package/dist/src/providers/vision-backend.d.ts +47 -0
  381. package/dist/src/providers/vision-backend.js +258 -0
  382. package/dist/src/providers/vision-proxy.d.ts +22 -9
  383. package/dist/src/providers/vision-proxy.js +63 -132
  384. package/dist/src/providers/warm.d.ts +65 -0
  385. package/dist/src/providers/warm.js +145 -0
  386. package/dist/src/providers/wire-debug.js +95 -0
  387. package/dist/src/router/decide.d.ts +13 -0
  388. package/dist/src/router/decide.js +138 -36
  389. package/dist/src/router/peak-hour.d.ts +38 -0
  390. package/dist/src/router/peak-hour.js +107 -0
  391. package/dist/src/router/step-router.js +3 -2
  392. package/dist/src/router/warm.js +4 -5
  393. package/dist/src/scaffold/continuation-prompt.d.ts +11 -0
  394. package/dist/src/scaffold/continuation-prompt.js +26 -0
  395. package/dist/src/scaffold/point-to-existing.d.ts +21 -0
  396. package/dist/src/scaffold/point-to-existing.js +25 -0
  397. package/dist/src/self-qa/agentic-loop.js +6 -5
  398. package/dist/src/{ui/state → state}/active-run.d.ts +19 -0
  399. package/dist/src/{ui/state → state}/active-run.js +21 -0
  400. package/dist/src/{ui/status-bar/store.d.ts → state/status-bar-store.d.ts} +4 -1
  401. package/dist/src/{ui/status-bar/store.js → state/status-bar-store.js} +12 -9
  402. package/dist/src/state/turn-trace.d.ts +43 -0
  403. package/dist/src/state/turn-trace.js +32 -0
  404. package/dist/src/storage/db.js +2 -1
  405. package/dist/src/storage/index.d.ts +1 -1
  406. package/dist/src/storage/index.js +1 -1
  407. package/dist/src/storage/interaction-log.d.ts +1 -1
  408. package/dist/src/storage/migrations.js +71 -1
  409. package/dist/src/storage/sessions.d.ts +28 -10
  410. package/dist/src/storage/sessions.js +78 -21
  411. package/dist/src/storage/transcript-view.js +1 -1
  412. package/dist/src/storage/transcript.d.ts +51 -0
  413. package/dist/src/storage/transcript.js +340 -15
  414. package/dist/src/tools/file.d.ts +15 -0
  415. package/dist/src/tools/file.js +32 -0
  416. package/dist/src/tools/git-safety.d.ts +19 -0
  417. package/dist/src/tools/git-safety.js +168 -0
  418. package/dist/src/tools/native-tools.d.ts +1 -1
  419. package/dist/src/tools/native-tools.js +81 -1
  420. package/dist/src/tools/registry.d.ts +20 -0
  421. package/dist/src/tools/registry.js +576 -23
  422. package/dist/src/tools/research.d.ts +29 -0
  423. package/dist/src/tools/research.js +233 -0
  424. package/dist/src/types/index.d.ts +147 -4
  425. package/dist/src/ui/app.js +0 -0
  426. package/dist/src/ui/cards/product-status-card.js +1 -1
  427. package/dist/src/ui/components/agent-rail-activities.d.ts +26 -0
  428. package/dist/src/ui/components/agent-rail-activities.js +47 -0
  429. package/dist/src/ui/components/bubble-body-guard.d.ts +27 -0
  430. package/dist/src/ui/components/bubble-body-guard.js +50 -0
  431. package/dist/src/ui/components/compact-progress-card.d.ts +24 -0
  432. package/dist/src/ui/components/compact-progress-card.js +42 -0
  433. package/dist/src/ui/components/context-rail.d.ts +26 -0
  434. package/dist/src/ui/components/context-rail.js +33 -0
  435. package/dist/src/ui/components/council-conclusion-card.d.ts +73 -0
  436. package/dist/src/ui/components/council-conclusion-card.js +420 -0
  437. package/dist/src/ui/components/council-debate-pill.d.ts +36 -0
  438. package/dist/src/ui/components/council-debate-pill.js +34 -0
  439. package/dist/src/ui/components/council-info-card.js +2 -2
  440. package/dist/src/ui/components/council-leader-bubble.d.ts +10 -3
  441. package/dist/src/ui/components/council-leader-bubble.js +21 -11
  442. package/dist/src/ui/components/council-message-bubble.d.ts +15 -2
  443. package/dist/src/ui/components/council-message-bubble.js +16 -15
  444. package/dist/src/ui/components/council-phase-timeline.d.ts +9 -1
  445. package/dist/src/ui/components/council-phase-timeline.js +66 -17
  446. package/dist/src/ui/components/council-placeholder-bubble.d.ts +16 -9
  447. package/dist/src/ui/components/council-placeholder-bubble.js +32 -29
  448. package/dist/src/ui/components/council-question-card.js +13 -12
  449. package/dist/src/ui/components/council-rail-rounds.d.ts +26 -0
  450. package/dist/src/ui/components/council-rail-rounds.js +57 -0
  451. package/dist/src/ui/components/council-round-group.d.ts +38 -0
  452. package/dist/src/ui/components/council-round-group.js +88 -0
  453. package/dist/src/ui/components/council-status-list.d.ts +3 -1
  454. package/dist/src/ui/components/council-status-list.js +36 -24
  455. package/dist/src/ui/components/council-synthesis-banner.d.ts +7 -2
  456. package/dist/src/ui/components/council-synthesis-banner.js +20 -5
  457. package/dist/src/ui/components/halt-recovery-card.js +9 -5
  458. package/dist/src/ui/components/jump-to-latest-pill.d.ts +11 -0
  459. package/dist/src/ui/components/jump-to-latest-pill.js +14 -0
  460. package/dist/src/ui/components/message-view.d.ts +15 -0
  461. package/dist/src/ui/components/message-view.js +50 -1
  462. package/dist/src/ui/components/prompt-box.js +18 -16
  463. package/dist/src/ui/components/session-tree-card.d.ts +14 -0
  464. package/dist/src/ui/components/session-tree-card.js +46 -0
  465. package/dist/src/ui/components/slash-inline-menu.d.ts +12 -0
  466. package/dist/src/ui/components/slash-inline-menu.js +26 -5
  467. package/dist/src/ui/components/task-list-panel.d.ts +14 -1
  468. package/dist/src/ui/components/task-list-panel.js +22 -2
  469. package/dist/src/ui/components/tool-group.d.ts +15 -3
  470. package/dist/src/ui/components/tool-group.js +69 -11
  471. package/dist/src/ui/containers/modals-layer.d.ts +4 -2
  472. package/dist/src/ui/containers/modals-layer.js +2 -2
  473. package/dist/src/ui/council-harness-event.d.ts +57 -0
  474. package/dist/src/ui/council-harness-event.js +46 -0
  475. package/dist/src/ui/heartbeat-debug.d.ts +29 -0
  476. package/dist/src/ui/heartbeat-debug.js +45 -0
  477. package/dist/src/ui/hooks/use-session-picker.d.ts +3 -3
  478. package/dist/src/ui/mcp-modal.js +2 -4
  479. package/dist/src/ui/modals/api-key-modal.js +1 -1
  480. package/dist/src/ui/modals/connect-modal.js +4 -3
  481. package/dist/src/ui/modals/model-picker-modal.d.ts +8 -18
  482. package/dist/src/ui/modals/model-picker-modal.js +8 -10
  483. package/dist/src/ui/modals/session-picker-modal.d.ts +2 -2
  484. package/dist/src/ui/modals/session-picker-modal.js +3 -5
  485. package/dist/src/ui/picker-providers.d.ts +1 -1
  486. package/dist/src/ui/picker-providers.js +1 -1
  487. package/dist/src/ui/primitives/index.d.ts +1 -0
  488. package/dist/src/ui/primitives/index.js +2 -0
  489. package/dist/src/ui/primitives/semantic-primitives.d.ts +76 -0
  490. package/dist/src/ui/primitives/semantic-primitives.js +81 -0
  491. package/dist/src/ui/slash/compact.js +5 -7
  492. package/dist/src/ui/slash/cost.js +1 -1
  493. package/dist/src/ui/slash/council.js +19 -1
  494. package/dist/src/ui/slash/debug.d.ts +3 -31
  495. package/dist/src/ui/slash/debug.js +9 -20
  496. package/dist/src/ui/slash/ee.js +81 -0
  497. package/dist/src/ui/slash/ideal.d.ts +6 -2
  498. package/dist/src/ui/slash/ideal.js +97 -7
  499. package/dist/src/ui/slash/menu-items.d.ts +7 -0
  500. package/dist/src/ui/slash/menu-items.js +23 -20
  501. package/dist/src/ui/slash/registry.d.ts +2 -0
  502. package/dist/src/ui/slash/registry.js +4 -0
  503. package/dist/src/ui/status-bar/cache-hit.d.ts +6 -0
  504. package/dist/src/ui/status-bar/cache-hit.js +9 -0
  505. package/dist/src/ui/status-bar/index.d.ts +1 -1
  506. package/dist/src/ui/status-bar/index.js +7 -3
  507. package/dist/src/ui/status-bar/usd-meter.d.ts +5 -4
  508. package/dist/src/ui/status-bar/usd-meter.js +6 -4
  509. package/dist/src/ui/theme.d.ts +1 -0
  510. package/dist/src/ui/theme.js +2 -0
  511. package/dist/src/ui/types.d.ts +7 -0
  512. package/dist/src/ui/use-app-logic.js +0 -0
  513. package/dist/src/ui/utils/agent-activities.d.ts +39 -0
  514. package/dist/src/ui/utils/agent-activities.js +96 -0
  515. package/dist/src/ui/utils/format.d.ts +14 -0
  516. package/dist/src/ui/utils/format.js +23 -3
  517. package/dist/src/ui/utils/group-tool-entries.d.ts +26 -0
  518. package/dist/src/ui/utils/group-tool-entries.js +111 -0
  519. package/dist/src/ui/utils/tool-summary.d.ts +21 -0
  520. package/dist/src/ui/utils/tool-summary.js +91 -0
  521. package/dist/src/usage/downgrade.js +2 -2
  522. package/dist/src/usage/product-ledger.js +2 -2
  523. package/dist/src/utils/event-loop-monitor.d.ts +85 -0
  524. package/dist/src/utils/event-loop-monitor.js +107 -0
  525. package/dist/src/utils/install-manager.js +2 -1
  526. package/dist/src/utils/llm-deadline.d.ts +14 -0
  527. package/dist/src/utils/llm-deadline.js +19 -0
  528. package/dist/src/utils/logger.js +2 -2
  529. package/dist/src/utils/loop-profiler.d.ts +102 -0
  530. package/dist/src/utils/loop-profiler.js +202 -0
  531. package/dist/src/utils/permission-mode.js +5 -3
  532. package/dist/src/utils/redactor.js +1 -1
  533. package/dist/src/utils/settings.d.ts +180 -5
  534. package/dist/src/utils/settings.js +271 -31
  535. package/dist/src/utils/side-question.d.ts +1 -2
  536. package/dist/src/utils/side-question.js +2 -2
  537. package/dist/src/utils/visible-retry.d.ts +11 -0
  538. package/dist/src/utils/visible-retry.js +10 -1
  539. package/dist/src/verify/entrypoint.d.ts +1 -1
  540. package/dist/src/verify/entrypoint.js +52 -17
  541. package/dist/src/verify/orchestrator.d.ts +1 -1
  542. package/dist/src/verify/orchestrator.js +20 -3
  543. package/dist/src/verify/recipes.d.ts +13 -0
  544. package/dist/src/verify/recipes.js +15 -0
  545. package/package.json +134 -132
  546. package/dist/src/cli/bw-vault.d.ts +0 -55
  547. package/dist/src/cli/bw-vault.js +0 -133
  548. package/dist/src/mcp/ee-tools.d.ts +0 -46
  549. package/dist/src/mcp/ee-tools.js +0 -193
  550. package/dist/src/providers/auth/gcloud.d.ts +0 -28
  551. package/dist/src/providers/auth/gcloud.js +0 -102
  552. package/dist/src/providers/auth/gemini-oauth.d.ts +0 -82
  553. package/dist/src/providers/auth/gemini-oauth.js +0 -472
  554. package/dist/src/providers/gemini.d.ts +0 -11
  555. package/dist/src/providers/gemini.js +0 -45
  556. package/dist/src/providers/siliconflow-sse-repair.d.ts +0 -58
  557. package/dist/src/providers/siliconflow-sse-repair.js +0 -177
  558. package/dist/src/providers/strategies/google.strategy.d.ts +0 -22
  559. package/dist/src/providers/strategies/google.strategy.js +0 -174
  560. package/dist/src/providers/strategies/siliconflow.strategy.js +0 -29
  561. package/dist/src/ui/containers/chat-feed.d.ts +0 -40
  562. package/dist/src/ui/containers/chat-feed.js +0 -66
@@ -0,0 +1,145 @@
1
+ /**
2
+ * src/providers/warm.ts
3
+ *
4
+ * Boot-time warm-up of the provider factory registry.
5
+ *
6
+ * Root cause it addresses (measured live, 2026-07-16, session 0c6728ba1a25):
7
+ * an xai session POSTed model `gpt-5.4` to api.x.ai and got 404 "The model
8
+ * gpt-5.4 does not exist" — an openai model sent to the xai endpoint. The
9
+ * factory/model guard in `runtime.ts` DID spot the mismatch and tried to
10
+ * redirect the request to openai's own factory, but the registry had no openai
11
+ * entry: a session only ever built the factory for ITS OWN provider, so any
12
+ * sub-task that resolved a model from another provider had nothing to redirect
13
+ * to and fell through to the wrong endpoint.
14
+ *
15
+ * That is the actual hole. Model ids and provider factories travel as two
16
+ * independent values, so "borrow the session's factory" is the silent default
17
+ * for every sub-task (compaction, classify, sub-agents, mode switches) and only
18
+ * some paths remember to re-derive the provider. Warming the registry for every
19
+ * credentialed provider closes it at the source: the factory for a model's own
20
+ * provider is then always present, so `resolveModelRuntime` can derive it from
21
+ * the model itself instead of trusting whatever factory a caller passed.
22
+ *
23
+ * Best-effort by construction: a provider that fails to warm is simply absent
24
+ * (the same state as today), never a boot failure.
25
+ */
26
+ import { logger } from "../utils/logger.js";
27
+ import { createProviderFactoryAsync, hasProviderFactory } from "./runtime.js";
28
+ import { ALL_PROVIDER_IDS } from "./types.js";
29
+ /**
30
+ * Build and register a factory for every provider the user has credentials for.
31
+ *
32
+ * Runs providers concurrently — each is an independent credential read, and a
33
+ * serial loop would add every provider's latency to boot.
34
+ *
35
+ * Skips providers that already have a factory: the session builds its own with
36
+ * session-specific options (custom baseURL, OAuth headers), and rebuilding it
37
+ * from bare defaults here would silently downgrade the live session's wiring.
38
+ */
39
+ /**
40
+ * Rebuild ONE provider's factory after its credentials changed mid-session.
41
+ *
42
+ * `createProviderFactoryAsync` reads OAuth tokens at CONSTRUCTION and bakes the
43
+ * resulting auth headers into the factory (runtime.ts: `loadTokensWithRefresh()`
44
+ * then `authHeaders(tokens)`). Boot warms openai/xai even with no tokens —
45
+ * `getOAuthProviderConfig` only reports that a provider SUPPORTS OAuth — so the
46
+ * entry built at boot is an API-key-path factory. Signing in later saved tokens
47
+ * that nothing re-read: the stale factory stayed registered and the provider
48
+ * kept failing until the next process start. That is the "OAuth only works
49
+ * after I restart the session" report; the same held for a key set via `K` on a
50
+ * provider skipped at boot for "no credentials".
51
+ *
52
+ * warmProviderFactories() cannot be reused for this: it deliberately SKIPS a
53
+ * provider that already has a factory. The registry is last-built-wins, so
54
+ * building again is what replaces the stale entry.
55
+ */
56
+ export async function rewarmProviderFactory(id) {
57
+ try {
58
+ const { loadUserSettings } = await import("../utils/settings.js");
59
+ const baseURL = loadUserSettings()?.providers?.[id]?.baseURL;
60
+ let apiKey;
61
+ try {
62
+ const { loadKeyForProvider } = await import("./keychain.js");
63
+ apiKey = (await loadKeyForProvider(id)) || undefined;
64
+ }
65
+ catch (err) {
66
+ // No stored key is the normal OAuth case, so this is not an error —
67
+ // but log it: a keychain fault here silently downgrades auth.
68
+ logger.debug("cli", `[provider-warm] key read failed for ${id}: ${err?.message}`, { error: err });
69
+ apiKey = undefined;
70
+ }
71
+ await createProviderFactoryAsync(id, { ...(apiKey ? { apiKey } : {}), ...(baseURL ? { baseURL } : {}) });
72
+ logger.info("cli", `[provider-warm] rebuilt ${id} factory after a credential change`, { providerId: id });
73
+ return true;
74
+ }
75
+ catch (err) {
76
+ logger.warn("cli", `[provider-warm] failed to rebuild factory for ${id}: ${err?.message}`, {
77
+ error: err,
78
+ providerId: id,
79
+ });
80
+ return false;
81
+ }
82
+ }
83
+ export async function warmProviderFactories() {
84
+ const warmed = [];
85
+ const skipped = [];
86
+ const { isProviderDisabled } = await import("../utils/settings.js");
87
+ const { loadUserSettings } = await import("../utils/settings.js");
88
+ const userSettings = loadUserSettings();
89
+ await Promise.all(ALL_PROVIDER_IDS.map(async (id) => {
90
+ try {
91
+ if (hasProviderFactory(id)) {
92
+ skipped.push({ id, reason: "already built" });
93
+ return;
94
+ }
95
+ if (isProviderDisabled(id)) {
96
+ skipped.push({ id, reason: "disabled" });
97
+ return;
98
+ }
99
+ let apiKey;
100
+ try {
101
+ const { loadKeyForProvider } = await import("./keychain.js");
102
+ apiKey = (await loadKeyForProvider(id)) || undefined;
103
+ }
104
+ catch {
105
+ // No stored key for this provider — normal; OAuth may still cover it.
106
+ apiKey = undefined;
107
+ }
108
+ let hasOAuth = false;
109
+ try {
110
+ const { getOAuthProviderConfig } = await import("./auth/registry.js");
111
+ hasOAuth = !!(await getOAuthProviderConfig(id));
112
+ }
113
+ catch (err) {
114
+ logger.debug("cli", `[provider-warm] OAuth probe failed for ${id}: ${err?.message}`, {
115
+ error: err,
116
+ });
117
+ }
118
+ if (!apiKey && !hasOAuth) {
119
+ skipped.push({ id, reason: "no credentials" });
120
+ return;
121
+ }
122
+ // Honour a user-configured endpoint; otherwise each strategy falls back
123
+ // to its own provider's apiBase, which is what a non-session provider
124
+ // should use.
125
+ const baseURL = userSettings?.providers?.[id]?.baseURL;
126
+ await createProviderFactoryAsync(id, { ...(apiKey ? { apiKey } : {}), ...(baseURL ? { baseURL } : {}) });
127
+ warmed.push(id);
128
+ }
129
+ catch (err) {
130
+ // Never let one provider's credential problem break boot: absent from
131
+ // the registry is exactly the pre-warm status quo.
132
+ logger.warn("cli", `[provider-warm] failed to build factory for ${id}: ${err?.message}`, {
133
+ error: err,
134
+ providerId: id,
135
+ });
136
+ skipped.push({ id, reason: `error: ${err?.message ?? "unknown"}` });
137
+ }
138
+ }));
139
+ logger.info("cli", `[provider-warm] registry warmed: ${warmed.join(", ") || "(none)"}`, {
140
+ warmed,
141
+ skipped,
142
+ });
143
+ return { warmed, skipped };
144
+ }
145
+ //# sourceMappingURL=warm.js.map
@@ -90,6 +90,95 @@ function summarizeMessage(m) {
90
90
  }
91
91
  return { role, contentKind: "string", textChars: 0 };
92
92
  }
93
+ /**
94
+ * Reduce a request body (from AI SDK's `error.requestBodyValues`) to a
95
+ * PII-safe shape: top-level param key list + each assistant message's field
96
+ * key list. Values are NEVER persisted — only key names. This is the
97
+ * diagnostic evidence needed when a provider rejects "an invalid parameter"
98
+ * (Z.ai 1210, SiliconFlow 20015) and we must see which field was present or
99
+ * missing on each assistant turn in a multi-step tool loop.
100
+ */
101
+ function summarizeRequestBodyShape(body) {
102
+ if (!body || typeof body !== "object")
103
+ return undefined;
104
+ const b = body;
105
+ const paramKeys = Object.keys(b).sort();
106
+ const configParamValues = extractConfigParamValues(b);
107
+ const messages = b.messages;
108
+ if (!Array.isArray(messages)) {
109
+ return {
110
+ paramKeys,
111
+ assistantFieldKeys: [],
112
+ assistantCount: 0,
113
+ assistantLens: [],
114
+ totalReasoningChars: 0,
115
+ responseFormat: b.response_format ?? undefined,
116
+ configParamValues,
117
+ };
118
+ }
119
+ const assistantMsgs = messages.filter((m) => m?.role === "assistant");
120
+ // De-duplicate the field-key signature across assistant messages so a long
121
+ // history doesn't bloat the log — we only care WHICH fields co-occur.
122
+ const signatures = new Set();
123
+ const assistantLens = [];
124
+ let totalReasoningChars = 0;
125
+ for (const m of assistantMsgs) {
126
+ const msg = m;
127
+ const keys = Object.keys(msg ?? {})
128
+ .sort()
129
+ .join(",");
130
+ signatures.add(keys);
131
+ const rc = msg?.reasoning_content;
132
+ const rcLen = typeof rc === "string" ? rc.length : null;
133
+ if (rcLen !== null)
134
+ totalReasoningChars += rcLen;
135
+ const contentLen = typeof msg?.content === "string"
136
+ ? msg.content.length
137
+ : Array.isArray(msg?.content)
138
+ ? msg.content.reduce((n, p) => n + (typeof p?.text === "string" ? p.text.length : 0), 0)
139
+ : 0;
140
+ const toolCallsLen = Array.isArray(msg?.tool_calls) ? msg.tool_calls.length : 0;
141
+ assistantLens.push({ rc: rcLen, content: contentLen, toolCalls: toolCallsLen });
142
+ }
143
+ return {
144
+ paramKeys,
145
+ assistantFieldKeys: [...signatures],
146
+ assistantCount: assistantMsgs.length,
147
+ assistantLens,
148
+ totalReasoningChars,
149
+ responseFormat: b.response_format ?? undefined,
150
+ configParamValues,
151
+ };
152
+ }
153
+ /**
154
+ * Scalar SDK-config params whose VALUES are PII-safe (generation config, not
155
+ * user prompt content) and which are the likely culprits when a provider
156
+ * rejects with a generic "Invalid API parameter" (Z.ai 1210, SiliconFlow
157
+ * 20015). `messages` and `tools` are deliberately excluded — their values may
158
+ * carry prompts/PII, and counts are already captured elsewhere.
159
+ */
160
+ const CONFIG_PARAM_KEYS = [
161
+ "reasoning_effort",
162
+ "verbosity",
163
+ "tool_choice",
164
+ "response_format",
165
+ "max_tokens",
166
+ "temperature",
167
+ "top_p",
168
+ "frequency_penalty",
169
+ "presence_penalty",
170
+ "seed",
171
+ "stop",
172
+ "parallel_tool_calls",
173
+ ];
174
+ function extractConfigParamValues(body) {
175
+ const out = {};
176
+ for (const k of CONFIG_PARAM_KEYS) {
177
+ if (k in body)
178
+ out[k] = body[k] ?? null;
179
+ }
180
+ return out;
181
+ }
93
182
  export const wireDebug = {
94
183
  enabled: ENABLED,
95
184
  /** Log an outgoing streamText/streamObject call. */
@@ -129,6 +218,12 @@ export const wireDebug = {
129
218
  statusCode: typeof e?.statusCode === "number" ? e.statusCode : undefined,
130
219
  url: typeof e?.url === "string" ? e.url : undefined,
131
220
  responseBody: typeof e?.responseBody === "string" ? e.responseBody.slice(0, 4000) : undefined,
221
+ // Evidence for "Invalid API parameter" (e.g. Z.ai code 1210,
222
+ // SiliconFlow 20015): capture the SHAPE (key names only — no values,
223
+ // PII-safe) of every assistant message in the request body so we can
224
+ // see which field the provider rejected and whether reasoning_content
225
+ // was present/missing across the multi-step tool-loop history.
226
+ requestBodyShape: summarizeRequestBodyShape(e?.requestBodyValues),
132
227
  cause: e?.cause && typeof e.cause === "object"
133
228
  ? {
134
229
  message: typeof e.cause.message === "string"
@@ -14,6 +14,14 @@ export interface DecideOpts {
14
14
  signal?: AbortSignal;
15
15
  defaultModel: string;
16
16
  defaultProvider: string;
17
+ /**
18
+ * Optional session id for audit logging. When provided, a `routing`
19
+ * interaction event is emitted whenever the turn's routed model differs from
20
+ * `defaultModel` (the stored session.model) — making per-turn overrides
21
+ * observable instead of silent. Fixes the "session.model lie": a user on
22
+ * flash could not see when the router silently promoted them to pro.
23
+ */
24
+ sessionId?: string;
17
25
  /** Override home directory for ledger (testing). */
18
26
  homeOverride?: string;
19
27
  /** PIL enrichment signals — forwarded to EE context. */
@@ -27,6 +35,11 @@ export interface DecideOpts {
27
35
  projectSize?: "small" | "medium" | "large" | null;
28
36
  filesTouched?: number;
29
37
  mode?: string | null;
38
+ turnIndex?: number;
39
+ messageCount?: number;
40
+ compactionCount?: number;
41
+ totalSavedTokens?: number;
42
+ compactionSummary?: string | null;
30
43
  };
31
44
  }
32
45
  export declare function clearRouteCache(): void;
@@ -6,7 +6,7 @@
6
6
  * If cap breach detected, downgrade chain overrides classifier output (ROUTE-06).
7
7
  */
8
8
  import { getDefaultEEClient } from "../ee/intercept.js";
9
- import { getModelByTier, getModelInfo, getModelsForProvider } from "../models/registry.js";
9
+ import { getModelInfo, getModelsForProvider } from "../models/registry.js";
10
10
  import { taskTypeToRole } from "../pil/task-tier-map.js";
11
11
  import { detectProviderForModel } from "../providers/runtime.js";
12
12
  import { ALL_PROVIDER_IDS } from "../providers/types.js";
@@ -14,9 +14,10 @@ import { downgradeChain, emitDowngrade, getDowngradeChain } from "../usage/downg
14
14
  import { release, reserve } from "../usage/ledger.js";
15
15
  import { midstreamPolicy } from "../usage/midstream.js";
16
16
  import { CapBreachError } from "../usage/types.js";
17
- import { getRoleModel, isCouncilMultiProviderPreferred, isProviderDisabled } from "../utils/settings.js";
17
+ import { getRoleModel, getRoutingPromoteMax, isCouncilMultiProviderPreferred, isProviderDisabled, } from "../utils/settings.js";
18
18
  import { classify } from "./classifier/index.js";
19
19
  import { callColdRoute } from "./cold.js";
20
+ import { adjustPeakHourModel, getRoutedModelByTier } from "./peak-hour.js";
20
21
  import { isInheritProvider } from "./provider-sentinel.js";
21
22
  import { routerStore } from "./store.js";
22
23
  import { callWarmRoute } from "./warm.js";
@@ -75,6 +76,16 @@ function buildRouteContext(cwd, pil) {
75
76
  ctx.filesTouched = pil.filesTouched;
76
77
  if (pil?.mode)
77
78
  ctx.mode = pil.mode;
79
+ if (pil?.turnIndex !== undefined)
80
+ ctx.turnIndex = pil.turnIndex;
81
+ if (pil?.messageCount !== undefined)
82
+ ctx.messageCount = pil.messageCount;
83
+ if (pil?.compactionCount !== undefined)
84
+ ctx.compactionCount = pil.compactionCount;
85
+ if (pil?.totalSavedTokens !== undefined)
86
+ ctx.totalSavedTokens = pil.totalSavedTokens;
87
+ if (pil?.compactionSummary)
88
+ ctx.compactionSummary = pil.compactionSummary;
78
89
  return ctx;
79
90
  }
80
91
  // ─── Disabled-provider guard: fallback providers ────────────────────────────
@@ -90,7 +101,7 @@ function resolveEffectiveDefaults(opts) {
90
101
  }
91
102
  for (const p of FALLBACK_PROVIDERS) {
92
103
  if (!isProviderDisabled(p)) {
93
- const m = getModelByTier("balanced", p);
104
+ const m = getRoutedModelByTier("balanced", p);
94
105
  // Guard: getModelByTier may return a model from a different provider
95
106
  // when the preferred provider has no model for the requested tier.
96
107
  if (m && m.provider === p)
@@ -114,7 +125,7 @@ function resolveTierModel(tier, defaultProvider) {
114
125
  }
115
126
  for (const p of FALLBACK_PROVIDERS) {
116
127
  if (!isProviderDisabled(p)) {
117
- const m = getModelByTier(tier, p);
128
+ const m = getRoutedModelByTier(tier, p);
118
129
  // Guard: getModelByTier may return a model from a different provider
119
130
  // when the preferred provider has no model for the requested tier.
120
131
  if (m && m.provider === p)
@@ -126,6 +137,17 @@ function resolveTierModel(tier, defaultProvider) {
126
137
  }
127
138
  return undefined;
128
139
  }
140
+ function applyPeakHourRoute(dec) {
141
+ const adj = adjustPeakHourModel(dec.model);
142
+ if (!adj.adjusted)
143
+ return dec;
144
+ return {
145
+ ...dec,
146
+ model: adj.modelId,
147
+ provider: adj.provider,
148
+ reason: `${dec.reason}|${adj.reason}`,
149
+ };
150
+ }
129
151
  // ─── Provider constraint: never route to a provider the user lacks a key for ─
130
152
  function constrainToProvider(decision, opts) {
131
153
  // Inherit-sentinel: warm path may emit an empty provider to signal
@@ -134,11 +156,11 @@ function constrainToProvider(decision, opts) {
134
156
  if (isInheritProvider(decision.provider)) {
135
157
  const resolved = detectProviderForModel(decision.model);
136
158
  if (resolved && !isProviderDisabled(resolved))
137
- return decision;
159
+ return applyPeakHourRoute(decision);
138
160
  if (resolved && isProviderDisabled(resolved)) {
139
161
  return constrainToProvider({ ...decision, provider: resolved }, opts);
140
162
  }
141
- return decision;
163
+ return applyPeakHourRoute(decision);
142
164
  }
143
165
  // Provider-only UX: the user enables N providers and pins one as default.
144
166
  // Routing rules:
@@ -150,7 +172,7 @@ function constrainToProvider(decision, opts) {
150
172
  // surface a config error elsewhere).
151
173
  const decisionDisabled = isProviderDisabled(decision.provider);
152
174
  if (!decisionDisabled) {
153
- return decision;
175
+ return applyPeakHourRoute(decision);
154
176
  }
155
177
  if (isProviderDisabled(opts.defaultProvider)) {
156
178
  return {
@@ -158,7 +180,7 @@ function constrainToProvider(decision, opts) {
158
180
  reason: `${decision.reason}|provider-not-constrained(default-also-disabled)`,
159
181
  };
160
182
  }
161
- const sameProviderModel = getModelByTier(decision.tier === "hot" ? "fast" : decision.tier === "cold" ? "premium" : "balanced", opts.defaultProvider);
183
+ const sameProviderModel = getRoutedModelByTier(decision.tier === "hot" ? "fast" : decision.tier === "cold" ? "premium" : "balanced", opts.defaultProvider);
162
184
  if (sameProviderModel && sameProviderModel.provider !== opts.defaultProvider) {
163
185
  return {
164
186
  ...decision,
@@ -167,12 +189,12 @@ function constrainToProvider(decision, opts) {
167
189
  reason: `${decision.reason}|provider-constrained(forced-default)`,
168
190
  };
169
191
  }
170
- return {
192
+ return applyPeakHourRoute({
171
193
  ...decision,
172
194
  model: sameProviderModel?.id ?? opts.defaultModel,
173
195
  provider: sameProviderModel?.provider ?? opts.defaultProvider,
174
196
  reason: `${decision.reason}|provider-constrained`,
175
- };
197
+ });
176
198
  }
177
199
  // ─── Route feedback (HTTP path) ─────────────────────────────────────────────
178
200
  /**
@@ -194,12 +216,78 @@ export function reportRouteOutcome(taskHash, outcome, duration) {
194
216
  duration: duration ?? null,
195
217
  });
196
218
  }
219
+ // ─── Tier-promotion cap (cost-ceiling guard) ───────────────────────────────
220
+ const TIER_RANK = {
221
+ fast: 0,
222
+ balanced: 1,
223
+ premium: 2,
224
+ };
225
+ /**
226
+ * Enforce the user's tier-promotion ceiling. The session default model is the
227
+ * cost ceiling: the router may downgrade per turn but may not silently promote
228
+ * beyond `routingPromoteMax` (default "balanced"). See settings.ts.
229
+ *
230
+ * When the decision would promote, clamp down to the max allowed tier on the
231
+ * SAME provider. If no same-provider model exists at the ceiling tier, fall
232
+ * back to the session default model (the user's explicit pick). The clamp is
233
+ * skipped for: the `"any"` opt-in, the role path (explicit user roleModels
234
+ * config is itself the opt-in), cap-halt decisions, and provider-constrained
235
+ * disabled-provider recoveries (those already move toward the default).
236
+ */
237
+ function applyPromotionCap(dec, defaultModel) {
238
+ if (dec.model === "HALT" || dec.model === defaultModel)
239
+ return dec;
240
+ const cap = getRoutingPromoteMax();
241
+ if (cap === "any")
242
+ return dec;
243
+ const capRank = cap === "off" ? null : TIER_RANK[cap]; // "balanced" → 1
244
+ const defaultTier = getModelInfo(defaultModel)?.tier;
245
+ // "off" means ceiling = the default model's own tier.
246
+ const maxAllowedRank = capRank === null ? (defaultTier ? TIER_RANK[defaultTier] : 0) : capRank;
247
+ const decInfo = getModelInfo(dec.model);
248
+ const decTier = decInfo?.tier;
249
+ if (!decTier || TIER_RANK[decTier] <= maxAllowedRank)
250
+ return dec;
251
+ // Promotion exceeds the ceiling — clamp DOWN to the max allowed tier on the
252
+ // same provider. Walk down from the ceiling so we pick the highest permitted.
253
+ const provider = decInfo?.provider ?? detectProviderForModel(dec.model);
254
+ const targetTiers = capRank === null
255
+ ? defaultTier
256
+ ? [defaultTier]
257
+ : ["fast"]
258
+ : maxAllowedRank >= 1
259
+ ? ["balanced", "fast"]
260
+ : ["fast"];
261
+ for (const t of targetTiers) {
262
+ if (TIER_RANK[t] > maxAllowedRank)
263
+ continue;
264
+ const m = getRoutedModelByTier(t, provider);
265
+ if (m && m.provider === provider) {
266
+ return {
267
+ ...dec,
268
+ model: m.id,
269
+ reason: `${dec.reason} | promo-cap(${decTier}→${t})`,
270
+ };
271
+ }
272
+ }
273
+ // No cheaper model on the same provider — fall back to the session default.
274
+ return {
275
+ ...dec,
276
+ model: defaultModel,
277
+ reason: `${dec.reason} | promo-cap(${decTier}→default:${defaultModel})`,
278
+ };
279
+ }
197
280
  /**
198
281
  * Apply cap-check to a RouteDecision. Walks the downgrade chain if
199
282
  * the reservation would breach the cap. Returns the (possibly downgraded) decision.
283
+ *
284
+ * `opts` carries both the ledger homeOverride and the session defaultModel used
285
+ * by the promotion cap. `exempt` skips the promotion cap — used only for the
286
+ * role path, where the user's explicit roleModels config is itself the opt-in.
200
287
  */
201
- async function capCheck(dec, homeOverride) {
202
- let current = { ...dec };
288
+ async function capCheck(dec, opts, exempt) {
289
+ let current = exempt ? { ...dec } : applyPromotionCap({ ...dec }, opts.defaultModel);
290
+ const homeOverride = opts.homeOverride;
203
291
  let attempts = 0;
204
292
  while (attempts++ < getDowngradeChain().length) {
205
293
  // If midstream policy already refuses, halt immediately
@@ -305,14 +393,15 @@ export async function decide(prompt, opts) {
305
393
  providerDisabled: isProviderDisabled(provider),
306
394
  multiProviderPreferred: isCouncilMultiProviderPreferred(),
307
395
  })) {
396
+ const peak = adjustPeakHourModel(roleModelId);
308
397
  const d = {
309
398
  tier: "hot",
310
- model: roleModelId,
311
- provider,
312
- reason: `role:${role}→${roleModelId}`,
399
+ model: peak.modelId,
400
+ provider: peak.provider,
401
+ reason: peak.adjusted ? `role:${role}→${peak.modelId}|${peak.reason}` : `role:${role}→${roleModelId}`,
313
402
  source: "role",
314
403
  };
315
- const checked = await capCheck(d, opts.homeOverride);
404
+ const checked = await capCheck(d, opts, /* exempt */ true);
316
405
  routerStore.setState({ tier: checked.tier, lastDecision: checked, taskHash: null, source: "role" });
317
406
  if (cacheKey && !checked.cap_overridden)
318
407
  setCachedRoute(cacheKey, checked);
@@ -328,7 +417,7 @@ export async function decide(prompt, opts) {
328
417
  if (pilTier && pilConf >= 0.6) {
329
418
  // Use effective (non-disabled) provider when default is disabled
330
419
  const effective = resolveTierModel(pilTier, opts.defaultProvider);
331
- let tierModel = effective ?? getModelByTier(pilTier, opts.defaultProvider);
420
+ let tierModel = effective ?? getRoutedModelByTier(pilTier, opts.defaultProvider);
332
421
  // Guard: getModelByTier may cross to another provider when defaultProvider
333
422
  // has no model for the requested tier. If that cross-provider is disabled,
334
423
  // pin to the default model on the default provider instead.
@@ -338,17 +427,21 @@ export async function decide(prompt, opts) {
338
427
  isProviderDisabled(tierModel.provider)) {
339
428
  tierModel = undefined;
340
429
  }
430
+ const pilModel = tierModel?.id ?? opts.defaultModel;
431
+ const peak = adjustPeakHourModel(pilModel);
341
432
  const d = {
342
433
  tier: "hot",
343
- model: tierModel?.id ?? opts.defaultModel,
344
- provider: tierModel?.provider ?? opts.defaultProvider,
345
- reason: effective
346
- ? `pil:${pilTier}(${pilConf.toFixed(2)})-rerouted(disabled-default)`
347
- : `pil:${pilTier}(${pilConf.toFixed(2)})`,
434
+ model: peak.modelId,
435
+ provider: tierModel?.provider ?? peak.provider,
436
+ reason: peak.adjusted
437
+ ? `${effective ? `pil:${pilTier}(${pilConf.toFixed(2)})-rerouted(disabled-default)` : `pil:${pilTier}(${pilConf.toFixed(2)})`}|${peak.reason}`
438
+ : effective
439
+ ? `pil:${pilTier}(${pilConf.toFixed(2)})-rerouted(disabled-default)`
440
+ : `pil:${pilTier}(${pilConf.toFixed(2)})`,
348
441
  confidence: pilConf,
349
442
  source: "pil",
350
443
  };
351
- const checked = await capCheck(d, opts.homeOverride);
444
+ const checked = await capCheck(d, opts);
352
445
  routerStore.setState({
353
446
  tier: checked.tier,
354
447
  lastDecision: checked,
@@ -364,7 +457,7 @@ export async function decide(prompt, opts) {
364
457
  if (c.tier === "hot") {
365
458
  // Use effective (non-disabled) provider when default is disabled
366
459
  const effective = c.tierHint ? resolveTierModel(c.tierHint, opts.defaultProvider) : undefined;
367
- let tierModel = effective ?? (c.tierHint ? getModelByTier(c.tierHint, opts.defaultProvider) : undefined);
460
+ let tierModel = effective ?? (c.tierHint ? getRoutedModelByTier(c.tierHint, opts.defaultProvider) : undefined);
368
461
  // Same guard as the PIL branch above: drop cross-provider fallback when
369
462
  // the cross-provider is disabled, so we don't switch to a provider the
370
463
  // user has turned off in the splash modal.
@@ -374,14 +467,20 @@ export async function decide(prompt, opts) {
374
467
  isProviderDisabled(tierModel.provider)) {
375
468
  tierModel = undefined;
376
469
  }
470
+ const hotModel = tierModel?.id ?? opts.defaultModel;
471
+ const peak = adjustPeakHourModel(hotModel);
377
472
  const d = {
378
473
  tier: "hot",
379
- model: tierModel?.id ?? opts.defaultModel,
380
- provider: tierModel?.provider ?? opts.defaultProvider,
381
- reason: effective ? `${c.reason}-rerouted(disabled-default)` : c.reason,
474
+ model: peak.modelId,
475
+ provider: tierModel?.provider ?? peak.provider,
476
+ reason: peak.adjusted
477
+ ? `${effective ? `${c.reason}-rerouted(disabled-default)` : c.reason}|${peak.reason}`
478
+ : effective
479
+ ? `${c.reason}-rerouted(disabled-default)`
480
+ : c.reason,
382
481
  confidence: c.confidence,
383
482
  };
384
- const checked = await capCheck(d, opts.homeOverride);
483
+ const checked = await capCheck(d, opts);
385
484
  routerStore.setState({
386
485
  tier: checked.tier,
387
486
  lastDecision: checked,
@@ -395,7 +494,7 @@ export async function decide(prompt, opts) {
395
494
  // Step 2: Warm path (EE /api/route-model, 250ms timeout)
396
495
  const w = await callWarmRoute(prompt, { ...opts, context: routeCtx });
397
496
  if (w) {
398
- const checked = await capCheck(constrainToProvider(w, opts), opts.homeOverride);
497
+ const checked = await capCheck(constrainToProvider(w, opts), opts);
399
498
  routerStore.setState({
400
499
  tier: checked.tier,
401
500
  lastDecision: checked,
@@ -409,7 +508,7 @@ export async function decide(prompt, opts) {
409
508
  // Step 3: Cold path (EE /api/cold-route, 1s timeout)
410
509
  const cd = await callColdRoute(prompt, { ...opts, context: routeCtx });
411
510
  if (cd) {
412
- const checked = await capCheck(constrainToProvider(cd, opts), opts.homeOverride);
511
+ const checked = await capCheck(constrainToProvider(cd, opts), opts);
413
512
  routerStore.setState({
414
513
  tier: "cold",
415
514
  lastDecision: checked,
@@ -422,15 +521,18 @@ export async function decide(prompt, opts) {
422
521
  }
423
522
  // Step 4: Final fallback when EE entirely unreachable
424
523
  const effective = resolveEffectiveDefaults(opts);
524
+ const peak = adjustPeakHourModel(effective.model);
425
525
  const fallback = {
426
526
  tier: routerStore.getState().degraded ? "degraded" : "hot",
427
- model: effective.model,
428
- provider: effective.provider,
429
- reason: effective.provider !== opts.defaultProvider
430
- ? "fallback:ee-unreachable+rerouted(disabled-default)"
431
- : "fallback:ee-unreachable",
527
+ model: peak.modelId,
528
+ provider: peak.provider,
529
+ reason: peak.adjusted
530
+ ? `${effective.provider !== opts.defaultProvider ? "fallback:ee-unreachable+rerouted(disabled-default)" : "fallback:ee-unreachable"}|${peak.reason}`
531
+ : effective.provider !== opts.defaultProvider
532
+ ? "fallback:ee-unreachable+rerouted(disabled-default)"
533
+ : "fallback:ee-unreachable",
432
534
  };
433
- const checked = await capCheck(fallback, opts.homeOverride);
535
+ const checked = await capCheck(fallback, opts);
434
536
  routerStore.setState({
435
537
  lastDecision: checked,
436
538
  taskHash: null,
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Peak-hour routing — rules loaded from catalog API `provider_policies.peak_hour`
3
+ * (vendor-sourced metadata). User settings only toggle enabled + switch/downgrade mode.
4
+ */
5
+ import type { CatalogProviderPeakHour } from "../models/catalog-client.js";
6
+ import type { ProviderId } from "../providers/types.js";
7
+ import type { ModelInfo } from "../types/index.js";
8
+ import { type PeakHourPolicy } from "../utils/settings.js";
9
+ export type PeakHourMode = "downgrade" | "switch";
10
+ export interface PeakHourAdjustment {
11
+ modelId: string;
12
+ provider: ProviderId;
13
+ adjusted: boolean;
14
+ reason?: string;
15
+ }
16
+ export declare function hourInTimezone(now: Date, timezone: string): number;
17
+ /** @deprecated Use hourInTimezone — kept for tests referencing UTC+8. */
18
+ export declare function hourUtc8(now: Date): number;
19
+ export declare function peakHourWindows(rule: CatalogProviderPeakHour): Array<{
20
+ start_hour: number;
21
+ end_hour: number;
22
+ }>;
23
+ export declare function isPeakHourForProvider(provider: ProviderId, now: Date, userPolicy?: PeakHourPolicy): boolean;
24
+ /** @deprecated Use isPeakHourForProvider(provider, ...) — window is per-provider from catalog. */
25
+ export declare function isPeakHourUtc8(now: Date, userPolicy: PeakHourPolicy): boolean;
26
+ /**
27
+ * Adjust a concrete model id for peak-hour policy. No-op outside the provider's
28
+ * catalog-defined window or when user policy is disabled.
29
+ */
30
+ export declare function adjustPeakHourModel(modelId: string, opts?: {
31
+ now?: Date;
32
+ policy?: PeakHourPolicy;
33
+ }): PeakHourAdjustment;
34
+ /** Tier lookup with peak-hour adjustment applied to the resolved model. */
35
+ export declare function getRoutedModelByTier(tier: "fast" | "balanced" | "premium", preferProvider?: string, opts?: {
36
+ now?: Date;
37
+ policy?: PeakHourPolicy;
38
+ }): ModelInfo | undefined;