@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
@@ -9,17 +9,19 @@ import { buildModelsRequest, resolveModelsAuthToken } from "../../oauth";
9
9
  import type { OcxConfig, OcxProviderConfig } from "../../types";
10
10
  import { modelInList } from "../../types";
11
11
  import { CODEX_REASONING_LEVELS, codexEffortRank, configuredReasoningEfforts, modelRecordValue, sanitizeCodexReasoningEfforts } from "../../reasoning-effort";
12
- import { getJawcodeModelMetadata, getJawcodeModelMetadataCaseInsensitive, listJawcodeModelMetadata, resolveJawcodeProvider } from "../../generated/jawcode-model-metadata";
12
+ import { getModelMetadata, getModelMetadataCaseInsensitive, listModelMetadata, resolveMetadataProvider } from "../../generated/model-metadata";
13
13
  import { enrichProviderFromRegistry, shouldCaseFoldMetadataModelId } from "../../providers/derive";
14
14
  import { getProviderRegistryEntry } from "../../providers/registry";
15
15
  import { applyProviderContextCap, providerContextCap } from "../../providers/context-cap";
16
- import { routedSlug, slugEquals, slugsEquivalent } from "../../providers/slug-codec";
16
+ import { clampAutoCompactTokenLimit } from "../../providers/auto-compact-budget";
17
+ import { routedSlug, slugEquals, slugEquivalenceKey, slugsEquivalent } from "../../providers/slug-codec";
17
18
  import { CODEX_GPT5_IDENTITY_LINE } 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";
