@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
@@ -4,17 +4,18 @@ import { copyFileSync, existsSync, mkdirSync, readFileSync, realpathSync } from
4
4
  import { delimiter, dirname, join, resolve } from "node:path";
5
5
  import { atomicWriteFile, expandUserPath, getConfigDir, websocketsEnabled } from "../../config";
6
6
  import { CODEX_CONFIG_PATH, CODEX_MODELS_CACHE_PATH, DEFAULT_CATALOG_PATH, readRootTomlString, resolveCodexConfigPath } from "../paths";
7
+ import { codexAccountNamespaceEntries, isMainCodexAccountTarget } from "../account-namespaces";
7
8
  import { clearModelCache, DEFAULT_MODEL_CACHE_TTL_MS, getFreshCached, getStaleCached, isModelsFetchCoolingDown, markModelsFetchFailure, setCached } from "../model-cache";
8
9
  import { buildModelsRequest, resolveModelsAuthToken } from "../../oauth";
9
10
  import type { OcxConfig, OcxProviderConfig } from "../../types";
10
11
  import { modelInList } from "../../types";
11
12
  import { CODEX_REASONING_LEVELS, codexEffortRank, configuredReasoningEfforts, modelRecordValue, sanitizeCodexReasoningEfforts } from "../../reasoning-effort";
12
- import { getJawcodeModelMetadata, getJawcodeModelMetadataCaseInsensitive, listJawcodeModelMetadata, resolveJawcodeProvider } from "../../generated/jawcode-model-metadata";
13
+ import { getModelMetadata, getModelMetadataCaseInsensitive, listModelMetadata, resolveMetadataProvider } from "../../generated/model-metadata";
13
14
  import { enrichProviderFromRegistry, shouldCaseFoldMetadataModelId } from "../../providers/derive";
14
- import { getProviderRegistryEntry } from "../../providers/registry";
15
+ import { getProviderRegistryEntry, providerCodexAccountMode } from "../../providers/registry";
15
16
  import { applyProviderContextCap, providerContextCap } from "../../providers/context-cap";
16
17
  import { routedSlug, slugEquals, slugsEquivalent } from "../../providers/slug-codec";
17
- import { CODEX_GPT5_IDENTITY_LINE } from "../../adapters/identity";
18
+ import { identifyRoutedModel } from "../../adapters/identity";
18
19
  import { filterCursorConfiguredModelsByLiveDiscovery } from "../../adapters/cursor/discovery";
19
20
  import { fetchCursorUsableModels } from "../../adapters/cursor/live-models";
20
21
  import { isCanonicalOpenAiForwardProvider, OPENAI_API_PROVIDER_ID, OPENAI_CODEX_PROVIDER_ID } from "../../providers/openai-tiers";
@@ -22,6 +23,7 @@ import {
22
23
  COMBO_NAMESPACE,
23
24
  comboModelId,
24
25
  getCombo,
26
+ isNativeAliasCombo,
25
27
  listComboIds,
26
28
  targetKey,
27
29
  } from "../../combos";
@@ -31,21 +33,68 @@ import { redactSecretString } from "../../lib/redact";
31
33
  import upstreamModelsSnapshot from "../data/upstream-models.json";
32
34
 
33
35
 
34
- import { filterSupportedNativeSlugs } from "./parsing";
35
36
  import type { RawEntry } from "./parsing";
36
- import { readCurrentCatalogOrCache, unique } from "./bundled";
37
-
38
- export const NATIVE_OPENAI_MODELS = [
39
- "gpt-5.5", "gpt-5.4", "gpt-5.4-mini", "gpt-5.3-codex-spark",
40
- "gpt-5.6-sol", "gpt-5.6-terra", "gpt-5.6-luna",
41
- ];
37
+ import { readCurrentCatalogOrCache, readCurrentCodexCatalog, readCurrentCodexModelsCache, unique } from "./bundled";
38
+ import { trustedAccountBoundNativeCatalogSlug, visibleCodexAccountSelectors } from "./account-models";
39
+ import { CODEX_NATIVE_ALIAS_CATALOG_KIND } from "./kinds";
40
+ import {
41
+ ACCOUNT_GATED_NATIVE_OPENAI_MODELS,
42
+ NATIVE_DAYBREAK_BLUE_MODEL,
43
+ NATIVE_OPENAI_CAPABILITY_ALIAS_MODELS,
44
+ NATIVE_OPENAI_MODELS,
45
+ SUPPORTED_NATIVE_OPENAI_SLUGS,
46
+ isNativeOpenAiCapabilityAliasModel,
47
+ nativeOpenAiCapabilitySourceSlug,
48
+ } from "./native-models";
49
+ import { cachedAvailableAccountGatedNativeModels } from "../model-entitlements";
50
+ import { MAIN_CODEX_ACCOUNT_ID } from "../main-account";
51
+ export { CODEX_NATIVE_ALIAS_CATALOG_KIND } from "./kinds";
52
+ export {
53
+ NATIVE_DAYBREAK_BLUE_MODEL,
54
+ NATIVE_OPENAI_CAPABILITY_ALIAS_MODELS,
55
+ NATIVE_OPENAI_MODELS,
56
+ SUPPORTED_NATIVE_OPENAI_SLUGS,
57
+ isNativeOpenAiCapabilityAliasModel,
58
+ nativeOpenAiCapabilitySourceSlug,
59
+ } from "./native-models";
42
60
 
43
61
  export const DOCUMENTED_NATIVE_OPENAI_ADDITIONS = [
44
62
  "gpt-5.3-codex-spark",
45
63
  "gpt-5.6-sol", "gpt-5.6-terra", "gpt-5.6-luna",
46
64
  ];
