@iislee/opencodex 2.11.0 → 2.35.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 (733) hide show
  1. package/AGENTS_INSTALL.md +109 -0
  2. package/README.md +117 -22
  3. package/bin/ocx.mjs +245 -88
  4. package/bin/package-main.mjs +1 -1
  5. package/gui/dist/assets/index-Be1sDpWw.css +1 -0
  6. package/gui/dist/assets/index-D4OKgUV4.js +114 -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 +21 -10
  42. package/src/adapters/anthropic-output-schema.ts +137 -0
  43. package/src/adapters/anthropic.ts +475 -62
  44. package/src/adapters/base.ts +82 -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 +637 -0
  48. package/src/adapters/cursor/call-id.ts +44 -0
  49. package/src/adapters/cursor/catalog.ts +541 -0
  50. package/src/adapters/cursor/checkpoint-store.ts +308 -0
  51. package/src/adapters/cursor/cursor-errors.ts +144 -6
  52. package/src/adapters/cursor/discovery.ts +122 -14
  53. package/src/adapters/cursor/effort-map.ts +106 -4
  54. package/src/adapters/cursor/envelope-echo.ts +290 -0
  55. package/src/adapters/cursor/framing.ts +39 -0
  56. package/src/adapters/cursor/h2-pool.ts +123 -0
  57. package/src/adapters/cursor/http1-bidi.ts +361 -0
  58. package/src/adapters/cursor/images.ts +704 -0
  59. package/src/adapters/cursor/live-models.ts +180 -59
  60. package/src/adapters/cursor/live-transport.ts +623 -170
  61. package/src/adapters/cursor/message-mapper.ts +4 -1
  62. package/src/adapters/cursor/native-exec-common.ts +23 -2
  63. package/src/adapters/cursor/native-exec-desktop.ts +23 -0
  64. package/src/adapters/cursor/native-exec-fs.ts +10 -7
  65. package/src/adapters/cursor/native-exec-network.ts +1 -1
  66. package/src/adapters/cursor/native-exec-shell.ts +5 -3
  67. package/src/adapters/cursor/native-exec.ts +121 -14
  68. package/src/adapters/cursor/protobuf-events.ts +829 -11
  69. package/src/adapters/cursor/protobuf-request.ts +447 -75
  70. package/src/adapters/cursor/request-builder.ts +271 -35
  71. package/src/adapters/cursor/tool-definitions.ts +252 -12
  72. package/src/adapters/cursor/tool-result-normalize.ts +115 -0
  73. package/src/adapters/cursor/transport.ts +22 -0
  74. package/src/adapters/cursor/types.ts +48 -1
  75. package/src/adapters/cursor.ts +336 -39
  76. package/src/adapters/exec-tool-result-normalize.ts +99 -0
  77. package/src/adapters/google-antigravity-replay.ts +713 -41
  78. package/src/adapters/google-antigravity-wire.ts +48 -10
  79. package/src/adapters/google-errors.ts +44 -12
  80. package/src/adapters/google-http.ts +38 -10
  81. package/src/adapters/google-tool-schema.ts +80 -15
  82. package/src/adapters/google-truncation.ts +11 -0
  83. package/src/adapters/google.ts +742 -86
  84. package/src/adapters/identity.ts +39 -6
  85. package/src/adapters/image.ts +1 -1
  86. package/src/adapters/kiro-constants.ts +27 -0
  87. package/src/adapters/kiro-errors.ts +11 -0
  88. package/src/adapters/kiro-events.ts +19 -1
  89. package/src/adapters/kiro-thinking.ts +18 -2
  90. package/src/adapters/kiro-tools.ts +65 -17
  91. package/src/adapters/kiro.ts +270 -73
  92. package/src/adapters/mimo-free.ts +17 -0
  93. package/src/adapters/openai-chat-url.ts +11 -0
  94. package/src/adapters/openai-chat.ts +1377 -344
  95. package/src/adapters/openai-responses-url.ts +16 -0
  96. package/src/adapters/openai-responses.ts +1164 -64
  97. package/src/adapters/registry.ts +175 -0
  98. package/src/adapters/responses-tool-schema.ts +67 -0
  99. package/src/adapters/run-turn-queue.ts +36 -1
  100. package/src/adapters/tool-call-id.ts +119 -0
  101. package/src/adapters/tool-catalog-nudge.ts +105 -21
  102. package/src/adapters/xai-tool-schema.ts +436 -0
  103. package/src/adapters/xai-web-search.ts +186 -0
  104. package/src/bridge.ts +512 -92
  105. package/src/chat/inbound.ts +57 -20
  106. package/src/chat/outbound.ts +97 -33
  107. package/src/claude/agents-inject.ts +40 -10
  108. package/src/claude/context-windows.ts +37 -14
  109. package/src/claude/desktop-3p.ts +243 -9
  110. package/src/claude/gateway-cache.ts +41 -4
  111. package/src/claude/inbound.ts +72 -3
  112. package/src/claude/model-info.ts +38 -15
  113. package/src/claude/outbound.ts +88 -21
  114. package/src/cli/access.ts +46 -3
  115. package/src/cli/account-api.ts +150 -19
  116. package/src/cli/account-auth.ts +33 -6
  117. package/src/cli/account-catalog-refresh.ts +14 -0
  118. package/src/cli/account-extended.ts +648 -28
  119. package/src/cli/account-main.ts +317 -0
  120. package/src/cli/account.ts +97 -19
  121. package/src/cli/agent.ts +53 -2
  122. package/src/cli/alias.ts +66 -0
  123. package/src/cli/capabilities-command.ts +94 -0
  124. package/src/cli/capabilities.ts +496 -0
  125. package/src/cli/claude-agent-startup-sync.ts +73 -0
  126. package/src/cli/claude-desktop.ts +60 -15
  127. package/src/cli/claude.ts +129 -35
  128. package/src/cli/codex-log-guard-doctor.ts +103 -0
  129. package/src/cli/codex-shim-autorestore.ts +2 -0
  130. package/src/cli/codex-shim-readiness.ts +76 -0
  131. package/src/cli/combo.ts +8 -0
  132. package/src/cli/config-command.ts +74 -10
  133. package/src/cli/dispatch.ts +821 -0
  134. package/src/cli/doctor.ts +440 -56
  135. package/src/cli/ensure-desired-integrations.ts +152 -0
  136. package/src/cli/export-command.ts +46 -20
  137. package/src/cli/help.ts +34 -274
  138. package/src/cli/index.ts +417 -528
  139. package/src/cli/init.ts +5 -17
  140. package/src/cli/inspect.ts +230 -0
  141. package/src/cli/integrations.ts +120 -2
  142. package/src/cli/lab.ts +607 -0
  143. package/src/cli/launcher-context.ts +77 -0
  144. package/src/cli/minimax.ts +497 -0
  145. package/src/cli/models-runtime.ts +130 -2
  146. package/src/cli/models.ts +118 -16
  147. package/src/cli/observe.ts +123 -11
  148. package/src/cli/opencode.ts +4 -2
  149. package/src/cli/provider-runtime.ts +34 -3
  150. package/src/cli/provider.ts +25 -3
  151. package/src/cli/ready.ts +301 -0
  152. package/src/cli/registry.ts +476 -0
  153. package/src/cli/root.ts +86 -0
  154. package/src/cli/route-policy.ts +92 -0
  155. package/src/cli/runtime-api.ts +57 -10
  156. package/src/cli/star-prompt.ts +71 -15
  157. package/src/cli/status.ts +51 -4
  158. package/src/cli/storage.ts +234 -0
  159. package/src/cli/system-command.ts +16 -0
  160. package/src/cli/system-restart-client.ts +146 -0
  161. package/src/cli/tray-proxy.ts +153 -6
  162. package/src/cli/usage-report.ts +184 -0
  163. package/src/cli/v2.ts +137 -18
  164. package/src/cli/version-skew.ts +46 -0
  165. package/src/cli.ts +1 -1
  166. package/src/clients/config-export.ts +1442 -23
  167. package/src/clients/effective-status.ts +30 -2
  168. package/src/clients/probes/cline.ts +81 -0
  169. package/src/codex/account-label.ts +35 -1
  170. package/src/codex/account-lifecycle.ts +130 -13
  171. package/src/codex/account-namespaces.ts +49 -3
  172. package/src/codex/account-pause.ts +2 -1
  173. package/src/codex/account-priority.ts +84 -0
  174. package/src/codex/account-store.ts +29 -2
  175. package/src/codex/account-usability.ts +25 -2
  176. package/src/codex/admission.ts +256 -0
  177. package/src/codex/affinity-debug.ts +162 -0
  178. package/src/codex/app-server-processes.ts +570 -107
  179. package/src/codex/app-server-restart-service.ts +232 -0
  180. package/src/codex/auth-api.ts +893 -246
  181. package/src/codex/auth-collision.ts +5 -3
  182. package/src/codex/auth-context.ts +348 -32
  183. package/src/codex/autostart-health.ts +24 -1
  184. package/src/codex/catalog/account-models.ts +67 -0
  185. package/src/codex/catalog/aggregation.ts +86 -10
  186. package/src/codex/catalog/bundled.ts +331 -33
  187. package/src/codex/catalog/effort.ts +138 -32
  188. package/src/codex/catalog/filesystem-evidence.ts +302 -0
  189. package/src/codex/catalog/kinds.ts +2 -0
  190. package/src/codex/catalog/metadata.ts +555 -45
  191. package/src/codex/catalog/native-models.ts +75 -0
  192. package/src/codex/catalog/parsing.ts +269 -30
  193. package/src/codex/catalog/provider-fetch.ts +1626 -144
  194. package/src/codex/catalog/sync.ts +1576 -187
  195. package/src/codex/catalog-admission.ts +199 -0
  196. package/src/codex/catalog-refresh-status.ts +105 -0
  197. package/src/codex/catalog-write-serialization.ts +242 -0
  198. package/src/codex/catalog.ts +6 -3
  199. package/src/codex/codex-write-lock.ts +386 -0
  200. package/src/codex/convergence-types.ts +614 -0
  201. package/src/codex/convergence.ts +676 -0
  202. package/src/codex/coordinator-doctor.ts +332 -0
  203. package/src/codex/custom-model-catalog-migration.ts +176 -0
  204. package/src/codex/desired-state.ts +230 -0
  205. package/src/codex/desktop-app-restart.ts +355 -0
  206. package/src/codex/features.ts +636 -39
  207. package/src/codex/generation.ts +202 -0
  208. package/src/codex/history-job.ts +436 -0
  209. package/src/codex/history-lock.ts +242 -0
  210. package/src/codex/history-manifest.ts +112 -0
  211. package/src/codex/history-migration-guardian.ts +30 -24
  212. package/src/codex/history-provider.ts +1016 -235
  213. package/src/codex/history-transition.ts +105 -0
  214. package/src/codex/history-worker.ts +223 -0
  215. package/src/codex/inject-coordination.ts +373 -0
  216. package/src/codex/inject.ts +1114 -152
  217. package/src/codex/injected-marker.ts +37 -3
  218. package/src/codex/integration-record.ts +266 -0
  219. package/src/codex/internal/catalog-writer.ts +203 -0
  220. package/src/codex/internal/history-writer.ts +81 -0
  221. package/src/codex/journal.ts +66 -4
  222. package/src/codex/log-guard/inspect.ts +524 -0
  223. package/src/codex/log-guard/lock.ts +150 -0
  224. package/src/codex/log-guard/maintenance.ts +403 -0
  225. package/src/codex/log-guard/path-safety.ts +88 -0
  226. package/src/codex/log-guard/policy.ts +44 -0
  227. package/src/codex/log-guard/processes.ts +205 -0
  228. package/src/codex/log-guard/protection.ts +489 -0
  229. package/src/codex/log-guard/sqlite-errors.ts +9 -0
  230. package/src/codex/main-account-cache.ts +24 -0
  231. package/src/codex/main-account.ts +29 -1
  232. package/src/codex/management-convergence.ts +167 -0
  233. package/src/codex/model-cache.ts +56 -10
  234. package/src/codex/model-entitlements.ts +360 -0
  235. package/src/codex/native-main-admission.ts +47 -0
  236. package/src/codex/native-main-auth-temp.ts +187 -0
  237. package/src/codex/native-main-claim.ts +178 -0
  238. package/src/codex/native-main-lock-file.ts +162 -0
  239. package/src/codex/native-main-owner.ts +329 -0
  240. package/src/codex/native-profile-api.ts +247 -0
  241. package/src/codex/native-profile-manager.ts +1531 -0
  242. package/src/codex/native-profile-processes.ts +121 -0
  243. package/src/codex/native-profile-recovery.ts +99 -0
  244. package/src/codex/native-profile-stage-store.ts +387 -0
  245. package/src/codex/native-profile-startup.ts +622 -0
  246. package/src/codex/native-profile-store.ts +855 -0
  247. package/src/codex/native-profile-types.ts +120 -0
  248. package/src/codex/native-residue.ts +675 -0
  249. package/src/codex/paths.ts +80 -1
  250. package/src/codex/plan-from-token.ts +140 -0
  251. package/src/codex/plan.ts +40 -0
  252. package/src/codex/plugins-doctor.ts +1 -1
  253. package/src/codex/pool-rotation.ts +74 -4
  254. package/src/codex/project-config-warnings.ts +20 -6
  255. package/src/codex/prompt-journal.ts +352 -0
  256. package/src/codex/prompt-layers.ts +1313 -0
  257. package/src/codex/prompt-lock.ts +143 -0
  258. package/src/codex/prompt-text-probe.ts +238 -0
  259. package/src/codex/quota-rejection.ts +298 -0
  260. package/src/codex/quota.ts +264 -21
  261. package/src/codex/refresh.ts +11 -2
  262. package/src/codex/reset-credit-recovery.ts +1044 -0
  263. package/src/codex/routing.ts +514 -94
  264. package/src/codex/runtime.ts +159 -38
  265. package/src/codex/shim.ts +1065 -31
  266. package/src/codex/subagent-model-fallback.ts +437 -43
  267. package/src/codex/sync.ts +191 -2
  268. package/src/codex/transition-state.ts +720 -0
  269. package/src/codex/upstream-host-health.ts +368 -0
  270. package/src/codex/user-identity.ts +557 -0
  271. package/src/codex/warmup.ts +187 -81
  272. package/src/codex/write-coordination.ts +114 -0
  273. package/src/combos/failover.ts +47 -0
  274. package/src/combos/index.ts +4 -0
  275. package/src/combos/request.ts +32 -0
  276. package/src/combos/types.ts +91 -9
  277. package/src/compatibility/index.ts +26 -0
  278. package/src/compatibility/manifest.ts +253 -0
  279. package/src/compatibility/openai-responses.ts +121 -0
  280. package/src/config/atomic-write.ts +219 -0
  281. package/src/config/paths.ts +40 -0
  282. package/src/config/process-state.ts +309 -0
  283. package/src/config/provider-name.ts +24 -0
  284. package/src/config/provider-validation.ts +177 -0
  285. package/src/config/rebase-provenance.ts +68 -0
  286. package/src/config.ts +1713 -709
  287. package/src/generated/compatibility-version.json +3324 -0
  288. package/src/generated/{jawcode-model-metadata.ts → model-metadata.ts} +19 -17
  289. package/src/grok/inject.ts +16 -5
  290. package/src/grok/inspect.ts +45 -0
  291. package/src/grok/sync.ts +2 -2
  292. package/src/images/loop.ts +157 -33
  293. package/src/images/plan.ts +24 -13
  294. package/src/integrations/config-io.ts +269 -0
  295. package/src/integrations/journal.ts +315 -0
  296. package/src/integrations/merge.ts +135 -0
  297. package/src/integrations/mutation-flight.ts +71 -0
  298. package/src/integrations/native/ownership-preflight.ts +202 -0
  299. package/src/integrations/omp-yaml-source.ts +358 -0
  300. package/src/integrations/owned-refresh.ts +74 -0
  301. package/src/integrations/ownership-policy.ts +160 -0
  302. package/src/integrations/ownership.ts +155 -0
  303. package/src/integrations/registry.ts +166 -0
  304. package/src/integrations/serialize.ts +314 -0
  305. package/src/integrations/state.ts +433 -0
  306. package/src/integrations/store.ts +103 -0
  307. package/src/integrations/writer-lock.ts +98 -0
  308. package/src/integrations/writer.ts +715 -0
  309. package/src/lab/artifacts/sanitize.ts +586 -0
  310. package/src/lab/artifacts/secure-fs.ts +475 -0
  311. package/src/lab/artifacts/store.ts +310 -0
  312. package/src/lab/automation/budgets.ts +78 -0
  313. package/src/lab/automation/config-persistence.ts +256 -0
  314. package/src/lab/automation/constants.ts +39 -0
  315. package/src/lab/automation/cooldown.ts +103 -0
  316. package/src/lab/automation/dispatch.ts +211 -0
  317. package/src/lab/automation/index.ts +13 -0
  318. package/src/lab/automation/orchestrator.ts +499 -0
  319. package/src/lab/automation/persistence.ts +512 -0
  320. package/src/lab/automation/planner.ts +371 -0
  321. package/src/lab/automation/policy.ts +136 -0
  322. package/src/lab/automation/queue.ts +191 -0
  323. package/src/lab/automation/recovery.ts +24 -0
  324. package/src/lab/automation/route-context.ts +21 -0
  325. package/src/lab/automation/run-key.ts +44 -0
  326. package/src/lab/automation/runs-query.ts +34 -0
  327. package/src/lab/automation/types.ts +160 -0
  328. package/src/lab/conformance/assertion.ts +325 -0
  329. package/src/lab/conformance/digest.ts +22 -0
  330. package/src/lab/conformance/executor.ts +741 -0
  331. package/src/lab/conformance/fixture-provider.ts +27 -0
  332. package/src/lab/conformance/fixtures/live-v1-cases.json +175 -0
  333. package/src/lab/conformance/fixtures/protocol-v1-cases.json +461 -0
  334. package/src/lab/conformance/harness-budget.ts +47 -0
  335. package/src/lab/conformance/index.ts +5 -0
  336. package/src/lab/conformance/jcs.ts +64 -0
  337. package/src/lab/conformance/json-pointer.ts +39 -0
  338. package/src/lab/conformance/manifest.ts +180 -0
  339. package/src/lab/conformance/mcp-stub.ts +179 -0
  340. package/src/lab/conformance/negative-controls.ts +164 -0
  341. package/src/lab/conformance/observation.ts +355 -0
  342. package/src/lab/conformance/runner.ts +68 -0
  343. package/src/lab/conformance/sse-normalize.ts +59 -0
  344. package/src/lab/conformance/suite-manifest.ts +78 -0
  345. package/src/lab/conformance/types.ts +214 -0
  346. package/src/lab/constants.ts +126 -0
  347. package/src/lab/digest.ts +64 -0
  348. package/src/lab/events/errors.ts +9 -0
  349. package/src/lab/events/limits.ts +117 -0
  350. package/src/lab/events/types.ts +229 -0
  351. package/src/lab/events/validate.ts +781 -0
  352. package/src/lab/fabric/constants.ts +40 -0
  353. package/src/lab/fabric/executor.ts +492 -0
  354. package/src/lab/fabric/index.ts +80 -0
  355. package/src/lab/fabric/manifest.ts +222 -0
  356. package/src/lab/fabric/observe.ts +489 -0
  357. package/src/lab/fabric/patch.ts +79 -0
  358. package/src/lab/fabric/producer-child.ts +139 -0
  359. package/src/lab/fabric/producer-isolate.ts +276 -0
  360. package/src/lab/fabric/producer-protocol.ts +61 -0
  361. package/src/lab/fabric/scratch.ts +439 -0
  362. package/src/lab/fabric/subject.ts +106 -0
  363. package/src/lab/fabric/types.ts +134 -0
  364. package/src/lab/fabric/verifier.ts +98 -0
  365. package/src/lab/index.ts +54 -0
  366. package/src/lab/ledger/artifact-refs.ts +127 -0
  367. package/src/lab/ledger/invalidation.ts +136 -0
  368. package/src/lab/ledger/purge.ts +310 -0
  369. package/src/lab/ledger/store.ts +532 -0
  370. package/src/lab/live/credential-lease.ts +53 -0
  371. package/src/lab/live/destination.ts +155 -0
  372. package/src/lab/live/executor.ts +336 -0
  373. package/src/lab/live/inert-tools.ts +56 -0
  374. package/src/lab/live/manifest.ts +85 -0
  375. package/src/lab/live/mcp-loopback.ts +57 -0
  376. package/src/lab/live/runner.ts +19 -0
  377. package/src/lab/live/sandbox.ts +61 -0
  378. package/src/lab/live/suite-manifest.ts +41 -0
  379. package/src/lab/live/transport.ts +118 -0
  380. package/src/lab/live/types.ts +197 -0
  381. package/src/lab/observe/from-conformance.ts +301 -0
  382. package/src/lab/observe/from-live.ts +117 -0
  383. package/src/lab/paths.ts +153 -0
  384. package/src/lab/projection/rebuild.ts +495 -0
  385. package/src/lab/projection/schema.ts +135 -0
  386. package/src/lab/projection/verdicts.ts +474 -0
  387. package/src/lab/projection/verification.ts +412 -0
  388. package/src/lab/public/bundle.ts +217 -0
  389. package/src/lab/public/community-authority.ts +175 -0
  390. package/src/lab/public/community-files.ts +29 -0
  391. package/src/lab/public/community.ts +479 -0
  392. package/src/lab/public/file-safety.ts +155 -0
  393. package/src/lab/public/ids.ts +26 -0
  394. package/src/lab/public/index.ts +16 -0
  395. package/src/lab/public/mutation-lock.ts +424 -0
  396. package/src/lab/public/operator.ts +353 -0
  397. package/src/lab/public/origin-purge.ts +79 -0
  398. package/src/lab/public/origin.ts +203 -0
  399. package/src/lab/public/privacy.ts +143 -0
  400. package/src/lab/public/private-file.ts +261 -0
  401. package/src/lab/public/project.ts +124 -0
  402. package/src/lab/public/purge-test-fault.ts +21 -0
  403. package/src/lab/public/purge.ts +223 -0
  404. package/src/lab/public/registry.ts +44 -0
  405. package/src/lab/public/revocation.ts +252 -0
  406. package/src/lab/public/signature.ts +243 -0
  407. package/src/lab/public/storage.ts +105 -0
  408. package/src/lab/public/strict-json.ts +206 -0
  409. package/src/lab/public/time.ts +26 -0
  410. package/src/lab/public/types.ts +172 -0
  411. package/src/lab/public/validate.ts +391 -0
  412. package/src/lab/query/catalog.ts +101 -0
  413. package/src/lab/query/connection.ts +107 -0
  414. package/src/lab/query/constants.ts +4 -0
  415. package/src/lab/query/cursor.ts +132 -0
  416. package/src/lab/query/dto-map.ts +277 -0
  417. package/src/lab/query/errors.ts +22 -0
  418. package/src/lab/query/freshness.ts +53 -0
  419. package/src/lab/query/index.ts +45 -0
  420. package/src/lab/query/latest-observation.ts +59 -0
  421. package/src/lab/query/passive-production.ts +159 -0
  422. package/src/lab/query/queries.ts +444 -0
  423. package/src/lab/query/types.ts +266 -0
  424. package/src/lab/subject/behavior-fingerprint.ts +77 -0
  425. package/src/lab/subject/installation-salt.ts +112 -0
  426. package/src/lab/subject/protocol-subject.ts +80 -0
  427. package/src/lab/subject/route-subject.ts +74 -0
  428. package/src/lib/admin-secrets.ts +24 -0
  429. package/src/lib/app-owned-memory-stores.ts +22 -0
  430. package/src/lib/bounded-body.ts +167 -11
  431. package/src/lib/bun-runtime.ts +125 -12
  432. package/src/lib/bun-stream-caps.ts +13 -9
  433. package/src/lib/codex-restart-contract.ts +120 -0
  434. package/src/lib/config-ownership.ts +26 -2
  435. package/src/lib/destination-policy.ts +65 -1
  436. package/src/lib/errors.ts +80 -5
  437. package/src/lib/fabric-task-execution-authority.ts +7 -0
  438. package/src/lib/fabric-task-host.ts +29 -0
  439. package/src/lib/lab-activation.ts +223 -0
  440. package/src/lib/lab-live-execution-authority.ts +13 -0
  441. package/src/lib/lab-live-host.ts +30 -0
  442. package/src/lib/lab-live-pinned-sender.ts +56 -0
  443. package/src/lib/lab-live-route-production.ts +130 -0
  444. package/src/lib/lab-passive-linker-registration.ts +26 -0
  445. package/src/lib/local-management-attestation.ts +51 -0
  446. package/src/lib/local-management-capability.ts +100 -0
  447. package/src/lib/local-provider-reload-contract.ts +100 -0
  448. package/src/lib/optional-shutdown-hooks.ts +57 -0
  449. package/src/lib/package-tree-integrity.ts +101 -0
  450. package/src/lib/pinned-http.ts +145 -26
  451. package/src/lib/process-control.ts +6 -2
  452. package/src/lib/provider-outbound.ts +49 -9
  453. package/src/lib/redact.ts +419 -3
  454. package/src/lib/self-launch-argv.ts +15 -0
  455. package/src/lib/server-resource-ownership.ts +71 -0
  456. package/src/lib/service-secrets.ts +15 -0
  457. package/src/lib/shadow-call.ts +35 -4
  458. package/src/lib/sse-decoder.ts +41 -0
  459. package/src/lib/state-store-registrations.ts +10 -2
  460. package/src/lib/system-restart-contract.ts +73 -0
  461. package/src/lib/token-estimate.ts +19 -2
  462. package/src/lib/tool-argument-integers.ts +253 -0
  463. package/src/lib/translator-budget.ts +44 -0
  464. package/src/lib/upstream-http-version.ts +57 -0
  465. package/src/lib/upstream-reachability.ts +95 -0
  466. package/src/lib/upstream-retry.ts +156 -3
  467. package/src/lib/windows-atomic-replace.ts +155 -0
  468. package/src/lib/windows-elevation.ts +70 -2
  469. package/src/lib/windows-secret-acl.ts +409 -69
  470. package/src/lib/windows-service-wrappers.ts +72 -0
  471. package/src/lib/windows-text.ts +106 -0
  472. package/src/lib/windows-user-principal.ts +341 -0
  473. package/src/lib/winsw.ts +33 -5
  474. package/src/oauth/account-import/google-antigravity-adapter.ts +74 -0
  475. package/src/oauth/account-import/index.ts +15 -0
  476. package/src/oauth/account-import/parser.ts +83 -0
  477. package/src/oauth/account-import/registry.ts +18 -0
  478. package/src/oauth/account-import/service.ts +75 -0
  479. package/src/oauth/account-import/types.ts +91 -0
  480. package/src/oauth/anthropic.ts +12 -1
  481. package/src/oauth/callback-server.ts +30 -4
  482. package/src/oauth/chatgpt.ts +12 -1
  483. package/src/oauth/cline.ts +203 -0
  484. package/src/oauth/command-code.ts +239 -0
  485. package/src/oauth/cursor.ts +46 -5
  486. package/src/oauth/generic-account-failover.ts +231 -0
  487. package/src/oauth/google-antigravity.ts +35 -3
  488. package/src/oauth/health.ts +20 -12
  489. package/src/oauth/index.ts +462 -71
  490. package/src/oauth/key-providers.ts +25 -0
  491. package/src/oauth/kimi.ts +25 -3
  492. package/src/oauth/kiro.ts +95 -6
  493. package/src/oauth/local-token-detect.ts +13 -2
  494. package/src/oauth/log.ts +3 -1
  495. package/src/oauth/login-cli.ts +88 -28
  496. package/src/oauth/nous.ts +798 -0
  497. package/src/oauth/open-browser-choice.ts +26 -0
  498. package/src/oauth/store.ts +133 -26
  499. package/src/oauth/token-guardian.ts +9 -3
  500. package/src/oauth/types.ts +15 -0
  501. package/src/pi/models.ts +2 -2
  502. package/src/providers/alibaba-region-migration.ts +1 -1
  503. package/src/providers/antigravity-models.ts +521 -31
  504. package/src/providers/auto-compact-budget.ts +65 -0
  505. package/src/providers/base-url-choices.ts +10 -0
  506. package/src/providers/codex-capacity.ts +292 -0
  507. package/src/providers/command-code-efforts.ts +176 -0
  508. package/src/providers/context-cap.ts +26 -8
  509. package/src/providers/cursor-pool.ts +72 -0
  510. package/src/providers/default-aliases.ts +65 -0
  511. package/src/providers/derive.ts +281 -6
  512. package/src/providers/fastwire.ts +507 -0
  513. package/src/providers/free-directory.ts +10 -7
  514. package/src/providers/google-vertex-location.ts +14 -0
  515. package/src/providers/key-failover.ts +71 -3
  516. package/src/providers/label.ts +35 -2
  517. package/src/providers/model-discovery-limits.ts +16 -0
  518. package/src/providers/model-discovery.ts +115 -22
  519. package/src/providers/model-presets.ts +119 -0
  520. package/src/providers/model-rename-migration.ts +255 -0
  521. package/src/providers/model-rename-startup.ts +28 -0
  522. package/src/providers/new-model-policy.ts +146 -0
  523. package/src/providers/openai-sidecar.ts +72 -4
  524. package/src/providers/openai-tier-startup.ts +31 -2
  525. package/src/providers/openai-tiers.ts +119 -4
  526. package/src/providers/openai-virtual-models.ts +1 -0
  527. package/src/providers/opencode-zen-rate-limit.ts +102 -0
  528. package/src/providers/provider-id-rewrite.ts +30 -0
  529. package/src/providers/quota.ts +1379 -40
  530. package/src/providers/registry.ts +1545 -112
  531. package/src/providers/request-pacing.ts +310 -0
  532. package/src/providers/service-tier.ts +277 -0
  533. package/src/providers/slug-codec.ts +94 -6
  534. package/src/providers/static-model-discovery.ts +86 -0
  535. package/src/providers/xai-responses-opt-in.ts +15 -0
  536. package/src/providers/xai-transport.ts +32 -4
  537. package/src/reasoning-effort.ts +68 -3
  538. package/src/responses/apply-patch-envelope.ts +63 -0
  539. package/src/responses/code-mode-helper-compat.ts +50 -0
  540. package/src/responses/compaction.ts +26 -1
  541. package/src/responses/custom-tool-compat.ts +384 -0
  542. package/src/responses/hosted-tool-policy.ts +9 -0
  543. package/src/responses/namespace-tool-compat.ts +435 -0
  544. package/src/responses/parser.ts +225 -38
  545. package/src/responses/provider-continuation.ts +98 -0
  546. package/src/responses/provider-opaque-metadata.ts +73 -0
  547. package/src/responses/reasoning-envelope.ts +9 -1
  548. package/src/responses/reasoning-replay-cache.ts +504 -0
  549. package/src/responses/schema.ts +12 -2
  550. package/src/responses/spill-store.ts +75 -10
  551. package/src/responses/state.ts +659 -31
  552. package/src/responses/thought-signature-replay.ts +364 -0
  553. package/src/responses/tool-search-compat.ts +301 -0
  554. package/src/responses/truncated-stop-reason.ts +60 -0
  555. package/src/responses/turn-termination.ts +107 -0
  556. package/src/router.ts +405 -31
  557. package/src/routing/analytics.ts +379 -0
  558. package/src/routing/capability.ts +244 -0
  559. package/src/routing/compatibility/assemble.ts +73 -0
  560. package/src/routing/compatibility/behavior.ts +278 -0
  561. package/src/routing/compatibility/catalog.ts +99 -0
  562. package/src/routing/compatibility/endpoint.ts +52 -0
  563. package/src/routing/compatibility/lab-evidence-provider.ts +130 -0
  564. package/src/routing/compatibility/policy.ts +181 -0
  565. package/src/routing/compatibility/provider-slot.ts +56 -0
  566. package/src/routing/compatibility/reader.ts +110 -0
  567. package/src/routing/compatibility/subject.ts +191 -0
  568. package/src/routing/compatibility/types.ts +64 -0
  569. package/src/routing/compatibility/version.ts +104 -0
  570. package/src/routing/cost.ts +77 -0
  571. package/src/routing/evaluator.ts +495 -0
  572. package/src/routing/health.ts +412 -0
  573. package/src/routing/history/cursor.ts +43 -0
  574. package/src/routing/history/indexer.ts +605 -0
  575. package/src/routing/history/schema.ts +72 -0
  576. package/src/routing/profile-namespace.ts +15 -0
  577. package/src/routing/profile.ts +547 -0
  578. package/src/routing/quota.ts +155 -0
  579. package/src/routing/request-evidence.ts +45 -0
  580. package/src/routing/trace.ts +776 -0
  581. package/src/server/adapter-resolve.ts +2 -29
  582. package/src/server/auth-cors.ts +289 -48
  583. package/src/server/background-lifecycle.ts +182 -0
  584. package/src/server/chat-completions.ts +154 -72
  585. package/src/server/chat-native-sse.ts +331 -0
  586. package/src/server/chat-native.ts +445 -0
  587. package/src/server/claude-messages.ts +160 -44
  588. package/src/server/direct-local-http.ts +347 -0
  589. package/src/server/effort-policy.ts +18 -0
  590. package/src/server/github-copilot-responses-repair.ts +338 -0
  591. package/src/server/gui-static.ts +39 -10
  592. package/src/server/images.ts +94 -12
  593. package/src/server/index.ts +1021 -190
  594. package/src/server/lifecycle.ts +336 -14
  595. package/src/server/live.ts +136 -17
  596. package/src/server/local-management-read-client.ts +90 -0
  597. package/src/server/local-provider-reload-client.ts +137 -0
  598. package/src/server/management/agent-settings-routes.ts +433 -116
  599. package/src/server/management/api-key-usage.ts +31 -5
  600. package/src/server/management/body.ts +6 -0
  601. package/src/server/management/codex-prompt-routes.ts +570 -0
  602. package/src/server/management/combo-routes.ts +64 -25
  603. package/src/server/management/config-routes.ts +511 -51
  604. package/src/server/management/context.ts +89 -2
  605. package/src/server/management/integration-routes.ts +498 -0
  606. package/src/server/management/lab-automation-routes.ts +206 -0
  607. package/src/server/management/lab-routes.ts +563 -0
  608. package/src/server/management/logs-usage-routes.ts +127 -52
  609. package/src/server/management/model-routes.ts +461 -133
  610. package/src/server/management/model-rows.ts +167 -0
  611. package/src/server/management/native-integration-routes.ts +770 -0
  612. package/src/server/management/oauth-account-routes.ts +90 -8
  613. package/src/server/management/provider-capability-config.ts +48 -0
  614. package/src/server/management/provider-routes.ts +836 -159
  615. package/src/server/management/request-history-routes.ts +191 -0
  616. package/src/server/management/route-registry.ts +332 -0
  617. package/src/server/management/routing-analytics-routes.ts +74 -0
  618. package/src/server/management/routing-profile-routes.ts +380 -0
  619. package/src/server/management/shared.ts +27 -11
  620. package/src/server/management/sidebar-routes.ts +47 -31
  621. package/src/server/management/storage-log-guard-routes.ts +186 -0
  622. package/src/server/management/sync-response.ts +69 -0
  623. package/src/server/management/system-restart.ts +289 -33
  624. package/src/server/management/system-routes.ts +77 -0
  625. package/src/server/management/usage-summary-cache.ts +9 -1
  626. package/src/server/management/vision-sidecar-options.ts +167 -0
  627. package/src/server/management/web-search-sidecar-options.ts +120 -0
  628. package/src/server/management-api.ts +126 -23
  629. package/src/server/management-auth.ts +220 -5
  630. package/src/server/passive-route-linker.ts +66 -0
  631. package/src/server/port-reclaim.ts +1 -1
  632. package/src/server/ports.ts +41 -1
  633. package/src/server/proxy-liveness.ts +161 -10
  634. package/src/server/readiness.ts +99 -0
  635. package/src/server/relay-eager.ts +221 -54
  636. package/src/server/relay.ts +479 -87
  637. package/src/server/request-decompress.ts +113 -6
  638. package/src/server/request-log-conversation.ts +51 -0
  639. package/src/server/request-log.ts +298 -31
  640. package/src/server/responses/agent-task-recovery-cache.ts +143 -0
  641. package/src/server/responses/agent-task-recovery.ts +465 -0
  642. package/src/server/responses/codex-auth-error.ts +55 -0
  643. package/src/server/responses/collaboration.ts +239 -36
  644. package/src/server/responses/combo-stream-preflight.ts +178 -0
  645. package/src/server/responses/compact.ts +444 -72
  646. package/src/server/responses/core.ts +3579 -436
  647. package/src/server/responses/empty-completion-guard.ts +333 -0
  648. package/src/server/responses/encrypted-payload.ts +62 -39
  649. package/src/server/responses/fetch-helpers.ts +89 -99
  650. package/src/server/responses/input-admission.ts +187 -0
  651. package/src/server/responses/pacing-overload.ts +13 -0
  652. package/src/server/responses/passthrough-error.ts +33 -9
  653. package/src/server/responses/policy-fallback.ts +178 -0
  654. package/src/server/responses/responses-field-backfill.ts +343 -0
  655. package/src/server/responses/terminal-guard.ts +26 -5
  656. package/src/server/responses/upstream-error.ts +5 -0
  657. package/src/server/responses/ws-upstream.ts +381 -0
  658. package/src/server/responses-custom-tool-repair.ts +363 -0
  659. package/src/server/responses-item-id-repair.ts +54 -6
  660. package/src/server/responses-json-events.ts +90 -0
  661. package/src/server/responses-model-rewrite.ts +29 -0
  662. package/src/server/responses-reasoning-summary-rewrite.ts +178 -0
  663. package/src/server/responses-snapshot-repair.ts +621 -0
  664. package/src/server/responses-terminal-repair.ts +363 -0
  665. package/src/server/responses-tool-search-repair.ts +267 -0
  666. package/src/server/responses-undeclared-tool-guard.ts +376 -0
  667. package/src/server/responses.ts +18 -2
  668. package/src/server/search.ts +78 -13
  669. package/src/server/sse-frame-buffer.ts +319 -0
  670. package/src/server/sse-payload-rewrite.ts +110 -22
  671. package/src/server/startup-action-control.ts +8 -1
  672. package/src/server/startup-health-cache.ts +19 -1
  673. package/src/server/system-env.ts +80 -9
  674. package/src/server/ws-bridge.ts +53 -40
  675. package/src/service-manager-probe.ts +892 -0
  676. package/src/service.ts +1153 -94
  677. package/src/sidecar/auth.ts +92 -0
  678. package/src/sidecar/candidates.ts +83 -0
  679. package/src/storage/cleanup.ts +2 -2
  680. package/src/storage/policy-job.ts +14 -4
  681. package/src/storage/policy.ts +88 -23
  682. package/src/storage/scanner.ts +1 -1
  683. package/src/storage/worker-lifecycle.ts +14 -14
  684. package/src/tray/windows-tray.ps1 +83 -9
  685. package/src/tray/windows.ts +43 -16
  686. package/src/types/accounts.ts +37 -0
  687. package/src/types/config.ts +911 -0
  688. package/src/types/provider.ts +614 -0
  689. package/src/types/request.ts +397 -0
  690. package/src/types/tools.ts +236 -0
  691. package/src/types/wire.ts +80 -0
  692. package/src/types.ts +107 -1237
  693. package/src/update/index.ts +37 -23
  694. package/src/update/job.ts +445 -68
  695. package/src/update/notify.ts +12 -6
  696. package/src/update/npm-cache-preflight.d.mts +47 -0
  697. package/src/update/npm-cache-preflight.mjs +201 -0
  698. package/src/update/transactional-install.d.mts +22 -0
  699. package/src/update/transactional-install.mjs +266 -0
  700. package/src/usage/cost.ts +0 -0
  701. package/src/usage/expected-prices.ts +287 -16
  702. package/src/usage/log.ts +666 -50
  703. package/src/usage/summary.ts +388 -17
  704. package/src/usage/user-cost-overlay-reconciler.ts +313 -0
  705. package/src/usage/user-cost-overlays.ts +314 -0
  706. package/src/vision/anthropic-describe.ts +10 -6
  707. package/src/vision/backends.ts +97 -0
  708. package/src/vision/describe.ts +27 -16
  709. package/src/vision/eligibility.ts +250 -0
  710. package/src/vision/index.ts +238 -24
  711. package/src/vision/reasoning.ts +55 -0
  712. package/src/vision/routed-describe.ts +175 -0
  713. package/src/vision/timeout-bounds.ts +9 -0
  714. package/src/web-search/anthropic-executor.ts +13 -7
  715. package/src/web-search/backends.ts +108 -0
  716. package/src/web-search/exa-executor.ts +119 -0
  717. package/src/web-search/executor.ts +21 -6
  718. package/src/web-search/gemini-executor.ts +141 -0
  719. package/src/web-search/index.ts +150 -15
  720. package/src/web-search/loop.ts +284 -54
  721. package/src/web-search/parse.ts +125 -30
  722. package/src/web-search/sources.ts +60 -0
  723. package/src/web-search/xai-executor.ts +219 -0
  724. package/gui/dist/assets/index-DTpMHS4F.js +0 -67
  725. package/gui/dist/assets/index-ZNVDE3C7.css +0 -1
  726. package/gui/dist/provider-icons/antigravity.svg +0 -1
  727. package/gui/dist/provider-icons/claude.svg +0 -1
  728. package/gui/dist/provider-icons/copilot.svg +0 -1
  729. package/gui/dist/provider-icons/cursor.svg +0 -2
  730. package/gui/dist/provider-icons/gemini.svg +0 -1
  731. package/gui/dist/provider-icons/grok-color.svg +0 -1
  732. package/gui/dist/provider-icons/kiro.svg +0 -14
  733. package/src/cli/internal-dispatch.ts +0 -20
