@iislee/opencodex 2.11.0 → 2.31.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 (675) hide show
  1. package/AGENTS_INSTALL.md +109 -0
  2. package/README.md +114 -19
  3. package/bin/ocx.mjs +164 -36
  4. package/bin/package-main.mjs +1 -1
  5. package/gui/dist/assets/index-BF38heuV.js +104 -0
  6. package/gui/dist/assets/index-DMiI18Kv.css +1 -0
  7. package/gui/dist/index.html +2 -2
  8. package/gui/dist/provider-icons/alibaba-color.svg +1 -1
  9. package/gui/dist/provider-icons/antigravity-color.svg +1 -1
  10. package/gui/dist/provider-icons/claude-color.svg +1 -1
  11. package/gui/dist/provider-icons/cline-color.svg +16 -0
  12. package/gui/dist/provider-icons/cloudflare-ai-gateway-color.svg +1 -1
  13. package/gui/dist/provider-icons/commandcode-color.svg +1 -0
  14. package/gui/dist/provider-icons/copilot-color.svg +1 -1
  15. package/gui/dist/provider-icons/cursor-color.svg +1 -1
  16. package/gui/dist/provider-icons/deepseek-color.svg +1 -1
  17. package/gui/dist/provider-icons/firepass-color.svg +1 -1
  18. package/gui/dist/provider-icons/fireworks-color.svg +1 -1
  19. package/gui/dist/provider-icons/gemini-color.svg +1 -1
  20. package/gui/dist/provider-icons/github-copilot-color.svg +1 -1
  21. package/gui/dist/provider-icons/gitlab-duo-color.svg +1 -1
  22. package/gui/dist/provider-icons/grok.svg +1 -1
  23. package/gui/dist/provider-icons/groq-color.svg +1 -1
  24. package/gui/dist/provider-icons/huggingface-color.svg +1 -1
  25. package/gui/dist/provider-icons/kimi-color.svg +1 -1
  26. package/gui/dist/provider-icons/kiro-color.svg +2 -2
  27. package/gui/dist/provider-icons/lm-studio-color.svg +1 -1
  28. package/gui/dist/provider-icons/mistral-color.svg +1 -1
  29. package/gui/dist/provider-icons/moonshot-color.svg +1 -1
  30. package/gui/dist/provider-icons/nvidia-color.svg +1 -1
  31. package/gui/dist/provider-icons/ollama-color.svg +1 -1
  32. package/gui/dist/provider-icons/openai.svg +1 -1
  33. package/gui/dist/provider-icons/opencode.svg +2 -1
  34. package/gui/dist/provider-icons/openrouter-color.svg +1 -1
  35. package/gui/dist/provider-icons/pi.svg +2 -2
  36. package/gui/dist/provider-icons/qianfan-color.svg +1 -1
  37. package/gui/dist/provider-icons/qwen-portal-color.svg +1 -1
  38. package/gui/dist/provider-icons/vercel-ai-gateway-color.svg +1 -1
  39. package/gui/dist/provider-icons/vllm-color.svg +1 -1
  40. package/gui/dist/provider-icons/xiaomi-color.svg +1 -1
  41. package/package.json +19 -10
  42. package/src/adapters/anthropic-output-schema.ts +137 -0
  43. package/src/adapters/anthropic.ts +376 -52
  44. package/src/adapters/base.ts +54 -7
  45. package/src/adapters/client-fingerprint.ts +18 -12
  46. package/src/adapters/cline-pass-deepseek-v4-tool-replay.ts +69 -0
  47. package/src/adapters/command-code.ts +601 -0
  48. package/src/adapters/cursor/checkpoint-store.ts +303 -0
  49. package/src/adapters/cursor/cursor-errors.ts +129 -6
  50. package/src/adapters/cursor/discovery.ts +61 -4
  51. package/src/adapters/cursor/effort-map.ts +27 -3
  52. package/src/adapters/cursor/framing.ts +39 -0
  53. package/src/adapters/cursor/h2-pool.ts +123 -0
  54. package/src/adapters/cursor/http1-bidi.ts +361 -0
  55. package/src/adapters/cursor/images.ts +704 -0
  56. package/src/adapters/cursor/live-models.ts +174 -58
  57. package/src/adapters/cursor/live-transport.ts +609 -170
  58. package/src/adapters/cursor/native-exec-common.ts +23 -2
  59. package/src/adapters/cursor/native-exec-fs.ts +10 -7
  60. package/src/adapters/cursor/native-exec-network.ts +1 -1
  61. package/src/adapters/cursor/native-exec-shell.ts +0 -1
  62. package/src/adapters/cursor/native-exec.ts +101 -14
  63. package/src/adapters/cursor/protobuf-events.ts +829 -11
  64. package/src/adapters/cursor/protobuf-request.ts +383 -65
  65. package/src/adapters/cursor/request-builder.ts +237 -31
  66. package/src/adapters/cursor/tool-definitions.ts +242 -12
  67. package/src/adapters/cursor/tool-result-normalize.ts +92 -0
  68. package/src/adapters/cursor/transport.ts +22 -0
  69. package/src/adapters/cursor/types.ts +28 -1
  70. package/src/adapters/cursor.ts +133 -7
  71. package/src/adapters/google-antigravity-replay.ts +558 -34
  72. package/src/adapters/google-antigravity-wire.ts +43 -10
  73. package/src/adapters/google-http.ts +38 -10
  74. package/src/adapters/google-tool-schema.ts +80 -15
  75. package/src/adapters/google-truncation.ts +11 -0
  76. package/src/adapters/google.ts +618 -74
  77. package/src/adapters/identity.ts +39 -6
  78. package/src/adapters/kiro-errors.ts +11 -0
  79. package/src/adapters/kiro-events.ts +19 -1
  80. package/src/adapters/kiro-thinking.ts +18 -2
  81. package/src/adapters/kiro-tools.ts +10 -1
  82. package/src/adapters/kiro.ts +92 -54
  83. package/src/adapters/mimo-free.ts +17 -0
  84. package/src/adapters/openai-chat-url.ts +11 -0
  85. package/src/adapters/openai-chat.ts +1311 -336
  86. package/src/adapters/openai-responses-url.ts +16 -0
  87. package/src/adapters/openai-responses.ts +830 -56
  88. package/src/adapters/registry.ts +175 -0
  89. package/src/adapters/responses-tool-schema.ts +67 -0
  90. package/src/adapters/tool-call-id.ts +119 -0
  91. package/src/adapters/tool-catalog-nudge.ts +104 -21
  92. package/src/adapters/xai-web-search.ts +185 -0
  93. package/src/bridge.ts +428 -61
  94. package/src/chat/inbound.ts +43 -19
  95. package/src/chat/outbound.ts +82 -26
  96. package/src/claude/agents-inject.ts +32 -9
  97. package/src/claude/context-windows.ts +21 -5
  98. package/src/claude/desktop-3p.ts +243 -9
  99. package/src/claude/gateway-cache.ts +41 -4
  100. package/src/claude/inbound.ts +72 -3
  101. package/src/claude/model-info.ts +38 -15
  102. package/src/claude/outbound.ts +70 -16
  103. package/src/cli/account-api.ts +35 -1
  104. package/src/cli/account-auth.ts +33 -6
  105. package/src/cli/account-catalog-refresh.ts +14 -0
  106. package/src/cli/account-extended.ts +389 -2
  107. package/src/cli/account-main.ts +317 -0
  108. package/src/cli/account.ts +30 -6
  109. package/src/cli/agent.ts +45 -1
  110. package/src/cli/claude-agent-startup-sync.ts +73 -0
  111. package/src/cli/claude-desktop.ts +29 -4
  112. package/src/cli/claude.ts +103 -34
  113. package/src/cli/codex-log-guard-doctor.ts +103 -0
  114. package/src/cli/codex-shim-autorestore.ts +2 -0
  115. package/src/cli/codex-shim-readiness.ts +76 -0
  116. package/src/cli/combo.ts +8 -0
  117. package/src/cli/config-command.ts +74 -10
  118. package/src/cli/dispatch.ts +593 -0
  119. package/src/cli/doctor.ts +315 -43
  120. package/src/cli/ensure-desired-integrations.ts +152 -0
  121. package/src/cli/export-command.ts +46 -20
  122. package/src/cli/help.ts +20 -271
  123. package/src/cli/index.ts +378 -519
  124. package/src/cli/init.ts +4 -17
  125. package/src/cli/integrations.ts +120 -2
  126. package/src/cli/lab.ts +607 -0
  127. package/src/cli/launcher-context.ts +77 -0
  128. package/src/cli/minimax.ts +497 -0
  129. package/src/cli/models-runtime.ts +35 -2
  130. package/src/cli/models.ts +100 -14
  131. package/src/cli/observe.ts +92 -3
  132. package/src/cli/opencode.ts +4 -2
  133. package/src/cli/provider-runtime.ts +18 -1
  134. package/src/cli/provider.ts +24 -3
  135. package/src/cli/ready.ts +301 -0
  136. package/src/cli/registry.ts +437 -0
  137. package/src/cli/root.ts +86 -0
  138. package/src/cli/route-policy.ts +92 -0
  139. package/src/cli/runtime-api.ts +6 -3
  140. package/src/cli/star-prompt.ts +71 -15
  141. package/src/cli/status.ts +10 -3
  142. package/src/cli/system-restart-client.ts +146 -0
  143. package/src/cli/tray-proxy.ts +153 -6
  144. package/src/cli/v2.ts +105 -10
  145. package/src/cli.ts +1 -1
  146. package/src/clients/config-export.ts +1358 -21
  147. package/src/codex/account-label.ts +14 -1
  148. package/src/codex/account-lifecycle.ts +130 -13
  149. package/src/codex/account-namespaces.ts +49 -3
  150. package/src/codex/account-priority.ts +83 -0
  151. package/src/codex/account-store.ts +29 -2
  152. package/src/codex/account-usability.ts +25 -2
  153. package/src/codex/admission.ts +256 -0
  154. package/src/codex/affinity-debug.ts +162 -0
  155. package/src/codex/app-server-processes.ts +493 -106
  156. package/src/codex/app-server-restart-service.ts +232 -0
  157. package/src/codex/auth-api.ts +849 -242
  158. package/src/codex/auth-collision.ts +5 -3
  159. package/src/codex/auth-context.ts +345 -32
  160. package/src/codex/autostart-health.ts +8 -1
  161. package/src/codex/catalog/account-models.ts +67 -0
  162. package/src/codex/catalog/aggregation.ts +68 -10
  163. package/src/codex/catalog/bundled.ts +331 -33
  164. package/src/codex/catalog/effort.ts +121 -30
  165. package/src/codex/catalog/filesystem-evidence.ts +302 -0
  166. package/src/codex/catalog/kinds.ts +2 -0
  167. package/src/codex/catalog/metadata.ts +529 -45
  168. package/src/codex/catalog/native-models.ts +72 -0
  169. package/src/codex/catalog/parsing.ts +224 -30
  170. package/src/codex/catalog/provider-fetch.ts +1460 -134
  171. package/src/codex/catalog/sync.ts +1449 -186
  172. package/src/codex/catalog-admission.ts +199 -0
  173. package/src/codex/catalog-refresh-status.ts +105 -0
  174. package/src/codex/catalog-write-serialization.ts +242 -0
  175. package/src/codex/catalog.ts +6 -3
  176. package/src/codex/codex-write-lock.ts +384 -0
  177. package/src/codex/convergence-types.ts +614 -0
  178. package/src/codex/convergence.ts +651 -0
  179. package/src/codex/coordinator-doctor.ts +332 -0
  180. package/src/codex/custom-model-catalog-migration.ts +176 -0
  181. package/src/codex/desired-state.ts +230 -0
  182. package/src/codex/features.ts +636 -39
  183. package/src/codex/generation.ts +202 -0
  184. package/src/codex/history-job.ts +407 -0
  185. package/src/codex/history-lock.ts +242 -0
  186. package/src/codex/history-migration-guardian.ts +26 -20
  187. package/src/codex/history-provider.ts +231 -28
  188. package/src/codex/history-transition.ts +105 -0
  189. package/src/codex/history-worker.ts +220 -0
  190. package/src/codex/inject-coordination.ts +290 -0
  191. package/src/codex/inject.ts +1073 -152
  192. package/src/codex/injected-marker.ts +37 -3
  193. package/src/codex/integration-record.ts +266 -0
  194. package/src/codex/internal/catalog-writer.ts +203 -0
  195. package/src/codex/internal/history-writer.ts +80 -0
  196. package/src/codex/journal.ts +66 -4
  197. package/src/codex/log-guard/inspect.ts +506 -0
  198. package/src/codex/log-guard/lock.ts +150 -0
  199. package/src/codex/log-guard/maintenance.ts +403 -0
  200. package/src/codex/log-guard/path-safety.ts +88 -0
  201. package/src/codex/log-guard/policy.ts +44 -0
  202. package/src/codex/log-guard/processes.ts +205 -0
  203. package/src/codex/log-guard/protection.ts +489 -0
  204. package/src/codex/log-guard/sqlite-errors.ts +9 -0
  205. package/src/codex/main-account-cache.ts +24 -0
  206. package/src/codex/main-account.ts +29 -1
  207. package/src/codex/management-convergence.ts +167 -0
  208. package/src/codex/model-cache.ts +56 -10
  209. package/src/codex/model-entitlements.ts +353 -0
  210. package/src/codex/native-main-admission.ts +47 -0
  211. package/src/codex/native-main-auth-temp.ts +187 -0
  212. package/src/codex/native-main-claim.ts +178 -0
  213. package/src/codex/native-main-lock-file.ts +162 -0
  214. package/src/codex/native-main-owner.ts +329 -0
  215. package/src/codex/native-profile-api.ts +247 -0
  216. package/src/codex/native-profile-manager.ts +1531 -0
  217. package/src/codex/native-profile-processes.ts +121 -0
  218. package/src/codex/native-profile-recovery.ts +99 -0
  219. package/src/codex/native-profile-stage-store.ts +387 -0
  220. package/src/codex/native-profile-startup.ts +492 -0
  221. package/src/codex/native-profile-store.ts +855 -0
  222. package/src/codex/native-profile-types.ts +120 -0
  223. package/src/codex/native-residue.ts +682 -0
  224. package/src/codex/paths.ts +80 -1
  225. package/src/codex/plan-from-token.ts +140 -0
  226. package/src/codex/plan.ts +40 -0
  227. package/src/codex/plugins-doctor.ts +1 -1
  228. package/src/codex/pool-rotation.ts +74 -4
  229. package/src/codex/project-config-warnings.ts +20 -6
  230. package/src/codex/prompt-journal.ts +352 -0
  231. package/src/codex/prompt-layers.ts +967 -0
  232. package/src/codex/prompt-lock.ts +143 -0
  233. package/src/codex/quota-rejection.ts +298 -0
  234. package/src/codex/quota.ts +175 -13
  235. package/src/codex/refresh.ts +11 -2
  236. package/src/codex/reset-credit-recovery.ts +1044 -0
  237. package/src/codex/routing.ts +505 -94
  238. package/src/codex/runtime.ts +159 -38
  239. package/src/codex/shim.ts +1009 -28
  240. package/src/codex/subagent-model-fallback.ts +350 -35
  241. package/src/codex/sync.ts +191 -2
  242. package/src/codex/transition-state.ts +612 -0
  243. package/src/codex/upstream-host-health.ts +368 -0
  244. package/src/codex/user-identity.ts +557 -0
  245. package/src/codex/warmup.ts +187 -81
  246. package/src/codex/write-coordination.ts +114 -0
  247. package/src/combos/failover.ts +20 -0
  248. package/src/combos/index.ts +4 -0
  249. package/src/combos/request.ts +32 -0
  250. package/src/combos/types.ts +81 -9
  251. package/src/config/provider-name.ts +24 -0
  252. package/src/config.ts +1762 -140
  253. package/src/generated/compatibility-version.json +3164 -0
  254. package/src/generated/{jawcode-model-metadata.ts → model-metadata.ts} +19 -17
  255. package/src/grok/inject.ts +16 -5
  256. package/src/grok/inspect.ts +45 -0
  257. package/src/grok/sync.ts +2 -2
  258. package/src/images/loop.ts +152 -29
  259. package/src/images/plan.ts +23 -13
  260. package/src/integrations/config-io.ts +269 -0
  261. package/src/integrations/journal.ts +315 -0
  262. package/src/integrations/merge.ts +135 -0
  263. package/src/integrations/mutation-flight.ts +71 -0
  264. package/src/integrations/native/ownership-preflight.ts +202 -0
  265. package/src/integrations/omp-yaml-source.ts +358 -0
  266. package/src/integrations/owned-refresh.ts +74 -0
  267. package/src/integrations/ownership.ts +111 -0
  268. package/src/integrations/registry.ts +159 -0
  269. package/src/integrations/serialize.ts +314 -0
  270. package/src/integrations/state.ts +361 -0
  271. package/src/integrations/store.ts +103 -0
  272. package/src/integrations/writer-lock.ts +98 -0
  273. package/src/integrations/writer.ts +691 -0
  274. package/src/lab/artifacts/sanitize.ts +586 -0
  275. package/src/lab/artifacts/secure-fs.ts +475 -0
  276. package/src/lab/artifacts/store.ts +310 -0
  277. package/src/lab/automation/budgets.ts +78 -0
  278. package/src/lab/automation/config-persistence.ts +256 -0
  279. package/src/lab/automation/constants.ts +39 -0
  280. package/src/lab/automation/cooldown.ts +103 -0
  281. package/src/lab/automation/dispatch.ts +211 -0
  282. package/src/lab/automation/index.ts +13 -0
  283. package/src/lab/automation/orchestrator.ts +499 -0
  284. package/src/lab/automation/persistence.ts +512 -0
  285. package/src/lab/automation/planner.ts +371 -0
  286. package/src/lab/automation/policy.ts +136 -0
  287. package/src/lab/automation/queue.ts +191 -0
  288. package/src/lab/automation/recovery.ts +24 -0
  289. package/src/lab/automation/route-context.ts +21 -0
  290. package/src/lab/automation/run-key.ts +44 -0
  291. package/src/lab/automation/runs-query.ts +34 -0
  292. package/src/lab/automation/types.ts +160 -0
  293. package/src/lab/conformance/assertion.ts +325 -0
  294. package/src/lab/conformance/digest.ts +22 -0
  295. package/src/lab/conformance/executor.ts +741 -0
  296. package/src/lab/conformance/fixture-provider.ts +27 -0
  297. package/src/lab/conformance/fixtures/live-v1-cases.json +175 -0
  298. package/src/lab/conformance/fixtures/protocol-v1-cases.json +461 -0
  299. package/src/lab/conformance/harness-budget.ts +47 -0
  300. package/src/lab/conformance/index.ts +5 -0
  301. package/src/lab/conformance/jcs.ts +64 -0
  302. package/src/lab/conformance/json-pointer.ts +39 -0
  303. package/src/lab/conformance/manifest.ts +180 -0
  304. package/src/lab/conformance/mcp-stub.ts +179 -0
  305. package/src/lab/conformance/negative-controls.ts +164 -0
  306. package/src/lab/conformance/observation.ts +355 -0
  307. package/src/lab/conformance/runner.ts +68 -0
  308. package/src/lab/conformance/sse-normalize.ts +59 -0
  309. package/src/lab/conformance/suite-manifest.ts +78 -0
  310. package/src/lab/conformance/types.ts +214 -0
  311. package/src/lab/constants.ts +126 -0
  312. package/src/lab/digest.ts +64 -0
  313. package/src/lab/events/errors.ts +9 -0
  314. package/src/lab/events/limits.ts +117 -0
  315. package/src/lab/events/types.ts +229 -0
  316. package/src/lab/events/validate.ts +781 -0
  317. package/src/lab/fabric/constants.ts +40 -0
  318. package/src/lab/fabric/executor.ts +492 -0
  319. package/src/lab/fabric/index.ts +80 -0
  320. package/src/lab/fabric/manifest.ts +222 -0
  321. package/src/lab/fabric/observe.ts +489 -0
  322. package/src/lab/fabric/patch.ts +79 -0
  323. package/src/lab/fabric/producer-child.ts +139 -0
  324. package/src/lab/fabric/producer-isolate.ts +276 -0
  325. package/src/lab/fabric/producer-protocol.ts +61 -0
  326. package/src/lab/fabric/scratch.ts +439 -0
  327. package/src/lab/fabric/subject.ts +106 -0
  328. package/src/lab/fabric/types.ts +134 -0
  329. package/src/lab/fabric/verifier.ts +98 -0
  330. package/src/lab/index.ts +54 -0
  331. package/src/lab/ledger/artifact-refs.ts +127 -0
  332. package/src/lab/ledger/invalidation.ts +136 -0
  333. package/src/lab/ledger/purge.ts +310 -0
  334. package/src/lab/ledger/store.ts +532 -0
  335. package/src/lab/live/credential-lease.ts +53 -0
  336. package/src/lab/live/destination.ts +155 -0
  337. package/src/lab/live/executor.ts +336 -0
  338. package/src/lab/live/inert-tools.ts +56 -0
  339. package/src/lab/live/manifest.ts +85 -0
  340. package/src/lab/live/mcp-loopback.ts +57 -0
  341. package/src/lab/live/runner.ts +19 -0
  342. package/src/lab/live/sandbox.ts +61 -0
  343. package/src/lab/live/suite-manifest.ts +41 -0
  344. package/src/lab/live/transport.ts +118 -0
  345. package/src/lab/live/types.ts +197 -0
  346. package/src/lab/observe/from-conformance.ts +301 -0
  347. package/src/lab/observe/from-live.ts +117 -0
  348. package/src/lab/paths.ts +153 -0
  349. package/src/lab/projection/rebuild.ts +495 -0
  350. package/src/lab/projection/schema.ts +135 -0
  351. package/src/lab/projection/verdicts.ts +474 -0
  352. package/src/lab/projection/verification.ts +412 -0
  353. package/src/lab/public/bundle.ts +217 -0
  354. package/src/lab/public/community-authority.ts +175 -0
  355. package/src/lab/public/community-files.ts +29 -0
  356. package/src/lab/public/community.ts +479 -0
  357. package/src/lab/public/file-safety.ts +155 -0
  358. package/src/lab/public/ids.ts +26 -0
  359. package/src/lab/public/index.ts +16 -0
  360. package/src/lab/public/mutation-lock.ts +424 -0
  361. package/src/lab/public/operator.ts +353 -0
  362. package/src/lab/public/origin-purge.ts +79 -0
  363. package/src/lab/public/origin.ts +203 -0
  364. package/src/lab/public/privacy.ts +143 -0
  365. package/src/lab/public/private-file.ts +261 -0
  366. package/src/lab/public/project.ts +124 -0
  367. package/src/lab/public/purge-test-fault.ts +21 -0
  368. package/src/lab/public/purge.ts +223 -0
  369. package/src/lab/public/registry.ts +44 -0
  370. package/src/lab/public/revocation.ts +252 -0
  371. package/src/lab/public/signature.ts +243 -0
  372. package/src/lab/public/storage.ts +105 -0
  373. package/src/lab/public/strict-json.ts +206 -0
  374. package/src/lab/public/time.ts +26 -0
  375. package/src/lab/public/types.ts +172 -0
  376. package/src/lab/public/validate.ts +391 -0
  377. package/src/lab/query/catalog.ts +101 -0
  378. package/src/lab/query/connection.ts +107 -0
  379. package/src/lab/query/constants.ts +4 -0
  380. package/src/lab/query/cursor.ts +132 -0
  381. package/src/lab/query/dto-map.ts +277 -0
  382. package/src/lab/query/errors.ts +22 -0
  383. package/src/lab/query/freshness.ts +53 -0
  384. package/src/lab/query/index.ts +45 -0
  385. package/src/lab/query/latest-observation.ts +59 -0
  386. package/src/lab/query/passive-production.ts +159 -0
  387. package/src/lab/query/queries.ts +444 -0
  388. package/src/lab/query/types.ts +266 -0
  389. package/src/lab/subject/behavior-fingerprint.ts +77 -0
  390. package/src/lab/subject/installation-salt.ts +112 -0
  391. package/src/lab/subject/protocol-subject.ts +80 -0
  392. package/src/lab/subject/route-subject.ts +74 -0
  393. package/src/lib/app-owned-memory-stores.ts +22 -0
  394. package/src/lib/bounded-body.ts +153 -9
  395. package/src/lib/bun-runtime.ts +125 -12
  396. package/src/lib/bun-stream-caps.ts +13 -9
  397. package/src/lib/codex-restart-contract.ts +120 -0
  398. package/src/lib/config-ownership.ts +6 -2
  399. package/src/lib/destination-policy.ts +65 -1
  400. package/src/lib/errors.ts +44 -2
  401. package/src/lib/fabric-task-execution-authority.ts +7 -0
  402. package/src/lib/fabric-task-host.ts +29 -0
  403. package/src/lib/lab-activation.ts +223 -0
  404. package/src/lib/lab-live-execution-authority.ts +13 -0
  405. package/src/lib/lab-live-host.ts +30 -0
  406. package/src/lib/lab-live-pinned-sender.ts +56 -0
  407. package/src/lib/lab-live-route-production.ts +130 -0
  408. package/src/lib/lab-passive-linker-registration.ts +26 -0
  409. package/src/lib/local-management-attestation.ts +51 -0
  410. package/src/lib/local-management-capability.ts +100 -0
  411. package/src/lib/local-provider-reload-contract.ts +100 -0
  412. package/src/lib/optional-shutdown-hooks.ts +57 -0
  413. package/src/lib/pinned-http.ts +145 -26
  414. package/src/lib/process-control.ts +4 -1
  415. package/src/lib/provider-outbound.ts +49 -9
  416. package/src/lib/redact.ts +419 -3
  417. package/src/lib/self-launch-argv.ts +15 -0
  418. package/src/lib/server-resource-ownership.ts +71 -0
  419. package/src/lib/shadow-call.ts +35 -4
  420. package/src/lib/sse-decoder.ts +41 -0
  421. package/src/lib/state-store-registrations.ts +10 -2
  422. package/src/lib/system-restart-contract.ts +73 -0
  423. package/src/lib/token-estimate.ts +19 -2
  424. package/src/lib/tool-argument-integers.ts +202 -0
  425. package/src/lib/translator-budget.ts +44 -0
  426. package/src/lib/upstream-http-version.ts +57 -0
  427. package/src/lib/upstream-reachability.ts +95 -0
  428. package/src/lib/upstream-retry.ts +156 -3
  429. package/src/lib/windows-atomic-replace.ts +155 -0
  430. package/src/lib/windows-elevation.ts +70 -2
  431. package/src/lib/windows-secret-acl.ts +409 -69
  432. package/src/lib/windows-service-wrappers.ts +72 -0
  433. package/src/lib/windows-text.ts +106 -0
  434. package/src/lib/windows-user-principal.ts +341 -0
  435. package/src/lib/winsw.ts +33 -5
  436. package/src/oauth/account-import/google-antigravity-adapter.ts +74 -0
  437. package/src/oauth/account-import/index.ts +15 -0
  438. package/src/oauth/account-import/parser.ts +83 -0
  439. package/src/oauth/account-import/registry.ts +18 -0
  440. package/src/oauth/account-import/service.ts +75 -0
  441. package/src/oauth/account-import/types.ts +91 -0
  442. package/src/oauth/anthropic.ts +12 -1
  443. package/src/oauth/callback-server.ts +8 -2
  444. package/src/oauth/chatgpt.ts +12 -1
  445. package/src/oauth/command-code.ts +239 -0
  446. package/src/oauth/cursor.ts +46 -5
  447. package/src/oauth/google-antigravity.ts +35 -3
  448. package/src/oauth/health.ts +20 -12
  449. package/src/oauth/index.ts +398 -66
  450. package/src/oauth/key-providers.ts +16 -0
  451. package/src/oauth/kimi.ts +16 -2
  452. package/src/oauth/kiro.ts +50 -6
  453. package/src/oauth/local-token-detect.ts +11 -2
  454. package/src/oauth/log.ts +3 -1
  455. package/src/oauth/login-cli.ts +88 -28
  456. package/src/oauth/nous.ts +798 -0
  457. package/src/oauth/store.ts +119 -21
  458. package/src/oauth/token-guardian.ts +9 -3
  459. package/src/pi/models.ts +2 -2
  460. package/src/providers/alibaba-region-migration.ts +1 -1
  461. package/src/providers/antigravity-models.ts +521 -31
  462. package/src/providers/base-url-choices.ts +10 -0
  463. package/src/providers/codex-capacity.ts +292 -0
  464. package/src/providers/command-code-efforts.ts +144 -0
  465. package/src/providers/context-cap.ts +22 -5
  466. package/src/providers/cursor-pool.ts +72 -0
  467. package/src/providers/derive.ts +253 -6
  468. package/src/providers/fastwire.ts +501 -0
  469. package/src/providers/free-directory.ts +10 -7
  470. package/src/providers/google-vertex-location.ts +14 -0
  471. package/src/providers/key-failover.ts +71 -3
  472. package/src/providers/label.ts +1 -1
  473. package/src/providers/model-discovery-limits.ts +16 -0
  474. package/src/providers/model-discovery.ts +115 -22
  475. package/src/providers/model-rename-migration.ts +255 -0
  476. package/src/providers/model-rename-startup.ts +28 -0
  477. package/src/providers/openai-sidecar.ts +72 -4
  478. package/src/providers/openai-tier-startup.ts +31 -2
  479. package/src/providers/openai-tiers.ts +119 -4
  480. package/src/providers/openai-virtual-models.ts +1 -0
  481. package/src/providers/opencode-zen-rate-limit.ts +102 -0
  482. package/src/providers/provider-id-rewrite.ts +29 -0
  483. package/src/providers/quota.ts +1319 -38
  484. package/src/providers/registry.ts +1429 -111
  485. package/src/providers/request-pacing.ts +310 -0
  486. package/src/providers/service-tier.ts +277 -0
  487. package/src/providers/slug-codec.ts +42 -6
  488. package/src/providers/static-model-discovery.ts +86 -0
  489. package/src/providers/xai-responses-opt-in.ts +15 -0
  490. package/src/providers/xai-transport.ts +11 -4
  491. package/src/reasoning-effort.ts +49 -1
  492. package/src/responses/compaction.ts +26 -1
  493. package/src/responses/custom-tool-compat.ts +266 -0
  494. package/src/responses/hosted-tool-policy.ts +9 -0
  495. package/src/responses/namespace-tool-compat.ts +355 -0
  496. package/src/responses/parser.ts +220 -38
  497. package/src/responses/provider-continuation.ts +98 -0
  498. package/src/responses/provider-opaque-metadata.ts +73 -0
  499. package/src/responses/reasoning-envelope.ts +9 -1
  500. package/src/responses/reasoning-replay-cache.ts +426 -0
  501. package/src/responses/schema.ts +7 -1
  502. package/src/responses/spill-store.ts +75 -10
  503. package/src/responses/state.ts +565 -27
  504. package/src/responses/thought-signature-replay.ts +347 -0
  505. package/src/responses/tool-search-compat.ts +301 -0
  506. package/src/responses/truncated-stop-reason.ts +60 -0
  507. package/src/router.ts +366 -30
  508. package/src/routing/analytics.ts +378 -0
  509. package/src/routing/capability.ts +244 -0
  510. package/src/routing/compatibility/assemble.ts +73 -0
  511. package/src/routing/compatibility/behavior.ts +278 -0
  512. package/src/routing/compatibility/catalog.ts +99 -0
  513. package/src/routing/compatibility/endpoint.ts +52 -0
  514. package/src/routing/compatibility/lab-evidence-provider.ts +130 -0
  515. package/src/routing/compatibility/policy.ts +181 -0
  516. package/src/routing/compatibility/provider-slot.ts +56 -0
  517. package/src/routing/compatibility/reader.ts +110 -0
  518. package/src/routing/compatibility/subject.ts +191 -0
  519. package/src/routing/compatibility/types.ts +64 -0
  520. package/src/routing/compatibility/version.ts +104 -0
  521. package/src/routing/cost.ts +77 -0
  522. package/src/routing/evaluator.ts +495 -0
  523. package/src/routing/health.ts +412 -0
  524. package/src/routing/history/cursor.ts +43 -0
  525. package/src/routing/history/indexer.ts +605 -0
  526. package/src/routing/history/schema.ts +72 -0
  527. package/src/routing/profile-namespace.ts +15 -0
  528. package/src/routing/profile.ts +547 -0
  529. package/src/routing/quota.ts +145 -0
  530. package/src/routing/request-evidence.ts +45 -0
  531. package/src/routing/trace.ts +776 -0
  532. package/src/server/adapter-resolve.ts +2 -29
  533. package/src/server/auth-cors.ts +267 -46
  534. package/src/server/background-lifecycle.ts +182 -0
  535. package/src/server/chat-completions.ts +130 -56
  536. package/src/server/chat-native-sse.ts +331 -0
  537. package/src/server/chat-native.ts +426 -0
  538. package/src/server/claude-messages.ts +159 -43
  539. package/src/server/direct-local-http.ts +347 -0
  540. package/src/server/effort-policy.ts +18 -0
  541. package/src/server/github-copilot-responses-repair.ts +338 -0
  542. package/src/server/gui-static.ts +39 -10
  543. package/src/server/images.ts +94 -12
  544. package/src/server/index.ts +865 -181
  545. package/src/server/lifecycle.ts +284 -13
  546. package/src/server/live.ts +136 -17
  547. package/src/server/local-management-read-client.ts +90 -0
  548. package/src/server/local-provider-reload-client.ts +137 -0
  549. package/src/server/management/agent-settings-routes.ts +398 -103
  550. package/src/server/management/api-key-usage.ts +31 -5
  551. package/src/server/management/body.ts +6 -0
  552. package/src/server/management/combo-routes.ts +62 -24
  553. package/src/server/management/config-routes.ts +464 -51
  554. package/src/server/management/context.ts +80 -2
  555. package/src/server/management/integration-routes.ts +498 -0
  556. package/src/server/management/lab-automation-routes.ts +206 -0
  557. package/src/server/management/lab-routes.ts +563 -0
  558. package/src/server/management/logs-usage-routes.ts +101 -32
  559. package/src/server/management/model-routes.ts +189 -131
  560. package/src/server/management/model-rows.ts +163 -0
  561. package/src/server/management/native-integration-routes.ts +769 -0
  562. package/src/server/management/oauth-account-routes.ts +80 -4
  563. package/src/server/management/provider-capability-config.ts +48 -0
  564. package/src/server/management/provider-routes.ts +764 -157
  565. package/src/server/management/request-history-routes.ts +191 -0
  566. package/src/server/management/routing-analytics-routes.ts +74 -0
  567. package/src/server/management/routing-profile-routes.ts +380 -0
  568. package/src/server/management/shared.ts +27 -11
  569. package/src/server/management/sidebar-routes.ts +47 -31
  570. package/src/server/management/storage-log-guard-routes.ts +186 -0
  571. package/src/server/management/sync-response.ts +69 -0
  572. package/src/server/management/system-restart.ts +288 -32
  573. package/src/server/management/system-routes.ts +77 -0
  574. package/src/server/management/usage-summary-cache.ts +9 -1
  575. package/src/server/management/vision-sidecar-options.ts +167 -0
  576. package/src/server/management/web-search-sidecar-options.ts +120 -0
  577. package/src/server/management-api.ts +115 -14
  578. package/src/server/management-auth.ts +220 -5
  579. package/src/server/passive-route-linker.ts +66 -0
  580. package/src/server/ports.ts +41 -1
  581. package/src/server/proxy-liveness.ts +132 -5
  582. package/src/server/readiness.ts +99 -0
  583. package/src/server/relay-eager.ts +82 -42
  584. package/src/server/relay.ts +236 -76
  585. package/src/server/request-decompress.ts +113 -6
  586. package/src/server/request-log.ts +235 -22
  587. package/src/server/responses/agent-task-recovery-cache.ts +143 -0
  588. package/src/server/responses/agent-task-recovery.ts +465 -0
  589. package/src/server/responses/collaboration.ts +204 -35
  590. package/src/server/responses/compact.ts +442 -55
  591. package/src/server/responses/core.ts +2872 -331
  592. package/src/server/responses/empty-completion-guard.ts +276 -0
  593. package/src/server/responses/encrypted-payload.ts +62 -39
  594. package/src/server/responses/fetch-helpers.ts +79 -4
  595. package/src/server/responses/input-admission.ts +185 -0
  596. package/src/server/responses/pacing-overload.ts +13 -0
  597. package/src/server/responses/policy-fallback.ts +178 -0
  598. package/src/server/responses/responses-field-backfill.ts +251 -0
  599. package/src/server/responses/terminal-guard.ts +26 -5
  600. package/src/server/responses/upstream-error.ts +5 -0
  601. package/src/server/responses/ws-upstream.ts +308 -0
  602. package/src/server/responses-custom-tool-repair.ts +282 -0
  603. package/src/server/responses-item-id-repair.ts +54 -6
  604. package/src/server/responses-json-events.ts +90 -0
  605. package/src/server/responses-model-rewrite.ts +29 -0
  606. package/src/server/responses-reasoning-summary-rewrite.ts +178 -0
  607. package/src/server/responses-snapshot-repair.ts +621 -0
  608. package/src/server/responses-terminal-repair.ts +342 -0
  609. package/src/server/responses-tool-search-repair.ts +267 -0
  610. package/src/server/responses-undeclared-tool-guard.ts +153 -0
  611. package/src/server/responses.ts +18 -2
  612. package/src/server/search.ts +78 -13
  613. package/src/server/sse-frame-buffer.ts +292 -0
  614. package/src/server/sse-payload-rewrite.ts +110 -22
  615. package/src/server/startup-action-control.ts +8 -1
  616. package/src/server/startup-health-cache.ts +19 -1
  617. package/src/server/system-env.ts +80 -9
  618. package/src/server/ws-bridge.ts +39 -38
  619. package/src/service-manager-probe.ts +892 -0
  620. package/src/service.ts +1111 -90
  621. package/src/sidecar/auth.ts +92 -0
  622. package/src/sidecar/candidates.ts +83 -0
  623. package/src/storage/cleanup.ts +2 -2
  624. package/src/storage/scanner.ts +1 -1
  625. package/src/storage/worker-lifecycle.ts +14 -14
  626. package/src/tray/windows-tray.ps1 +83 -9
  627. package/src/tray/windows.ts +43 -16
  628. package/src/types/accounts.ts +37 -0
  629. package/src/types/config.ts +845 -0
  630. package/src/types/provider.ts +545 -0
  631. package/src/types/request.ts +384 -0
  632. package/src/types/tools.ts +131 -0
  633. package/src/types/wire.ts +80 -0
  634. package/src/types.ts +104 -1236
  635. package/src/update/index.ts +32 -19
  636. package/src/update/job.ts +442 -67
  637. package/src/update/notify.ts +12 -6
  638. package/src/update/npm-cache-preflight.d.mts +47 -0
  639. package/src/update/npm-cache-preflight.mjs +201 -0
  640. package/src/update/transactional-install.d.mts +22 -0
  641. package/src/update/transactional-install.mjs +259 -0
  642. package/src/usage/cost.ts +0 -0
  643. package/src/usage/expected-prices.ts +268 -16
  644. package/src/usage/log.ts +606 -41
  645. package/src/usage/summary.ts +177 -9
  646. package/src/usage/user-cost-overlay-reconciler.ts +313 -0
  647. package/src/usage/user-cost-overlays.ts +314 -0
  648. package/src/vision/anthropic-describe.ts +10 -6
  649. package/src/vision/backends.ts +97 -0
  650. package/src/vision/describe.ts +9 -3
  651. package/src/vision/eligibility.ts +250 -0
  652. package/src/vision/index.ts +238 -24
  653. package/src/vision/reasoning.ts +55 -0
  654. package/src/vision/routed-describe.ts +175 -0
  655. package/src/vision/timeout-bounds.ts +9 -0
  656. package/src/web-search/anthropic-executor.ts +13 -7
  657. package/src/web-search/backends.ts +108 -0
  658. package/src/web-search/exa-executor.ts +88 -0
  659. package/src/web-search/executor.ts +11 -3
  660. package/src/web-search/gemini-executor.ts +141 -0
  661. package/src/web-search/index.ts +150 -15
  662. package/src/web-search/loop.ts +279 -50
  663. package/src/web-search/parse.ts +125 -30
  664. package/src/web-search/sources.ts +60 -0
  665. package/src/web-search/xai-executor.ts +219 -0
  666. package/gui/dist/assets/index-DTpMHS4F.js +0 -67
  667. package/gui/dist/assets/index-ZNVDE3C7.css +0 -1
  668. package/gui/dist/provider-icons/antigravity.svg +0 -1
  669. package/gui/dist/provider-icons/claude.svg +0 -1
  670. package/gui/dist/provider-icons/copilot.svg +0 -1
  671. package/gui/dist/provider-icons/cursor.svg +0 -2
  672. package/gui/dist/provider-icons/gemini.svg +0 -1
  673. package/gui/dist/provider-icons/grok-color.svg +0 -1
  674. package/gui/dist/provider-icons/kiro.svg +0 -14
  675. package/src/cli/internal-dispatch.ts +0 -20
