@iislee/opencodex 2.11.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 (476) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +225 -0
  3. package/assets/architecture.png +0 -0
  4. package/assets/banner.png +0 -0
  5. package/assets/claude-code-models.gif +0 -0
  6. package/assets/codex-app-picker.png +0 -0
  7. package/bin/ocx.mjs +451 -0
  8. package/bin/package-main.mjs +9 -0
  9. package/gui/dist/assets/index-DTpMHS4F.js +67 -0
  10. package/gui/dist/assets/index-ZNVDE3C7.css +1 -0
  11. package/gui/dist/favicon.png +0 -0
  12. package/gui/dist/icons.svg +24 -0
  13. package/gui/dist/index.html +25 -0
  14. package/gui/dist/logo.png +0 -0
  15. package/gui/dist/provider-icons/alibaba-color.svg +1 -0
  16. package/gui/dist/provider-icons/antigravity-color.svg +1 -0
  17. package/gui/dist/provider-icons/antigravity.svg +1 -0
  18. package/gui/dist/provider-icons/claude-color.svg +1 -0
  19. package/gui/dist/provider-icons/claude.svg +1 -0
  20. package/gui/dist/provider-icons/cloudflare-ai-gateway-color.svg +1 -0
  21. package/gui/dist/provider-icons/copilot-color.svg +1 -0
  22. package/gui/dist/provider-icons/copilot.svg +1 -0
  23. package/gui/dist/provider-icons/cursor-color.svg +2 -0
  24. package/gui/dist/provider-icons/cursor.svg +2 -0
  25. package/gui/dist/provider-icons/deepseek-color.svg +1 -0
  26. package/gui/dist/provider-icons/discord.svg +1 -0
  27. package/gui/dist/provider-icons/firepass-color.svg +1 -0
  28. package/gui/dist/provider-icons/fireworks-color.svg +1 -0
  29. package/gui/dist/provider-icons/gemini-color.svg +1 -0
  30. package/gui/dist/provider-icons/gemini.svg +1 -0
  31. package/gui/dist/provider-icons/github-copilot-color.svg +1 -0
  32. package/gui/dist/provider-icons/gitlab-duo-color.svg +1 -0
  33. package/gui/dist/provider-icons/grok-color.svg +1 -0
  34. package/gui/dist/provider-icons/grok.svg +1 -0
  35. package/gui/dist/provider-icons/groq-color.svg +1 -0
  36. package/gui/dist/provider-icons/huggingface-color.svg +1 -0
  37. package/gui/dist/provider-icons/kimi-color.svg +1 -0
  38. package/gui/dist/provider-icons/kiro-color.svg +15 -0
  39. package/gui/dist/provider-icons/kiro.svg +14 -0
  40. package/gui/dist/provider-icons/lm-studio-color.svg +1 -0
  41. package/gui/dist/provider-icons/mistral-color.svg +1 -0
  42. package/gui/dist/provider-icons/moonshot-color.svg +1 -0
  43. package/gui/dist/provider-icons/nvidia-color.svg +1 -0
  44. package/gui/dist/provider-icons/ollama-color.svg +1 -0
  45. package/gui/dist/provider-icons/openai.svg +1 -0
  46. package/gui/dist/provider-icons/opencode.svg +1 -0
  47. package/gui/dist/provider-icons/openrouter-color.svg +1 -0
  48. package/gui/dist/provider-icons/pi.svg +21 -0
  49. package/gui/dist/provider-icons/qianfan-color.svg +1 -0
  50. package/gui/dist/provider-icons/qwen-portal-color.svg +1 -0
  51. package/gui/dist/provider-icons/telegram.svg +1 -0
  52. package/gui/dist/provider-icons/vercel-ai-gateway-color.svg +1 -0
  53. package/gui/dist/provider-icons/vllm-color.svg +1 -0
  54. package/gui/dist/provider-icons/xiaomi-color.svg +1 -0
  55. package/package.json +102 -0
  56. package/src/AGENTS.md +28 -0
  57. package/src/adapters/anthropic-image-guard.ts +251 -0
  58. package/src/adapters/anthropic-image-normalize.ts +518 -0
  59. package/src/adapters/anthropic.ts +1003 -0
  60. package/src/adapters/azure.ts +36 -0
  61. package/src/adapters/base.ts +72 -0
  62. package/src/adapters/client-fingerprint.ts +59 -0
  63. package/src/adapters/cursor/arg-codec.ts +38 -0
  64. package/src/adapters/cursor/arg-normalize.ts +104 -0
  65. package/src/adapters/cursor/cursor-errors.ts +165 -0
  66. package/src/adapters/cursor/discovery.ts +276 -0
  67. package/src/adapters/cursor/effort-map.ts +127 -0
  68. package/src/adapters/cursor/exec-policy.ts +88 -0
  69. package/src/adapters/cursor/framing.ts +211 -0
  70. package/src/adapters/cursor/gen/agent_pb.ts +15274 -0
  71. package/src/adapters/cursor/kv-store.ts +52 -0
  72. package/src/adapters/cursor/live-models.ts +153 -0
  73. package/src/adapters/cursor/live-smoke-gate.ts +41 -0
  74. package/src/adapters/cursor/live-transport.ts +1214 -0
  75. package/src/adapters/cursor/mcp-config.ts +42 -0
  76. package/src/adapters/cursor/mcp-manager.ts +333 -0
  77. package/src/adapters/cursor/message-mapper.ts +49 -0
  78. package/src/adapters/cursor/native-exec-common.ts +55 -0
  79. package/src/adapters/cursor/native-exec-desktop.ts +184 -0
  80. package/src/adapters/cursor/native-exec-fs.ts +329 -0
  81. package/src/adapters/cursor/native-exec-mcp.ts +153 -0
  82. package/src/adapters/cursor/native-exec-network.ts +43 -0
  83. package/src/adapters/cursor/native-exec-shell.ts +548 -0
  84. package/src/adapters/cursor/native-exec-tools.ts +118 -0
  85. package/src/adapters/cursor/native-exec.ts +576 -0
  86. package/src/adapters/cursor/protobuf-events.ts +563 -0
  87. package/src/adapters/cursor/protobuf-request.ts +714 -0
  88. package/src/adapters/cursor/request-builder.ts +255 -0
  89. package/src/adapters/cursor/thread-continuity.ts +67 -0
  90. package/src/adapters/cursor/tool-definitions.ts +505 -0
  91. package/src/adapters/cursor/transport-retry.ts +132 -0
  92. package/src/adapters/cursor/transport.ts +57 -0
  93. package/src/adapters/cursor/types.ts +52 -0
  94. package/src/adapters/cursor.ts +196 -0
  95. package/src/adapters/google-antigravity-replay.ts +303 -0
  96. package/src/adapters/google-antigravity-wire.ts +108 -0
  97. package/src/adapters/google-errors.ts +85 -0
  98. package/src/adapters/google-http.ts +100 -0
  99. package/src/adapters/google-tool-schema.ts +173 -0
  100. package/src/adapters/google-truncation.ts +13 -0
  101. package/src/adapters/google-wire-compiler.ts +232 -0
  102. package/src/adapters/google.ts +758 -0
  103. package/src/adapters/identity.ts +44 -0
  104. package/src/adapters/image.ts +23 -0
  105. package/src/adapters/kiro-constants.ts +16 -0
  106. package/src/adapters/kiro-errors.ts +197 -0
  107. package/src/adapters/kiro-events.ts +179 -0
  108. package/src/adapters/kiro-images.ts +129 -0
  109. package/src/adapters/kiro-retry.ts +312 -0
  110. package/src/adapters/kiro-thinking.ts +96 -0
  111. package/src/adapters/kiro-tool-fallback.ts +36 -0
  112. package/src/adapters/kiro-tools.ts +215 -0
  113. package/src/adapters/kiro-truncation.ts +33 -0
  114. package/src/adapters/kiro-wire.ts +129 -0
  115. package/src/adapters/kiro.ts +1898 -0
  116. package/src/adapters/mimo-free.ts +263 -0
  117. package/src/adapters/openai-chat.ts +1005 -0
  118. package/src/adapters/openai-responses.ts +1137 -0
  119. package/src/adapters/run-turn-queue.ts +114 -0
  120. package/src/adapters/tool-catalog-nudge.ts +71 -0
  121. package/src/adapters/upstream-http-error.ts +48 -0
  122. package/src/bridge.ts +1619 -0
  123. package/src/chat/inbound.ts +295 -0
  124. package/src/chat/outbound.ts +765 -0
  125. package/src/claude/agents-inject.ts +243 -0
  126. package/src/claude/alias.ts +149 -0
  127. package/src/claude/auth-detect.ts +229 -0
  128. package/src/claude/auth-mode-migration.ts +32 -0
  129. package/src/claude/auth-mode.ts +62 -0
  130. package/src/claude/context-windows.ts +189 -0
  131. package/src/claude/desktop-3p-guard.ts +35 -0
  132. package/src/claude/desktop-3p-paths.ts +84 -0
  133. package/src/claude/desktop-3p.ts +381 -0
  134. package/src/claude/desktop-health.ts +26 -0
  135. package/src/claude/desktop-profile.ts +263 -0
  136. package/src/claude/gateway-cache.ts +70 -0
  137. package/src/claude/inbound-debug.ts +163 -0
  138. package/src/claude/inbound.ts +509 -0
  139. package/src/claude/model-info.ts +151 -0
  140. package/src/claude/outbound.ts +872 -0
  141. package/src/cli/access.ts +108 -0
  142. package/src/cli/account-api.ts +268 -0
  143. package/src/cli/account-auth.ts +223 -0
  144. package/src/cli/account-extended.ts +350 -0
  145. package/src/cli/account.ts +275 -0
  146. package/src/cli/agent-driven.ts +70 -0
  147. package/src/cli/agent.ts +184 -0
  148. package/src/cli/catalog-prewarm.ts +27 -0
  149. package/src/cli/claude-desktop.ts +188 -0
  150. package/src/cli/claude.ts +286 -0
  151. package/src/cli/codex-shim-autorestore.ts +45 -0
  152. package/src/cli/combo.ts +119 -0
  153. package/src/cli/config-command.ts +145 -0
  154. package/src/cli/debug.ts +228 -0
  155. package/src/cli/doctor.ts +930 -0
  156. package/src/cli/export-command.ts +187 -0
  157. package/src/cli/help.ts +354 -0
  158. package/src/cli/index.ts +1113 -0
  159. package/src/cli/init.ts +224 -0
  160. package/src/cli/integrations.ts +142 -0
  161. package/src/cli/interactive-confirm.ts +133 -0
  162. package/src/cli/internal-dispatch.ts +20 -0
  163. package/src/cli/models-runtime.ts +212 -0
  164. package/src/cli/models.ts +336 -0
  165. package/src/cli/observe.ts +117 -0
  166. package/src/cli/opencode.ts +586 -0
  167. package/src/cli/pi.ts +188 -0
  168. package/src/cli/provider-runtime.ts +162 -0
  169. package/src/cli/provider.ts +463 -0
  170. package/src/cli/runtime-api.ts +325 -0
  171. package/src/cli/star-prompt.ts +155 -0
  172. package/src/cli/status-oauth.ts +78 -0
  173. package/src/cli/status.ts +321 -0
  174. package/src/cli/sync-cloud.ts +283 -0
  175. package/src/cli/system-command.ts +112 -0
  176. package/src/cli/tray-proxy.ts +52 -0
  177. package/src/cli/v2.ts +173 -0
  178. package/src/cli.ts +10 -0
  179. package/src/clients/config-export.ts +377 -0
  180. package/src/clients/effective-status.ts +385 -0
  181. package/src/clients/probes/agy.ts +55 -0
  182. package/src/clients/probes/cc-switch.ts +110 -0
  183. package/src/clients/probes/claude.ts +90 -0
  184. package/src/clients/probes/codex.ts +125 -0
  185. package/src/clients/probes/grok.ts +29 -0
  186. package/src/clients/probes/opencode.ts +109 -0
  187. package/src/clients/probes/paseo.ts +55 -0
  188. package/src/clients/probes/pi.ts +55 -0
  189. package/src/cloud/onedrive-auth.ts +666 -0
  190. package/src/cloud/onedrive-graph.ts +108 -0
  191. package/src/cloud/settings.ts +75 -0
  192. package/src/cloud/sync.ts +212 -0
  193. package/src/cloud/types.ts +56 -0
  194. package/src/cloud/vault.ts +89 -0
  195. package/src/codex/account-id.ts +34 -0
  196. package/src/codex/account-label.ts +34 -0
  197. package/src/codex/account-lifecycle.ts +55 -0
  198. package/src/codex/account-namespace-match.ts +63 -0
  199. package/src/codex/account-namespaces.ts +149 -0
  200. package/src/codex/account-pause.ts +20 -0
  201. package/src/codex/account-runtime-state.ts +31 -0
  202. package/src/codex/account-store.ts +517 -0
  203. package/src/codex/account-usability.ts +20 -0
  204. package/src/codex/app-server-processes.ts +756 -0
  205. package/src/codex/auth-api.ts +1540 -0
  206. package/src/codex/auth-collision.ts +107 -0
  207. package/src/codex/auth-context.ts +352 -0
  208. package/src/codex/autostart-health.ts +149 -0
  209. package/src/codex/catalog/aggregation.ts +378 -0
  210. package/src/codex/catalog/bundled.ts +251 -0
  211. package/src/codex/catalog/effort.ts +355 -0
  212. package/src/codex/catalog/metadata.ts +180 -0
  213. package/src/codex/catalog/parsing.ts +456 -0
  214. package/src/codex/catalog/provider-fetch.ts +902 -0
  215. package/src/codex/catalog/sync.ts +620 -0
  216. package/src/codex/catalog.ts +12 -0
  217. package/src/codex/data/upstream-models.json +830 -0
  218. package/src/codex/exec-invocation.ts +22 -0
  219. package/src/codex/features.ts +969 -0
  220. package/src/codex/history-migration-guardian.ts +102 -0
  221. package/src/codex/history-provider.ts +776 -0
  222. package/src/codex/home.ts +206 -0
  223. package/src/codex/inject.ts +799 -0
  224. package/src/codex/injected-marker.ts +72 -0
  225. package/src/codex/journal.ts +163 -0
  226. package/src/codex/main-account-cache.ts +32 -0
  227. package/src/codex/main-account.ts +40 -0
  228. package/src/codex/model-cache.ts +227 -0
  229. package/src/codex/paths.ts +65 -0
  230. package/src/codex/plugins-doctor.ts +242 -0
  231. package/src/codex/pool-rotation.ts +225 -0
  232. package/src/codex/project-config-warnings.ts +411 -0
  233. package/src/codex/quota.ts +411 -0
  234. package/src/codex/refresh.ts +53 -0
  235. package/src/codex/routing.ts +1477 -0
  236. package/src/codex/runtime.ts +538 -0
  237. package/src/codex/shim.ts +1189 -0
  238. package/src/codex/subagent-defaults.ts +550 -0
  239. package/src/codex/subagent-model-fallback.ts +469 -0
  240. package/src/codex/sync.ts +130 -0
  241. package/src/codex/warmup.ts +192 -0
  242. package/src/codex/websocket-registry.ts +100 -0
  243. package/src/combos/failover.ts +140 -0
  244. package/src/combos/index.ts +41 -0
  245. package/src/combos/request.ts +62 -0
  246. package/src/combos/resolve.ts +232 -0
  247. package/src/combos/types.ts +326 -0
  248. package/src/config.ts +2356 -0
  249. package/src/generated/jawcode-model-metadata.ts +104 -0
  250. package/src/github/star-state.ts +203 -0
  251. package/src/grok/inject.ts +545 -0
  252. package/src/grok/status.ts +121 -0
  253. package/src/grok/sync.ts +103 -0
  254. package/src/grok/usage-hook/report.mjs +348 -0
  255. package/src/grok/usage-hook.ts +278 -0
  256. package/src/images/artifacts.ts +516 -0
  257. package/src/images/fulfill-video.ts +163 -0
  258. package/src/images/fulfill.ts +149 -0
  259. package/src/images/index.ts +4 -0
  260. package/src/images/loop.ts +829 -0
  261. package/src/images/plan.ts +133 -0
  262. package/src/images/synthetic-tool.ts +133 -0
  263. package/src/images/types.ts +41 -0
  264. package/src/images/xai-client.ts +141 -0
  265. package/src/images/xai-video-client.ts +163 -0
  266. package/src/index.ts +22 -0
  267. package/src/lib/abort.ts +146 -0
  268. package/src/lib/admin-secrets.ts +25 -0
  269. package/src/lib/admission.ts +83 -0
  270. package/src/lib/app-owned-memory-stores.ts +173 -0
  271. package/src/lib/app-owned-memory.ts +265 -0
  272. package/src/lib/bounded-body.ts +202 -0
  273. package/src/lib/bun-binary-validator.d.mts +3 -0
  274. package/src/lib/bun-binary-validator.mjs +18 -0
  275. package/src/lib/bun-runtime.ts +71 -0
  276. package/src/lib/bun-stream-caps.ts +126 -0
  277. package/src/lib/config-ownership.ts +360 -0
  278. package/src/lib/crash-guard.ts +344 -0
  279. package/src/lib/debug-log-buffer.ts +83 -0
  280. package/src/lib/debug-settings.ts +108 -0
  281. package/src/lib/debug.ts +31 -0
  282. package/src/lib/destination-policy.ts +316 -0
  283. package/src/lib/errors.ts +364 -0
  284. package/src/lib/eventstream-decoder.ts +253 -0
  285. package/src/lib/gcp-adc.ts +341 -0
  286. package/src/lib/injection-debug-log.ts +58 -0
  287. package/src/lib/open-url.ts +25 -0
  288. package/src/lib/pinned-http.ts +151 -0
  289. package/src/lib/privacy.ts +20 -0
  290. package/src/lib/process-control.ts +165 -0
  291. package/src/lib/provider-outbound.ts +170 -0
  292. package/src/lib/provider-url.ts +14 -0
  293. package/src/lib/proxy-env.ts +18 -0
  294. package/src/lib/redact.ts +105 -0
  295. package/src/lib/retry-after.ts +55 -0
  296. package/src/lib/service-secrets.ts +25 -0
  297. package/src/lib/shadow-call.ts +30 -0
  298. package/src/lib/sidecar-tracker.ts +52 -0
  299. package/src/lib/sse-decoder.ts +323 -0
  300. package/src/lib/state-store-registrations.ts +109 -0
  301. package/src/lib/state-store-sweeper.ts +184 -0
  302. package/src/lib/test-home-guard.ts +90 -0
  303. package/src/lib/token-estimate.ts +69 -0
  304. package/src/lib/translator-budget.ts +356 -0
  305. package/src/lib/upstream-retry.ts +239 -0
  306. package/src/lib/win-exec.ts +115 -0
  307. package/src/lib/win-paths.ts +68 -0
  308. package/src/lib/windows-elevation.ts +705 -0
  309. package/src/lib/windows-secret-acl.ts +514 -0
  310. package/src/lib/winsw.ts +375 -0
  311. package/src/oauth/anthropic-routing.ts +594 -0
  312. package/src/oauth/anthropic.ts +177 -0
  313. package/src/oauth/callback-server.ts +294 -0
  314. package/src/oauth/chatgpt.ts +150 -0
  315. package/src/oauth/cursor.ts +211 -0
  316. package/src/oauth/github-copilot.ts +428 -0
  317. package/src/oauth/google-antigravity.ts +230 -0
  318. package/src/oauth/health.ts +399 -0
  319. package/src/oauth/index.ts +1174 -0
  320. package/src/oauth/key-providers.ts +108 -0
  321. package/src/oauth/kimi.ts +213 -0
  322. package/src/oauth/kiro-credentials.ts +726 -0
  323. package/src/oauth/kiro.ts +577 -0
  324. package/src/oauth/local-token-detect.ts +121 -0
  325. package/src/oauth/log.ts +48 -0
  326. package/src/oauth/login-cli.ts +163 -0
  327. package/src/oauth/pkce.ts +15 -0
  328. package/src/oauth/store.ts +630 -0
  329. package/src/oauth/token-guardian.ts +303 -0
  330. package/src/oauth/types.ts +62 -0
  331. package/src/oauth/xai.ts +241 -0
  332. package/src/pi/extensions.ts +72 -0
  333. package/src/pi/home.ts +42 -0
  334. package/src/pi/index.ts +40 -0
  335. package/src/pi/models.ts +278 -0
  336. package/src/pi/packages.ts +219 -0
  337. package/src/pi/settings.ts +365 -0
  338. package/src/pi/status.ts +68 -0
  339. package/src/pi/sync.ts +75 -0
  340. package/src/providers/alibaba-region-backup.ts +75 -0
  341. package/src/providers/alibaba-region-migration.ts +156 -0
  342. package/src/providers/alibaba-region-startup.ts +36 -0
  343. package/src/providers/antigravity-models.ts +205 -0
  344. package/src/providers/api-keys.ts +140 -0
  345. package/src/providers/base-url-choices.ts +64 -0
  346. package/src/providers/context-cap.ts +65 -0
  347. package/src/providers/derive.ts +339 -0
  348. package/src/providers/free-directory.ts +184 -0
  349. package/src/providers/github-copilot-transport.ts +56 -0
  350. package/src/providers/key-failover.ts +203 -0
  351. package/src/providers/kiro-models.ts +67 -0
  352. package/src/providers/label.ts +19 -0
  353. package/src/providers/model-discovery.ts +356 -0
  354. package/src/providers/openai-sidecar.ts +175 -0
  355. package/src/providers/openai-tier-startup.ts +27 -0
  356. package/src/providers/openai-tiers.ts +301 -0
  357. package/src/providers/openai-virtual-models.ts +82 -0
  358. package/src/providers/openrouter-routing.ts +102 -0
  359. package/src/providers/provider-id-rewrite.ts +150 -0
  360. package/src/providers/quota.ts +1260 -0
  361. package/src/providers/registry.ts +1600 -0
  362. package/src/providers/slug-codec.ts +67 -0
  363. package/src/providers/xai-transport.ts +141 -0
  364. package/src/reasoning-effort.ts +135 -0
  365. package/src/responses/compaction.ts +117 -0
  366. package/src/responses/parser.ts +656 -0
  367. package/src/responses/reasoning-envelope.ts +52 -0
  368. package/src/responses/schema.ts +159 -0
  369. package/src/responses/spill-store.ts +394 -0
  370. package/src/responses/state.ts +895 -0
  371. package/src/responses/tool-groups.ts +19 -0
  372. package/src/router.ts +425 -0
  373. package/src/server/adapter-resolve.ts +80 -0
  374. package/src/server/auth-cors.ts +530 -0
  375. package/src/server/chat-completions.ts +368 -0
  376. package/src/server/claude-messages.ts +914 -0
  377. package/src/server/effort-policy.ts +172 -0
  378. package/src/server/gui-static.ts +123 -0
  379. package/src/server/image-retry.ts +42 -0
  380. package/src/server/images.ts +476 -0
  381. package/src/server/index.ts +1126 -0
  382. package/src/server/lifecycle.ts +227 -0
  383. package/src/server/live.ts +598 -0
  384. package/src/server/management/agent-settings-routes.ts +1169 -0
  385. package/src/server/management/api-access.ts +141 -0
  386. package/src/server/management/api-key-usage.ts +167 -0
  387. package/src/server/management/body.ts +35 -0
  388. package/src/server/management/clients-routes.ts +63 -0
  389. package/src/server/management/cloud-sync-routes.ts +266 -0
  390. package/src/server/management/combo-routes.ts +220 -0
  391. package/src/server/management/config-routes.ts +422 -0
  392. package/src/server/management/context.ts +31 -0
  393. package/src/server/management/logs-usage-routes.ts +707 -0
  394. package/src/server/management/model-routes.ts +525 -0
  395. package/src/server/management/oauth-account-routes.ts +563 -0
  396. package/src/server/management/provider-routes.ts +556 -0
  397. package/src/server/management/shared.ts +277 -0
  398. package/src/server/management/sidebar-routes.ts +90 -0
  399. package/src/server/management/system-restart.ts +179 -0
  400. package/src/server/management/system-routes.ts +117 -0
  401. package/src/server/management/usage-summary-cache.ts +86 -0
  402. package/src/server/management-api.ts +215 -0
  403. package/src/server/management-auth.ts +267 -0
  404. package/src/server/memory-watchdog.ts +156 -0
  405. package/src/server/port-reclaim.ts +307 -0
  406. package/src/server/ports.ts +116 -0
  407. package/src/server/proxy-liveness.ts +201 -0
  408. package/src/server/relay-eager.ts +313 -0
  409. package/src/server/relay.ts +1049 -0
  410. package/src/server/request-decompress.ts +132 -0
  411. package/src/server/request-log-conversation.ts +168 -0
  412. package/src/server/request-log.ts +1046 -0
  413. package/src/server/responses/collaboration.ts +354 -0
  414. package/src/server/responses/compact.ts +384 -0
  415. package/src/server/responses/core.ts +2758 -0
  416. package/src/server/responses/encrypted-payload.ts +308 -0
  417. package/src/server/responses/fetch-helpers.ts +157 -0
  418. package/src/server/responses/passthrough-error.ts +78 -0
  419. package/src/server/responses/terminal-guard.ts +230 -0
  420. package/src/server/responses/upstream-error.ts +48 -0
  421. package/src/server/responses-image-gen-repair.ts +132 -0
  422. package/src/server/responses-item-id-repair.ts +224 -0
  423. package/src/server/responses.ts +9 -0
  424. package/src/server/search.ts +136 -0
  425. package/src/server/sse-payload-rewrite.ts +175 -0
  426. package/src/server/startup-action-control.ts +308 -0
  427. package/src/server/startup-health-cache.ts +113 -0
  428. package/src/server/system-env.ts +413 -0
  429. package/src/server/windows-tcp-drop.ts +184 -0
  430. package/src/server/windows-tray-control.ts +41 -0
  431. package/src/server/ws-bridge.ts +471 -0
  432. package/src/service.ts +2554 -0
  433. package/src/stall-timeout.ts +20 -0
  434. package/src/storage/cleanup-job.ts +57 -0
  435. package/src/storage/cleanup.ts +3085 -0
  436. package/src/storage/policy-job.ts +457 -0
  437. package/src/storage/policy-scheduler.ts +40 -0
  438. package/src/storage/policy-worker.ts +59 -0
  439. package/src/storage/policy.ts +527 -0
  440. package/src/storage/restore-job.ts +299 -0
  441. package/src/storage/restore-worker.ts +58 -0
  442. package/src/storage/scanner.ts +238 -0
  443. package/src/storage/storage-mutation-coordinator.ts +139 -0
  444. package/src/storage/worker-lifecycle.ts +215 -0
  445. package/src/tray/assets/opencodex-tray-offline.ico +0 -0
  446. package/src/tray/assets/opencodex-tray-online.ico +0 -0
  447. package/src/tray/assets/opencodex-tray-warning.ico +0 -0
  448. package/src/tray/assets/opencodex-tray.png +0 -0
  449. package/src/tray/windows-tray.ps1 +290 -0
  450. package/src/tray/windows.ts +730 -0
  451. package/src/types.ts +1237 -0
  452. package/src/update/badge.ts +72 -0
  453. package/src/update/index.ts +407 -0
  454. package/src/update/job.ts +1520 -0
  455. package/src/update/notify.ts +257 -0
  456. package/src/update/npm-invocation.d.mts +23 -0
  457. package/src/update/npm-invocation.mjs +94 -0
  458. package/src/update/tray-update-plan.d.mts +18 -0
  459. package/src/update/tray-update-plan.mjs +38 -0
  460. package/src/usage/cost.ts +0 -0
  461. package/src/usage/debug.ts +97 -0
  462. package/src/usage/expected-prices.ts +164 -0
  463. package/src/usage/log.ts +658 -0
  464. package/src/usage/summary.ts +585 -0
  465. package/src/usage/totals.ts +14 -0
  466. package/src/vision/anthropic-describe.ts +185 -0
  467. package/src/vision/describe.ts +125 -0
  468. package/src/vision/index.ts +467 -0
  469. package/src/web-search/anthropic-executor.ts +189 -0
  470. package/src/web-search/executor.ts +105 -0
  471. package/src/web-search/format-result.ts +89 -0
  472. package/src/web-search/index.ts +196 -0
  473. package/src/web-search/loop.ts +664 -0
  474. package/src/web-search/parse.ts +220 -0
  475. package/src/web-search/progress-stream.ts +342 -0
  476. package/src/web-search/synthetic-tool.ts +47 -0