@@ -0,0 +1,497 @@
1
+ /**
2
+ * MiniMax client launchers.
3
+ *
4
+ * `ocx mcode` uses the managed `custom_provider.opencodex` block written by the
5
+ * existing file-integration subsystem. `ocx mmx` is intentionally text-only:
6
+ * the official platform CLI's text commands speak Anthropic Messages, while its
7
+ * image/video/speech/music/search/quota endpoints are MiniMax-specific APIs that
8
+ * OpenCodex does not claim to implement.
9
+ */
10
+ import { execFileSync, spawn, type ChildProcess } from "node:child_process";
11
+ import { mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
12
+ import { tmpdir } from "node:os";
13
+ import { join } from "node:path";
14
+ import { ClientPathError, mcodeConfigPath, LOOPBACK_API_KEY_PLACEHOLDER } from "../clients/config-export";
15
+ import { loadConfig } from "../config";
16
+ import { clearableDeadline } from "../lib/abort";
17
+ import { withProcessRuntimeProvenance } from "../lib/bun-runtime";
18
+ import { selfLaunchArgv } from "../lib/self-launch-argv";
19
+ import { commandInvocation } from "../lib/win-exec";
20
+ import { isLoopbackHostname } from "../server/auth-cors";
21
+ import { findLiveProxy, probeHostname, type LiveProxy } from "../server/proxy-liveness";
22
+ import type { OcxConfig } from "../types";
23
+ import { opencodeProxyStartEnv } from "./opencode";
24
+
25
+ export interface MinimaxLaunchEnv {
26
+ [key: string]: string | undefined;
27
+ }
28
+
29
+ export interface MmxTextBridge {
30
+ baseUrl: string;
31
+ port: number;
32
+ stop(): Promise<void>;
33
+ }
34
+
35
+ export interface MmxTextBridgeOptions {
36
+ /** Optional outer guard; production delegates timeout policy to `/v1/messages`. */
37
+ headerTimeoutMs?: number;
38
+ }
39
+
40
+ export interface MmxTerminationTarget {
41
+ pid?: number;
42
+ exitCode: number | null;
43
+ signalCode: NodeJS.Signals | null;
44
+ kill(signal?: NodeJS.Signals | number): boolean;
45
+ }
46
+
47
+ export interface MmxTerminationDeps {
48
+ platform?: NodeJS.Platform;
49
+ killWindowsTree?: (pid: number) => void;
50
+ }
51
+
52
+ export interface MmxSignalHost {
53
+ on(signal: "SIGINT" | "SIGTERM", listener: () => void): unknown;
54
+ off(signal: "SIGINT" | "SIGTERM", listener: () => void): unknown;
55
+ }
56
+
57
+ export interface MmxTerminationHandlersOptions {
58
+ getChild: () => MmxTerminationTarget | null;
59
+ cleanup: () => Promise<void>;
60
+ host?: MmxSignalHost;
61
+ now?: () => number;
62
+ terminationDeps?: MmxTerminationDeps;
63
+ onCleanupError?: (error: unknown) => void;
64
+ }
65
+
66
+ const MMX_TERMINATION_DUPLICATE_WINDOW_MS = 500;
67
+
68
+ const MMX_CHILD_OWNED_ENV_KEYS = new Set([
69
+ "MMX_CONFIG_DIR",
70
+ "MINIMAX_BASE_URL",
71
+ "MINIMAX_REGION",
72
+ "MINIMAX_API_KEY",
73
+ "HTTP_PROXY",
74
+ "HTTPS_PROXY",
75
+ "ALL_PROXY",
76
+ ]);
77
+
78
+ const MMX_GLOBAL_BOOLEAN_FLAGS = new Set([
79
+ "--quiet",
80
+ "--verbose",
81
+ "--no-color",
82
+ "--dry-run",
83
+ "--non-interactive",
84
+ "--yes",
85
+ "--async",
86
+ "--stream",
87
+ "--no-stream",
88
+ "--no-wait",
89
+ "--help",
90
+ "--version",
91
+ ]);
92
+
93
+ /** Mirrors the official mmx command scanner's global-flag skipping behavior. */
94
+ export function mmxCommandPath(argv: readonly string[]): string[] {
95
+ const path: string[] = [];
96
+ for (let index = 0; index < argv.length;) {
97
+ const arg = argv[index]!;
98
+ if (arg === "--") break;
99
+ if (arg.startsWith("--")) {
100
+ const equals = arg.indexOf("=");
101
+ const name = equals >= 0 ? arg.slice(0, equals) : arg;
102
+ index += equals < 0 && !MMX_GLOBAL_BOOLEAN_FLAGS.has(name) ? 2 : 1;
103
+ continue;
104
+ }
105
+ if (arg.startsWith("-")) {
106
+ index += 1;
107
+ continue;
108
+ }
109
+ path.push(arg);
110
+ index += 1;
111
+ }
112
+ return path;
113
+ }
114
+
115
+ /** Caller credentials and destinations may never override the proxy wrapper. */
116
+ export function mmxUnsafeOverride(argv: readonly string[]): string | null {
117
+ for (const arg of argv) {
118
+ if (arg === "--api-key" || arg.startsWith("--api-key=")) return "--api-key";
119
+ if (arg === "--base-url" || arg.startsWith("--base-url=")) return "--base-url";
120
+ if (arg === "--region" || arg.startsWith("--region=")) return "--region";
121
+ }
122
+ return null;
123
+ }
124
+
125
+ export function buildMmxEnv(
126
+ live: Pick<LiveProxy, "hostname" | "port">,
127
+ configDir: string,
128
+ base: MinimaxLaunchEnv = process.env,
129
+ ): MinimaxLaunchEnv {
130
+ const env: MinimaxLaunchEnv = { ...base };
131
+ // The official MMX client installs one ProxyAgent whenever any proxy variable
132
+ // is present and does not apply NO_PROXY. Its OpenCodex destination is always
133
+ // loopback, so carrying these variables could send the request off-machine.
134
+ // Windows environment names are case-insensitive; strip every inherited
135
+ // spelling before installing the wrapper-owned values below.
136
+ for (const key of Object.keys(env)) {
137
+ if (MMX_CHILD_OWNED_ENV_KEYS.has(key.toUpperCase())) delete env[key];
138
+ }
139
+ env.MMX_CONFIG_DIR = configDir;
140
+ env.MINIMAX_BASE_URL = `http://${probeHostname(live.hostname)}:${live.port}`;
141
+ // Prevent a parent-shell region from triggering key detection against the
142
+ // official MiniMax hosts. The base URL above remains authoritative.
143
+ env.MINIMAX_REGION = "global";
144
+ return env;
145
+ }
146
+
147
+ /**
148
+ * MMX hard-codes `/anthropic/v1/messages` below its configured base URL while
149
+ * OpenCodex already exposes the canonical Anthropic data plane at
150
+ * `/v1/messages`. Keep that client-specific path adaptation inside the checked
151
+ * launcher instead of widening the proxy server's authentication surface.
152
+ */
153
+ export function startMmxTextBridge(
154
+ live: Pick<LiveProxy, "hostname" | "port">,
155
+ options: MmxTextBridgeOptions = {},
156
+ ): MmxTextBridge {
157
+ const upstreamOrigin = `http://${probeHostname(live.hostname)}:${live.port}`;
158
+ const server = Bun.serve({
159
+ hostname: "127.0.0.1",
160
+ port: 0,
161
+ async fetch(req) {
162
+ const incoming = new URL(req.url);
163
+ const canonicalPath = incoming.pathname === "/anthropic/v1/messages"
164
+ ? "/v1/messages"
165
+ : incoming.pathname === "/anthropic/v1/messages/count_tokens"
166
+ ? "/v1/messages/count_tokens"
167
+ : null;
168
+ if (req.method !== "POST" || !canonicalPath) {
169
+ return Response.json({
170
+ type: "error",
171
+ error: { type: "not_found_error", message: "unsupported MMX bridge route" },
172
+ }, { status: 404 });
173
+ }
174
+
175
+ const target = new URL(canonicalPath, `${upstreamOrigin}/`);
176
+ target.search = incoming.search;
177
+ const headers = new Headers(req.headers);
178
+ // The bridge is loopback-only and OpenCodex does not require a real key
179
+ // there. Pin the public placeholder even if a future MMX release loads a
180
+ // credential from somewhere outside the isolated config directory.
181
+ headers.delete("authorization");
182
+ headers.delete("x-opencodex-api-key");
183
+ headers.set("x-api-key", LOOPBACK_API_KEY_PLACEHOLDER);
184
+ headers.delete("host");
185
+ headers.delete("content-length");
186
+ // The canonical data plane owns its configured response-header, retry,
187
+ // and stream-stall budgets. An extra default here would cut off valid
188
+ // non-streaming or failover completions before their real response.
189
+ const headerDeadline = options.headerTimeoutMs === undefined
190
+ ? null
191
+ : clearableDeadline(options.headerTimeoutMs, req.signal);
192
+ try {
193
+ const upstreamRequest = new Request(target, {
194
+ method: "POST",
195
+ headers,
196
+ body: req.body,
197
+ signal: headerDeadline?.signal ?? req.signal,
198
+ });
199
+ return await fetch(upstreamRequest, {
200
+ // Override HTTP(S)_PROXY with the loopback listener itself. Bun sends
201
+ // the HTTP proxy-form request directly to this exact origin, so the
202
+ // hop cannot leave the machine even when the parent has proxy vars.
203
+ proxy: { url: upstreamOrigin },
204
+ });
205
+ } catch {
206
+ return Response.json({
207
+ type: "error",
208
+ error: { type: "api_error", message: "OpenCodex proxy unavailable" },
209
+ }, { status: 502 });
210
+ } finally {
211
+ // Once response headers arrive, streaming body cancellation remains
212
+ // linked to the client while this response-header timer is disarmed.
213
+ headerDeadline?.clear();
214
+ }
215
+ },
216
+ });
217
+ const bridgePort = server.port;
218
+ if (bridgePort === undefined) {
219
+ void server.stop(true);
220
+ throw new Error("MMX text bridge did not receive a TCP port");
221
+ }
222
+ return {
223
+ baseUrl: `http://127.0.0.1:${bridgePort}`,
224
+ port: bridgePort,
225
+ stop: () => server.stop(true),
226
+ };
227
+ }
228
+
229
+ function normalizedMcodeBaseUrl(value: string): string | null {
230
+ try {
231
+ const url = new URL(value);
232
+ if (
233
+ url.username
234
+ || url.password
235
+ || (url.pathname !== "" && url.pathname !== "/")
236
+ || url.search
237
+ || url.hash
238
+ ) return null;
239
+ return url.origin;
240
+ } catch {
241
+ return null;
242
+ }
243
+ }
244
+
245
+ /** Read only the provider destination; never return or log the persisted key. */
246
+ export function mcodeOpenCodexBaseUrl(text: string): string | null {
247
+ try {
248
+ const parsed = Bun.YAML.parse(text) as {
249
+ custom_provider?: { opencodex?: { options?: { baseURL?: unknown } } };
250
+ };
251
+ const baseURL = parsed?.custom_provider?.opencodex?.options?.baseURL;
252
+ return typeof baseURL === "string" ? baseURL : null;
253
+ } catch {
254
+ return null;
255
+ }
256
+ }
257
+
258
+ /** Reject stale runtime metadata that points a loopback-only launcher off-machine. */
259
+ export function usableMinimaxLiveProxy(live: LiveProxy | null): LiveProxy | null {
260
+ if (!live) return null;
261
+ return isLoopbackHostname(probeHostname(live.hostname)) ? live : null;
262
+ }
263
+
264
+ async function ensureProxy(config: OcxConfig): Promise<LiveProxy | null> {
265
+ const live = usableMinimaxLiveProxy(await findLiveProxy());
266
+ if (live) return live;
267
+ const pinPort = typeof config.port === "number" && config.port > 0 ? config.port : 10100;
268
+ const child = spawn(process.execPath, selfLaunchArgv(["start", "--port", String(pinPort)]), {
269
+ detached: true,
270
+ stdio: "ignore",
271
+ windowsHide: true,
272
+ // Reuse the established service-token lookup so a detached start works
273
+ // when admission lives in the hardened token file rather than this shell.
274
+ env: withProcessRuntimeProvenance(opencodeProxyStartEnv(process.env) as NodeJS.ProcessEnv),
275
+ });
276
+ child.on("error", () => { /* the bounded health poll reports failure */ });
277
+ child.unref();
278
+ const deadline = Date.now() + 8_000;
279
+ while (Date.now() < deadline) {
280
+ const started = usableMinimaxLiveProxy(await findLiveProxy());
281
+ if (started) return started;
282
+ await new Promise(resolve => setTimeout(resolve, 250));
283
+ }
284
+ return null;
285
+ }
286
+
287
+ /** Only a root-level, single-token info request may bypass proxy isolation. */
288
+ export function isStandaloneInformationalInvocation(
289
+ argv: readonly string[],
290
+ client: "mcode" | "mmx",
291
+ ): boolean {
292
+ if (argv.length !== 1) return false;
293
+ const arg = argv[0];
294
+ if (arg === "--help" || arg === "-h" || arg === "--version") return true;
295
+ // MMX 1.0.19 implements -v for version and does not implement -V. Preserve
296
+ // MCode's established -V passthrough separately.
297
+ return client === "mmx" ? arg === "-v" : arg === "-v" || arg === "-V";
298
+ }
299
+
300
+ /** Forward wrapper termination only while the MMX child is still live. */
301
+ export function forwardMmxTerminationSignal(
302
+ child: MmxTerminationTarget,
303
+ signal: "SIGINT" | "SIGTERM",
304
+ deps: MmxTerminationDeps = {},
305
+ ): boolean {
306
+ if (child.exitCode !== null || child.signalCode !== null) return false;
307
+ try {
308
+ if ((deps.platform ?? process.platform) === "win32") {
309
+ if (!Number.isInteger(child.pid) || child.pid === undefined || child.pid <= 0) return false;
310
+ const killWindowsTree = deps.killWindowsTree ?? (pid => {
311
+ const taskkill = `${process.env.SystemRoot ?? "C:\\Windows"}\\System32\\taskkill.exe`;
312
+ execFileSync(taskkill, ["/PID", String(pid), "/T", "/F"], {
313
+ stdio: "ignore",
314
+ windowsHide: true,
315
+ });
316
+ });
317
+ killWindowsTree(child.pid);
318
+ return true;
319
+ }
320
+ return child.kill(signal);
321
+ } catch {
322
+ return false;
323
+ }
324
+ }
325
+
326
+ /** Install persistent, duplicate-aware wrapper signal handlers. */
327
+ export function installMmxTerminationHandlers(
328
+ options: MmxTerminationHandlersOptions,
329
+ ): () => void {
330
+ const host = options.host ?? process;
331
+ const now = options.now ?? Date.now;
332
+ let lastTerminationSignalAt: number | null = null;
333
+ const onTerminationSignal = (signal: "SIGINT" | "SIGTERM") => {
334
+ const receivedAt = now();
335
+ // Ctrl-C reaches the foreground Bun process directly and is also
336
+ // forwarded by bin/ocx.mjs. Keep the listener installed and coalesce the
337
+ // near-simultaneous duplicate so async cleanup cannot be interrupted by
338
+ // the default signal action after a once-listener disappears.
339
+ if (
340
+ lastTerminationSignalAt !== null
341
+ && receivedAt - lastTerminationSignalAt < MMX_TERMINATION_DUPLICATE_WINDOW_MS
342
+ ) return;
343
+ lastTerminationSignalAt = receivedAt;
344
+ const child = options.getChild();
345
+ if (child) forwardMmxTerminationSignal(child, signal, options.terminationDeps);
346
+ try {
347
+ void options.cleanup().catch(error => { options.onCleanupError?.(error); });
348
+ } catch (error) {
349
+ options.onCleanupError?.(error);
350
+ }
351
+ };
352
+ const onSigint = () => onTerminationSignal("SIGINT");
353
+ const onSigterm = () => onTerminationSignal("SIGTERM");
354
+ host.on("SIGINT", onSigint);
355
+ host.on("SIGTERM", onSigterm);
356
+ return () => {
357
+ host.off("SIGINT", onSigint);
358
+ host.off("SIGTERM", onSigterm);
359
+ };
360
+ }
361
+
362
+ /** Keep signal handlers active until asynchronous bridge cleanup has settled. */
363
+ export async function finishMmxClientCleanup(
364
+ cleanup: () => Promise<void>,
365
+ removeTerminationHandlers: () => void,
366
+ ): Promise<void> {
367
+ try {
368
+ await cleanup();
369
+ } finally {
370
+ removeTerminationHandlers();
371
+ }
372
+ }
373
+
374
+ function spawnClient(
375
+ command: "mcode" | "mmx",
376
+ args: readonly string[],
377
+ env: NodeJS.ProcessEnv,
378
+ installHint: string,
379
+ onSpawn?: (child: ChildProcess) => void,
380
+ ): Promise<number> {
381
+ return new Promise(resolve => {
382
+ const inv = commandInvocation(command, [...args]);
383
+ const child = spawn(inv.file, inv.args, { stdio: "inherit", env, ...inv.options });
384
+ onSpawn?.(child);
385
+ child.on("error", (error: NodeJS.ErrnoException) => {
386
+ console.error(error.code === "ENOENT" ? installHint : `❌ Failed to launch ${command}: ${error.message}`);
387
+ resolve(1);
388
+ });
389
+ child.on("exit", (code, signal) => {
390
+ if (process.platform === "win32" && code === 9009 && !signal) console.error(installHint);
391
+ resolve(signal ? 1 : code ?? 0);
392
+ });
393
+ });
394
+ }
395
+
396
+ const MCODE_INSTALL_HINT = "❌ `mcode` CLI not found. Install MiniMax Code first: https://github.com/MiniMax-AI/minimax-code";
397
+ const MMX_INSTALL_HINT = "❌ `mmx` CLI not found. Install it first: npm install -g mmx-cli";
398
+
399
+ export async function cmdMcode(args: string[]): Promise<number> {
400
+ if (isStandaloneInformationalInvocation(args, "mcode")) return spawnClient("mcode", args, process.env, MCODE_INSTALL_HINT);
401
+ const config = loadConfig();
402
+ if (!isLoopbackHostname(config.hostname)) {
403
+ console.error("❌ MiniMax Code integration is loopback-only; its config cannot carry OpenCodex's dedicated remote-admission header.");
404
+ return 2;
405
+ }
406
+ const live = await ensureProxy(config);
407
+ if (!live) {
408
+ console.error("❌ Proxy did not become healthy after starting.");
409
+ return 1;
410
+ }
411
+ let configuredBase: string | null = null;
412
+ try {
413
+ configuredBase = mcodeOpenCodexBaseUrl(readFileSync(mcodeConfigPath(process.env), "utf8"));
414
+ } catch (error) {
415
+ // Missing or unreadable is reported as not connected below. An unstable
416
+ // relative override needs its own message because re-enabling cannot fix it.
417
+ if (error instanceof ClientPathError) {
418
+ console.error(`❌ ${error.message}`);
419
+ return 2;
420
+ }
421
+ }
422
+ if (!configuredBase) {
423
+ console.error("❌ MiniMax Code is not connected. Run: ocx integration client enable --client mcode");
424
+ return 2;
425
+ }
426
+ const expected = `http://${probeHostname(live.hostname)}:${live.port}`;
427
+ if (normalizedMcodeBaseUrl(configuredBase) !== normalizedMcodeBaseUrl(expected)) {
428
+ console.error("❌ MiniMax Code's OpenCodex provider points at a stale proxy address. Re-run: ocx integration client enable --client mcode");
429
+ return 2;
430
+ }
431
+ console.error(`✅ MiniMax Code wired to ${expected}; select custom_provider:opencodex/<model> in MCode.`);
432
+ return spawnClient("mcode", args, process.env, MCODE_INSTALL_HINT);
433
+ }
434
+
435
+ export async function cmdMmx(args: string[]): Promise<number> {
436
+ if (isStandaloneInformationalInvocation(args, "mmx")) return spawnClient("mmx", args, process.env, MMX_INSTALL_HINT);
437
+ const unsafe = mmxUnsafeOverride(args);
438
+ if (unsafe) {
439
+ console.error(`❌ ${unsafe} is not accepted by ocx mmx because it could bypass the proxy or expose a caller credential.`);
440
+ return 2;
441
+ }
442
+ const commandPath = mmxCommandPath(args);
443
+ if (commandPath[0] !== "text") {
444
+ console.error("❌ ocx mmx supports only `mmx text` commands. Use plain `mmx` for MiniMax image, video, speech, music, vision, search, quota, auth, config, file, and update APIs.");
445
+ return 2;
446
+ }
447
+ const config = loadConfig();
448
+ if (!isLoopbackHostname(config.hostname)) {
449
+ console.error("❌ ocx mmx is loopback-only; MMX has no field for OpenCodex's dedicated remote-admission header.");
450
+ return 2;
451
+ }
452
+ const live = await ensureProxy(config);
453
+ if (!live) {
454
+ console.error("❌ Proxy did not become healthy after starting.");
455
+ return 1;
456
+ }
457
+
458
+ const configDir = mkdtempSync(join(tmpdir(), "opencodex-mmx-"));
459
+ let bridge: MmxTextBridge | null = null;
460
+ let mmxChild: ChildProcess | null = null;
461
+ let cleanupPromise: Promise<void> | null = null;
462
+ let removeTerminationHandlers = () => {};
463
+ const cleanup = (): Promise<void> => {
464
+ cleanupPromise ??= (async () => {
465
+ const activeBridge = bridge;
466
+ bridge = null;
467
+ try {
468
+ if (activeBridge) await activeBridge.stop();
469
+ } finally {
470
+ rmSync(configDir, { recursive: true, force: true });
471
+ }
472
+ })();
473
+ return cleanupPromise;
474
+ };
475
+ try {
476
+ // Isolate MMX from ~/.mmx OAuth/API-key state. The only credential in this
477
+ // temporary file is a public loopback placeholder, and the directory is
478
+ // removed as soon as the child exits.
479
+ writeFileSync(join(configDir, "config.json"), `${JSON.stringify({
480
+ api_key: LOOPBACK_API_KEY_PLACEHOLDER,
481
+ region: "global",
482
+ }, null, 2)}\n`, { encoding: "utf8", mode: 0o600 });
483
+ bridge = startMmxTextBridge(live);
484
+ const env = buildMmxEnv({ hostname: "127.0.0.1", port: bridge.port }, configDir, process.env) as NodeJS.ProcessEnv;
485
+ console.error(`✅ MiniMax CLI text bridged to http://${probeHostname(live.hostname)}:${live.port}/v1/messages.`);
486
+ removeTerminationHandlers = installMmxTerminationHandlers({
487
+ getChild: () => mmxChild,
488
+ cleanup,
489
+ onCleanupError: error => {
490
+ console.error(`❌ Failed to clean up the MMX bridge after a termination signal: ${String(error)}`);
491
+ },
492
+ });
493
+ return await spawnClient("mmx", args, env, MMX_INSTALL_HINT, child => { mmxChild = child; });
494
+ } finally {
495
+ await finishMmxClientCleanup(cleanup, removeTerminationHandlers);
496
+ }
497
+ }
@@ -16,11 +16,17 @@ import {
16
16
  const USAGE = `Usage:
17
17
  ocx models live [--provider <name>] [--json]
18
18
  ocx models edit <custom-id> [--model-id <id>] [--display-name <name|->]
19
- [--context-window <tokens|0>] [--modalities <text,image,audio|->] [--json]
19
+ [--context-window <tokens|0>] [--modalities <text,image,audio|->]
20
+ [--reasoning-efforts <none,minimal,low,medium,high,xhigh,max,ultra|->]
21
+ [--default-reasoning-effort <level|->] [--json]
20
22
  ocx models <enable|disable> <provider/model|native-model> [--native] [--json]
21
23
  ocx models provider <name> <on|off> [--json]
22
24
  ocx models selected <provider> [--set <id,id...>|--clear] [--json]
23
- ocx models context <status|value <tokens>|provider <name> <on|off>|all <on|off>> [--json]
25
+ ocx models preset show [--provider <name>] [--json]
26
+ ocx models preset apply <provider> [--all] [--json]
27
+ ocx models new-policy [on|off] [--provider <name>] [--json]
28
+ ocx models new-arrivals [--json]
29
+ ocx models context <status|value <tokens> [--set-all]|provider <name> on [--value <tokens>]|provider <name> off|all <on|off>> [--json]
24
30
  ocx models shadow <status|set> [model|-] [--enabled <on|off>] [--json]`;
25
31
 
26
32
  type ModelRow = {
@@ -57,6 +63,8 @@ async function edit(argv: string[], deps: RuntimeApiDeps): Promise<void> {
57
63
  const displayName = takeOption(args, "--display-name");
58
64
  const contextRaw = takeOption(args, "--context-window");
59
65
  const modalitiesRaw = takeOption(args, "--modalities");
66
+ const reasoningEffortsRaw = takeOption(args, "--reasoning-efforts");
67
+ const defaultEffortRaw = takeOption(args, "--default-reasoning-effort");
60
68
  rejectArgs(args, USAGE);
61
69
  if (modelId !== undefined) patch.modelId = modelId;
62
70
  if (displayName !== undefined) patch.displayName = displayName === "-" ? "" : displayName;
@@ -66,6 +74,23 @@ async function edit(argv: string[], deps: RuntimeApiDeps): Promise<void> {
66
74
  patch.contextWindow = value === 0 ? null : value;
67
75
  }
68
76
  if (modalitiesRaw !== undefined) patch.inputModalities = modalitiesRaw === "-" ? [] : csv(modalitiesRaw);
77
+ // "-" restores inheritance by clearing the stored ladder (null); "" stores an explicit
78
+ // empty ladder (the "no reasoning" override, same as the dashboard's uncheck-all).
79
+ // Embedded blank CSV members (`low,,high`, `,,`) are malformed and must be rejected, not
80
+ // silently normalized by csv().
81
+ if (reasoningEffortsRaw !== undefined) {
82
+ if (reasoningEffortsRaw === "-") {
83
+ patch.reasoningEfforts = null;
84
+ } else {
85
+ const trimmed = reasoningEffortsRaw.trim();
86
+ const values = trimmed === "" ? [] : trimmed.split(",").map(value => value.trim());
87
+ if (values.some(value => value === "")) {
88
+ throw new CliUsageError("--reasoning-efforts must be comma-separated values from none, minimal, low, medium, high, xhigh, max, ultra (\"\" for no reasoning, \"-\" to inherit)", USAGE);
89
+ }
90
+ patch.reasoningEfforts = values;
91
+ }
92
+ }
93
+ if (defaultEffortRaw !== undefined) patch.defaultReasoningEffort = defaultEffortRaw === "-" ? null : defaultEffortRaw;
69
94
  if (Object.keys(patch).length === 0) throw new CliUsageError("at least one edit option is required", USAGE);
70
95
  const result = await runtimeRequest(`/api/custom-models/${encodeURIComponent(id)}`, {
71
96
  method: "PUT",
@@ -141,6 +166,94 @@ async function selected(argv: string[], deps: RuntimeApiDeps): Promise<void> {
141
166
  printData(result, wantsJson, [`${provider}: ${models.length ? models.join(", ") : "all models"}`]);
142
167
  }
143
168
 
169
+
170
+ interface ModelPresetView {
171
+ mode: string;
172
+ appliedVersion?: number;
173
+ availableVersion: number;
174
+ presetIds: string[];
175
+ presetCount: number;
176
+ totalCount: number;
177
+ fallback?: string;
178
+ }
179
+
180
+ function presetLine(name: string, view: ModelPresetView): string {
181
+ const parts = [`${name}: mode=${view.mode}`];
182
+ if (view.appliedVersion !== undefined && view.appliedVersion !== view.availableVersion) {
183
+ parts.push(`applied v${view.appliedVersion}, available v${view.availableVersion}`);
184
+ } else {
185
+ parts.push(`preset v${view.availableVersion}`);
186
+ }
187
+ parts.push(`(${view.presetCount} of ${view.totalCount} models)`);
188
+ if (view.fallback) parts.push(`fallback=${view.fallback}`);
189
+ return parts.join(" ");
190
+ }
191
+
192
+ async function preset(argv: string[], deps: RuntimeApiDeps): Promise<void> {
193
+ const args = [...argv];
194
+ const action = (args.shift() ?? "show").toLowerCase();
195
+ const wantsJson = takeFlag(args, "--json");
196
+ if (action === "show") {
197
+ const only = takeOption(args, "--provider")?.trim();
198
+ rejectArgs(args, USAGE);
199
+ const result = await runtimeRequest<{ providers?: Record<string, ModelPresetView> }>("/api/model-presets", {}, deps);
200
+ const providers = result.providers ?? {};
201
+ const entries = Object.entries(providers).filter(([name]) => !only || name === only);
202
+ const lines = entries.length > 0
203
+ ? entries.map(([name, view]) => presetLine(name, view))
204
+ // A provider with no shipped preset is not an error: it simply has nothing to curate.
205
+ : [only ? `${only}: no model preset is shipped for this provider` : "no providers have a shipped model preset"];
206
+ printData(only ? providers[only] ?? {} : result, wantsJson, lines);
207
+ return;
208
+ }
209
+ if (action !== "apply") throw new CliUsageError(`unknown preset action '${action}'`, USAGE);
210
+ const provider = args.shift()?.trim();
211
+ const all = takeFlag(args, "--all");
212
+ if (!provider) throw new CliUsageError("provider is required", USAGE);
213
+ rejectArgs(args, USAGE);
214
+ const mode = all ? "all" : "preset";
215
+ const result = await runtimeRequest<{ selected?: string[]; fallback?: string; appliedVersion?: number }>(
216
+ "/api/model-presets",
217
+ { method: "PUT", body: JSON.stringify({ provider, mode }) },
218
+ deps,
219
+ );
220
+ const selectedIds = result.selected ?? [];
221
+ const line = result.fallback === "preset-empty"
222
+ // Never silently narrow to nothing: empty means ALL, so a zero-match preset keeps what was
223
+ // there and says so.
224
+ ? `${provider}: preset matched no models — selection unchanged (fallback to all)`
225
+ : all
226
+ ? `${provider}: showing all models (allowlist cleared)`
227
+ : `${provider}: preset v${result.appliedVersion ?? "?"} applied — ${selectedIds.length} models selected`;
228
+ printData(result, wantsJson, [line]);
229
+ }
230
+
231
+ async function newPolicy(argv: string[], deps: RuntimeApiDeps): Promise<void> {
232
+ const args = [...argv];
233
+ const state = args[0] && !args[0].startsWith("--") ? args.shift()!.toLowerCase() : undefined;
234
+ const provider = takeOption(args, "--provider")?.trim();
235
+ const wantsJson = takeFlag(args, "--json");
236
+ if (state !== undefined && state !== "on" && state !== "off") throw new CliUsageError("new policy must be on or off", USAGE);
237
+ rejectArgs(args, USAGE);
238
+ if (!state) {
239
+ const result = await runtimeRequest<{ policy: string; providers: Record<string, string> }>("/api/model-discovery", {}, deps);
240
+ const value = provider ? result.providers[provider] ?? "inherit" : result.policy;
241
+ printData(provider ? { provider, policy: value } : result, wantsJson, [`${provider ?? "global"}: ${value}`]);
242
+ return;
243
+ }
244
+ const result = await runtimeRequest<{ baselineBootstrapped?: boolean }>("/api/model-discovery", {
245
+ method: "PUT", body: JSON.stringify({ policy: state, provider: provider ?? null }),
246
+ }, deps);
247
+ printData(result, wantsJson, [`${provider ?? "global"}: ${state}${result.baselineBootstrapped ? " (current models recorded as known)" : ""}`]);
248
+ }
249
+
250
+ async function newArrivals(argv: string[], deps: RuntimeApiDeps): Promise<void> {
251
+ const args = [...argv]; const wantsJson = takeFlag(args, "--json"); rejectArgs(args, USAGE);
252
+ const result = await runtimeRequest<{ recentArrivals: Record<string, Array<{ id: string; at: string; state: string }>> }>("/api/model-discovery", {}, deps);
253
+ const lines = Object.entries(result.recentArrivals).flatMap(([provider, rows]) => rows.map(row => `${provider}/${row.id} [${row.state}] ${row.at}`));
254
+ printData(result.recentArrivals, wantsJson, lines.length ? lines : ["no recent model arrivals"]);
255
+ }
256
+
144
257
  async function context(argv: string[], deps: RuntimeApiDeps): Promise<void> {
145
258
  const args = [...argv];
146
259
  const action = (args.shift() ?? "status").toLowerCase();
@@ -158,11 +271,23 @@ async function context(argv: string[], deps: RuntimeApiDeps): Promise<void> {
158
271
  const value = Number(raw.replace(/[_,]/g, ""));
159
272
  if (!Number.isInteger(value) || value <= 0) throw new CliUsageError("context value must be a positive integer", USAGE);
160
273
  body = { value };
274
+ // Explicit apply-to-all switch for headless use: re-points every routed provider to
275
+ // the new value, mirroring the dashboard's "apply to every routed provider" toggle.
276
+ // Without it the value only becomes the default for future toggles.
277
+ if (takeFlag(args, "--set-all")) body.setAll = true;
161
278
  } else if (action === "provider") {
162
279
  const provider = args.shift()?.trim();
163
280
  const state = args.shift()?.toLowerCase();
164
281
  if (!provider || (state !== "on" && state !== "off")) throw new CliUsageError("provider and on|off are required", USAGE);
165
282
  body = { provider, enabled: state === "on" };
283
+ // Optional explicit cap value for this provider only (`ocx models context provider
284
+ // openai on --value 128000`). Mirrors the dashboard's per-provider cap picker; the
285
+ // value never leaks to other providers.
286
+ const value = takeIntegerOption(args, "--value", { min: 1 });
287
+ if (value !== undefined && state !== "on") {
288
+ throw new CliUsageError("--value can only be used with on", USAGE);
289
+ }
290
+ if (value !== undefined) body.value = value;
166
291
  } else if (action === "all") {
167
292
  const state = args.shift()?.toLowerCase();
168
293
  if (state !== "on" && state !== "off") throw new CliUsageError("all requires on|off", USAGE);
@@ -203,6 +328,9 @@ export async function handleModelsRuntimeCommand(sub: string, argv: string[], de
203
328
  else if (sub === "disable") action = () => visibility(false, argv, deps);
204
329
  else if (sub === "provider") action = () => providerVisibility(argv, deps);
205
330
  else if (sub === "selected") action = () => selected(argv, deps);
331
+ else if (sub === "preset") action = () => preset(argv, deps);
332
+ else if (sub === "new-policy") action = () => newPolicy(argv, deps);
333
+ else if (sub === "new-arrivals") action = () => newArrivals(argv, deps);
206
334
  else if (sub === "context") action = () => context(argv, deps);
207
335
  else if (sub === "shadow") action = () => shadow(argv, deps);
208
336
  if (!action) return null;