@@ -29,8 +29,48 @@ function readInputModalities(raw: unknown): { values?: string[]; error?: string
29
29
  }
30
30
  return { values: raw as string[] };
31
31
  }
32
+
33
+ /**
34
+ * Custom-row reasoning ladder. Labels are validated against the Codex ladder (low..ultra)
35
+ * exactly like provider `modelReasoningEfforts` values; unknown labels would otherwise
36
+ * surface in a catalog the upstream never accepts. An empty array is meaningful (explicit
37
+ * "no reasoning" hides the effort control) and must be preserved, not cleared.
38
+ */
39
+ function readReasoningEfforts(raw: unknown): { values?: string[]; error?: string } {
40
+ if (raw === undefined) return {};
41
+ if (!Array.isArray(raw)) return { error: "reasoningEfforts must be an array" };
42
+ const rejected: string[] = [];
43
+ const values: string[] = [];
44
+ for (const value of raw) {
45
+ if (typeof value !== "string") return { error: "reasoningEfforts must contain only strings" };
46
+ if (!isDeclaredReasoningEffort(value)) { rejected.push(value); continue; }
47
+ if (!values.includes(value)) values.push(value);
48
+ }
49
+ if (rejected.length > 0) {
50
+ return { error: `unsupported reasoning effort: ${rejected.join(", ")} (allowed: none, minimal, low, medium, high, xhigh, max, ultra)` };
51
+ }
52
+ // Canonical order: the catalog writes supported_reasoning_levels in input order and the
53
+ // fallback default picks the first entry, so a caller-chosen order must not leak through.
54
+ return { values: canonicalizeReasoningEfforts(values) };
55
+ }
56
+
57
+ /** Default effort must be a ladder member that the declared ladder actually includes. */
58
+ function readDefaultReasoningEffort(raw: unknown, efforts: string[] | undefined): { value?: string; error?: string } {
59
+ if (raw === undefined) return {};
60
+ if (raw === null) return { value: undefined };
61
+ if (typeof raw !== "string" || !isDeclaredReasoningEffort(raw)) {
62
+ return { error: "defaultReasoningEffort must be one of: none, minimal, low, medium, high, xhigh, max, ultra" };
63
+ }
64
+ if (efforts === undefined || efforts.length === 0) {
65
+ return { error: "defaultReasoningEffort requires a non-empty reasoningEfforts ladder" };
66
+ }
67
+ if (!efforts.includes(raw)) {
68
+ return { error: `defaultReasoningEffort "${raw}" is not in the declared reasoningEfforts ladder` };
69
+ }
70
+ return { value: raw };
71
+ }
32
72
  import type { CatalogModel } from "../../codex/catalog";