@@ -0,0 +1,456 @@
1
+ import { execFileSync } from "node:child_process";
2
+ import { createHash } from "node:crypto";
3
+ import { copyFileSync, existsSync, mkdirSync, readFileSync, realpathSync } from "node:fs";
4
+ import { delimiter, dirname, join, resolve } from "node:path";
5
+ import { atomicWriteFile, expandUserPath, getConfigDir, websocketsEnabled } from "../../config";
6
+ import { CODEX_CONFIG_PATH, CODEX_MODELS_CACHE_PATH, DEFAULT_CATALOG_PATH, readRootTomlString, resolveCodexConfigPath } from "../paths";
7
+ import { clearModelCache, DEFAULT_MODEL_CACHE_TTL_MS, getFreshCached, getStaleCached, isModelsFetchCoolingDown, markModelsFetchFailure, setCached } from "../model-cache";
8
+ import { buildModelsRequest, resolveModelsAuthToken } from "../../oauth";
9
+ import type { OcxConfig, OcxProviderConfig } from "../../types";
10
+ import { modelInList } from "../../types";
11
+ import { CODEX_REASONING_LEVELS, codexEffortRank, configuredReasoningEfforts, modelRecordValue, sanitizeCodexReasoningEfforts } from "../../reasoning-effort";
12
+ import { getJawcodeModelMetadata, getJawcodeModelMetadataCaseInsensitive, listJawcodeModelMetadata, resolveJawcodeProvider } from "../../generated/jawcode-model-metadata";
13
+ import { enrichProviderFromRegistry, shouldCaseFoldMetadataModelId } from "../../providers/derive";
14
+ import { getProviderRegistryEntry } from "../../providers/registry";
15
+ import { applyProviderContextCap, providerContextCap } from "../../providers/context-cap";
16
+ import { encodeRoutedModelId, routedSlug, slugEquals, slugsEquivalent } from "../../providers/slug-codec";
17
+ import { CODEX_GPT5_IDENTITY_LINE } from "../../adapters/identity";
18
+ import { filterCursorConfiguredModelsByLiveDiscovery } from "../../adapters/cursor/discovery";
19
+ import { fetchCursorUsableModels } from "../../adapters/cursor/live-models";
20
+ import { isCanonicalOpenAiForwardProvider, OPENAI_API_PROVIDER_ID, OPENAI_CODEX_PROVIDER_ID } from "../../providers/openai-tiers";
21
+ import {
22
+ COMBO_NAMESPACE,
23
+ comboModelId,
24
+ getCombo,
25
+ listComboIds,
26
+ targetKey,
27
+ } from "../../combos";
28
+ import type { NormalizedComboConfig } from "../../combos/types";
29
+ import { providerDestinationResolvedError } from "../../lib/destination-policy";
30
+ import { redactSecretString } from "../../lib/redact";
31
+ import upstreamModelsSnapshot from "../data/upstream-models.json";
32
+
33
+
34
+ import { NATIVE_OPENAI_CONTEXT_OVERRIDES, SUPPORTED_NATIVE_OPENAI_SLUGS, UPSTREAM_NATIVE_ENTRIES } from "./metadata";
35
+
36
+ export function legacyCatalogBackupPath(): string {
37
+ return join(getConfigDir(), "catalog-backup.json");
38
+ }
39
+
40
+ export function catalogBackupPathFor(catalogPath: string): string {
41
+ const normalized = process.platform === "win32" ? resolve(catalogPath).toLowerCase() : resolve(catalogPath);
42
+ const id = createHash("sha256").update(normalized).digest("hex").slice(0, 16);
43
+ return join(getConfigDir(), `catalog-backup-${id}.json`);
44
+ }
45
+
46
+ export function samePath(a: string, b: string): boolean {
47
+ const left = resolve(a);
48
+ const right = resolve(b);
49
+ return process.platform === "win32" ? left.toLowerCase() === right.toLowerCase() : left === right;
50
+ }
51
+
52
+ export function activeCodexHome(): string | null {
53
+ const raw = process.env.CODEX_HOME?.trim();
54
+ if (!raw) return null;
55
+ const path = resolve(expandUserPath(raw));
56
+ try {
57
+ return realpathSync.native(path);
58
+ } catch {
59
+ return path;
60
+ }
61
+ }
62
+
63
+ export function activeCodexConfigPath(): string {
64
+ const home = activeCodexHome();
65
+ return home ? join(home, "config.toml") : CODEX_CONFIG_PATH;
66
+ }
67
+
68
+ export function activeDefaultCatalogPath(): string {
69
+ const home = activeCodexHome();
70
+ return home ? join(home, "opencodex-catalog.json") : DEFAULT_CATALOG_PATH;
71
+ }
72
+
73
+ export function activeCodexModelsCachePath(): string {
74
+ const home = activeCodexHome();
75
+ return home ? join(home, "models_cache.json") : CODEX_MODELS_CACHE_PATH;
76
+ }
77
+
78
+ export function resolveActiveCodexConfigPath(path: string): string {
79
+ const home = activeCodexHome();
80
+ return home ? resolve(home, path) : resolveCodexConfigPath(path);
81
+ }
82
+
83
+ export function isDefaultCatalogPath(path: string): boolean {
84
+ return samePath(path, activeDefaultCatalogPath());
85
+ }
86
+
87
+ export interface CatalogModel {
88
+ id: string;
89
+ provider: string;
90
+ /** Public Codex-facing slug override (used by combo aliases). */
91
+ alias?: string;
92
+ /**
93
+ * Display-only Codex catalog `display_name` override. Relabels the picker row ONLY — it never
94
+ * affects the routing slug, alias-collision order, native marketing-name precedence, or provider
95
+ * behavior. When unset, the entry falls back to its Codex-facing slug (the historical behavior).
96
+ * Native upstream entries (e.g. gpt-5.6-sol → "GPT-5.6-Sol") come from the pinned snapshot path
97
+ * which carries no CatalogModel, so a configured displayName can never override a native name.
98
+ */
99
+ displayName?: string;
100
+ owned_by?: string;
101
+ reasoningEfforts?: string[];
102
+ defaultReasoningEffort?: string;
103
+ contextWindow?: number;
104
+ maxInputTokens?: number;
105
+ contextCap?: number;
106
+ contextCapped?: boolean;
107
+ inputModalities?: string[];
108
+ /** Provider opted into parallel tool calls (OcxProviderConfig.parallelToolCalls). */
109
+ parallelToolCalls?: boolean;
110
+ /** Whether Codex may send Responses text.verbosity for this routed model. */
111
+ supportsVerbosity?: boolean;
112
+ supportsReasoningSummaries?: boolean;
113
+ /** Normalized upstream capability names retained for management/API consumers (#485 follow-up). */
114
+ capabilities?: string[];
115
+ }
116
+
117
+ export type RawEntry = Record<string, unknown>;
118
+
119
+ export type RawCatalog = { models?: RawEntry[]; [k: string]: unknown };
120
+
121
+ export const JAWCODE_CATALOG_AUGMENT_PROVIDERS = new Set(["opencode-go"]);
122
+
123
+ export const ROUTED_MODEL_COMPATIBILITY_EXCLUSIONS = new Set([
124
+ // Issue #82: Zen Go /models advertises HY3, but Console Go rejects it as outside the lite list.
125
+ "opencode-go/hy3-preview",
126
+ ]);
127
+
128
+ export function isRoutedModelCompatibilityExcluded(slug: string): boolean {
129
+ return ROUTED_MODEL_COMPATIBILITY_EXCLUSIONS.has(slug);
130
+ }
131
+
132
+ export const MEDIA_GEN_FAMILIES = [
133
+ "dall-e", "dalle", "imagen", "sora", "veo", "flux", "kling",
134
+ "seedance", "hailuo", "stable-diffusion", "sdxl", "midjourney",
135
+ ];
136
+
137
+ export const MEDIA_GEN_ID_RE = new RegExp(
138
+ `(?:^|[/_-])(?:image|video)(?:[/_-]|$)|(?:^|[/_-])(?:${MEDIA_GEN_FAMILIES.join("|")})(?:[/_-]|$|\\d)`,
139
+ "i",
140
+ );
141
+
142
+ export function isMediaGenerationModelId(id: string): boolean {
143
+ return MEDIA_GEN_ID_RE.test(id);
144
+ }
145
+
146
+ /**
147
+ * Gemini image-capable chat models produce inline images within text responses
148
+ * via the Responses API. Explicit allowlist only — a broad `/gemini/ && /image/`
149
+ * heuristic resurrects standalone media-gen IDs (e.g. gemini-3-pro-image).
150
+ */
151
+ const GEMINI_IMAGE_CHAT_MODEL_IDS = new Set([
152
+ "gemini-3.1-flash-image",
153
+ "gemini-2.0-flash-preview-image-generation",
154
+ "gemini-3-pro-image-preview",
155
+ ]);
156
+
157
+ function isGeminiImageChatModel(id: string): boolean {
158
+ return GEMINI_IMAGE_CHAT_MODEL_IDS.has(id);
159
+ }
160
+
161
+ export function shouldExposeRoutedModel(model: CatalogModel): boolean {
162
+ if (isRoutedModelCompatibilityExcluded(`${model.provider}/${model.id}`)) return false;
163
+ if (isGeminiImageChatModel(model.id)) return true;
164
+ return !isMediaGenerationModelId(model.id);
165
+ }
166
+
167
+ export function readCodexCatalogPath(): string {
168
+ try {
169
+ const configPath = activeCodexConfigPath();
170
+ if (existsSync(configPath)) {
171
+ const toml = readFileSync(configPath, "utf-8");
172
+ const path = readRootTomlString(toml, "model_catalog_json");
173
+ if (path) return resolveActiveCodexConfigPath(path);
174
+ }
175
+ } catch { /* ignore */ }
176
+ return activeDefaultCatalogPath();
177
+ }
178
+
179
+ export function parseCatalogJson(raw: string): RawCatalog | null {
180
+ try {
181
+ const cat = JSON.parse(raw);
182
+ return (cat && Array.isArray(cat.models)) ? cat : null;
183
+ } catch { return null; }
184
+ }
185
+
186
+ export function readCatalog(path: string): RawCatalog | null {
187
+ try {
188
+ if (!existsSync(path)) return null;
189
+ return parseCatalogJson(readFileSync(path, "utf-8"));
190
+ } catch { return null; }
191
+ }
192
+
193
+ export function findNativeTemplate(catalog: RawCatalog | null): RawEntry | null {
194
+ return catalog?.models?.find(
195
+ m => typeof m.slug === "string" && !m.slug.includes("/") && "base_instructions" in m,
196
+ ) ?? null;
197
+ }
198
+
199
+ /**
200
+ * Native OpenAI slugs that do NOT support the Fast (priority) service tier.
201
+ * Upstream may advertise service_tiers for these models, but the tier is not
202
+ * actually available — strip it so the Codex UI does not offer a dead toggle.
203
+ */
204
+ const NO_FAST_TIER_NATIVE_SLUGS = new Set([
205
+ "gpt-5.3-codex-spark",
206
+ ]);
207
+
208
+ export function normalizeServiceTiers(entry: RawEntry): RawEntry {
209
+ // Strip service tiers for models that do not actually support the Fast tier.
210
+ if (typeof entry.slug === "string" && NO_FAST_TIER_NATIVE_SLUGS.has(entry.slug)) {
211
+ delete entry.service_tier;
212
+ delete entry.service_tiers;
213
+ delete entry.default_service_tier;
214
+ delete entry.additional_speed_tiers;
215
+ return entry;
216
+ }
217
+ // Codex stores the user-facing config spelling as "fast", but the catalog/request
218
+ // service tier id is "priority" in current codex-rs. Keep legacy catalogs working.
219
+ if (entry.service_tier === "fast") entry.service_tier = "priority";
220
+ if (Array.isArray(entry.service_tiers)) {
221
+ entry.service_tiers = entry.service_tiers.map(tier => {
222
+ if (tier && typeof tier === "object" && "id" in tier && tier.id === "fast") {
223
+ return { ...tier, id: "priority" };
224
+ }
225
+ return tier;
226
+ });
227
+ }
228
+ return entry;
229
+ }
230
+
231
+ export function ensureAutoCompactTokenLimit(entry: RawEntry): RawEntry {
232
+ if (
233
+ typeof entry.context_window === "number"
234
+ && entry.context_window > 0
235
+ && typeof entry.auto_compact_token_limit !== "number"
236
+ ) {
237
+ entry.auto_compact_token_limit = Math.floor(entry.context_window * 0.9);
238
+ }
239
+ return entry;
240
+ }
241
+
242
+ export function isNativeOpenAiEntry(entry: RawEntry): boolean {
243
+ return typeof entry.slug === "string" && !entry.slug.includes("/");
244
+ }
245
+
246
+ export function applyNativeOpenAiContextOverride(entry: RawEntry): void {
247
+ if (!isNativeOpenAiEntry(entry)) return;
248
+ const override = NATIVE_OPENAI_CONTEXT_OVERRIDES[entry.slug as string];
249
+ if (!override) return;
250
+ if (typeof override.contextWindow === "number") {
251
+ entry.context_window = override.contextWindow;
252
+ entry.auto_compact_token_limit = Math.floor(override.contextWindow * 0.9);
253
+ }
254
+ if (typeof override.maxContextWindow === "number") {
255
+ entry.max_context_window = override.maxContextWindow;
256
+ }
257
+ }
258
+
259
+ export function ensureStrictCatalogFields(
260
+ entry: RawEntry,
261
+ options: { preserveExactInputModalities?: boolean; isRouted?: boolean } = {},
262
+ ): RawEntry {
263
+ if (typeof entry.supports_reasoning_summaries !== "boolean") entry.supports_reasoning_summaries = false;
264
+ if (typeof entry.default_reasoning_summary !== "string") entry.default_reasoning_summary = "none";
265
+ if (typeof entry.support_verbosity !== "boolean") entry.support_verbosity = true;
266
+ if (typeof entry.default_verbosity !== "string") entry.default_verbosity = "low";
267
+ if (typeof entry.apply_patch_tool_type !== "string") entry.apply_patch_tool_type = "freeform";
268
+ if (!entry.truncation_policy || typeof entry.truncation_policy !== "object" || Array.isArray(entry.truncation_policy)) {
269
+ entry.truncation_policy = { mode: "tokens", limit: 10000 };
270
+ }
271
+ if (typeof entry.supports_parallel_tool_calls !== "boolean") entry.supports_parallel_tool_calls = true;
272
+ if (typeof entry.supports_image_detail_original !== "boolean") entry.supports_image_detail_original = false;
273
+ if (!Array.isArray(entry.experimental_supported_tools)) entry.experimental_supported_tools = [];
274
+ if (!Array.isArray(entry.input_modalities) && !options.preserveExactInputModalities) {
275
+ entry.input_modalities = ["text"];
276
+ }
277
+ // Codex parses `input_modalities` as a closed enum. One out-of-enum value (zenmux advertises
278
+ // "video") makes its config loader reject the entire catalog, which takes down plugins, apps and
279
+ // MCP servers — not just that model. Normalize at the single point every entry passes through,
280
+ // because provider metadata, jawcode metadata and effort sync each write this field.
281
+ if (Array.isArray(entry.input_modalities)) {
282
+ const accepted = entry.input_modalities.filter(value =>
283
+ value === "text" || value === "image" || value === "audio");
284
+ // Never leave it empty: an entry with no modality at all is worse than a text-only one.
285
+ entry.input_modalities = accepted.length > 0 ? accepted : ["text"];
286
+ }
287
+ const contextWindow = typeof entry.context_window === "number" && entry.context_window > 0 ? entry.context_window : 128000;
288
+ entry.context_window = contextWindow;
289
+ if (
290
+ typeof entry.max_context_window !== "number"
291
+ || entry.max_context_window <= 0
292
+ || ((options.isRouted === true || !isNativeOpenAiEntry(entry)) && entry.max_context_window > contextWindow)
293
+ ) {
294
+ entry.max_context_window = contextWindow;
295
+ }
296
+ if (typeof entry.effective_context_window_percent !== "number") entry.effective_context_window_percent = 95;
297
+ if (typeof entry.comp_hash !== "string") entry.comp_hash = "opencodex";
298
+ return ensureAutoCompactTokenLimit(entry);
299
+ }
300
+
301
+ export type MultiAgentMode = "v1" | "default" | "v2";
302
+
303
+ /**
304
+ * @param v2FeatureEnabled When the native multi_agent_v2 feature is on, "default"
305
+ * mode stamps unpinned entries as "v2" instead of deleting the key. The native
306
+ * binary validates spawn_agent models against THIS catalog with its own
307
+ * `multi_agent_version == Some(V2)` test (codex-rs multi_agents_common.rs), so an
308
+ * absent pin means a clean refusal at spawn time — exactly the cross-provider
309
+ * spawns opencodex exists to enable (option B, devlog
310
+ * 260730_codex_rs_upstream_v2_live_handoff/060). Upstream pins are always
311
+ * preserved: a genuine "v1" pin is a real capability statement and stays excluded.
312
+ * With the feature off the output is byte-identical to the historical behavior.
313
+ */
314
+ export function applyMultiAgentMode(entries: RawEntry[], mode: MultiAgentMode, v2FeatureEnabled = false): RawEntry[] {
315
+ if (mode === "default") {
316
+ // Restore upstream defaults: clear any stale forced multi_agent_version and
317
+ // re-apply upstream pins from the snapshot for native entries that have one.
318
+ for (const entry of entries) {
319
+ const slug = typeof entry.slug === "string" ? entry.slug : "";
320
+ const upstream = UPSTREAM_NATIVE_ENTRIES.get(slug);
321
+ const upstreamPin = upstream?.multi_agent_version;
322
+ if (typeof upstreamPin === "string") {
323
+ entry.multi_agent_version = upstreamPin;
324
+ } else if (v2FeatureEnabled) {
325
+ entry.multi_agent_version = "v2";
326
+ } else {
327
+ delete entry.multi_agent_version;
328
+ }
329
+ }
330
+ return entries;
331
+ }
332
+ for (const entry of entries) {
333
+ entry.multi_agent_version = mode;
334
+ }
335
+ return entries;
336
+ }
337
+
338
+ export function normalizeRoutedCatalogEntry(entry: RawEntry, parallelToolCalls = false): RawEntry {
339
+ delete entry.model_messages;
340
+ delete entry.tool_mode;
341
+ delete entry.multi_agent_version;
342
+ delete entry.use_responses_lite;
343
+ delete entry.supports_websockets;
344
+ delete entry.additional_speed_tiers;
345
+ delete entry.service_tier;
346
+ delete entry.service_tiers;
347
+ delete entry.default_service_tier;
348
+ // Routed rows cloned from native templates must not inherit OpenAI-only summary delivery.
349
+ // Per-model routed opt-ins can be added once provider metadata exposes this capability.
350
+ delete entry.supports_reasoning_summaries;
351
+ const isCursorEntry = typeof entry.slug === "string" && entry.slug.startsWith("cursor/");
352
+ // Routed providers use opencodex sidecars and client-executed tool discovery. The sidecar
353
+ // runs through native gpt-5.4-mini, so image search is available and verbalized for text-only
354
+ // models. EXCEPT cursor: its runTurn transport bypasses the web-search plan entirely and
355
+ // rejects server search queries — advertising the tool would make models call into a void.
356
+ if (isCursorEntry) {
357
+ delete entry.web_search_tool_type;
358
+ entry.supports_search_tool = false;
359
+ } else {
360
+ entry.web_search_tool_type = "text_and_image";
361
+ entry.supports_search_tool = true;
362
+ }
363
+ // Cursor's transport already serializes overlapping tool calls into atomic Responses tool events.
364
+ // Advertising parallel calls lets Codex send the same native capability bit it sends for OpenAI.
365
+ // Opt-in providers (OcxProviderConfig.parallelToolCalls, e.g. xAI) advertise it too: the
366
+ // openai-chat adapter stops forcing parallel_tool_calls:false and the buffered stream parser
367
+ // assembles multi-call turns (devlog/_plan/260709_parallel_tool_calls).
368
+ entry.supports_parallel_tool_calls = isCursorEntry || parallelToolCalls === true;
369
+ return ensureStrictCatalogFields(entry, { isRouted: true });
370
+ }
371
+
372
+ /** Resolve reasoning-summary support from the active Codex catalog for wire sanitization. */
373
+ export function catalogModelSupportsReasoningSummaries(modelId: string): boolean | undefined {
374
+ if (typeof modelId !== "string" || modelId.length === 0) return undefined;
375
+ const catalog = readCatalog(readCodexCatalogPath()) ?? readCatalog(activeCodexModelsCachePath());
376
+ const models = catalog?.models ?? [];
377
+ const exact = models.find(entry => entry.slug === modelId || entry.id === modelId);
378
+ if (typeof exact?.supports_reasoning_summaries === "boolean") {
379
+ return exact.supports_reasoning_summaries;
380
+ }
381
+ const encodedModelId = encodeRoutedModelId(modelId);
382
+ const matches = models.filter(entry => (
383
+ typeof entry.slug === "string"
384
+ && entry.slug.includes("/")
385
+ && entry.slug.slice(entry.slug.indexOf("/") + 1) === encodedModelId
386
+ && typeof entry.supports_reasoning_summaries === "boolean"
387
+ ));
388
+ const values = new Set(matches.map(entry => entry.supports_reasoning_summaries as boolean));
389
+ return values.size === 1 ? values.values().next().value : undefined;
390
+ }
391
+
392
+ export function applyJawcodeCatalogMetadata(entry: RawEntry, provider: string, modelId: string, contextCap?: number): void {
393
+ const jawcodeProvider = resolveJawcodeProvider(provider);
394
+ if (!jawcodeProvider) return;
395
+ const meta = getJawcodeModelMetadata(jawcodeProvider, modelId)
396
+ ?? (shouldCaseFoldMetadataModelId(provider) ? getJawcodeModelMetadataCaseInsensitive(jawcodeProvider, modelId) : undefined);
397
+ if (!meta) return;
398
+ if (typeof meta.contextWindow === "number" && meta.contextWindow > 0) {
399
+ const contextWindow = applyProviderContextCap(meta.contextWindow, contextCap) ?? meta.contextWindow;
400
+ entry.context_window = contextWindow;
401
+ entry.max_context_window = contextWindow;
402
+ entry.auto_compact_token_limit = Math.floor(contextWindow * 0.9);
403
+ }
404
+ if (Array.isArray(meta.input) && meta.input.length > 0) {
405
+ entry.input_modalities = meta.input;
406
+ }
407
+ }
408
+
409
+ export function catalogModelSlug(model: CatalogModel): string {
410
+ return model.alias ?? routedSlug(model.provider, model.id);
411
+ }
412
+
413
+ export function filterSupportedNativeSlugs(models: RawEntry[]): string[] {
414
+ return models
415
+ .filter(m => typeof m.slug === "string" && !(m.slug as string).includes("/") && m.visibility === "list" && SUPPORTED_NATIVE_OPENAI_SLUGS.has(m.slug as string))
416
+ .map(m => m.slug as string);
417
+ }
418
+
419
+ export function readCatalogBackup(catalogPath: string): RawCatalog | null {
420
+ return readCatalog(catalogBackupPathFor(catalogPath))
421
+ ?? (isDefaultCatalogPath(catalogPath) ? readCatalog(legacyCatalogBackupPath()) : null);
422
+ }
423
+
424
+ export function catalogHasRoutedEntries(catalog: RawCatalog | null): boolean {
425
+ return (catalog?.models ?? []).some(m => typeof m.slug === "string" && m.slug.includes("/"));
426
+ }
427
+
428
+ export function writePristineCatalogBackup(backupPath: string, catalogPath: string, catalog: RawCatalog): void {
429
+ if (existsSync(backupPath)) return;
430
+ const onDisk = readCatalog(catalogPath);
431
+ if (onDisk && !catalogHasRoutedEntries(onDisk)) {
432
+ copyFileSync(catalogPath, backupPath);
433
+ return;
434
+ }
435
+ if (!catalogHasRoutedEntries(catalog)) {
436
+ atomicWriteFile(backupPath, JSON.stringify(catalog, null, 2) + "\n");
437
+ }
438
+ }
439
+
440
+ export function ensureCatalogBackup(catalogPath: string, catalog: RawCatalog): void {
441
+ const dir = getConfigDir();
442
+ if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
443
+ writePristineCatalogBackup(catalogBackupPathFor(catalogPath), catalogPath, catalog);
444
+ if (isDefaultCatalogPath(catalogPath)) writePristineCatalogBackup(legacyCatalogBackupPath(), catalogPath, catalog);
445
+ }
446
+
447
+ export function readNativeBaseline(catalogPath: string): Map<string, number> {
448
+ const backup = readCatalogBackup(catalogPath);
449
+ const out = new Map<string, number>();
450
+ for (const e of backup?.models ?? []) {
451
+ if (typeof e.slug === "string" && !e.slug.includes("/") && typeof e.priority === "number") {
452
+ out.set(e.slug, e.priority);
453
+ }
454
+ }
455
+ return out;
456
+ }