21
22
  import {
22
23
  COMBO_NAMESPACE,
24
+ comboDisabledModelSelectors,
23
25
  comboModelId,
24
26
  getCombo,
25
27
  listComboIds,
@@ -128,16 +130,41 @@ export function deriveComboCatalogModel(
128
130
  ): CatalogModel | null {
129
131
  if (comboCatalogOmissionReason(combo, members) !== null) return null;
130
132
 
131
- const inputModalities = intersectStrings(
133
+ const derivedInputModalities = intersectStrings(
132
134
  members.map(member => member.inputModalities ?? ["text"]),
133
135
  );
134
- const reasoningEfforts = intersectStrings(
135
- members.map(member => member.reasoningEfforts ?? []),
136
- );
136
+ const inputModalities = combo.imageInput === "disabled"
137
+ ? derivedInputModalities.filter(modality => modality !== "image")
138
+ : derivedInputModalities;
139
+ if (inputModalities.length === 0) return null;
140
+ // Unknown ladders (`undefined`) are wildcards for catalog derivation — same
141
+ // boundary as the GUI picker. An explicit empty ladder still constrains.
142
+ const advertisedLadders = members
143
+ .map(member => member.reasoningEfforts)
144
+ .filter((ladder): ladder is string[] => ladder !== undefined);
145
+ const reasoningEfforts = advertisedLadders.length === 0
146
+ ? []
147
+ : intersectStrings(advertisedLadders);
137
148
  const contextWindow = Math.min(...members.map(member => member.contextWindow!));
149
+ const limitingMembers = members.filter(member => member.contextWindow === contextWindow);
150
+ const hasLimitingContextCapMetadata = limitingMembers.some(
151
+ member => typeof member.contextCapped === "boolean",
152
+ );
153
+ // A combo is cap-limited only when every member defining its effective minimum was
154
+ // itself reduced by a provider cap. An uncapped member at the same minimum means the
155
+ // combo would have the same window even without the cap.
156
+ const contextCapped = limitingMembers.every(member => member.contextCapped === true);
138
157
  const maxInputTokens = Math.min(
158
+ contextWindow,
139
159
  ...members.map(member => member.maxInputTokens ?? member.contextWindow!),
140
160
  );
161
+ const autoCompactTokenLimit = Math.min(
162
+ ...members.map(member => clampAutoCompactTokenLimit(
163
+ member.contextWindow!,
164
+ member.maxInputTokens,
165
+ member.autoCompactTokenLimit,
166
+ )),
167
+ );
141
168
  const defaultReasoningEffort = effectiveComboDefault(
142
169
  combo.defaultEffort,
143
170
  reasoningEfforts,
@@ -149,14 +176,32 @@ export function deriveComboCatalogModel(
149
176
  owned_by: COMBO_NAMESPACE,
150
177
  contextWindow,
151
178
  maxInputTokens,
179
+ autoCompactTokenLimit,
180
+ ...(hasLimitingContextCapMetadata ? { contextCapped } : {}),
152
181
  inputModalities,
153
182
  reasoningEfforts,
154
183
  ...(combo.alias ? { alias: combo.alias } : {}),
184
+ ...(combo.nativeAlias ? { nativeAlias: true } : {}),
185
+ ...(combo.displayName ? { displayName: combo.displayName } : {}),
155
186
  ...(defaultReasoningEffort ? { defaultReasoningEffort } : {}),
156
187
  ...(members.every(member => member.parallelToolCalls === true)
157
188
  ? { parallelToolCalls: true }
158
189
  : {}),
190
+ ...(members.every(member => member.supportsServiceTier === true)
191
+ ? { supportsServiceTier: true }
192
+ : members.some(member => member.supportsServiceTier === false)
193
+ ? { supportsServiceTier: false }
194
+ : {}),
159
195
  ...(members.some(member => member.supportsReasoningSummaries === false) ? { supportsReasoningSummaries: false } : {}),
196
+ // A combo is only as capable as its least capable member. One member that cannot honour
197
+ // text.verbosity is enough to make the control a no-op for the whole combo, so the
198
+ // conservative false propagates — the same rule supportsReasoningSummaries uses above.
199
+ // Without this, routing a combo through an xAI or Kiro member re-advertised a control the
200
+ // upstream accepts and ignores.
201
+ ...(members.some(member => member.supportsVerbosity === false) ? { supportsVerbosity: false } : {}),
202
+ ...(members.every(member => member.codexToolMode === "shell")
203
+ ? { codexToolMode: "shell" as const }
204
+ : {}),
160
205
  };
161
206
  }
162
207
 
@@ -181,6 +226,7 @@ export function comboCatalogWarningSignature(
181
226
  key,
182
227
  contextWindow: member?.contextWindow ?? null,
183
228
  maxInputTokens: member?.maxInputTokens ?? null,
229
+ autoCompactTokenLimit: member?.autoCompactTokenLimit ?? null,
184
230
  inputModalities: [...new Set(member?.inputModalities ?? [])].sort(),
185
231
  reasoningEfforts: [...new Set(member?.reasoningEfforts ?? [])].sort(),
186
232
  parallelToolCalls: member?.parallelToolCalls === true,
@@ -252,12 +298,15 @@ export function exactComboCatalogSlugs(
252
298
  ): Set<string> {
253
299
  const disabled = new Set(config.disabledModels ?? []);
254
300
  return new Set(listComboIds(config).flatMap(id => {
255
- const alias = typeof config.combos?.[id]?.alias === "string"
256
- ? config.combos[id]!.alias!.trim()
301
+ const raw = config.combos?.[id];
302
+ const alias = typeof raw?.alias === "string"
303
+ ? raw.alias.trim()
257
304
  : "";
258
305
  const canonical = comboModelId(id);
259
306
  const publicSlug = alias || canonical;
260
- return disabled.has(publicSlug) || disabled.has(canonical) ? [] : [publicSlug];
307
+ const comboDisabled = comboDisabledModelSelectors(id, raw ?? {})
308
+ .some(selector => disabled.has(selector));
309
+ return comboDisabled ? [] : [publicSlug];
261
310
  }));
262
311
  }
263
312
 
@@ -267,6 +316,7 @@ export function normalizedOpenAiApiSignature(model: CatalogModel): string {
267
316
  id: model.id,
268
317
  contextWindow: model.contextWindow ?? null,
269
318
  maxInputTokens: model.maxInputTokens ?? null,
319
+ autoCompactTokenLimit: model.autoCompactTokenLimit ?? null,
270
320
  inputModalities: [...new Set(model.inputModalities ?? [])].sort(),
271
321
  reasoningEfforts: [...new Set(model.reasoningEfforts ?? [])].sort(),
272
322
  ownedBy: model.owned_by ?? null,
@@ -281,6 +331,10 @@ export function resetOpenAiApiCatalogWarningStateForTests(): void {
281
331
  export const slugAliasCollisionWarnings = new Set<string>();
282
332
 
283
333
  export const comboMasqueradeCollisionWarnings = new Set<string>();
334
+
335
+ export const comboUnrestorableShadowWarnings = new Set<string>();
336
+
337
+ export const accountSelectorShadowCollisionWarnings = new Set<string>();
284
338
  let lastWarningReconciledGeneration = 0;
285
339
 
286
340
  export function reconcileCatalogWarningMemos(generation: number): number {
@@ -288,11 +342,15 @@ export function reconcileCatalogWarningMemos(generation: number): number {
288
342
  const removed = openAiApiCollisionWarnings.size
289
343
  + comboCatalogWarningSignatures.size
290
344
  + slugAliasCollisionWarnings.size
291
- + comboMasqueradeCollisionWarnings.size;
345
+ + comboMasqueradeCollisionWarnings.size
346
+ + comboUnrestorableShadowWarnings.size
347
+ + accountSelectorShadowCollisionWarnings.size;
292
348
  openAiApiCollisionWarnings.clear();
293
349
  comboCatalogWarningSignatures.clear();
294
350
  slugAliasCollisionWarnings.clear();
295
351
  comboMasqueradeCollisionWarnings.clear();
352
+ comboUnrestorableShadowWarnings.clear();
353
+ accountSelectorShadowCollisionWarnings.clear();
296
354
  lastWarningReconciledGeneration = generation;
297
355
  return removed;
298
356
  }
@@ -305,6 +363,24 @@ export function warnComboMasqueradeCollisionOnce(slug: string): void {
305
363
  );
306
364
  }
307
365
 
366
+ export function warnComboUnrestorableShadowOnce(slug: string): void {
367
+ const key = slugEquivalenceKey(slug);
368
+ if (comboUnrestorableShadowWarnings.has(key)) return;
369
+ comboUnrestorableShadowWarnings.add(key);
370
+ console.warn(
371
+ `[opencodex] combo alias collision on "${safeCatalogWarningLabel(slug)}": the existing user-managed or foreign catalog row is retained because no pristine backup can restore it. Rename the combo alias to expose both models.`,
372
+ );
373
+ }
374
+
375
+ /** Warn once when a live provider row loses its reserved slug to an account selector. */
376
+ export function warnAccountSelectorShadowedProviderOnce(slug: string): void {
377
+ if (accountSelectorShadowCollisionWarnings.has(slug)) return;
378
+ accountSelectorShadowCollisionWarnings.add(slug);
379
+ console.warn(
380
+ `[opencodex] account selector collision on "${safeCatalogWarningLabel(slug)}": the account-bound native model wins and the shadowed provider model is omitted from the catalog. Rename the provider or account selector.`,
381
+ );
382
+ }
383
+
308
384
  export function resolveSlugAliasCollisions(goModels: CatalogModel[]): Set<CatalogModel> {
309
385
  const skipped = new Set<CatalogModel>();
310
386
  const winnerByAlias = new Map<string, CatalogModel>();
@@ -9,7 +9,7 @@ import { buildModelsRequest, resolveModelsAuthToken } from "../../oauth";
9
9
  import type { OcxConfig, OcxProviderConfig } from "../../types";
10
10
  import { modelInList } from "../../types";
11
11
  import { CODEX_REASONING_LEVELS, codexEffortRank, configuredReasoningEfforts, modelRecordValue, sanitizeCodexReasoningEfforts } from "../../reasoning-effort";
12
- import { getJawcodeModelMetadata, getJawcodeModelMetadataCaseInsensitive, listJawcodeModelMetadata, resolveJawcodeProvider } from "../../generated/jawcode-model-metadata";
12
+ import { getModelMetadata, getModelMetadataCaseInsensitive, listModelMetadata, resolveMetadataProvider } from "../../generated/model-metadata";
13
13
  import { enrichProviderFromRegistry, shouldCaseFoldMetadataModelId } from "../../providers/derive";
14
14
  import { getProviderRegistryEntry } from "../../providers/registry";
15
15
  import { applyProviderContextCap, providerContextCap } from "../../providers/context-cap";
@@ -34,28 +34,121 @@ import upstreamModelsSnapshot from "../data/upstream-models.json";
34
34
  import { activeCodexModelsCachePath, catalogBackupPathFor, findNativeTemplate, isDefaultCatalogPath, legacyCatalogBackupPath, parseCatalogJson, readCatalog, readCatalogBackup, readCodexCatalogPath } from "./parsing";
35
35
  import type { RawCatalog, RawEntry } from "./parsing";
36
36
  import { codexExecInvocation, isSpawnableCodexCandidate } from "../exec-invocation";
37
- import { resolveAndPersistCodexRuntime } from "../runtime";
38
- import type { EffortClampDiagnostic } from "../runtime";
37
+ import {
38
+ parsePersistedCodexRuntime,
39
+ peekCodexRuntimeProcessCache,
40
+ resolveAndPersistCodexRuntime,
41
+ } from "../runtime";
42
+ import type {
43
+ DeepReadonly,
44
+ EffortClampDiagnostic,
45
+ ResolvedCodexRuntime,
46
+ } from "../runtime";
47
+ import type {
48
+ CatalogGatherEvidenceSession,
49
+ CatalogGatherReadableSourceRole,
50
+ } from "./filesystem-evidence";
39
51
 
40
52
  export { isSpawnableCodexCandidate, codexExecInvocation } from "../exec-invocation";
53
+ export type {
54
+ CatalogGatherEvidenceSession,
55
+ CatalogGatherReadableSourceRole,
56
+ } from "./filesystem-evidence";
41
57
 
42
58
  export const BUNDLED_CATALOG_CACHE_MS = 60_000;
43
59
 
44
- export let bundledCatalogCache: {
60
+ export type ReadonlyRawCatalog = DeepReadonly<RawCatalog>;
61
+
62
+ interface BundledCatalogMemo {
45
63
  /** Selected runtime identity; must change when doctor/sync picks a different binary. */
46
- key: string;
47
- expiresAt: number;
48
- value: RawCatalog | null;
49
- } | null = null;
64
+ readonly key: string;
65
+ readonly expiresAt: number;
66
+ readonly epoch: number;
67
+ readonly valueIdentity: string;
68
+ readonly value: ReadonlyRawCatalog | null;
69
+ }
70
+
71
+ export interface BundledCatalogCacheState {
72
+ readonly epoch: number;
73
+ readonly valueIdentity: string | null;
74
+ }
75
+
76
+ let bundledCatalogEpoch = 0;
77
+ let bundledCatalogCache: BundledCatalogMemo | null = null;
78
+
79
+ function cloneAndDeepFreeze<T>(value: T): DeepReadonly<T> {
80
+ const clone = (current: unknown): unknown => {
81
+ if (Array.isArray(current)) return current.map(clone);
82
+ if (current && typeof current === "object") {
83
+ const out: Record<string, unknown> = {};
84
+ for (const [key, child] of Object.entries(current)) out[key] = clone(child);
85
+ return out;
86
+ }
87
+ return current;
88
+ };
89
+ const freeze = (current: unknown): unknown => {
90
+ if (!current || typeof current !== "object" || Object.isFrozen(current)) return current;
91
+ for (const child of Object.values(current)) freeze(child);
92
+ return Object.freeze(current);
93
+ };
94
+ return freeze(clone(value)) as DeepReadonly<T>;
95
+ }
96
+
97
+ function bundledRuntimeKey(
98
+ runtime: Pick<ResolvedCodexRuntime, "command" | "version">,
99
+ opencodexHome: string = process.env.OPENCODEX_HOME ?? "",
100
+ ): string {
101
+ return [runtime.command, runtime.version ?? "", opencodexHome].join("\0");
102
+ }
103
+
104
+ function publishBundledCatalogCache(
105
+ key: string,
106
+ expiresAt: number,
107
+ value: RawCatalog | null,
108
+ ): void {
109
+ const epoch = ++bundledCatalogEpoch;
110
+ bundledCatalogCache = {
111
+ key,
112
+ expiresAt,
113
+ epoch,
114
+ valueIdentity: `bundled:${epoch}`,
115
+ value: value === null ? null : cloneAndDeepFreeze(value),
116
+ };
117
+ }
118
+
119
+ function clearBundledCatalogCache(): void {
120
+ bundledCatalogEpoch += 1;
121
+ bundledCatalogCache = null;
122
+ }
123
+
124
+ export function bundledCatalogCacheState(): Readonly<BundledCatalogCacheState> {
125
+ return Object.freeze({
126
+ epoch: bundledCatalogEpoch,
127
+ valueIdentity: bundledCatalogCache?.valueIdentity ?? null,
128
+ });
129
+ }
50
130
 
51
131
  /** Test-only: clear the bundled-catalog cache (owned here; sync.ts calls this instead of assigning the import). */
52
132
  export function resetBundledCatalogCacheForTests(): void {
53
- bundledCatalogCache = null;
133
+ clearBundledCatalogCache();
54
134
  }
55
135
 
56
136
  /** Drop the process-local bundled catalog memo (e.g. after runtime selection changes). */
57
137
  export function invalidateBundledCatalogCache(): void {
58
- bundledCatalogCache = null;
138
+ clearBundledCatalogCache();
139
+ }
140
+
141
+ /** Test-only owner mutation seam; input is cloned and frozen before publication. */
142
+ export function setBundledCatalogCacheForTests(
143
+ runtime: Pick<ResolvedCodexRuntime, "command" | "version">,
144
+ value: RawCatalog | null,
145
+ options: Readonly<{ expiresAt?: number; opencodexHome?: string }> = {},
146
+ ): void {
147
+ publishBundledCatalogCache(
148
+ bundledRuntimeKey(runtime, options.opencodexHome),
149
+ options.expiresAt ?? Date.now() + BUNDLED_CATALOG_CACHE_MS,
150
+ value,
151
+ );
59
152
  }
60
153
 
61
154
  export type ExecFile = (
@@ -143,7 +236,7 @@ export function runCodexDebugModels(
143
236
  });
144
237
  }
145
238
 
146
- export function loadBundledCodexCatalog(deps: BundledCatalogDeps = {}): RawCatalog | null {
239
+ export function loadBundledCodexCatalog(deps: BundledCatalogDeps = {}): ReadonlyRawCatalog | null {
147
240
  const useCache = !deps.commandCandidates && !deps.execFileSync && !deps.configDir && !deps.env;
148
241
  const execFile = deps.execFileSync ?? (execFileSync as unknown as ExecFile);
149
242
  // Prefer the single resolved runtime so sync/clamp never probe a different binary
@@ -168,11 +261,7 @@ export function loadBundledCodexCatalog(deps: BundledCatalogDeps = {}): RawCatal
168
261
  discoverAlternatives: deps.discoverAlternatives ?? false,
169
262
  });
170
263
  if (useCache) {
171
- cacheKey = [
172
- resolved.runtime.command,
173
- resolved.runtime.version ?? "",
174
- process.env.OPENCODEX_HOME ?? "",
175
- ].join("\0");
264
+ cacheKey = bundledRuntimeKey(resolved.runtime);
176
265
  }
177
266
  return [resolved.runtime.command];
178
267
  })();
@@ -183,33 +272,225 @@ export function loadBundledCodexCatalog(deps: BundledCatalogDeps = {}): RawCatal
183
272
  && bundledCatalogCache.key === cacheKey
184
273
  && bundledCatalogCache.expiresAt > Date.now()
185
274
  ) {
186
- return bundledCatalogCache.value;
275
+ return bundledCatalogCache.value === null
276
+ ? null
277
+ : cloneAndDeepFreeze(bundledCatalogCache.value);
187
278
  }
188
279
  for (const command of unique(candidates)) {
189
280
  try {
190
281
  const catalog = parseCatalogJson(runCodexDebugModels(command, execFile, deps));
191
282
  if (catalog && findNativeTemplate(catalog)) {
192
283
  if (useCache && cacheKey) {
193
- bundledCatalogCache = {
194
- key: cacheKey,
195
- expiresAt: Date.now() + BUNDLED_CATALOG_CACHE_MS,
196
- value: catalog,
197
- };
284
+ publishBundledCatalogCache(
285
+ cacheKey,
286
+ Date.now() + BUNDLED_CATALOG_CACHE_MS,
287
+ catalog,
288
+ );
289
+ return cloneAndDeepFreeze(bundledCatalogCache!.value!);
198
290
  }
199
- return catalog;
291
+ return cloneAndDeepFreeze(catalog);
200
292
  }
201
293
  } catch { /* try next candidate */ }
202
294
  }
203
295
  if (useCache && cacheKey) {
204
- bundledCatalogCache = {
205
- key: cacheKey,
206
- expiresAt: Date.now() + BUNDLED_CATALOG_CACHE_MS,
207
- value: null,
208
- };
296
+ publishBundledCatalogCache(
297
+ cacheKey,
298
+ Date.now() + BUNDLED_CATALOG_CACHE_MS,
299
+ null,
300
+ );
209
301
  }
210
302
  return null;
211
303
  }
212
304
 
305
+ export type CatalogGatherProcessLocalObservation =
306
+ | Readonly<{ state: "unused" }>
307
+ | Readonly<{ state: "used"; epoch: number; valueIdentity: string }>;
308
+
309
+ export type CodexRuntimeForCatalogGather =
310
+ | Readonly<{
311
+ kind: "available";
312
+ origin: "process-cache" | "persisted";
313
+ runtime: DeepReadonly<ResolvedCodexRuntime>;
314
+ processLocal: CatalogGatherProcessLocalObservation;
315
+ }>
316
+ | Readonly<{
317
+ kind: "runtime-unavailable";
318
+ processLocal: Readonly<{ state: "unused" }>;
319
+ }>;
320
+
321
+ export type CatalogSourceForGather =
322
+ | Readonly<{
323
+ kind: "available";
324
+ source:
325
+ | "bundled-catalog-template"
326
+ | "active-catalog-merge"
327
+ | "hashed-backup-fallback"
328
+ | "legacy-backup-fallback"
329
+ | "models-cache-fallback";
330
+ catalog: ReadonlyRawCatalog;
331
+ runtimeSupport:
332
+ | Readonly<{ kind: "available"; catalog: ReadonlyRawCatalog }>
333
+ | Readonly<{ kind: "unavailable" }>;
334
+ processLocal: Readonly<{
335
+ runtime: CatalogGatherProcessLocalObservation;
336
+ bundledCatalog: CatalogGatherProcessLocalObservation;
337
+ }>;
338
+ }>
339
+ | Readonly<{
340
+ kind: "catalog-unavailable";
341
+ processLocal: Readonly<{
342
+ runtime: Readonly<{ state: "unused" }>;
343
+ bundledCatalog: Readonly<{ state: "unused" }>;
344
+ }>;
345
+ }>;
346
+
347
+ export type CatalogGatherPathKind = "default" | "custom";
348
+
349
+ const UNUSED_PROCESS_LOCAL = Object.freeze({ state: "unused" as const });
350
+
351
+ function sameRuntimeIdentity(
352
+ left: Pick<ResolvedCodexRuntime, "command" | "version">,
353
+ right: Pick<ResolvedCodexRuntime, "command" | "version">,
354
+ ): boolean {
355
+ return left.command === right.command && (left.version ?? null) === (right.version ?? null);
356
+ }
357
+
358
+ /**
359
+ * Observe an already-resolved runtime only. The evidence owner supplies the
360
+ * exact persisted bytes (or observed absence); this path never probes or writes.
361
+ */
362
+ export function peekCodexRuntimeForCatalogGather(
363
+ evidenceSession: CatalogGatherEvidenceSession,
364
+ ): CodexRuntimeForCatalogGather {
365
+ const persistedBytes = evidenceSession.readSource("runtime-selection");
366
+ const persisted = persistedBytes === null
367
+ ? null
368
+ : parsePersistedCodexRuntime(persistedBytes);
369
+ const processMemo = peekCodexRuntimeProcessCache();
370
+
371
+ if (processMemo.kind === "available") {
372
+ const runtime = processMemo.value.runtime;
373
+ if (persistedBytes === null || (persisted && sameRuntimeIdentity(runtime, {
374
+ command: persisted.command,
375
+ version: persisted.selectedVersion ?? null,
376
+ }))) {
377
+ return cloneAndDeepFreeze({
378
+ kind: "available" as const,
379
+ origin: "process-cache" as const,
380
+ runtime,
381
+ processLocal: {
382
+ state: "used" as const,
383
+ epoch: processMemo.epoch,
384
+ valueIdentity: processMemo.valueIdentity,
385
+ },
386
+ });
387
+ }
388
+ }
389
+
390
+ if (persisted) {
391
+ return cloneAndDeepFreeze({
392
+ kind: "available" as const,
393
+ origin: "persisted" as const,
394
+ runtime: {
395
+ command: persisted.command,
396
+ version: persisted.selectedVersion ?? null,
397
+ source: persisted.source,
398
+ },
399
+ processLocal: UNUSED_PROCESS_LOCAL,
400
+ });
401
+ }
402
+
403
+ return Object.freeze({
404
+ kind: "runtime-unavailable" as const,
405
+ processLocal: UNUSED_PROCESS_LOCAL,
406
+ });
407
+ }
408
+
409
+ /**
410
+ * Resolve only already-observed catalog sources. A cold process cache falls
411
+ * through to evidence-owned persisted sources and never becomes probe authority.
412
+ */
413
+ export function resolveCatalogSourceForGather(
414
+ evidenceSession: CatalogGatherEvidenceSession,
415
+ pathKind: CatalogGatherPathKind,
416
+ ): CatalogSourceForGather {
417
+ const bundledMemo = bundledCatalogCache;
418
+ let runtimeSupport:
419
+ | Readonly<{ kind: "available"; catalog: ReadonlyRawCatalog }>
420
+ | Readonly<{ kind: "unavailable" }> = Object.freeze({ kind: "unavailable" });
421
+ let processLocal: Readonly<{
422
+ runtime: CatalogGatherProcessLocalObservation;
423
+ bundledCatalog: CatalogGatherProcessLocalObservation;
424
+ }> = {
425
+ runtime: UNUSED_PROCESS_LOCAL,
426
+ bundledCatalog: UNUSED_PROCESS_LOCAL,
427
+ };
428
+ if (bundledMemo?.value && bundledMemo.expiresAt > Date.now()) {
429
+ const runtime = peekCodexRuntimeForCatalogGather(evidenceSession);
430
+ if (runtime.kind === "available" && bundledMemo.key === bundledRuntimeKey(runtime.runtime)) {
431
+ runtimeSupport = Object.freeze({
432
+ kind: "available" as const,
433
+ catalog: bundledMemo.value,
434
+ });
435
+ processLocal = {
436
+ runtime: runtime.processLocal,
437
+ bundledCatalog: {
438
+ state: "used" as const,
439
+ epoch: bundledMemo.epoch,
440
+ valueIdentity: bundledMemo.valueIdentity,
441
+ },
442
+ };
443
+ if (pathKind === "default") {
444
+ return cloneAndDeepFreeze({
445
+ kind: "available" as const,
446
+ source: "bundled-catalog-template" as const,
447
+ catalog: bundledMemo.value,
448
+ runtimeSupport,
449
+ processLocal,
450
+ });
451
+ }
452
+ }
453
+ }
454
+
455
+ const roles = pathKind === "default"
456
+ ? [
457
+ "active-catalog-merge",
458
+ "hashed-backup-fallback",
459
+ "legacy-backup-fallback",
460
+ "models-cache-fallback",
461
+ ] as const
462
+ : [
463
+ "active-catalog-merge",
464
+ "hashed-backup-fallback",
465
+ "models-cache-fallback",
466
+ ] as const;
467
+ for (const role of roles) {
468
+ const bytes = evidenceSession.readSource(role);
469
+ if (bytes === null) continue;
470
+ const catalog = parseCatalogJson(Buffer.from(bytes).toString("utf8"));
471
+ if (!catalog) continue;
472
+ // Custom catalogs may intentionally contain only routed rows. Keep their existing source
473
+ // priority (active, then backup/cache) without imposing the default catalog's native-template
474
+ // requirement; a valid active custom file therefore remains authoritative over stale fallbacks.
475
+ if (pathKind === "default" && !findNativeTemplate(catalog)) continue;
476
+ return cloneAndDeepFreeze({
477
+ kind: "available" as const,
478
+ source: role,
479
+ catalog,
480
+ runtimeSupport,
481
+ processLocal,
482
+ });
483
+ }
484
+
485
+ return Object.freeze({
486
+ kind: "catalog-unavailable" as const,
487
+ processLocal: Object.freeze({
488
+ runtime: UNUSED_PROCESS_LOCAL,
489
+ bundledCatalog: UNUSED_PROCESS_LOCAL,
490
+ }),
491
+ });
492
+ }
493
+
213
494
  export function materializeBundledCodexCatalog(path: string, deps: BundledCatalogDeps = {}): RawCatalog | null {
214
495
  const catalog = loadBundledCodexCatalog(deps);
215
496
  if (!catalog) return null;
@@ -219,7 +500,7 @@ export function materializeBundledCodexCatalog(path: string, deps: BundledCatalo
219
500
  } catch {
220
501
  return null;
221
502
  }
222
- return catalog;
503
+ return JSON.parse(JSON.stringify(catalog)) as RawCatalog;
223
504
  }
224
505
 
225
506
  export function loadCatalogForSync(path: string): RawCatalog | null {
@@ -236,16 +517,33 @@ export function loadCatalogForSync(path: string): RawCatalog | null {
236
517
 
237
518
  export function readCurrentCatalogOrCache(): RawCatalog | null {
238
519
  const path = readCodexCatalogPath();
239
- return (isDefaultCatalogPath(path) ? loadBundledCodexCatalog() : null)
240
- ?? readCatalog(path)
241
- ?? readCatalog(activeCodexModelsCachePath());
520
+ const bundled = isDefaultCatalogPath(path) ? loadBundledCodexCatalog() : null;
521
+ if (bundled) return JSON.parse(JSON.stringify(bundled)) as RawCatalog;
522
+ return readCatalog(path) ?? readCatalog(activeCodexModelsCachePath());
523
+ }
524
+
525
+ /**
526
+ * Read the user-owned Codex catalog surfaces without substituting the bundled catalog.
527
+ *
528
+ * The bundled catalog is intentionally the authority for static native metadata on the default
529
+ * path. Account-qualified discovery needs the opposite view: an exact model id that Codex has
530
+ * observed in the user's catalog/cache may be account-scoped even when this release does not know
531
+ * it statically yet.
532
+ */
533
+ export function readCurrentCodexCatalog(): RawCatalog | null {
534
+ return readCatalog(readCodexCatalogPath());
535
+ }
536
+
537
+ export function readCurrentCodexModelsCache(): RawCatalog | null {
538
+ return readCatalog(activeCodexModelsCachePath());
242
539
  }
243
540
 
244
541
  export function loadCatalogTemplate(): RawEntry | null {
245
542
  const catalogPath = readCodexCatalogPath();
543
+ const bundled = loadBundledCodexCatalog();
246
544
  const native = findNativeTemplate(readCatalog(catalogPath))
247
545
  ?? findNativeTemplate(readCatalogBackup(catalogPath))
248
546
  ?? findNativeTemplate(readCatalog(activeCodexModelsCachePath()))
249
- ?? findNativeTemplate(loadBundledCodexCatalog());
547
+ ?? findNativeTemplate(bundled ? JSON.parse(JSON.stringify(bundled)) as RawCatalog : null);
250
548
  return native ? JSON.parse(JSON.stringify(native)) : null;
251
549
  }