33
- import { catalogModelSlug, disabledNativeSlugs, invalidateCodexModelsCache, nativeModelRows, uniqueCatalogModelsForPublicList } from "../../codex/catalog";
73
+ import { accountBoundNativeOpenAiSlugsBySelector, catalogModelSlug, configuredNativeAliasSlugs, disabledNativeSlugs, invalidateCodexModelsCache, nativeModelRows, shouldIncludeAccountBoundNativeOpenAi, uniqueCatalogModelsForPublicList } from "../../codex/catalog";
34
74
  import { CatalogGatherBusyError } from "../../codex/catalog/provider-fetch";
35
75
  import { getProviderLiveModelCount } from "../../codex/model-cache";
36
76
  import {
@@ -57,8 +97,9 @@ import { providerDestinationResolvedError } from "../../lib/destination-policy";
57
97
  import { enrichProviderFromCatalog, listKeyLoginProviders } from "../../oauth/key-providers";
58
98
  import { deriveProviderPresets } from "../../providers/derive";
59
99
  import { providerCodexAccountMode } from "../../providers/registry";
60
- import { routedSlug, slugEquals } from "../../providers/slug-codec";
61
- import { COMBO_NAMESPACE, comboModelId, comboPublicModelId, preservesPhysicalComboProvider } from "../../combos";
100
+ import { encodedModelIdCollides, routedSlug, slugEquals } from "../../providers/slug-codec";
101
+ import { knownModelIdsForProvider } from "../../router";
102
+ import { COMBO_NAMESPACE, comboDisabledModelSelectors, comboModelId, preservesPhysicalComboProvider } from "../../combos";
62
103
  import { clearProviderQuotaCache, fetchProviderQuotaReports } from "../../providers/quota";
63
104
  import { isCanonicalOpenAiForwardProvider } from "../../providers/openai-tiers";
64
105
  import { clearThreadAccountMap } from "../../codex/routing";
@@ -71,6 +112,7 @@ import { parseRange, parseUsageSurface, summarizeUsage } from "../../usage/summa
71
112
  import { stripCodexRuntimeProviderFields } from "../../codex/auth-context";
72
113
  import { getProviderRegistryEntry } from "../../providers/registry";
73
114
  import { getDebugLogEntries } from "../../lib/debug-log-buffer";
115
+ import { canonicalizeReasoningEfforts, isDeclaredReasoningEffort } from "../../reasoning-effort";
74
116
  import { getInjectionDebugLogEntries } from "../../lib/injection-debug-log";
75
117
  import {
76
118
  clearDebugSettings,
@@ -87,10 +129,11 @@ import type { PersistedUsageAttempt } from "../../usage/log";
87
129
  import { isAllowedRequestOrigin, jsonResponse, providerManagementConfigError, publicProviderBaseUrl, safeConfigDTO, corsHeaders } from "../auth-cors";
88
130
  import { applySystemEnvToggle } from "../system-env";
89
131
  import {
132
+ ClientPathError,
90
133
  EXPORT_CLIENTS,
91
134
  EXPORT_CLIENT_IDS,
92
135
  OPENCODE_PROVIDER_ID,
93
- buildClientConfig,
136
+ buildClientConfigText,
94
137
  isExportClientId,
95
138
  opencodeProxyBaseUrl,
96
139
  } from "../../clients/config-export";
@@ -104,93 +147,9 @@ import type {
104
147
  import { isPlainRecord, parseDebugLogQuery, tokPerSecondResult, unavailableCostReason, costResult, requestLogDto, stripRegistryOnlyStaticHeaders, fetchAllModels } from "./shared";
105
148
  import type { MetricUnavailableReason, TokPerSecondResult, CostEstimateReason, CostResult, MetricSource } from "./shared";
106
149
  import type { ManagementContext } from "./context";
150
+ import { listManagementModelRows, loadExportModels } from "./model-rows";
107
151
  import { readManagementJsonBody, rethrowManagementBodyTooLarge } from "./body";
108
152
 
109
- /**
110
- * One row of the `/api/models` list. Routed rows spread a `CatalogModel`, so the shape is
111
- * that model plus the identity/visibility fields this boundary computes for every row
112
- * regardless of source. `disabled` is always present; the rest vary by row origin.
113
- */
114
- type ManagementModelRow = Partial<CatalogModel> & {
115
- provider: string;
116
- id: string;
117
- namespaced: string;
118
- disabled: boolean;
119
- native?: boolean;
120
- custom?: boolean;
121
- customId?: string;
122
- };
123
-
124
- /**
125
- * The exact row list `/api/models` returns. Extracted so `/api/client-config` exports the
126
- * models the GUI's Models tab shows — including this function's `disabled` computation,
127
- * which the export core (src/clients/config-export.ts) deliberately does not perform.
128
- */
129
- async function listManagementModelRows(config: OcxConfig): Promise<ManagementModelRow[]> {
130
- const models = await fetchAllModels(config);
131
- const disabled = new Set(config.disabledModels ?? []);
132
- // Native GPT passthrough rows lead (provider "openai", bare-slug namespaced ids): sourced
133
- // from the static supported set so a disabled model stays listed and re-enableable.
134
- const native: ManagementModelRow[] = nativeModelRows(config).map(row => ({
135
- provider: "openai",
136
- id: row.slug,
137
- namespaced: row.slug,
138
- disabled: row.disabled,
139
- native: true,
140
- ...(row.contextWindow !== undefined ? { contextWindow: row.contextWindow } : {}),
141
- }));
142
- const customModels: ManagementModelRow[] = (config.customModels ?? []).map(cm => {
143
- const namespaced = routedSlug(cm.provider, cm.modelId);
144
- return {
145
- provider: cm.provider,
146
- id: cm.modelId,
147
- namespaced,
148
- disabled: [...disabled].some(stored => slugEquals(stored, cm.provider, cm.modelId)),
149
- custom: true,
150
- customId: cm.id,
151
- displayName: cm.displayName,
152
- ...(cm.contextWindow ? { contextWindow: cm.contextWindow } : {}),
153
- ...(cm.inputModalities ? { inputModalities: cm.inputModalities } : {}),
154
- };
155
- });
156
- const publicModels = uniqueCatalogModelsForPublicList(models);
157
- const comboNamespaced = new Set(
158
- publicModels.filter(model => model.provider === "combo").map(catalogModelSlug),
159
- );
160
- const visibleCustomModels = customModels.filter(model => !comboNamespaced.has(model.namespaced));
161
- // Custom metadata wins when a physical live/static row resolves to the same Codex-facing
162
- // slug, while a combo keeps the same precedence it has in routing and /v1/models.
163
- const customNamespaced = new Set(visibleCustomModels.map(c => c.namespaced));
164
- const dedupedRouted = publicModels.map((m): ManagementModelRow | null => {
165
- // Codex-facing slug (one "/", slug-codec); disabledModels compares tolerate both forms.
166
- const namespaced = catalogModelSlug(m);
167
- if (m.provider !== "combo" && customNamespaced.has(namespaced)) return null;
168
- const contextCap = providerContextCap(config, m.provider);
169
- return {
170
- ...m,
171
- namespaced,
172
- disabled: [...disabled].some(stored => (
173
- stored === namespaced || slugEquals(stored, m.provider, m.id)
174
- )),
175
- ...(contextCap !== undefined ? { contextCap, contextCapped: m.contextCapped === true } : {}),
176
- };
177
- }).filter((row): row is ManagementModelRow => row !== null);
178
- return [...native, ...dedupedRouted, ...visibleCustomModels];
179
- }
180
-
181
- /** `/api/models` row → the narrower input the client-config serializers accept. */
182
- function toExportModel(row: ManagementModelRow): ExportModel {
183
- return {
184
- namespaced: row.namespaced,
185
- provider: row.provider,
186
- id: row.id,
187
- ...(row.native ? { native: true } : {}),
188
- ...(row.displayName ? { displayName: row.displayName } : {}),
189
- ...(row.contextWindow !== undefined ? { contextWindow: row.contextWindow } : {}),
190
- ...(row.inputModalities ? { inputModalities: row.inputModalities } : {}),
191
- };
192
- }
193
-
194
153
  /**
195
154
  * Counts read back off the SERIALIZED document rather than recomputed from the input rows.
196
155
  * `modelsWithoutLimits` drives a GUI line claiming "these models ship without limits", so it
@@ -198,17 +157,14 @@ function toExportModel(row: ManagementModelRow): ExportModel {
198
157
  * core's "authoritative context window" rule would be free to drift from it silently.
199
158
  */
200
159
  function summarizeExportedModels(client: ExportClientId, document: unknown): { modelCount: number; modelsWithoutLimits: number } {
201
- if (client === "opencode") {
202
- const models = (document as OpencodeGeneratedConfig).provider[OPENCODE_PROVIDER_ID].models;
203
- const entries = Object.values(models);
204
- return { modelCount: entries.length, modelsWithoutLimits: entries.filter(entry => entry.limit === undefined).length };
205
- }
206
- const models = (document as PiGeneratedConfig).providers[OPENCODE_PROVIDER_ID].models;
207
- return { modelCount: models.length, modelsWithoutLimits: models.filter(entry => entry.contextWindow === undefined).length };
160
+ // Each client counts its own document shape. The previous branch assumed
161
+ // "anything that is not OpenCode must be Pi", which silently misread the
162
+ // moment a third client existed.
163
+ return EXPORT_CLIENTS[client].summarize(document);
208
164
  }
209
165
 
210
166
  export async function handleModelRoutes(ctx: ManagementContext): Promise<Response | null> {
211
- const { req, url, config, deps, refreshCodexCatalogBestEffort, syncClaudeAgentDefsBestEffort } = ctx;
167
+ const { req, url, config, deps, convergeCodexCatalog, syncClaudeAgentDefsBestEffort } = ctx;
212
168
  // A handler persists the exact config object passed in. Production defaults to
213
169
  // the real store; tests that pass an in-memory fixture inject a no-op/spy. Do not
214
170
  // bypass this seam with a dynamic config import — doing so replaced a user's
@@ -249,9 +205,33 @@ export async function handleModelRoutes(ctx: ManagementContext): Promise<Respons
249
205
  );
250
206
  }
251
207
  const spec = EXPORT_CLIENTS[requested];
252
- let rows: ManagementModelRow[];
208
+ // Resolved before the catalog load on purpose. A refused override is a
209
+ // property of the request, not of the catalog: validating it afterwards
210
+ // let a busy or failing catalog answer 503 first, so a user with a
211
+ // relative override never saw the message that says how to fix it — and
212
+ // the route did the enumeration work anyway for input it was going to
213
+ // reject.
214
+ let destination: string;
253
215
  try {
254
- rows = await listManagementModelRows(config);
216
+ destination = spec.destination(process.env);
217
+ } catch (error) {
218
+ // A client's own environment override can name a path the resolver
219
+ // refuses — a relative value, which this process and the client would
220
+ // resolve against different working directories. That is a
221
+ // user-correctable configuration error, not a server fault, so it leaves
222
+ // this boundary as a bounded 400 instead of escaping handleManagementAPI
223
+ // as a generic 500 and stripping the message that says how to fix it.
224
+ // `integrations/state.ts` and `integrations/writer.ts` already catch the
225
+ // same error on their paths; this route was the one that did not.
226
+ if (!(error instanceof ClientPathError)) throw error;
227
+ return jsonResponse({ error: error.message }, 400, req, config);
228
+ }
229
+ let models: ExportModel[];
230
+ try {
231
+ // The ONE loader every export surface uses. It carries the visibility
232
+ // filter with it, so this route and the integration routes cannot end up
233
+ // telling a client about different models.
234
+ models = await loadExportModels(config);
255
235
  } catch (error) {
256
236
  // A partial or empty `models` block reads as a valid config while offering nothing,
257
237
  // so a catalog failure is surfaced as unavailable rather than serialized. The
@@ -264,21 +244,24 @@ export async function handleModelRoutes(ctx: ManagementContext): Promise<Respons
264
244
  config,
265
245
  );
266
246
  }
267
- // The export core does not filter visibility — it serializes what it is given. A model the
268
- // user disabled in the Models tab is absent from /v1/models, so exporting it would hand the
269
- // client a selector the proxy refuses to route.
270
- const models = rows.filter(row => !row.disabled).map(toExportModel);
271
- const document = buildClientConfig(requested, {
247
+ const built = buildClientConfigText(requested, {
272
248
  baseUrl: opencodeProxyBaseUrl(Number(url.port) || config.port, config.hostname),
273
249
  models,
274
250
  config,
275
251
  });
252
+ const document = built.document;
276
253
  return jsonResponse({
277
254
  client: spec.id,
278
255
  filename: spec.filename,
279
- destination: spec.destination(process.env),
256
+ destination,
280
257
  apiKeyEnv: spec.apiKeyEnv,
281
258
  exportHint: spec.exportHint,
259
+ // The client's own format and the exact bytes for it. The GUI previously
260
+ // re-serialized `config` as JSON, which is wrong for four of the six
261
+ // clients; `mediaType` also drives the download blob.
262
+ format: built.format,
263
+ mediaType: built.mediaType,
264
+ text: built.text,
282
265
  ...summarizeExportedModels(requested, document),
283
266
  config: document,
284
267
  }, 200, req, config);
@@ -292,8 +275,8 @@ export async function handleModelRoutes(ctx: ManagementContext): Promise<Respons
292
275
  const disabled = Array.isArray(body.models) ? body.models.filter((m): m is string => typeof m === "string") : [];
293
276
  config.disabledModels = disabled;
294
277
  persistConfig(config);
295
- await refreshCodexCatalogBestEffort();
296
- return jsonResponse({ ok: true, disabled });
278
+ const catalogRefresh = await convergeCodexCatalog();
279
+ return jsonResponse({ ok: true, disabled, catalogRefresh });
297
280
  }
298
281
 
299
282
  // One user-facing visibility switch spans two persisted filters: a provider allowlist and the
@@ -315,7 +298,14 @@ export async function handleModelRoutes(ctx: ManagementContext): Promise<Respons
315
298
  if (!providerConfig && provider !== "openai" && !isVirtualComboNamespace) {
316
299
  return jsonResponse({ error: "unknown model visibility provider" }, 400);
317
300
  }
318
- const supportedNative = new Set(nativeModelRows(config).map(row => row.slug));
301
+ const accountNativeQualified = shouldIncludeAccountBoundNativeOpenAi(config)
302
+ ? [...accountBoundNativeOpenAiSlugsBySelector(config).entries()].flatMap(([selector, slugs]) =>
303
+ slugs.filter(slug => !nativeModelRows(config).some(row => row.slug === slug)).map(slug => `${selector}/${slug}`))
304
+ : [];
305
+ const supportedNative = new Set([
306
+ ...nativeModelRows(config).map(row => row.slug),
307
+ ...accountNativeQualified,
308
+ ]);
319
309
  const targets: Array<{ id: string; native: boolean }> = [];
320
310
  const seen = new Set<string>();
321
311
  for (const value of body.targets) {
@@ -336,17 +326,16 @@ export async function handleModelRoutes(ctx: ManagementContext): Promise<Respons
336
326
  if (targets.length === 0) return jsonResponse({ error: "model visibility targets required" }, 400);
337
327
 
338
328
  const knownComboSelectors = new Set(
339
- Object.entries(config.combos ?? {}).flatMap(([id, combo]) => [
340
- comboModelId(id),
341
- comboPublicModelId(id, combo),
342
- ]),
329
+ Object.entries(config.combos ?? {}).flatMap(([id, combo]) => (
330
+ comboDisabledModelSelectors(id, combo)
331
+ )),
343
332
  );
344
333
  const targetComboSelectors = new Map<string, Set<string>>();
345
334
  if (isVirtualComboNamespace) {
346
335
  for (const target of targets) {
347
336
  const combo = config.combos && Object.hasOwn(config.combos, target.id) ? config.combos[target.id] : undefined;
348
337
  if (!combo) return jsonResponse({ error: "invalid model visibility target" }, 400);
349
- targetComboSelectors.set(target.id, new Set([comboModelId(target.id), comboPublicModelId(target.id, combo)]));
338
+ targetComboSelectors.set(target.id, new Set(comboDisabledModelSelectors(target.id, combo)));
350
339
  }
351
340
  }
352
341
  const matchesTarget = (stored: string, target: { id: string; native: boolean }) => target.native
@@ -365,9 +354,14 @@ export async function handleModelRoutes(ctx: ManagementContext): Promise<Respons
365
354
  const nativeIds = provider === "openai"
366
355
  ? disabledNativeSlugs({ disabledModels: disabled })
367
356
  : new Set<string>();
357
+ const accountNativeIds = provider === "openai" ? new Set(accountNativeQualified) : new Set<string>();
358
+ const nativeAliasSlugs = provider === "openai"
359
+ ? configuredNativeAliasSlugs(config)
360
+ : new Set<string>();
368
361
  disabled = disabled.filter(stored => (
369
362
  knownComboSelectors.has(stored)
370
- || (!stored.startsWith(`${provider}/`) && !nativeIds.has(stored))
363
+ || nativeAliasSlugs.has(stored)
364
+ || (!stored.startsWith(`${provider}/`) && !nativeIds.has(stored) && !accountNativeIds.has(stored))
371
365
  ));
372
366
  }
373
367
  } else {
@@ -391,8 +385,8 @@ export async function handleModelRoutes(ctx: ManagementContext): Promise<Respons
391
385
 
392
386
  config.disabledModels = disabled;
393
387
  persistConfig(config);
394
- await refreshCodexCatalogBestEffort();
395
- return jsonResponse({ ok: true, scope, provider, enabled: body.enabled, disabled });
388
+ const catalogRefresh = await convergeCodexCatalog();
389
+ return jsonResponse({ ok: true, scope, provider, enabled: body.enabled, disabled, catalogRefresh });
396
390
  }
397
391
 
398
392
  if (url.pathname === "/api/custom-models" && req.method === "GET") {
@@ -400,12 +394,11 @@ export async function handleModelRoutes(ctx: ManagementContext): Promise<Respons
400
394
  }
401
395
 
402
396
  if (url.pathname === "/api/custom-models" && req.method === "POST") {
403
- let body: { provider?: unknown; modelId?: unknown; displayName?: unknown; contextWindow?: unknown; inputModalities?: unknown };
397
+ let body: { provider?: unknown; modelId?: unknown; displayName?: unknown; contextWindow?: unknown; inputModalities?: unknown; reasoningEfforts?: unknown; defaultReasoningEffort?: unknown };
404
398
  try { body = await readManagementJsonBody(req); } catch (error) { rethrowManagementBodyTooLarge(error); return jsonResponse({ error: "invalid JSON body" }, 400); }
405
399
  const provider = typeof body.provider === "string" ? body.provider.trim() : "";
406
400
  const modelId = typeof body.modelId === "string" ? body.modelId.trim() : "";
407
401
  if (!provider || !modelId) return jsonResponse({ error: "provider and modelId are required" }, 400);
408
- if (modelId.includes("/")) return jsonResponse({ error: "modelId must not contain /" }, 400);
409
402
  if (!isValidProviderName(provider)) return jsonResponse({ error: "invalid provider name" }, 400);
410
403
  if (!hasOwnProvider(config.providers, provider)) return jsonResponse({ error: "provider not configured" }, 404);
411
404
  const displayName = typeof body.displayName === "string" && body.displayName.trim() ? body.displayName.trim() : undefined;
@@ -414,11 +407,19 @@ export async function handleModelRoutes(ctx: ManagementContext): Promise<Respons
414
407
  const modalities = readInputModalities(body.inputModalities);
415
408
  if (modalities.error) return jsonResponse({ error: modalities.error }, 400);
416
409
  const inputModalities = modalities.values;
410
+ const reasoning = readReasoningEfforts(body.reasoningEfforts);
411
+ if (reasoning.error) return jsonResponse({ error: reasoning.error }, 400);
412
+ const defaultEffort = readDefaultReasoningEffort(body.defaultReasoningEffort, reasoning.values);
413
+ if (defaultEffort.error) return jsonResponse({ error: defaultEffort.error }, 400);
417
414
  const existing = config.customModels ?? [];
418
415
  const newSlug = routedSlug(provider, modelId);
419
416
  if (existing.some(cm => routedSlug(cm.provider, cm.modelId) === newSlug)) {
420
417
  return jsonResponse({ error: "duplicate model" }, 409);
421
418
  }
419
+ const known = knownModelIdsForProvider(provider, config.providers[provider], config);
420
+ if (encodedModelIdCollides(modelId, known)) {
421
+ return jsonResponse({ error: "ambiguous model id" }, 409);
422
+ }
422
423
  const entry: OcxCustomModel = {
423
424
  id: randomUUID(),
424
425
  provider,
@@ -426,26 +427,27 @@ export async function handleModelRoutes(ctx: ManagementContext): Promise<Respons
426
427
  ...(displayName ? { displayName } : {}),
427
428
  ...(contextWindow ? { contextWindow } : {}),
428
429
  ...(inputModalities && inputModalities.length > 0 ? { inputModalities } : {}),
430
+ ...(reasoning.values !== undefined ? { reasoningEfforts: reasoning.values } : {}),
431
+ ...(defaultEffort.value ? { defaultReasoningEffort: defaultEffort.value } : {}),
429
432
  addedAt: new Date().toISOString(),
430
433
  };
431
434
  config.customModels = [...existing, entry];
432
435
  persistConfig(config);
433
- await refreshCodexCatalogBestEffort();
434
- return jsonResponse(entry, 201);
436
+ const catalogRefresh = await convergeCodexCatalog();
437
+ return jsonResponse({ ...entry, catalogRefresh }, 201);
435
438
  }
436
439
 
437
440
  const customPutMatch = url.pathname.match(/^\/api\/custom-models\/([^/]+)$/);
438
441
  if (customPutMatch && req.method === "PUT") {
439
442
  let id: string;
440
443
  try { id = decodeURIComponent(customPutMatch[1]); } catch { return jsonResponse({ error: "invalid id encoding" }, 400); }
441
- let body: { displayName?: unknown; contextWindow?: unknown; inputModalities?: unknown; modelId?: unknown };
444
+ let body: { displayName?: unknown; contextWindow?: unknown; inputModalities?: unknown; modelId?: unknown; reasoningEfforts?: unknown; defaultReasoningEffort?: unknown };
442
445
  try { body = await readManagementJsonBody(req); } catch (error) { rethrowManagementBodyTooLarge(error); return jsonResponse({ error: "invalid JSON body" }, 400); }
443
446
  const list = config.customModels ?? [];
444
447
  const idx = list.findIndex(cm => cm.id === id);
445
448
  if (idx === -1) return jsonResponse({ error: "not found" }, 404);
446
449
  const cm = { ...list[idx] };
447
450
  if (typeof body.modelId === "string" && body.modelId.trim()) {
448
- if (body.modelId.includes("/")) return jsonResponse({ error: "modelId must not contain /" }, 400);
449
451
  cm.modelId = body.modelId.trim();
450
452
  }
451
453
  if (body.displayName !== undefined) {
@@ -461,15 +463,48 @@ export async function handleModelRoutes(ctx: ManagementContext): Promise<Respons
461
463
  if (edited.error) return jsonResponse({ error: edited.error }, 400);
462
464
  cm.inputModalities = edited.values && edited.values.length > 0 ? edited.values : undefined;
463
465
  }
466
+ // `null` clears the stored ladder back to "inherit from the provider row"; `[]` stays
467
+ // stored as an explicit "no reasoning" override. The default effort rides along and is
468
+ // validated against the ladder the row ends up with.
469
+ if (body.reasoningEfforts !== undefined) {
470
+ if (body.reasoningEfforts === null) {
471
+ cm.reasoningEfforts = undefined;
472
+ } else {
473
+ const edited = readReasoningEfforts(body.reasoningEfforts);
474
+ if (edited.error) return jsonResponse({ error: edited.error }, 400);
475
+ cm.reasoningEfforts = edited.values;
476
+ }
477
+ }
478
+ if (body.defaultReasoningEffort !== undefined) {
479
+ const edited = readDefaultReasoningEffort(body.defaultReasoningEffort, cm.reasoningEfforts);
480
+ if (edited.error) return jsonResponse({ error: edited.error }, 400);
481
+ cm.defaultReasoningEffort = edited.value;
482
+ }
483
+ // Mirror of the POST invariant: a default only survives as a member of the final ladder.
484
+ // Without this, a ladder shrink/clear on a row that was created with a default leaves a
485
+ // stale default that re-applies itself onto the inherited ladder in the generated catalog
486
+ // (the GUI toggle-off path sends only reasoningEfforts, never the default).
487
+ if (cm.defaultReasoningEffort !== undefined) {
488
+ const ladder = cm.reasoningEfforts;
489
+ if (!ladder || ladder.length === 0 || !ladder.includes(cm.defaultReasoningEffort)) {
490
+ cm.defaultReasoningEffort = undefined;
491
+ }
492
+ }
464
493
  const updatedSlug = routedSlug(cm.provider, cm.modelId);
465
494
  if (list.some((other, i) => i !== idx && routedSlug(other.provider, other.modelId) === updatedSlug)) {
466
495
  return jsonResponse({ error: "duplicate model" }, 409);
467
496
  }
497
+ const known = knownModelIdsForProvider(cm.provider, config.providers[cm.provider], {
498
+ customModels: list.filter((_, i) => i !== idx),
499
+ });
500
+ if (encodedModelIdCollides(cm.modelId, known)) {
501
+ return jsonResponse({ error: "ambiguous model id" }, 409);
502
+ }
468
503
  list[idx] = cm;
469
504
  config.customModels = list;
470
505
  persistConfig(config);
471
- await refreshCodexCatalogBestEffort();
472
- return jsonResponse(cm);
506
+ const catalogRefresh = await convergeCodexCatalog();
507
+ return jsonResponse({ ...cm, catalogRefresh });
473
508
  }
474
509
 
475
510
  const customDelMatch = url.pathname.match(/^\/api\/custom-models\/([^/]+)$/);
@@ -482,15 +517,24 @@ export async function handleModelRoutes(ctx: ManagementContext): Promise<Respons
482
517
  list.splice(idx, 1);
483
518
  config.customModels = list.length > 0 ? list : undefined;
484
519
  persistConfig(config);
485
- await refreshCodexCatalogBestEffort();
486
- return jsonResponse({ ok: true });
520
+ const catalogRefresh = await convergeCodexCatalog();
521
+ return jsonResponse({ ok: true, catalogRefresh });
487
522
  }