47
65
 
48
- export const SUPPORTED_NATIVE_OPENAI_SLUGS = new Set(NATIVE_OPENAI_MODELS);
66
+ export function configuredNativeAliasSlugs(
67
+ config: Pick<OcxConfig, "combos">,
68
+ ): Set<string> {
69
+ const aliases = new Set<string>();
70
+ for (const raw of Object.values(config.combos ?? {})) {
71
+ if (!isNativeAliasCombo(raw)) continue;
72
+ const alias = raw.alias!.trim();
73
+ if (SUPPORTED_NATIVE_OPENAI_SLUGS.has(alias)) aliases.add(alias);
74
+ }
75
+ return aliases;
76
+ }
77
+
78
+ /**
79
+ * Bare native rows that must be absent, rather than merely hidden, while Desktop native-alias
80
+ * compatibility is active. Codex Desktop's remote allowlist can ignore `visibility: "hide"`;
81
+ * omitting disabled native rows is therefore part of the explicit native-alias opt-in.
82
+ */
83
+ export function desktopAllowlistSuppressedNativeSlugs(
84
+ config: Pick<OcxConfig, "combos" | "disabledModels">,
85
+ ): Set<string> {
86
+ const suppressed = configuredNativeAliasSlugs(config);
87
+ if (suppressed.size === 0) return suppressed;
88
+ const disabled = disabledNativeSlugs(config);
89
+ for (const slug of NATIVE_OPENAI_MODELS) {
90
+ if (disabled.has(slug)) suppressed.add(slug);
91
+ }
92
+ return suppressed;
93
+ }
94
+
95
+ export function isNativeAliasCatalogEntry(entry: RawEntry): boolean {
96
+ return entry.opencodex_catalog_kind === CODEX_NATIVE_ALIAS_CATALOG_KIND;
97
+ }
49
98
 