488
523
 
489
524
  // Per-provider catalog allowlist (issue #52): when a provider has a non-empty selectedModels list,
490
525
  // only those ids ship to Codex's catalog / /v1/models. GET returns the CURRENT selection plus the
491
- // FULL available set per provider (unfiltered the picker needs everything to choose from).
526
+ // FULL available set per provider for the management picker.
527
+ //
528
+ // `fetchAllModels` hides media-generation ids (image/video) from the Codex-facing catalog, but the
529
+ // Providers → Models tab must still list every id the user fetched and saved on the provider
530
+ // (e.g. grok2api's grok-imagine-*). Merge `providers[name].models` on top so those rows are not
531
+ // silently dropped after a successful refresh-models persist.
532
+ //
533
+ // Cold path: prefer cache/configured seeds so the Providers page paints in milliseconds instead
534
+ // of waiting on every upstream `/models` (often multi-second). When any live provider still needs
535
+ // a network probe, kick a background gather and set `refreshing: true` so the GUI can re-poll.
492
536
  if (url.pathname === "/api/selected-models" && req.method === "GET") {
493
- const models = await fetchAllModels(config);
537
+ const models = await fetchAllModels(config, { preferCached: true });
494
538
  const available: Record<string, string[]> = {};
495
539
  for (const m of models) (available[m.provider] ??= []).push(m.id);
496
540
  const selected: Record<string, string[]> = {};
@@ -501,8 +545,22 @@ export async function handleModelRoutes(ctx: ManagementContext): Promise<Respons
501
545
  if (Array.isArray(prov.selectedModels) && prov.selectedModels.length > 0) selected[name] = [...prov.selectedModels];
502
546
  const liveCount = getProviderLiveModelCount(name);
503
547
  if (liveCount !== undefined) liveModelCounts[name] = liveCount;
548
+ const configured = prov.models;
549
+ if (!Array.isArray(configured) || configured.length === 0) continue;
550
+ const bucket = available[name] ?? (available[name] = []);
551
+ const seen = new Set(bucket);
552
+ for (const id of configured) {
553
+ if (typeof id !== "string" || !id || seen.has(id)) continue;
554
+ seen.add(id);
555
+ bucket.push(id);
556
+ }
504
557
  }
505
- return jsonResponse({ selected, available, liveModelCounts });
558
+ // Re-check after the local gather: preferCached may have kicked a background flight whose
559
+ // first probe already filled some caches, but `refreshing` still means "more work in flight
560
+ // or still needed" for the GUI re-poll loop.
561
+ const { catalogGatherNeedsLiveRefresh } = await import("../../codex/catalog");
562
+ const refreshing = catalogGatherNeedsLiveRefresh(config);
563
+ return jsonResponse({ selected, available, liveModelCounts, refreshing });
506
564
  }
507
565
  if (url.pathname === "/api/selected-models" && req.method === "PUT") {
508
566
  let body: { provider?: unknown; models?: unknown };
@@ -518,8 +576,8 @@ export async function handleModelRoutes(ctx: ManagementContext): Promise<Respons
518
576
  if (models.length > 0) config.providers[provider].selectedModels = models;
519
577
  else delete config.providers[provider].selectedModels;
520
578
  persistConfig(config);
521
- await refreshCodexCatalogBestEffort();
522
- return jsonResponse({ ok: true, provider, selected: models });
579
+ const catalogRefresh = await convergeCodexCatalog();
580
+ return jsonResponse({ ok: true, provider, selected: models, catalogRefresh });
523
581
  }
524
582
  return null;
525
583
  }