50
99
  export function isUnsupportedOpenAiNativeSlug(slug: string): boolean {
51
100
  if (slug.includes("/")) return false;
@@ -53,26 +102,183 @@ export function isUnsupportedOpenAiNativeSlug(slug: string): boolean {
53
102
  return /^(?:gpt|codex)-/.test(slug);
54
103
  }
55
104
 
56
- export const NATIVE_GPT56_CONTEXT_WINDOW = 372_000;
105
+ /**
106
+ * Advertised context for the Codex-login native GPT-5.6 family.
107
+ *
108
+ * This is an OPERATING CAP, not the hard ceiling — the same shape upstream uses. The live
109
+ * catalog reports `context_window: 272000` against a `max_context_window: 872000` for these
110
+ * slugs, and gpt-5.4 runs 272,000 against 1,000,000: the advertised window is always well
111
+ * inside what the model can take.
112
+ *
113
+ * The hard ceiling here was measured on 2026-08-17 against a real Codex-login account:
114
+ * `POST /backend-api/codex/responses` admitted 921,508 input tokens and refused 922,013 with
115
+ * `error.code: context_length_exceeded` on sol, terra and luna alike.
116
+ *
117
+ * Codex spends `context_window * effective_context_window_percent`, which defaults to 95%
118
+ * (codex-rs `openai_models.rs` / `turn_context.rs`). So this value yields a 875,900-token
119
+ * budget and leaves ~46k of headroom under the measured ceiling. An earlier release shipped
120
+ * 1,050,000 here, which spent 997,500 — past what the upstream accepts.
121
+ *
122
+ * Do NOT back-solve this from the ceiling (970,000 would land the budget at 921,500, inside
123
+ * the 1,840-token gap between the last success and the first refusal). The 95% is a safety
124
+ * margin to keep, not a discount to cancel out.
125
+ *
126
+ * Evidence: devlog/_plan/260817_native_gpt56_1m_context/001_measurement_evidence.md
127
+ * and 014_final_922k_with_margin.md.
128
+ */
129
+ export const NATIVE_GPT56_CONTEXT_WINDOW = 272_000;
130
+
131
+ /**
132
+ * Hard ceiling: the largest input the native GPT-5.6 family actually accepts (measured).
133
+ *
134
+ * Equal to the advertised window above rather than below it, because that window is already
135
+ * capped under this ceiling. The clamp stays because routed and API-key rows carry the same
136
+ * family at a 1,050,000 window, where 90% (945,000) WOULD overshoot this limit.
137
+ */
138
+ export const NATIVE_GPT56_MAX_INPUT_TOKENS = 922_000;
139
+
140
+ /** User-facing 1M opt-in: the largest window the native 5.6 family may advertise. */
141
+ export const NATIVE_GPT56_OPT_IN_CONTEXT_WINDOW = NATIVE_GPT56_MAX_INPUT_TOKENS;
142
+
143
+ const NATIVE_GPT56_FAMILY = new Set<string>([
144
+ "gpt-5.6-sol",
145
+ "gpt-5.6-terra",
146
+ "gpt-5.6-luna",
147
+ NATIVE_DAYBREAK_BLUE_MODEL,
148
+ ]);
57
149
 
58
- export const NATIVE_OPENAI_CONTEXT_OVERRIDES: Record<string, { contextWindow?: number; maxContextWindow?: number }> = {
150
+ export const NATIVE_OPENAI_CONTEXT_OVERRIDES: Record<string, { contextWindow?: number; maxContextWindow?: number; maxInputTokens?: number }> = {
59
151
  "gpt-5.5": { contextWindow: 272_000, maxContextWindow: 272_000 },
60
152
  "gpt-5.4": { contextWindow: 1_000_000, maxContextWindow: 1_000_000 },
61
153
  "gpt-5.3-codex-spark": { contextWindow: 100_000, maxContextWindow: 100_000 },
62
- "gpt-5.6-sol": { contextWindow: NATIVE_GPT56_CONTEXT_WINDOW, maxContextWindow: NATIVE_GPT56_CONTEXT_WINDOW },
63
- "gpt-5.6-terra": { contextWindow: NATIVE_GPT56_CONTEXT_WINDOW, maxContextWindow: NATIVE_GPT56_CONTEXT_WINDOW },
64
- "gpt-5.6-luna": { contextWindow: NATIVE_GPT56_CONTEXT_WINDOW, maxContextWindow: NATIVE_GPT56_CONTEXT_WINDOW },
154
+ "gpt-5.6-sol": { contextWindow: NATIVE_GPT56_CONTEXT_WINDOW, maxContextWindow: NATIVE_GPT56_MAX_INPUT_TOKENS, maxInputTokens: NATIVE_GPT56_MAX_INPUT_TOKENS },
155
+ "gpt-5.6-terra": { contextWindow: NATIVE_GPT56_CONTEXT_WINDOW, maxContextWindow: NATIVE_GPT56_MAX_INPUT_TOKENS, maxInputTokens: NATIVE_GPT56_MAX_INPUT_TOKENS },
156
+ "gpt-5.6-luna": { contextWindow: NATIVE_GPT56_CONTEXT_WINDOW, maxContextWindow: NATIVE_GPT56_MAX_INPUT_TOKENS, maxInputTokens: NATIVE_GPT56_MAX_INPUT_TOKENS },
157
+ // Daybreak Blue borrows Sol's capability metadata and rides the same family contract.
158
+ // Unlike sol/terra/luna its window was NOT measured here: this account cannot reach it
159
+ // (`400 "The 'gpt-daybreak-blue-latest' model is not supported when using Codex with a
160
+ // ChatGPT account."`), so the promotion rests on a report from an account that has
161
+ // access rather than on a probe. Treat it as the weaker evidence of the four.
162
+ [NATIVE_DAYBREAK_BLUE_MODEL]: { contextWindow: NATIVE_GPT56_CONTEXT_WINDOW, maxContextWindow: NATIVE_GPT56_MAX_INPUT_TOKENS, maxInputTokens: NATIVE_GPT56_MAX_INPUT_TOKENS },
65
163
  };
66
164
 
67
- export function nativeOpenAiContextWindow(slug: string): number | undefined {
68
- return NATIVE_OPENAI_CONTEXT_OVERRIDES[slug]?.contextWindow
69
- ?? (typeof UPSTREAM_NATIVE_ENTRIES.get(slug)?.context_window === "number"
70
- ? UPSTREAM_NATIVE_ENTRIES.get(slug)!.context_window as number
165
+ const PINNED_UPSTREAM_MODELS: Map<string, RawEntry> = new Map(
166
+ ((upstreamModelsSnapshot as unknown as { models?: RawEntry[] }).models ?? [])
167
+ .flatMap(model => typeof model.slug === "string" ? [[model.slug, model] as const] : []),
168
+ );
169
+
170
+ function pinnedNativeCapabilityEntry(slug: string): RawEntry | undefined {
171
+ return PINNED_UPSTREAM_MODELS.get(nativeOpenAiCapabilitySourceSlug(slug));
172
+ }
173
+
174
+ /**
175
+ * Pinned capability metadata is safe to use as a fallback for every supported native model.
176
+ * Keep it separate from UPSTREAM_NATIVE_ENTRIES: that narrower map also authorizes replacing
177
+ * persisted native rows during sync, which is currently intentional only for the GPT-5.6 family.
178
+ */
179
+ const PINNED_NATIVE_CAPABILITY_ENTRIES: Map<string, RawEntry> = new Map(
180
+ [...NATIVE_OPENAI_MODELS, ...NATIVE_OPENAI_CAPABILITY_ALIAS_MODELS].flatMap(slug => {
181
+ const entry = pinnedNativeCapabilityEntry(slug);
182
+ return entry ? [[slug, entry] as const] : [];
183
+ }),
184
+ );
185
+
186
+ /**
187
+ * The user-owned levers that set a native window, carried together.
188
+ *
189
+ * For the GPT-5.6 family these may raise the Codex 272k default up to the measured
190
+ * 922k ceiling. Other native slugs still only ever lower.
191
+ *
192
+ * This travels as an ARGUMENT rather than module state on purpose. `grok/sync.ts` runs in
193
+ * the `ocx ensure` parent process, outside the server, so an injected global would never
194
+ * reach it — that failure is recorded in
195
+ * devlog/_plan/260817_native_gpt56_1m_context/006_root_cause_replan.md. Every call site
196
+ * already holds a config or a cap, so passing one more field costs nothing.
197
+ *
198
+ * A bare number is still accepted for the many call sites that only know the cap.
199
+ */
200
+ export interface NativeContextLimits {
201
+ /** `providerContextCaps.openai` */
202
+ readonly cap?: number;
203
+ /** `providers.openai.contextWindow` — a floor-wide user override. */
204
+ readonly providerWindow?: number;
205
+ /** `providers.openai.modelContextWindows` — per-model, wins over `providerWindow`. */
206
+ readonly modelWindows?: Readonly<Record<string, number>>;
207
+ }
208
+
209
+ export type NativeContextLimitsInput = NativeContextLimits | number | undefined;
210
+
211
+ function positiveInt(value: unknown): number | undefined {
212
+ return typeof value === "number" && Number.isSafeInteger(value) && value > 0 ? value : undefined;
213
+ }
214
+
215
+ function asLimits(input: NativeContextLimitsInput): NativeContextLimits {
216
+ if (input === undefined) return {};
217
+ return typeof input === "number" ? { cap: input } : input;
218
+ }
219
+
220
+ /** Read both levers out of a config once, for call sites that hold one. */
221
+ export function nativeContextLimits(
222
+ config: Pick<OcxConfig, "providers" | "providerContextCaps">,
223
+ ): NativeContextLimits {
224
+ const provider = config.providers?.[OPENAI_CODEX_PROVIDER_ID];
225
+ const modelWindows: Record<string, number> = {};
226
+ for (const [slug, value] of Object.entries(provider?.modelContextWindows ?? {})) {
227
+ const window = positiveInt(value);
228
+ if (window !== undefined) modelWindows[slug] = window;
229
+ }
230
+ return {
231
+ ...(positiveInt(providerContextCap(config, OPENAI_CODEX_PROVIDER_ID)) !== undefined
232
+ ? { cap: providerContextCap(config, OPENAI_CODEX_PROVIDER_ID) }
233
+ : {}),
234
+ ...(positiveInt(provider?.contextWindow) !== undefined ? { providerWindow: provider!.contextWindow } : {}),
235
+ ...(Object.keys(modelWindows).length > 0 ? { modelWindows } : {}),
236
+ };
237
+ }
238
+
239
+ /** Apply the user levers to an authoritative value. */
240
+ function narrowToLimits(raw: number | undefined, slug: string, input: NativeContextLimitsInput): number | undefined {
241
+ if (raw === undefined) return undefined;
242
+ const limits = asLimits(input);
243
+ const overlay = positiveInt(limits.modelWindows?.[slug]) ?? positiveInt(limits.providerWindow);
244
+ const cap = positiveInt(limits.cap);
245
+ if (NATIVE_GPT56_FAMILY.has(slug)) {
246
+ const ceiling = NATIVE_GPT56_MAX_INPUT_TOKENS;
247
+ const chosen = overlay ?? cap ?? raw;
248
+ const window = Math.min(chosen, ceiling);
249
+ return overlay !== undefined && cap !== undefined ? Math.min(window, cap) : window;
250
+ }
251
+ const narrowed = overlay === undefined ? raw : Math.min(raw, overlay);
252
+ // 922k is the GPT-5.6 1M opt-in, not a request to shrink gpt-5.4's 1M window.
253
+ if (cap === NATIVE_GPT56_MAX_INPUT_TOKENS) return narrowed;
254
+ return applyProviderContextCap(narrowed, cap) ?? narrowed;
255
+ }
256
+
257
+ export function nativeOpenAiContextWindow(slug: string, limits?: NativeContextLimitsInput): number | undefined {
258
+ const raw = NATIVE_OPENAI_CONTEXT_OVERRIDES[slug]?.contextWindow
259
+ ?? (typeof PINNED_NATIVE_CAPABILITY_ENTRIES.get(slug)?.context_window === "number"
260
+ ? PINNED_NATIVE_CAPABILITY_ENTRIES.get(slug)!.context_window as number
71
261
  : undefined);
262
+ return narrowToLimits(raw, slug, limits);
263
+ }
264
+
265
+ /**
266
+ * Largest input a native slug accepts, or undefined when no separate limit is known
267
+ * (the caller then falls back to the context window).
268
+ *
269
+ * A provider context cap lowers this too: a capped 272k window must not keep advertising a
270
+ * 922k input ceiling, or the cap would be cosmetic on every input-side surface.
271
+ */
272
+ export function nativeOpenAiMaxInputTokens(slug: string, limits?: NativeContextLimitsInput): number | undefined {
273
+ const raw = NATIVE_OPENAI_CONTEXT_OVERRIDES[slug]?.maxInputTokens;
274
+ if (raw === undefined) return undefined;
275
+ const window = nativeOpenAiContextWindow(slug, limits);
276
+ const narrowed = narrowToLimits(raw, slug, limits) ?? raw;
277
+ return window === undefined ? narrowed : Math.min(narrowed, window);
72
278
  }
73
279
 
74
280
  export function nativeInputModalities(slug: string): string[] {
75
- const upstream = UPSTREAM_NATIVE_ENTRIES.get(slug);
281
+ const upstream = PINNED_NATIVE_CAPABILITY_ENTRIES.get(slug);
76
282
  if (Array.isArray(upstream?.input_modalities) && upstream!.input_modalities!.length > 0) {
77
283
  return [...upstream!.input_modalities as string[]];
78
284
  }
@@ -82,7 +288,7 @@ export function nativeInputModalities(slug: string): string[] {
82
288
  }
83
289
 
84
290
  export function nativeReasoningEfforts(slug: string): string[] {
85
- const upstream = UPSTREAM_NATIVE_ENTRIES.get(slug);
291
+ const upstream = PINNED_NATIVE_CAPABILITY_ENTRIES.get(slug);
86
292
  const levels = Array.isArray(upstream?.supported_reasoning_levels)
87
293
  ? upstream!.supported_reasoning_levels as Array<{ effort?: string }>
88
294
  : [];
@@ -97,12 +303,18 @@ export function nativeReasoningEfforts(slug: string): string[] {
97
303
 
98
304
  /** Upstream-pinned default for a native slug, when present and non-empty. */
99
305
  export function nativeDefaultReasoningEffort(slug: string): string | undefined {
100
- const level = UPSTREAM_NATIVE_ENTRIES.get(slug)?.default_reasoning_level;
306
+ const level = PINNED_NATIVE_CAPABILITY_ENTRIES.get(slug)?.default_reasoning_level;
101
307
  return typeof level === "string" && level.length > 0 ? level : undefined;
102
308
  }
103
309
 
310
+ /** Upstream-pinned multi-agent surface for a supported native slug, when present. */
311
+ export function nativeMultiAgentVersion(slug: string): string | undefined {
312
+ const version = PINNED_NATIVE_CAPABILITY_ENTRIES.get(slug)?.multi_agent_version;
313
+ return typeof version === "string" && version.length > 0 ? version : undefined;
314
+ }
315
+
104
316
  export function nativeParallelToolCalls(slug: string): boolean {
105
- return UPSTREAM_NATIVE_ENTRIES.get(slug)?.supports_parallel_tool_calls === true
317
+ return PINNED_NATIVE_CAPABILITY_ENTRIES.get(slug)?.supports_parallel_tool_calls === true
106
318
  || false;
107
319
  }
108
320
 
@@ -116,40 +328,145 @@ export function disabledNativeSlugs(config: Pick<OcxConfig, "disabledModels">):
116
328
  return new Set((config.disabledModels ?? []).filter(id => !id.includes("/")));
117
329
  }
118
330
 
119
- export function visibleNativeSlugs(config: Pick<OcxConfig, "disabledModels">): string[] {
331
+ export function visibleNativeSlugs(config: Pick<OcxConfig, "disabledModels" | "combos">): string[] {
120
332
  const disabled = disabledNativeSlugs(config);
121
- return nativeOpenAiSlugs().filter(slug => !disabled.has(slug));
333
+ const shadowed = configuredNativeAliasSlugs(config);
334
+ return nativeOpenAiSlugs().filter(slug => !disabled.has(slug) && !shadowed.has(slug));
335
+ }
336
+
337
+ /** Whether an enabled canonical OpenAI provider can serve exact account-qualified routes. */
338
+ export function shouldIncludeAccountBoundNativeOpenAi(
339
+ config: Pick<OcxConfig, "providers">,
340
+ ): boolean {
341
+ const provider = config.providers[OPENAI_CODEX_PROVIDER_ID];
342
+ if (!provider || provider.disabled === true) return false;
343
+ // Registry routing defaults an omitted authMode on the built-in OpenAI row to forward.
344
+ const canonical = provider.authMode === undefined
345
+ ? { ...provider, authMode: "forward" as const }
346
+ : provider;
347
+ return isCanonicalOpenAiForwardProvider(canonical);
348
+ }
349
+
350
+ /** Whether native ChatGPT/Codex rows belong in this provider configuration. */
351
+ export function shouldIncludeNativeOpenAi(config: Pick<OcxConfig, "providers">): boolean {
352
+ const hasEnabledProvider = Object.values(config.providers)
353
+ .some(provider => provider.disabled !== true);
354
+ // Preserve the existing no-enabled-provider catalog bootstrap, but do not use that bootstrap
355
+ // exception for account-qualified rows: exact-account routing requires a live OpenAI provider.
356
+ return !hasEnabledProvider || shouldIncludeAccountBoundNativeOpenAi(config);
357
+ }
358
+
359
+ type AccountSelectorConfig = Pick<
360
+ OcxConfig,
361
+ "codexAccounts" | "codexAccountNamespaces" | "codexAccountPickerEnabled"
362
+ >;
363
+
364
+ function mainAccountSelectors(config: AccountSelectorConfig): string[] {
365
+ const targets = new Map(codexAccountNamespaceEntries(config));
366
+ return visibleCodexAccountSelectors(config).filter(selector =>
367
+ isMainCodexAccountTarget(targets.get(selector) ?? ""));
122
368
  }
123
369
 
124
370
  /** Native slugs exposed to Claude Desktop show/export/apply (opt-out via claudeCode.desktopNativeModels). */
125
- export function desktopVisibleNativeSlugs(config: Pick<OcxConfig, "claudeCode" | "disabledModels">): string[] {
371
+ export function desktopVisibleNativeSlugs(
372
+ config: Pick<OcxConfig, "claudeCode" | "disabledModels" | "combos" | "providers"
373
+ | "codexAccounts" | "codexAccountNamespaces" | "codexAccountPickerEnabled">,
374
+ ): string[] {
126
375
  if (config.claudeCode?.desktopNativeModels === false) return [];
127
- return visibleNativeSlugs(config);
376
+ const visible = visibleNativeSlugs(config);
377
+ if (!shouldIncludeAccountBoundNativeOpenAi(config)) return visible;
378
+ const qualified = [...accountBoundNativeOpenAiSlugsBySelector(config).entries()].flatMap(([selector, slugs]) =>
379
+ slugs
380
+ .filter(slug => !SUPPORTED_NATIVE_OPENAI_SLUGS.has(slug))
381
+ .map(slug => `${selector}/${slug}`),
382
+ );
383
+ const disabled = new Set(config.disabledModels ?? []);
384
+ return unique([
385
+ ...visible,
386
+ ...qualified.filter(slug => !disabled.has(slug) && !disabled.has(slug.slice(slug.indexOf("/") + 1))),
387
+ ]);
128
388
  }
129
389
 
130
- export function nativeModelRows(config: Pick<OcxConfig, "disabledModels">): Array<{ slug: string; disabled: boolean; contextWindow?: number }> {
390
+ export function nativeModelRows(config: Pick<OcxConfig, "disabledModels" | "combos" | "providerContextCaps" | "providers">): Array<{ slug: string; disabled: boolean; contextWindow?: number; maxInputTokens?: number }> {
131
391
  const disabled = disabledNativeSlugs(config);
132
- return NATIVE_OPENAI_MODELS.map(slug => {
133
- const contextWindow = nativeOpenAiContextWindow(slug);
134
- return { slug, disabled: disabled.has(slug), ...(contextWindow !== undefined ? { contextWindow } : {}) };
392
+ const shadowed = configuredNativeAliasSlugs(config);
393
+ // Both user levers, not just the cap: a per-model window set from the dashboard has to show
394
+ // up on the row the dashboard itself renders.
395
+ const limits = nativeContextLimits(config);
396
+ const bareEligibleAccountIds = providerCodexAccountMode(
397
+ OPENAI_CODEX_PROVIDER_ID,
398
+ config.providers?.[OPENAI_CODEX_PROVIDER_ID],
399
+ ) === "direct" ? new Set([MAIN_CODEX_ACCOUNT_ID]) : undefined;
400
+ const availableGated = cachedAvailableAccountGatedNativeModels(Date.now(), bareEligibleAccountIds);
401
+ return NATIVE_OPENAI_MODELS
402
+ .filter(slug => !ACCOUNT_GATED_NATIVE_OPENAI_MODELS.has(slug) || availableGated.has(slug))
403
+ .filter(slug => !shadowed.has(slug)).map(slug => {
404
+ const contextWindow = nativeOpenAiContextWindow(slug, limits);
405
+ const maxInputTokens = nativeOpenAiMaxInputTokens(slug, limits);
406
+ return {
407
+ slug,
408
+ disabled: disabled.has(slug),
409
+ ...(contextWindow !== undefined ? { contextWindow } : {}),
410
+ ...(maxInputTokens !== undefined ? { maxInputTokens } : {}),
411
+ };
135
412
  });
136
413
  }
137
414
 
138
- export function applyNativeVisibility(entries: RawEntry[], disabledNative: Set<string>): RawEntry[] {
415
+ export function applyNativeVisibility(
416
+ entries: RawEntry[],
417
+ disabledModels: ReadonlySet<string>,
418
+ hideBareNative = false,
419
+ observedNativeSlugs: ReadonlySet<string> = new Set(),
420
+ ): RawEntry[] {
139
421
  for (const entry of entries) {
422
+ if (isNativeAliasCatalogEntry(entry)) continue;
140
423
  const slug = typeof entry.slug === "string" ? entry.slug : "";
141
- if (!slug || slug.includes("/") || !SUPPORTED_NATIVE_OPENAI_SLUGS.has(slug)) continue;
142
- entry.visibility = disabledNative.has(slug) ? "hide" : "list";
424
+ const accountBoundSlug = trustedAccountBoundNativeCatalogSlug(entry);
425
+ const nativeSlug = accountBoundSlug ?? slug;
426
+ if (!nativeSlug
427
+ || (!accountBoundSlug && slug.includes("/"))
428
+ || (!SUPPORTED_NATIVE_OPENAI_SLUGS.has(nativeSlug) && !observedNativeSlugs.has(nativeSlug))) continue;
429
+ const disabled = disabledModels.has(nativeSlug)
430
+ || (accountBoundSlug !== undefined && disabledModels.has(slug));
431
+ entry.visibility = disabled || (!accountBoundSlug && hideBareNative)
432
+ ? "hide"
433
+ : "list";
143
434
  }
144
435
  return entries;
145
436
  }
146
437
 
438
+ function upstreamNativeEntryForSlug(slug: string): RawEntry | undefined {
439
+ const sourceSlug = nativeOpenAiCapabilitySourceSlug(slug);
440
+ if (!sourceSlug.startsWith("gpt-5.6-")) return undefined;
441
+ const source = PINNED_UPSTREAM_MODELS.get(sourceSlug);
442
+ if (!source) return undefined;
443
+ if (slug === sourceSlug) return source;
444
+
445
+ const alias = structuredClone(source) as RawEntry;
446
+ alias.slug = slug;
447
+ alias.display_name = "Daybreak Blue";
448
+ alias.description = "Frontier general-purpose model with safeguards for defensive cybersecurity work.";
449
+ if (typeof alias.base_instructions === "string") {
450
+ alias.base_instructions = identifyRoutedModel(alias.base_instructions, slug);
451
+ }
452
+ if (alias.model_messages && typeof alias.model_messages === "object" && !Array.isArray(alias.model_messages)) {
453
+ const modelMessages = alias.model_messages as Record<string, unknown>;
454
+ if (typeof modelMessages.instructions_template === "string") {
455
+ alias.model_messages = {
456
+ ...modelMessages,
457
+ instructions_template: identifyRoutedModel(modelMessages.instructions_template, slug),
458
+ };
459
+ }
460
+ }
461
+ delete alias.availability_nux;
462
+ return alias;
463
+ }
464
+
147
465
  export const UPSTREAM_NATIVE_ENTRIES: Map<string, RawEntry> = new Map(
148
- ((upstreamModelsSnapshot as unknown as { models?: RawEntry[] }).models ?? [])
149
- .filter(m => typeof m.slug === "string"
150
- && SUPPORTED_NATIVE_OPENAI_SLUGS.has(m.slug as string)
151
- && (m.slug as string).startsWith("gpt-5.6-"))
152
- .map(m => [m.slug as string, m]),
466
+ [...NATIVE_OPENAI_MODELS, ...NATIVE_OPENAI_CAPABILITY_ALIAS_MODELS].flatMap(slug => {
467
+ const entry = upstreamNativeEntryForSlug(slug);
468
+ return entry ? [[slug, entry] as const] : [];
469
+ }),
153
470
  );
154
471
 
155
472
  export function upstreamNativeEntry(slug: string): RawEntry | null {
@@ -167,14 +484,181 @@ export function shouldUpgradeToUpstreamEntry(entry: RawEntry): boolean {
167
484
  }
168
485
 
169
486
  export function nativeOpenAiSlugs(): string[] {
170
- const live = listCatalogNativeSlugs();
171
- return live.length > 0 ? unique([...live, ...DOCUMENTED_NATIVE_OPENAI_ADDITIONS]) : NATIVE_OPENAI_MODELS;
487
+ const live = catalogNativeSlugs();
488
+ const availableGated = cachedAvailableAccountGatedNativeModels();
489
+ const candidates = live.length > 0 ? unique([...live, ...DOCUMENTED_NATIVE_OPENAI_ADDITIONS]) : NATIVE_OPENAI_MODELS;
490
+ return candidates.filter(slug => (
491
+ !ACCOUNT_GATED_NATIVE_OPENAI_MODELS.has(slug) || availableGated.has(slug)
492
+ ));
172
493
  }
173
494
 
174
- export function listCatalogNativeSlugs(): string[] {
495
+ const ACCOUNT_BOUND_OPENAI_NATIVE_PREFIX = /^(?:gpt-|o1-|o3-|o4-)/;
496
+ const ACCOUNT_BOUND_OBSERVED_NATIVE_MARKER = "opencodex_account_observed_native";
497
+ const ACCOUNT_BOUND_OBSERVED_SELECTORS_MARKER = "opencodex_account_observed_selectors";
498
+
499
+ function isAccountBoundOpenAiNativeSlug(slug: string): boolean {
500
+ return !slug.includes("/") && ACCOUNT_BOUND_OPENAI_NATIVE_PREFIX.test(slug);
501
+ }
502
+
503
+ /**
504
+ * Shape/plausibility filter for a candidate account-native row. **This is not a trust control.**
505
+ *
506
+ * It checks that a row carries the field shape a real Codex catalog row has, which rejects
507
+ * malformed and minimal hand-written rows. It cannot distinguish a genuine upstream observation
508
+ * from a complete row typed by hand into `$CODEX_HOME/models_cache.json`: there is no signature,
509
+ * source identity, or server attestation to check. A full-shape forged row is accepted, and
510
+ * `observedFullShapeRowIsAccepted` in tests/native-model-toggle.test.ts pins that so nobody
511
+ * later mistakes this predicate for a security boundary.
512
+ *
513
+ * That is acceptable here because the file is user-owned and written by Codex itself: anyone
514
+ * able to rewrite it can already edit `config.json` or run `ocx` directly, and `router.ts`
515
+ * accepts any bare `gpt-*` id under an account namespace regardless of this catalog. What the
516
+ * filter buys is that garbage rows do not get advertised through discovery — not that an
517
+ * advertised row is proven genuine.
518
+ */
519
+ function hasNativeCatalogRowShape(entry: RawEntry): boolean {
520
+ const levels = entry.supported_reasoning_levels;
521
+ const messages = entry.model_messages;
522
+ return typeof entry.base_instructions === "string"
523
+ && entry.base_instructions.length > 0
524
+ && (typeof entry.comp_hash === "string" || entry.comp_hash === null)
525
+ && entry.shell_type === "shell_command"
526
+ && Array.isArray(levels)
527
+ && levels.length > 0
528
+ && levels.every(level => typeof level === "object" && level !== null
529
+ && typeof (level as { effort?: unknown }).effort === "string")
530
+ && typeof messages === "object"
531
+ && messages !== null
532
+ && !Array.isArray(messages);
533
+ }
534
+
535
+ function observedAccountBoundNativeSlug(entry: RawEntry): string | undefined {
536
+ const accountBound = trustedAccountBoundNativeCatalogSlug(entry);
537
+ const slug = accountBound ?? (typeof entry.slug === "string" ? entry.slug : "");
538
+ if (!isAccountBoundOpenAiNativeSlug(slug)
539
+ || entry.supported_in_api !== true
540
+ || !hasNativeCatalogRowShape(entry)
541
+ || (entry.visibility !== "list" && entry[ACCOUNT_BOUND_OBSERVED_NATIVE_MARKER] !== true)) {
542
+ return undefined;
543
+ }
544
+ return slug;
545
+ }
546
+
547
+ /**
548
+ * Return exact, previously observed account-native rows that are not in the static release set.
549
+ * The result is used only to carry a hidden observation across startup cache invalidation.
550
+ */
551
+ export function observedAccountBoundNativeEntries(
552
+ observedEntries: readonly RawEntry[],
553
+ ): RawEntry[] {
554
+ const seen = new Set<string>();
555
+ return observedEntries.flatMap(entry => {
556
+ const slug = observedAccountBoundNativeSlug(entry);
557
+ // Only carry bare upstream observations across cache replacement. Account-qualified rows are
558
+ // already a projection of the current selector map and must not preserve private/stale labels.
559
+ if (!slug
560
+ || typeof entry.slug !== "string"
561
+ || entry.slug.includes("/")
562
+ || SUPPORTED_NATIVE_OPENAI_SLUGS.has(slug)
563
+ || seen.has(slug)) return [];
564
+ seen.add(slug);
565
+ return [structuredClone(entry)];
566
+ });
567
+ }
568
+
569
+ /**
570
+ * Native ids observed in the user's Codex catalog/cache for account-qualified discovery.
571
+ *
572
+ * Unknown ids are deliberately returned only to callers that build selector-qualified rows. The
573
+ * static bare set remains the source of truth for global/API-key discovery, while this preserves
574
+ * exact account-scoped ids such as `gpt-daybreak-blue-latest` until the static set catches up.
575
+ */
576
+ export function accountBoundNativeOpenAiSlugs(
577
+ observedEntries: readonly RawEntry[] = [
578
+ ...(readCurrentCodexModelsCache()?.models ?? []),
579
+ // Existing generated rows are also safe to reuse after a process starts without a cache
580
+ // invalidation pass; bare user-authored catalog rows are intentionally not trusted here.
581
+ ...(readCurrentCodexCatalog()?.models ?? []).filter(entry =>
582
+ trustedAccountBoundNativeCatalogSlug(entry) !== undefined),
583
+ ],
584
+ ): string[] {
585
+ const observed = observedEntries.flatMap(entry => {
586
+ const slug = observedAccountBoundNativeSlug(entry);
587
+ return slug === undefined ? [] : [slug];
588
+ });
589
+ return unique([...NATIVE_OPENAI_MODELS, ...observed]);
590
+ }
591
+
592
+ /**
593
+ * Resolve account-native ids per public selector. Bare observations come from Codex's main
594
+ * catalog/cache, so they are eligible only for selectors that target the main account. A
595
+ * generated qualified row carries its own selector and never gets copied to an unrelated pool
596
+ * account. An explicit observation marker is public selector metadata only; private account ids
597
+ * never enter the catalog or cache.
598
+ */
599
+ export function accountBoundNativeOpenAiSlugsBySelector(
600
+ config: AccountSelectorConfig,
601
+ observedEntries: readonly RawEntry[] = [
602
+ ...(readCurrentCodexModelsCache()?.models ?? []),
603
+ ...(readCurrentCodexCatalog()?.models ?? []).filter(entry =>
604
+ trustedAccountBoundNativeCatalogSlug(entry) !== undefined),
605
+ ],
606
+ ): ReadonlyMap<string, readonly string[]> {
607
+ const selectors = visibleCodexAccountSelectors(config);
608
+ const mainSelectors = new Set(mainAccountSelectors(config));
609
+ const result = new Map<string, Set<string>>(
610
+ selectors.map(selector => [selector, new Set(NATIVE_OPENAI_MODELS)]),
611
+ );
612
+ for (const entry of observedEntries) {
613
+ const slug = observedAccountBoundNativeSlug(entry);
614
+ if (slug === undefined || SUPPORTED_NATIVE_OPENAI_SLUGS.has(slug)) continue;
615
+ const generated = trustedAccountBoundNativeCatalogSlug(entry);
616
+ const generatedSelector = generated === undefined || typeof entry.slug !== "string"
617
+ ? undefined
618
+ : entry.slug.slice(0, entry.slug.indexOf("/"));
619
+ const markedSelectors = Array.isArray(entry[ACCOUNT_BOUND_OBSERVED_SELECTORS_MARKER])
620
+ ? entry[ACCOUNT_BOUND_OBSERVED_SELECTORS_MARKER].filter((value): value is string => typeof value === "string")
621
+ : [];
622
+ const eligible = generatedSelector !== undefined
623
+ ? (mainSelectors.has(generatedSelector) ? [generatedSelector] : [])
624
+ : markedSelectors.length > 0
625
+ ? markedSelectors.filter(selector => mainSelectors.has(selector))
626
+ : [...mainSelectors];
627
+ for (const selector of eligible) {
628
+ const rows = result.get(selector);
629
+ if (rows) rows.add(slug);
630
+ }
631
+ }
632
+ return new Map([...result.entries()].map(([selector, slugs]) => [selector, [...slugs]]));
633
+ }
634
+
635
+ /** Unknown native ids observed from Codex, excluding the static release set. */
636
+ export function observedAccountBoundNativeOpenAiSlugs(
637
+ observedEntries?: readonly RawEntry[],
638
+ ): string[] {
639
+ const all = accountBoundNativeOpenAiSlugs(observedEntries);
640
+ return all.filter(slug => !SUPPORTED_NATIVE_OPENAI_SLUGS.has(slug));
641
+ }
642
+
643
+ function catalogNativeSlugs(): string[] {
175
644
  const cat = readCurrentCatalogOrCache();
176
- const live = filterSupportedNativeSlugs(cat?.models ?? []);
645
+ const models = cat?.models ?? [];
646
+ const live = models.flatMap(entry => {
647
+ const slug = typeof entry.slug === "string" ? entry.slug : "";
648
+ return !slug.includes("/") && SUPPORTED_NATIVE_OPENAI_SLUGS.has(slug) ? [slug] : [];
649
+ });
650
+ const accountBound = models.flatMap(entry => {
651
+ const slug = trustedAccountBoundNativeCatalogSlug(entry);
652
+ return slug !== undefined && SUPPORTED_NATIVE_OPENAI_SLUGS.has(slug) ? [slug] : [];
653
+ });
654
+ // Deliberately ignore `visibility`: it is a rendered projection of disabledModels and account
655
+ // selectors, so treating it as fresh availability would shrink the supported set between syncs.
656
+ // visibleNativeSlugs applies the current disabledModels source of truth for public consumers.
657
+ return unique([...live, ...accountBound]);
658
+ }
659
+
660
+ export function listCatalogNativeSlugs(): string[] {
177
661
  // Ensure documented additions (e.g. gpt-5.3-codex-spark) appear even when the bundled catalog
178
662
  // predates the slug — mirrors nativeOpenAiSlugs() which already merges them for /v1/models.
179
- return unique([...live, ...DOCUMENTED_NATIVE_OPENAI_ADDITIONS]);
663
+ return unique([...catalogNativeSlugs(), ...DOCUMENTED_NATIVE_OPENAI_ADDITIONS]);
180
664
  }