@remodex/rmx 1.0.2

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 (588) hide show
  1. package/AGENTS_INSTALL.md +91 -0
  2. package/LICENSE +21 -0
  3. package/README.md +242 -0
  4. package/assets/architecture.png +0 -0
  5. package/assets/banner.png +0 -0
  6. package/assets/claude-code-models.gif +0 -0
  7. package/assets/codex-app-picker.png +0 -0
  8. package/bin/ocx.mjs +584 -0
  9. package/bin/package-main.mjs +9 -0
  10. package/gui/dist/assets/index-CZqebSPQ.css +1 -0
  11. package/gui/dist/assets/index-CkETtt7P.js +71 -0
  12. package/gui/dist/favicon.png +0 -0
  13. package/gui/dist/fonts/google-sans-cyrillic.woff2 +0 -0
  14. package/gui/dist/fonts/google-sans-latin.woff2 +0 -0
  15. package/gui/dist/icons.svg +24 -0
  16. package/gui/dist/index.html +25 -0
  17. package/gui/dist/logo.png +0 -0
  18. package/gui/dist/provider-icons/alibaba-color.svg +1 -0
  19. package/gui/dist/provider-icons/antigravity-color.svg +1 -0
  20. package/gui/dist/provider-icons/claude-color.svg +1 -0
  21. package/gui/dist/provider-icons/cline-color.svg +16 -0
  22. package/gui/dist/provider-icons/cloudflare-ai-gateway-color.svg +1 -0
  23. package/gui/dist/provider-icons/commandcode-color.svg +1 -0
  24. package/gui/dist/provider-icons/copilot-color.svg +1 -0
  25. package/gui/dist/provider-icons/cursor-color.svg +2 -0
  26. package/gui/dist/provider-icons/deepseek-color.svg +1 -0
  27. package/gui/dist/provider-icons/discord.svg +1 -0
  28. package/gui/dist/provider-icons/firepass-color.svg +1 -0
  29. package/gui/dist/provider-icons/fireworks-color.svg +1 -0
  30. package/gui/dist/provider-icons/gemini-color.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.svg +1 -0
  34. package/gui/dist/provider-icons/groq-color.svg +1 -0
  35. package/gui/dist/provider-icons/huggingface-color.svg +1 -0
  36. package/gui/dist/provider-icons/kimi-color.svg +1 -0
  37. package/gui/dist/provider-icons/kiro-color.svg +15 -0
  38. package/gui/dist/provider-icons/lm-studio-color.svg +1 -0
  39. package/gui/dist/provider-icons/mistral-color.svg +1 -0
  40. package/gui/dist/provider-icons/moonshot-color.svg +1 -0
  41. package/gui/dist/provider-icons/nvidia-color.svg +1 -0
  42. package/gui/dist/provider-icons/ollama-color.svg +1 -0
  43. package/gui/dist/provider-icons/openai.svg +1 -0
  44. package/gui/dist/provider-icons/opencode.svg +2 -0
  45. package/gui/dist/provider-icons/openrouter-color.svg +1 -0
  46. package/gui/dist/provider-icons/pi.svg +21 -0
  47. package/gui/dist/provider-icons/qianfan-color.svg +1 -0
  48. package/gui/dist/provider-icons/qwen-portal-color.svg +1 -0
  49. package/gui/dist/provider-icons/telegram.svg +1 -0
  50. package/gui/dist/provider-icons/vercel-ai-gateway-color.svg +1 -0
  51. package/gui/dist/provider-icons/vllm-color.svg +1 -0
  52. package/gui/dist/provider-icons/xiaomi-color.svg +1 -0
  53. package/package.json +118 -0
  54. package/src/AGENTS.md +28 -0
  55. package/src/adapters/anthropic-image-guard.ts +251 -0
  56. package/src/adapters/anthropic-image-normalize.ts +518 -0
  57. package/src/adapters/anthropic.ts +1205 -0
  58. package/src/adapters/azure.ts +36 -0
  59. package/src/adapters/base.ts +83 -0
  60. package/src/adapters/client-fingerprint.ts +59 -0
  61. package/src/adapters/command-code.ts +453 -0
  62. package/src/adapters/cursor/arg-codec.ts +38 -0
  63. package/src/adapters/cursor/arg-normalize.ts +104 -0
  64. package/src/adapters/cursor/cursor-errors.ts +165 -0
  65. package/src/adapters/cursor/discovery.ts +276 -0
  66. package/src/adapters/cursor/effort-map.ts +139 -0
  67. package/src/adapters/cursor/exec-policy.ts +88 -0
  68. package/src/adapters/cursor/framing.ts +250 -0
  69. package/src/adapters/cursor/gen/agent_pb.ts +15274 -0
  70. package/src/adapters/cursor/kv-store.ts +52 -0
  71. package/src/adapters/cursor/live-models.ts +153 -0
  72. package/src/adapters/cursor/live-smoke-gate.ts +41 -0
  73. package/src/adapters/cursor/live-transport.ts +1235 -0
  74. package/src/adapters/cursor/mcp-config.ts +42 -0
  75. package/src/adapters/cursor/mcp-manager.ts +333 -0
  76. package/src/adapters/cursor/message-mapper.ts +49 -0
  77. package/src/adapters/cursor/native-exec-common.ts +59 -0
  78. package/src/adapters/cursor/native-exec-desktop.ts +184 -0
  79. package/src/adapters/cursor/native-exec-fs.ts +332 -0
  80. package/src/adapters/cursor/native-exec-mcp.ts +153 -0
  81. package/src/adapters/cursor/native-exec-network.ts +43 -0
  82. package/src/adapters/cursor/native-exec-shell.ts +548 -0
  83. package/src/adapters/cursor/native-exec-tools.ts +118 -0
  84. package/src/adapters/cursor/native-exec.ts +604 -0
  85. package/src/adapters/cursor/protobuf-events.ts +735 -0
  86. package/src/adapters/cursor/protobuf-request.ts +719 -0
  87. package/src/adapters/cursor/request-builder.ts +280 -0
  88. package/src/adapters/cursor/thread-continuity.ts +67 -0
  89. package/src/adapters/cursor/tool-definitions.ts +621 -0
  90. package/src/adapters/cursor/transport-retry.ts +132 -0
  91. package/src/adapters/cursor/transport.ts +57 -0
  92. package/src/adapters/cursor/types.ts +59 -0
  93. package/src/adapters/cursor.ts +196 -0
  94. package/src/adapters/google-antigravity-replay.ts +520 -0
  95. package/src/adapters/google-antigravity-wire.ts +140 -0
  96. package/src/adapters/google-errors.ts +85 -0
  97. package/src/adapters/google-http.ts +100 -0
  98. package/src/adapters/google-tool-schema.ts +173 -0
  99. package/src/adapters/google-truncation.ts +24 -0
  100. package/src/adapters/google-wire-compiler.ts +232 -0
  101. package/src/adapters/google.ts +859 -0
  102. package/src/adapters/identity.ts +77 -0
  103. package/src/adapters/image.ts +23 -0
  104. package/src/adapters/kiro-constants.ts +16 -0
  105. package/src/adapters/kiro-errors.ts +208 -0
  106. package/src/adapters/kiro-events.ts +197 -0
  107. package/src/adapters/kiro-images.ts +129 -0
  108. package/src/adapters/kiro-retry.ts +312 -0
  109. package/src/adapters/kiro-thinking.ts +104 -0
  110. package/src/adapters/kiro-tool-fallback.ts +36 -0
  111. package/src/adapters/kiro-tools.ts +224 -0
  112. package/src/adapters/kiro-truncation.ts +33 -0
  113. package/src/adapters/kiro-wire.ts +129 -0
  114. package/src/adapters/kiro.ts +1924 -0
  115. package/src/adapters/mimo-free.ts +263 -0
  116. package/src/adapters/openai-chat.ts +1265 -0
  117. package/src/adapters/openai-responses.ts +1309 -0
  118. package/src/adapters/run-turn-queue.ts +114 -0
  119. package/src/adapters/tool-catalog-nudge.ts +71 -0
  120. package/src/adapters/upstream-http-error.ts +48 -0
  121. package/src/android-remote/assets.ts +218 -0
  122. package/src/android-remote/attachments.ts +168 -0
  123. package/src/android-remote/auth.ts +237 -0
  124. package/src/android-remote/cloudflare-provisioning.ts +409 -0
  125. package/src/android-remote/cloudflare-secret.ts +106 -0
  126. package/src/android-remote/cloudflare-tunnel.ts +488 -0
  127. package/src/android-remote/cloudflared.ts +286 -0
  128. package/src/android-remote/codex-app-server.ts +565 -0
  129. package/src/android-remote/desktop-history-page.ts +936 -0
  130. package/src/android-remote/desktop-ipc.ts +3643 -0
  131. package/src/android-remote/desktop-ownership-store.ts +98 -0
  132. package/src/android-remote/desktop-project-registration.ts +129 -0
  133. package/src/android-remote/desktop-session-stream.ts +1110 -0
  134. package/src/android-remote/desktop-workspace-state.ts +443 -0
  135. package/src/android-remote/file-change-parser.ts +112 -0
  136. package/src/android-remote/gateway.ts +9108 -0
  137. package/src/android-remote/mutation-store.ts +299 -0
  138. package/src/android-remote/projection.ts +1780 -0
  139. package/src/android-remote/queued-turn-store.ts +248 -0
  140. package/src/android-remote/session-command-recovery.ts +1384 -0
  141. package/src/android-remote/store.ts +466 -0
  142. package/src/android-remote/thread-reconciliation.ts +133 -0
  143. package/src/android-remote/thread-source-paths.ts +307 -0
  144. package/src/android-remote/thread-stream.ts +546 -0
  145. package/src/android-remote/turn-activity.ts +235 -0
  146. package/src/android-remote/user-message-identity.ts +94 -0
  147. package/src/bridge.ts +1793 -0
  148. package/src/chat/inbound.ts +295 -0
  149. package/src/chat/outbound.ts +821 -0
  150. package/src/claude/agents-inject.ts +267 -0
  151. package/src/claude/alias.ts +149 -0
  152. package/src/claude/auth-detect.ts +229 -0
  153. package/src/claude/auth-mode-migration.ts +32 -0
  154. package/src/claude/auth-mode.ts +62 -0
  155. package/src/claude/context-windows.ts +189 -0
  156. package/src/claude/desktop-3p-guard.ts +35 -0
  157. package/src/claude/desktop-3p-paths.ts +84 -0
  158. package/src/claude/desktop-3p.ts +601 -0
  159. package/src/claude/desktop-health.ts +26 -0
  160. package/src/claude/desktop-profile.ts +263 -0
  161. package/src/claude/gateway-cache.ts +70 -0
  162. package/src/claude/inbound-debug.ts +163 -0
  163. package/src/claude/inbound.ts +519 -0
  164. package/src/claude/model-info.ts +154 -0
  165. package/src/claude/outbound.ts +898 -0
  166. package/src/cli/access.ts +108 -0
  167. package/src/cli/account-api.ts +296 -0
  168. package/src/cli/account-auth.ts +250 -0
  169. package/src/cli/account-catalog-refresh.ts +14 -0
  170. package/src/cli/account-extended.ts +476 -0
  171. package/src/cli/account-main.ts +317 -0
  172. package/src/cli/account.ts +297 -0
  173. package/src/cli/agent-driven.ts +70 -0
  174. package/src/cli/agent.ts +184 -0
  175. package/src/cli/catalog-prewarm.ts +27 -0
  176. package/src/cli/claude-desktop.ts +211 -0
  177. package/src/cli/claude.ts +302 -0
  178. package/src/cli/codex-shim-autorestore.ts +45 -0
  179. package/src/cli/codex-shim-readiness.ts +69 -0
  180. package/src/cli/combo.ts +124 -0
  181. package/src/cli/config-command.ts +183 -0
  182. package/src/cli/debug.ts +228 -0
  183. package/src/cli/desktop-first-run.ts +25 -0
  184. package/src/cli/doctor.ts +1022 -0
  185. package/src/cli/export-command.ts +201 -0
  186. package/src/cli/help.ts +370 -0
  187. package/src/cli/index.ts +1565 -0
  188. package/src/cli/init.ts +224 -0
  189. package/src/cli/integrations.ts +225 -0
  190. package/src/cli/interactive-confirm.ts +133 -0
  191. package/src/cli/internal-dispatch.ts +35 -0
  192. package/src/cli/launcher-context.ts +77 -0
  193. package/src/cli/models-runtime.ts +224 -0
  194. package/src/cli/models.ts +340 -0
  195. package/src/cli/observe.ts +170 -0
  196. package/src/cli/opencode.ts +587 -0
  197. package/src/cli/provider-runtime.ts +179 -0
  198. package/src/cli/provider.ts +476 -0
  199. package/src/cli/ready.ts +301 -0
  200. package/src/cli/route-policy.ts +92 -0
  201. package/src/cli/runtime-api.ts +328 -0
  202. package/src/cli/star-prompt.ts +211 -0
  203. package/src/cli/status-oauth.ts +78 -0
  204. package/src/cli/status.ts +321 -0
  205. package/src/cli/system-command.ts +196 -0
  206. package/src/cli/system-restart-client.ts +146 -0
  207. package/src/cli/tray-proxy.ts +205 -0
  208. package/src/cli/v2.ts +200 -0
  209. package/src/cli.ts +10 -0
  210. package/src/clients/config-export.ts +1109 -0
  211. package/src/codex/account-id.ts +34 -0
  212. package/src/codex/account-label.ts +34 -0
  213. package/src/codex/account-lifecycle.ts +172 -0
  214. package/src/codex/account-namespace-match.ts +63 -0
  215. package/src/codex/account-namespaces.ts +195 -0
  216. package/src/codex/account-pause.ts +20 -0
  217. package/src/codex/account-priority.ts +83 -0
  218. package/src/codex/account-runtime-state.ts +31 -0
  219. package/src/codex/account-store.ts +517 -0
  220. package/src/codex/account-usability.ts +40 -0
  221. package/src/codex/admission.ts +263 -0
  222. package/src/codex/app-server-processes.ts +799 -0
  223. package/src/codex/auth-api.ts +2098 -0
  224. package/src/codex/auth-collision.ts +107 -0
  225. package/src/codex/auth-context.ts +480 -0
  226. package/src/codex/autostart-health.ts +156 -0
  227. package/src/codex/catalog/account-models.ts +67 -0
  228. package/src/codex/catalog/aggregation.ts +471 -0
  229. package/src/codex/catalog/bundled.ts +533 -0
  230. package/src/codex/catalog/effort.ts +432 -0
  231. package/src/codex/catalog/filesystem-evidence.ts +302 -0
  232. package/src/codex/catalog/kinds.ts +2 -0
  233. package/src/codex/catalog/metadata.ts +287 -0
  234. package/src/codex/catalog/native-models.ts +7 -0
  235. package/src/codex/catalog/parsing.ts +503 -0
  236. package/src/codex/catalog/provider-fetch.ts +2267 -0
  237. package/src/codex/catalog/sync.ts +1606 -0
  238. package/src/codex/catalog-admission.ts +197 -0
  239. package/src/codex/catalog-refresh-status.ts +87 -0
  240. package/src/codex/catalog-write-serialization.ts +242 -0
  241. package/src/codex/catalog.ts +15 -0
  242. package/src/codex/codex-write-lock.ts +384 -0
  243. package/src/codex/convergence-types.ts +593 -0
  244. package/src/codex/convergence.ts +580 -0
  245. package/src/codex/custom-model-catalog-migration.ts +176 -0
  246. package/src/codex/data/upstream-models.json +830 -0
  247. package/src/codex/desired-state.ts +230 -0
  248. package/src/codex/desktop-client-processes.ts +521 -0
  249. package/src/codex/exec-invocation.ts +22 -0
  250. package/src/codex/features.ts +1091 -0
  251. package/src/codex/generation.ts +202 -0
  252. package/src/codex/history-job.ts +347 -0
  253. package/src/codex/history-lock.ts +242 -0
  254. package/src/codex/history-migration-guardian.ts +115 -0
  255. package/src/codex/history-provider.ts +1075 -0
  256. package/src/codex/history-transition.ts +105 -0
  257. package/src/codex/history-worker.ts +204 -0
  258. package/src/codex/home.ts +206 -0
  259. package/src/codex/inject-coordination.ts +257 -0
  260. package/src/codex/inject.ts +1857 -0
  261. package/src/codex/injected-marker.ts +79 -0
  262. package/src/codex/integration-record.ts +266 -0
  263. package/src/codex/internal/catalog-writer.ts +203 -0
  264. package/src/codex/internal/history-writer.ts +105 -0
  265. package/src/codex/journal.ts +172 -0
  266. package/src/codex/main-account-cache.ts +56 -0
  267. package/src/codex/main-account.ts +40 -0
  268. package/src/codex/management-convergence.ts +114 -0
  269. package/src/codex/model-cache.ts +267 -0
  270. package/src/codex/native-main-admission.ts +47 -0
  271. package/src/codex/native-main-auth-temp.ts +187 -0
  272. package/src/codex/native-main-claim.ts +167 -0
  273. package/src/codex/native-main-lock-file.ts +162 -0
  274. package/src/codex/native-main-owner.ts +329 -0
  275. package/src/codex/native-profile-api.ts +247 -0
  276. package/src/codex/native-profile-manager.ts +1531 -0
  277. package/src/codex/native-profile-processes.ts +121 -0
  278. package/src/codex/native-profile-recovery.ts +99 -0
  279. package/src/codex/native-profile-stage-store.ts +387 -0
  280. package/src/codex/native-profile-startup.ts +348 -0
  281. package/src/codex/native-profile-store.ts +855 -0
  282. package/src/codex/native-profile-types.ts +120 -0
  283. package/src/codex/native-residue.ts +691 -0
  284. package/src/codex/paths.ts +78 -0
  285. package/src/codex/plugins-doctor.ts +242 -0
  286. package/src/codex/pool-rotation.ts +295 -0
  287. package/src/codex/project-config-warnings.ts +426 -0
  288. package/src/codex/prompt-journal.ts +311 -0
  289. package/src/codex/prompt-layers.ts +967 -0
  290. package/src/codex/prompt-lock.ts +143 -0
  291. package/src/codex/provider-adoption.ts +242 -0
  292. package/src/codex/quota-rejection.ts +224 -0
  293. package/src/codex/quota.ts +494 -0
  294. package/src/codex/refresh.ts +60 -0
  295. package/src/codex/routing.ts +1855 -0
  296. package/src/codex/runtime.ts +659 -0
  297. package/src/codex/shim.ts +1215 -0
  298. package/src/codex/subagent-defaults.ts +557 -0
  299. package/src/codex/subagent-model-fallback.ts +560 -0
  300. package/src/codex/sync.ts +238 -0
  301. package/src/codex/transition-state.ts +612 -0
  302. package/src/codex/upstream-host-health.ts +368 -0
  303. package/src/codex/user-identity.ts +374 -0
  304. package/src/codex/warmup.ts +192 -0
  305. package/src/codex/websocket-registry.ts +100 -0
  306. package/src/codex/write-coordination.ts +114 -0
  307. package/src/combos/failover.ts +140 -0
  308. package/src/combos/index.ts +44 -0
  309. package/src/combos/request.ts +64 -0
  310. package/src/combos/resolve.ts +232 -0
  311. package/src/combos/types.ts +392 -0
  312. package/src/config.ts +3270 -0
  313. package/src/generated/model-metadata.ts +144 -0
  314. package/src/github/star-state.ts +203 -0
  315. package/src/grok/inject.ts +540 -0
  316. package/src/grok/inspect.ts +45 -0
  317. package/src/grok/status.ts +127 -0
  318. package/src/grok/sync.ts +66 -0
  319. package/src/images/artifacts.ts +516 -0
  320. package/src/images/fulfill-video.ts +163 -0
  321. package/src/images/fulfill.ts +149 -0
  322. package/src/images/index.ts +4 -0
  323. package/src/images/loop.ts +922 -0
  324. package/src/images/plan.ts +133 -0
  325. package/src/images/synthetic-tool.ts +133 -0
  326. package/src/images/types.ts +41 -0
  327. package/src/images/xai-client.ts +141 -0
  328. package/src/images/xai-video-client.ts +163 -0
  329. package/src/index.ts +22 -0
  330. package/src/integrations/config-io.ts +151 -0
  331. package/src/integrations/journal.ts +315 -0
  332. package/src/integrations/merge.ts +135 -0
  333. package/src/integrations/native/ownership-preflight.ts +202 -0
  334. package/src/integrations/ownership.ts +111 -0
  335. package/src/integrations/registry.ts +108 -0
  336. package/src/integrations/serialize.ts +235 -0
  337. package/src/integrations/state.ts +290 -0
  338. package/src/integrations/store.ts +103 -0
  339. package/src/integrations/writer.ts +492 -0
  340. package/src/lib/abort.ts +146 -0
  341. package/src/lib/admin-secrets.ts +25 -0
  342. package/src/lib/admission.ts +83 -0
  343. package/src/lib/app-owned-memory-stores.ts +173 -0
  344. package/src/lib/app-owned-memory.ts +265 -0
  345. package/src/lib/bounded-body.ts +242 -0
  346. package/src/lib/bun-binary-validator.d.mts +3 -0
  347. package/src/lib/bun-binary-validator.mjs +18 -0
  348. package/src/lib/bun-runtime.ts +184 -0
  349. package/src/lib/bun-stream-caps.ts +127 -0
  350. package/src/lib/config-ownership.ts +438 -0
  351. package/src/lib/crash-guard.ts +344 -0
  352. package/src/lib/debug-log-buffer.ts +83 -0
  353. package/src/lib/debug-settings.ts +108 -0
  354. package/src/lib/debug.ts +31 -0
  355. package/src/lib/destination-policy.ts +316 -0
  356. package/src/lib/errors.ts +364 -0
  357. package/src/lib/eventstream-decoder.ts +253 -0
  358. package/src/lib/gcp-adc.ts +341 -0
  359. package/src/lib/injection-debug-log.ts +58 -0
  360. package/src/lib/local-management-attestation.ts +51 -0
  361. package/src/lib/open-url.ts +25 -0
  362. package/src/lib/pinned-http.ts +182 -0
  363. package/src/lib/privacy.ts +20 -0
  364. package/src/lib/process-control.ts +168 -0
  365. package/src/lib/provider-environment.ts +470 -0
  366. package/src/lib/provider-outbound.ts +203 -0
  367. package/src/lib/provider-url.ts +14 -0
  368. package/src/lib/proxy-env.ts +18 -0
  369. package/src/lib/redact.ts +510 -0
  370. package/src/lib/remodex-home.ts +616 -0
  371. package/src/lib/retry-after.ts +55 -0
  372. package/src/lib/service-secrets.ts +178 -0
  373. package/src/lib/shadow-call.ts +54 -0
  374. package/src/lib/sidecar-tracker.ts +52 -0
  375. package/src/lib/sse-decoder.ts +364 -0
  376. package/src/lib/state-store-registrations.ts +109 -0
  377. package/src/lib/state-store-sweeper.ts +184 -0
  378. package/src/lib/system-restart-contract.ts +73 -0
  379. package/src/lib/test-home-guard.ts +98 -0
  380. package/src/lib/token-estimate.ts +69 -0
  381. package/src/lib/translator-budget.ts +366 -0
  382. package/src/lib/upstream-reachability.ts +91 -0
  383. package/src/lib/upstream-retry.ts +508 -0
  384. package/src/lib/win-exec.ts +115 -0
  385. package/src/lib/win-paths.ts +68 -0
  386. package/src/lib/windows-elevation.ts +705 -0
  387. package/src/lib/windows-secret-acl.ts +817 -0
  388. package/src/lib/windows-user-principal.ts +283 -0
  389. package/src/lib/winsw.ts +402 -0
  390. package/src/model-sources.ts +73 -0
  391. package/src/oauth/anthropic-routing.ts +594 -0
  392. package/src/oauth/anthropic.ts +177 -0
  393. package/src/oauth/callback-server.ts +294 -0
  394. package/src/oauth/chatgpt.ts +150 -0
  395. package/src/oauth/command-code.ts +239 -0
  396. package/src/oauth/cursor.ts +231 -0
  397. package/src/oauth/github-copilot.ts +428 -0
  398. package/src/oauth/google-antigravity.ts +230 -0
  399. package/src/oauth/health.ts +443 -0
  400. package/src/oauth/index.ts +1280 -0
  401. package/src/oauth/key-providers.ts +128 -0
  402. package/src/oauth/kimi.ts +213 -0
  403. package/src/oauth/kiro-credentials.ts +726 -0
  404. package/src/oauth/kiro.ts +621 -0
  405. package/src/oauth/local-token-detect.ts +121 -0
  406. package/src/oauth/log.ts +48 -0
  407. package/src/oauth/login-cli.ts +163 -0
  408. package/src/oauth/pkce.ts +15 -0
  409. package/src/oauth/store.ts +655 -0
  410. package/src/oauth/token-guardian.ts +309 -0
  411. package/src/oauth/types.ts +62 -0
  412. package/src/oauth/xai.ts +241 -0
  413. package/src/providers/alibaba-region-backup.ts +75 -0
  414. package/src/providers/alibaba-region-migration.ts +156 -0
  415. package/src/providers/alibaba-region-startup.ts +36 -0
  416. package/src/providers/antigravity-models.ts +317 -0
  417. package/src/providers/api-keys.ts +140 -0
  418. package/src/providers/base-url-choices.ts +64 -0
  419. package/src/providers/codex-capacity.ts +288 -0
  420. package/src/providers/command-code-efforts.ts +85 -0
  421. package/src/providers/context-cap.ts +73 -0
  422. package/src/providers/derive.ts +451 -0
  423. package/src/providers/free-directory.ts +187 -0
  424. package/src/providers/github-copilot-transport.ts +56 -0
  425. package/src/providers/google-vertex-location.ts +14 -0
  426. package/src/providers/key-failover.ts +271 -0
  427. package/src/providers/kiro-models.ts +67 -0
  428. package/src/providers/label.ts +19 -0
  429. package/src/providers/model-discovery-limits.ts +16 -0
  430. package/src/providers/model-discovery.ts +361 -0
  431. package/src/providers/openai-sidecar.ts +235 -0
  432. package/src/providers/openai-tier-startup.ts +27 -0
  433. package/src/providers/openai-tiers.ts +301 -0
  434. package/src/providers/openai-virtual-models.ts +83 -0
  435. package/src/providers/openrouter-routing.ts +102 -0
  436. package/src/providers/provider-id-rewrite.ts +179 -0
  437. package/src/providers/quota.ts +1942 -0
  438. package/src/providers/reasoning-capabilities.ts +336 -0
  439. package/src/providers/registry.ts +2375 -0
  440. package/src/providers/slug-codec.ts +74 -0
  441. package/src/providers/xai-transport.ts +149 -0
  442. package/src/reasoning-effort.ts +243 -0
  443. package/src/responses/compaction.ts +124 -0
  444. package/src/responses/hosted-tool-policy.ts +9 -0
  445. package/src/responses/parser.ts +714 -0
  446. package/src/responses/reasoning-envelope.ts +60 -0
  447. package/src/responses/reasoning-replay-cache.ts +106 -0
  448. package/src/responses/schema.ts +159 -0
  449. package/src/responses/spill-store.ts +431 -0
  450. package/src/responses/state.ts +1039 -0
  451. package/src/responses/tool-groups.ts +19 -0
  452. package/src/router.ts +802 -0
  453. package/src/routing/analytics.ts +377 -0
  454. package/src/routing/capability.ts +205 -0
  455. package/src/routing/cost.ts +77 -0
  456. package/src/routing/evaluator.ts +444 -0
  457. package/src/routing/health.ts +401 -0
  458. package/src/routing/history/cursor.ts +43 -0
  459. package/src/routing/history/indexer.ts +605 -0
  460. package/src/routing/history/schema.ts +72 -0
  461. package/src/routing/profile-namespace.ts +15 -0
  462. package/src/routing/profile.ts +424 -0
  463. package/src/routing/quota.ts +145 -0
  464. package/src/routing/request-evidence.ts +45 -0
  465. package/src/routing/trace.ts +686 -0
  466. package/src/server/adapter-resolve.ts +83 -0
  467. package/src/server/auth-cors.ts +606 -0
  468. package/src/server/chat-completions.ts +379 -0
  469. package/src/server/claude-messages.ts +980 -0
  470. package/src/server/effort-policy.ts +251 -0
  471. package/src/server/github-copilot-responses-repair.ts +338 -0
  472. package/src/server/gui-static.ts +152 -0
  473. package/src/server/image-retry.ts +42 -0
  474. package/src/server/images.ts +485 -0
  475. package/src/server/index.ts +1633 -0
  476. package/src/server/lifecycle.ts +482 -0
  477. package/src/server/live.ts +609 -0
  478. package/src/server/management/agent-settings-routes.ts +1180 -0
  479. package/src/server/management/android-remote-routes.ts +390 -0
  480. package/src/server/management/api-access.ts +141 -0
  481. package/src/server/management/api-key-usage.ts +167 -0
  482. package/src/server/management/body.ts +35 -0
  483. package/src/server/management/combo-routes.ts +244 -0
  484. package/src/server/management/config-routes.ts +602 -0
  485. package/src/server/management/context.ts +88 -0
  486. package/src/server/management/integration-routes.ts +538 -0
  487. package/src/server/management/logs-usage-routes.ts +516 -0
  488. package/src/server/management/model-routes.ts +519 -0
  489. package/src/server/management/model-rows.ts +143 -0
  490. package/src/server/management/native-integration-routes.ts +781 -0
  491. package/src/server/management/oauth-account-routes.ts +573 -0
  492. package/src/server/management/provider-routes.ts +781 -0
  493. package/src/server/management/request-history-routes.ts +191 -0
  494. package/src/server/management/routing-analytics-routes.ts +74 -0
  495. package/src/server/management/routing-profile-routes.ts +384 -0
  496. package/src/server/management/shared.ts +277 -0
  497. package/src/server/management/sidebar-routes.ts +106 -0
  498. package/src/server/management/sync-response.ts +69 -0
  499. package/src/server/management/system-restart.ts +433 -0
  500. package/src/server/management/system-routes.ts +141 -0
  501. package/src/server/management/usage-summary-cache.ts +86 -0
  502. package/src/server/management-api.ts +269 -0
  503. package/src/server/management-auth.ts +353 -0
  504. package/src/server/memory-watchdog.ts +156 -0
  505. package/src/server/port-reclaim.ts +307 -0
  506. package/src/server/ports.ts +156 -0
  507. package/src/server/proxy-liveness.ts +326 -0
  508. package/src/server/proxy-stop.ts +92 -0
  509. package/src/server/readiness.ts +99 -0
  510. package/src/server/relay-eager.ts +353 -0
  511. package/src/server/relay.ts +1179 -0
  512. package/src/server/request-decompress.ts +132 -0
  513. package/src/server/request-log-conversation.ts +168 -0
  514. package/src/server/request-log.ts +1072 -0
  515. package/src/server/responses/collaboration.ts +409 -0
  516. package/src/server/responses/compact.ts +710 -0
  517. package/src/server/responses/core.ts +3561 -0
  518. package/src/server/responses/encrypted-payload.ts +308 -0
  519. package/src/server/responses/fetch-helpers.ts +171 -0
  520. package/src/server/responses/passthrough-error.ts +78 -0
  521. package/src/server/responses/policy-fallback.ts +152 -0
  522. package/src/server/responses/terminal-guard.ts +230 -0
  523. package/src/server/responses/upstream-error.ts +48 -0
  524. package/src/server/responses-image-gen-repair.ts +132 -0
  525. package/src/server/responses-item-id-repair.ts +272 -0
  526. package/src/server/responses-json-events.ts +52 -0
  527. package/src/server/responses-model-rewrite.ts +29 -0
  528. package/src/server/responses-snapshot-repair.ts +621 -0
  529. package/src/server/responses.ts +10 -0
  530. package/src/server/search.ts +181 -0
  531. package/src/server/sse-frame-buffer.ts +292 -0
  532. package/src/server/sse-payload-rewrite.ts +263 -0
  533. package/src/server/startup-action-control.ts +308 -0
  534. package/src/server/startup-health-cache.ts +119 -0
  535. package/src/server/system-env.ts +418 -0
  536. package/src/server/windows-tcp-drop.ts +184 -0
  537. package/src/server/windows-tray-control.ts +41 -0
  538. package/src/server/ws-bridge.ts +470 -0
  539. package/src/service-manager-probe.ts +824 -0
  540. package/src/service.ts +3011 -0
  541. package/src/stall-timeout.ts +20 -0
  542. package/src/storage/cleanup-job.ts +57 -0
  543. package/src/storage/cleanup.ts +3085 -0
  544. package/src/storage/policy-job.ts +457 -0
  545. package/src/storage/policy-scheduler.ts +40 -0
  546. package/src/storage/policy-worker.ts +59 -0
  547. package/src/storage/policy.ts +527 -0
  548. package/src/storage/restore-job.ts +299 -0
  549. package/src/storage/restore-worker.ts +58 -0
  550. package/src/storage/scanner.ts +238 -0
  551. package/src/storage/storage-mutation-coordinator.ts +139 -0
  552. package/src/storage/worker-lifecycle.ts +215 -0
  553. package/src/tray/assets/opencodex-tray-offline.ico +0 -0
  554. package/src/tray/assets/opencodex-tray-online.ico +0 -0
  555. package/src/tray/assets/opencodex-tray-warning.ico +0 -0
  556. package/src/tray/assets/opencodex-tray.png +0 -0
  557. package/src/tray/windows-tray.ps1 +364 -0
  558. package/src/tray/windows.ts +738 -0
  559. package/src/types.ts +1531 -0
  560. package/src/update/badge.ts +72 -0
  561. package/src/update/desktop-release.ts +1620 -0
  562. package/src/update/index.ts +402 -0
  563. package/src/update/job.ts +1906 -0
  564. package/src/update/notify.ts +261 -0
  565. package/src/update/npm-cache-preflight.d.mts +47 -0
  566. package/src/update/npm-cache-preflight.mjs +201 -0
  567. package/src/update/npm-invocation.d.mts +23 -0
  568. package/src/update/npm-invocation.mjs +94 -0
  569. package/src/update/tray-update-plan.d.mts +18 -0
  570. package/src/update/tray-update-plan.mjs +38 -0
  571. package/src/usage/cost.ts +0 -0
  572. package/src/usage/debug.ts +97 -0
  573. package/src/usage/expected-prices.ts +283 -0
  574. package/src/usage/log.ts +695 -0
  575. package/src/usage/summary.ts +585 -0
  576. package/src/usage/totals.ts +14 -0
  577. package/src/vision/anthropic-describe.ts +185 -0
  578. package/src/vision/describe.ts +127 -0
  579. package/src/vision/index.ts +558 -0
  580. package/src/vision/reasoning.ts +55 -0
  581. package/src/web-search/anthropic-executor.ts +189 -0
  582. package/src/web-search/executor.ts +105 -0
  583. package/src/web-search/format-result.ts +89 -0
  584. package/src/web-search/index.ts +196 -0
  585. package/src/web-search/loop.ts +791 -0
  586. package/src/web-search/parse.ts +235 -0
  587. package/src/web-search/progress-stream.ts +342 -0
  588. package/src/web-search/synthetic-tool.ts +47 -0
@@ -0,0 +1,301 @@
1
+ import type { CodexAccountMode, OcxConfig, OcxProviderConfig } from "../types";
2
+ import { OPENAI_PROVIDER_TIER_VERSION } from "../types";
3
+
4
+ export const OPENAI_CODEX_PROVIDER_ID = "openai";
5
+ export const LEGACY_OPENAI_MULTI_PROVIDER_ID = "openai-multi";
6
+ export const OPENAI_API_PROVIDER_ID = "openai-apikey";
7
+ export const LEGACY_CHATGPT_PROVIDER_ID = "chatgpt";
8
+
9
+ export const CODEX_FORWARD_BASE_URL = "https://chatgpt.com/backend-api/codex";
10
+ const LEGACY_OPENAI_MULTI_PREFIX = `${LEGACY_OPENAI_MULTI_PROVIDER_ID}/`;
11
+
12
+ function canonicalCodexForwardProvider(mode: CodexAccountMode): OcxProviderConfig {
13
+ return {
14
+ adapter: "openai-responses",
15
+ baseUrl: CODEX_FORWARD_BASE_URL,
16
+ authMode: "forward",
17
+ codexAccountMode: mode,
18
+ };
19
+ }
20
+
21
+ function normalizedBaseUrl(value: string): string | undefined {
22
+ try {
23
+ const url = new URL(value.trim());
24
+ if (url.username || url.password || url.search || url.hash) return undefined;
25
+ const path = url.pathname.replace(/\/+$/, "");
26
+ return `${url.origin}${path}`;
27
+ } catch {
28
+ return undefined;
29
+ }
30
+ }
31
+
32
+ export function isCanonicalOpenAiForwardProvider(provider: OcxProviderConfig): boolean {
33
+ return provider.adapter === "openai-responses"
34
+ && provider.authMode === "forward"
35
+ && normalizedBaseUrl(provider.baseUrl) === CODEX_FORWARD_BASE_URL;
36
+ }
37
+
38
+ const OPENAI_API_BASE_URL = "https://api.openai.com/v1";
39
+
40
+ /**
41
+ * Whether this provider can serve `POST /responses/compact`. The canonical ChatGPT
42
+ * backend can, and so can the official OpenAI API — but an arbitrary gateway that
43
+ * merely speaks the Responses wire cannot, and calling it there fails compaction
44
+ * with an unhelpful error instead of falling back to a routed summary (#422).
45
+ */
46
+ export function supportsNativeResponsesCompactEndpoint(
47
+ providerName: string,
48
+ provider: OcxProviderConfig,
49
+ ): boolean {
50
+ if (isCanonicalOpenAiForwardProvider(provider)) return true;
51
+ return providerName === OPENAI_API_PROVIDER_ID
52
+ && provider.adapter === "openai-responses"
53
+ && normalizedBaseUrl(provider.baseUrl) === OPENAI_API_BASE_URL;
54
+ }
55
+
56
+ export interface OpenAiTierMigrationProjection {
57
+ config: OcxConfig;
58
+ changed: boolean;
59
+ resolvedMode: CodexAccountMode;
60
+ warnings: string[];
61
+ }
62
+
63
+ export class OpenAiTierMigrationCollisionError extends Error {
64
+ readonly providerName = LEGACY_OPENAI_MULTI_PROVIDER_ID;
65
+
66
+ constructor() {
67
+ super(`Reserved provider id "${LEGACY_OPENAI_MULTI_PROVIDER_ID}" is already configured with a noncanonical shape`);
68
+ this.name = "OpenAiTierMigrationCollisionError";
69
+ }
70
+ }
71
+
72
+ function managedLegacyMultiOverlay(provider: OcxProviderConfig): Pick<OcxProviderConfig, "disabled" | "selectedModels"> | null {
73
+ const allowed = new Set(["adapter", "authMode", "baseUrl", "disabled", "selectedModels"]);
74
+ if (!Object.keys(provider).every(key => allowed.has(key))) return null;
75
+ if (!isCanonicalOpenAiForwardProvider(provider)) return null;
76
+ if (provider.disabled !== undefined && typeof provider.disabled !== "boolean") return null;
77
+ if (provider.selectedModels !== undefined && (
78
+ !Array.isArray(provider.selectedModels)
79
+ || provider.selectedModels.some(model => typeof model !== "string")
80
+ )) return null;
81
+ return {
82
+ ...(provider.disabled !== undefined ? { disabled: provider.disabled } : {}),
83
+ ...(provider.selectedModels !== undefined ? { selectedModels: [...provider.selectedModels] } : {}),
84
+ };
85
+ }
86
+
87
+ function rewriteLegacyOpenAiSelectedId(value: string): string {
88
+ return value.startsWith(LEGACY_OPENAI_MULTI_PREFIX)
89
+ ? value.slice(LEGACY_OPENAI_MULTI_PREFIX.length)
90
+ : value;
91
+ }
92
+
93
+ function rewriteLegacyOpenAiModelList(values: string[] | undefined): string[] | undefined {
94
+ if (!values) return undefined;
95
+ return [...new Set(values.map(rewriteLegacyOpenAiSelectedId))];
96
+ }
97
+
98
+ function mergeLegacyOpenAiProviderRows(
99
+ openai: OcxProviderConfig | undefined,
100
+ legacyMulti: OcxProviderConfig | undefined,
101
+ mode: CodexAccountMode,
102
+ ): OcxProviderConfig {
103
+ const selectedModels = rewriteLegacyOpenAiModelList([
104
+ ...(openai?.selectedModels ?? []),
105
+ ...(legacyMulti?.selectedModels ?? []),
106
+ ]);
107
+ const formerRows = [openai, legacyMulti].filter((row): row is OcxProviderConfig => row !== undefined);
108
+ const disabled = formerRows.length > 0 && formerRows.every(row => row.disabled === true);
109
+ return {
110
+ ...canonicalCodexForwardProvider(mode),
111
+ ...(disabled ? { disabled: true } : {}),
112
+ ...(selectedModels && selectedModels.length > 0 ? { selectedModels } : {}),
113
+ };
114
+ }
115
+
116
+ function hasKnownLegacyOpenAiReference(config: OcxConfig): boolean {
117
+ const matches = (value: unknown): boolean => typeof value === "string" && value.startsWith(LEGACY_OPENAI_MULTI_PREFIX);
118
+ const matchesList = (value: unknown): boolean => Array.isArray(value) && value.some(matches);
119
+ const claude = config.claudeCode;
120
+ return config.defaultProvider === LEGACY_OPENAI_MULTI_PROVIDER_ID
121
+ || matchesList(config.disabledModels)
122
+ || matchesList(config.subagentModels)
123
+ || matches(config.injectionModel)
124
+ || matches(config.shadowCallIntercept?.model)
125
+ || matches(config.webSearchSidecar?.model)
126
+ || matches(config.visionSidecar?.model)
127
+ || matches(claude?.webSearchSidecar?.model)
128
+ || matches(claude?.visionSidecar?.model)
129
+ || matches(claude?.model)
130
+ || matches(claude?.smallFastModel)
131
+ || Object.values(claude?.tierModels ?? {}).some(matches)
132
+ || Object.values(claude?.modelMap ?? {}).some(matches)
133
+ || matchesList(config.providers[OPENAI_CODEX_PROVIDER_ID]?.selectedModels)
134
+ || matchesList(config.providers[LEGACY_OPENAI_MULTI_PROVIDER_ID]?.selectedModels)
135
+ || config.providerContextCaps?.[LEGACY_OPENAI_MULTI_PROVIDER_ID] !== undefined;
136
+ }
137
+
138
+ function rewriteLegacyOpenAiReferences(config: OcxConfig, warnings: string[]): void {
139
+ config.disabledModels = rewriteLegacyOpenAiModelList(config.disabledModels);
140
+ config.subagentModels = rewriteLegacyOpenAiModelList(config.subagentModels);
141
+ if (config.injectionModel) config.injectionModel = rewriteLegacyOpenAiSelectedId(config.injectionModel);
142
+ if (config.shadowCallIntercept?.model) {
143
+ config.shadowCallIntercept.model = rewriteLegacyOpenAiSelectedId(config.shadowCallIntercept.model);
144
+ }
145
+ if (config.webSearchSidecar?.model) config.webSearchSidecar.model = rewriteLegacyOpenAiSelectedId(config.webSearchSidecar.model);
146
+ if (config.visionSidecar?.model) config.visionSidecar.model = rewriteLegacyOpenAiSelectedId(config.visionSidecar.model);
147
+
148
+ const claude = config.claudeCode;
149
+ if (claude?.webSearchSidecar?.model) claude.webSearchSidecar.model = rewriteLegacyOpenAiSelectedId(claude.webSearchSidecar.model);
150
+ if (claude?.visionSidecar?.model) claude.visionSidecar.model = rewriteLegacyOpenAiSelectedId(claude.visionSidecar.model);
151
+ if (claude?.model) claude.model = rewriteLegacyOpenAiSelectedId(claude.model);
152
+ if (claude?.smallFastModel) claude.smallFastModel = rewriteLegacyOpenAiSelectedId(claude.smallFastModel);
153
+ if (claude?.tierModels) {
154
+ for (const tier of ["opus", "sonnet", "haiku", "fable"] as const) {
155
+ const value = claude.tierModels[tier];
156
+ if (value) claude.tierModels[tier] = rewriteLegacyOpenAiSelectedId(value);
157
+ }
158
+ }
159
+ if (claude?.modelMap) {
160
+ for (const key of Object.keys(claude.modelMap)) {
161
+ claude.modelMap[key] = rewriteLegacyOpenAiSelectedId(claude.modelMap[key]!);
162
+ }
163
+ }
164
+
165
+ const caps = config.providerContextCaps;
166
+ const legacyCap = caps?.[LEGACY_OPENAI_MULTI_PROVIDER_ID];
167
+ if (caps && legacyCap !== undefined) {
168
+ const currentCap = caps[OPENAI_CODEX_PROVIDER_ID];
169
+ if (currentCap !== undefined) {
170
+ caps[OPENAI_CODEX_PROVIDER_ID] = Math.min(currentCap, legacyCap);
171
+ warnings.push("providerContextCaps.openai + providerContextCaps.openai-multi: kept lower positive cap");
172
+ } else {
173
+ caps[OPENAI_CODEX_PROVIDER_ID] = legacyCap;
174
+ }
175
+ delete caps[LEGACY_OPENAI_MULTI_PROVIDER_ID];
176
+ }
177
+ }
178
+
179
+ function isKnownLegacyValuePath(path: readonly string[]): boolean {
180
+ const joined = path.join(".");
181
+ if (joined === "defaultProvider") return true;
182
+ if (/^(disabledModels|subagentModels)\.\d+$/.test(joined)) return true;
183
+ if (/^providers\.(openai|openai-multi)\.selectedModels\.\d+$/.test(joined)) return true;
184
+ return new Set([
185
+ "injectionModel",
186
+ "shadowCallIntercept.model",
187
+ "webSearchSidecar.model",
188
+ "visionSidecar.model",
189
+ "claudeCode.webSearchSidecar.model",
190
+ "claudeCode.visionSidecar.model",
191
+ "claudeCode.model",
192
+ "claudeCode.smallFastModel",
193
+ "claudeCode.tierModels.opus",
194
+ "claudeCode.tierModels.sonnet",
195
+ "claudeCode.tierModels.haiku",
196
+ "claudeCode.tierModels.fable",
197
+ ]).has(joined) || /^claudeCode\.modelMap\..+$/.test(joined);
198
+ }
199
+
200
+ function unknownLegacyOpenAiWarnings(config: OcxConfig): string[] {
201
+ const warnings = new Set<string>();
202
+ const visit = (value: unknown, path: string[]): void => {
203
+ if (typeof value === "string") {
204
+ if (value.includes(LEGACY_OPENAI_MULTI_PROVIDER_ID) && !isKnownLegacyValuePath(path)) {
205
+ warnings.add(`${path.join(".")}: legacy OpenAI provider id left unchanged`);
206
+ }
207
+ return;
208
+ }
209
+ if (!value || typeof value !== "object") return;
210
+ if (Array.isArray(value)) {
211
+ value.forEach((item, index) => visit(item, [...path, String(index)]));
212
+ return;
213
+ }
214
+ for (const [key, item] of Object.entries(value as Record<string, unknown>)) {
215
+ visit(item, [...path, key]);
216
+ }
217
+ };
218
+ visit(config, []);
219
+ return [...warnings];
220
+ }
221
+
222
+ function resolvedOpenAiMode(
223
+ config: OcxConfig,
224
+ openai: OcxProviderConfig | undefined,
225
+ legacyMulti: OcxProviderConfig | undefined,
226
+ knownLegacyReference: boolean,
227
+ ): CodexAccountMode {
228
+ if (openai?.codexAccountMode === "pool" || openai?.codexAccountMode === "direct") {
229
+ return openai.codexAccountMode;
230
+ }
231
+ if (
232
+ (legacyMulti && legacyMulti.disabled !== true)
233
+ || config.defaultProvider === LEGACY_OPENAI_MULTI_PROVIDER_ID
234
+ || knownLegacyReference
235
+ ) return "pool";
236
+ if (config.openaiProviderTierVersion === 1 && openai) return "direct";
237
+ if (config.openaiProviderTierVersion === 1 && legacyMulti) return "pool";
238
+ return "pool";
239
+ }
240
+
241
+ export function projectOpenAiTierMigration(config: OcxConfig): OpenAiTierMigrationProjection {
242
+ const projected = structuredClone(config);
243
+ const legacyMulti = projected.providers[LEGACY_OPENAI_MULTI_PROVIDER_ID];
244
+ if (legacyMulti && !managedLegacyMultiOverlay(legacyMulti)) {
245
+ throw new OpenAiTierMigrationCollisionError();
246
+ }
247
+
248
+ const openai = projected.providers[OPENAI_CODEX_PROVIDER_ID];
249
+ const knownLegacyReference = hasKnownLegacyOpenAiReference(projected);
250
+ const resolvedMode = resolvedOpenAiMode(projected, openai, legacyMulti, knownLegacyReference);
251
+ if (
252
+ projected.openaiProviderTierVersion === OPENAI_PROVIDER_TIER_VERSION
253
+ && !legacyMulti
254
+ && !Object.hasOwn(projected.providers, LEGACY_CHATGPT_PROVIDER_ID)
255
+ && projected.defaultProvider !== LEGACY_OPENAI_MULTI_PROVIDER_ID
256
+ && !knownLegacyReference
257
+ ) {
258
+ return { config: projected, changed: false, resolvedMode, warnings: [] };
259
+ }
260
+
261
+ const warnings = unknownLegacyOpenAiWarnings(projected);
262
+ const referencesCodexForward = !!openai
263
+ || !!legacyMulti
264
+ || Object.hasOwn(projected.providers, LEGACY_CHATGPT_PROVIDER_ID)
265
+ || projected.defaultProvider === OPENAI_CODEX_PROVIDER_ID
266
+ || projected.defaultProvider === LEGACY_OPENAI_MULTI_PROVIDER_ID
267
+ || projected.defaultProvider === LEGACY_CHATGPT_PROVIDER_ID
268
+ || knownLegacyReference;
269
+ const mergedOpenAi = referencesCodexForward
270
+ ? mergeLegacyOpenAiProviderRows(openai, legacyMulti, resolvedMode)
271
+ : undefined;
272
+
273
+ const nextProviders: Array<[string, OcxProviderConfig]> = [];
274
+ let inserted = false;
275
+ for (const [name, provider] of Object.entries(projected.providers)) {
276
+ if (name === OPENAI_CODEX_PROVIDER_ID) {
277
+ if (mergedOpenAi && !inserted) nextProviders.push([OPENAI_CODEX_PROVIDER_ID, mergedOpenAi]);
278
+ inserted = true;
279
+ continue;
280
+ }
281
+ if (name === LEGACY_OPENAI_MULTI_PROVIDER_ID || name === LEGACY_CHATGPT_PROVIDER_ID) {
282
+ if (mergedOpenAi && !inserted && !openai) {
283
+ nextProviders.push([OPENAI_CODEX_PROVIDER_ID, mergedOpenAi]);
284
+ inserted = true;
285
+ }
286
+ continue;
287
+ }
288
+ nextProviders.push([name, provider]);
289
+ }
290
+ if (mergedOpenAi && !inserted) nextProviders.push([OPENAI_CODEX_PROVIDER_ID, mergedOpenAi]);
291
+ projected.providers = Object.fromEntries(nextProviders);
292
+
293
+ if (
294
+ projected.defaultProvider === LEGACY_OPENAI_MULTI_PROVIDER_ID
295
+ || projected.defaultProvider === LEGACY_CHATGPT_PROVIDER_ID
296
+ ) projected.defaultProvider = OPENAI_CODEX_PROVIDER_ID;
297
+
298
+ rewriteLegacyOpenAiReferences(projected, warnings);
299
+ projected.openaiProviderTierVersion = OPENAI_PROVIDER_TIER_VERSION;
300
+ return { config: projected, changed: true, resolvedMode, warnings: [...new Set(warnings)] };
301
+ }
@@ -0,0 +1,83 @@
1
+ import { PROVIDER_REGISTRY } from "./registry";
2
+ import { OPENAI_API_PROVIDER_ID } from "./openai-tiers";
3
+ import type { OcxParsedRequest } from "../types";
4
+ import type { RouteResult } from "../router";
5
+ import type { RequestLogContext } from "../server/request-log";
6
+
7
+ export interface OpenAiVirtualModelResolution {
8
+ selectedModelId: string;
9
+ wireModelId: string;
10
+ reasoningMode: "pro";
11
+ }
12
+
13
+ export class InvalidOpenAiVirtualModelRegistryError extends Error {
14
+ constructor(selectedModelId: string) {
15
+ super(`Invalid OpenAI virtual model registry definition: ${selectedModelId}`);
16
+ this.name = "InvalidOpenAiVirtualModelRegistryError";
17
+ }
18
+ }
19
+
20
+ export function validateOpenAiVirtualModelDefinition(
21
+ selectedModelId: string,
22
+ definition: unknown,
23
+ ): OpenAiVirtualModelResolution {
24
+ if (!definition || typeof definition !== "object" || Array.isArray(definition)) {
25
+ throw new InvalidOpenAiVirtualModelRegistryError(selectedModelId);
26
+ }
27
+ const raw = definition as { wireModelId?: unknown; reasoningMode?: unknown };
28
+ if (
29
+ typeof raw.wireModelId !== "string"
30
+ || raw.wireModelId.trim() !== raw.wireModelId
31
+ || raw.wireModelId.length === 0
32
+ || raw.wireModelId.includes("/")
33
+ || raw.wireModelId === selectedModelId
34
+ || raw.reasoningMode !== "pro"
35
+ ) {
36
+ throw new InvalidOpenAiVirtualModelRegistryError(selectedModelId);
37
+ }
38
+ return { selectedModelId, wireModelId: raw.wireModelId, reasoningMode: "pro" };
39
+ }
40
+
41
+ export function resolveOpenAiVirtualModel(
42
+ providerName: string,
43
+ selectedModelId: string,
44
+ ): OpenAiVirtualModelResolution | undefined {
45
+ if (providerName !== OPENAI_API_PROVIDER_ID) return undefined;
46
+ const entry = PROVIDER_REGISTRY.find(row => row.id === OPENAI_API_PROVIDER_ID);
47
+ if (!entry?.virtualModels || !Object.hasOwn(entry.virtualModels, selectedModelId)) return undefined;
48
+ const definition = entry.virtualModels[selectedModelId];
49
+ return validateOpenAiVirtualModelDefinition(selectedModelId, definition);
50
+ }
51
+
52
+ export function applyOpenAiVirtualModel(
53
+ parsed: OcxParsedRequest,
54
+ route: RouteResult,
55
+ logCtx: RequestLogContext,
56
+ ): OpenAiVirtualModelResolution | undefined {
57
+ const selectedModelId = logCtx.model && logCtx.model !== route.modelId ? logCtx.model : route.modelId;
58
+ const resolution = resolveOpenAiVirtualModel(route.providerName, selectedModelId);
59
+ if (!resolution) return undefined;
60
+
61
+ logCtx.model = resolution.selectedModelId;
62
+ logCtx.resolvedModel = resolution.wireModelId;
63
+ route.modelId = resolution.wireModelId;
64
+ parsed.modelId = resolution.wireModelId;
65
+ parsed._openAiVirtualSelectedModelId = resolution.selectedModelId;
66
+
67
+ if (parsed._rawBody && typeof parsed._rawBody === "object" && !Array.isArray(parsed._rawBody)) {
68
+ const raw = parsed._rawBody as Record<string, unknown>;
69
+ raw.model = resolution.wireModelId;
70
+ const existing = raw.reasoning;
71
+ raw.reasoning = existing && typeof existing === "object" && !Array.isArray(existing)
72
+ ? { ...(existing as Record<string, unknown>), mode: resolution.reasoningMode }
73
+ : { mode: resolution.reasoningMode };
74
+ }
75
+ return resolution;
76
+ }
77
+
78
+ export function resolveOpenAiCompactModel(
79
+ providerName: string,
80
+ selectedModelId: string,
81
+ ): OpenAiVirtualModelResolution | undefined {
82
+ return resolveOpenAiVirtualModel(providerName, selectedModelId);
83
+ }
@@ -0,0 +1,102 @@
1
+ import type { OcxProviderConfig, OpenRouterProviderRouting } from "../types";
2
+
3
+ const ROUTING_KEYS = new Set(["order", "only", "allowFallbacks"]);
4
+ const MAX_PROVIDER_SLUGS = 64;
5
+
6
+ function isPlainRecord(value: unknown): value is Record<string, unknown> {
7
+ if (!value || typeof value !== "object" || Array.isArray(value)) return false;
8
+ const prototype = Object.getPrototypeOf(value);
9
+ return prototype === Object.prototype || prototype === null;
10
+ }
11
+
12
+ export function isCanonicalOpenRouterTarget(baseUrl: string): boolean {
13
+ try {
14
+ const url = new URL(baseUrl);
15
+ return url.origin === "https://openrouter.ai"
16
+ && !url.username
17
+ && !url.password
18
+ && !url.search
19
+ && !url.hash
20
+ && url.pathname.replace(/\/+$/, "") === "/api/v1";
21
+ } catch {
22
+ return false;
23
+ }
24
+ }
25
+
26
+ function routingPreferenceError(value: unknown, field: string): string | null {
27
+ if (!isPlainRecord(value)) return `${field} must be a plain object`;
28
+ const unknown = Object.keys(value).find(key => !ROUTING_KEYS.has(key));
29
+ if (unknown) return `${field} contains unknown field "${unknown}"`;
30
+
31
+ for (const listField of ["order", "only"] as const) {
32
+ const list = value[listField];
33
+ if (list === undefined) continue;
34
+ if (!Array.isArray(list) || list.length === 0 || list.length > MAX_PROVIDER_SLUGS) {
35
+ return `${field}.${listField} must contain 1-${MAX_PROVIDER_SLUGS} provider slugs`;
36
+ }
37
+ const seen = new Set<string>();
38
+ for (const slug of list) {
39
+ if (typeof slug !== "string" || !slug.trim() || slug !== slug.trim() || slug.length > 128) {
40
+ return `${field}.${listField} must contain nonblank trimmed provider slugs up to 128 characters`;
41
+ }
42
+ if (seen.has(slug)) return `${field}.${listField} must not contain duplicate provider slugs`;
43
+ seen.add(slug);
44
+ }
45
+ }
46
+ if (value.allowFallbacks !== undefined && typeof value.allowFallbacks !== "boolean") {
47
+ return `${field}.allowFallbacks must be a boolean`;
48
+ }
49
+ if (value.order === undefined && value.only === undefined && value.allowFallbacks === undefined) {
50
+ return `${field} must define order, only, or allowFallbacks`;
51
+ }
52
+ return null;
53
+ }
54
+
55
+ export function openRouterRoutingConfigError(provider: OcxProviderConfig): string | null {
56
+ const hasDefault = provider.openRouterRouting !== undefined;
57
+ const hasModels = provider.modelOpenRouterRouting !== undefined;
58
+ if (!hasDefault && !hasModels) return null;
59
+ if (provider.adapter !== "openai-chat") {
60
+ return "OpenRouter routing preferences require the openai-chat adapter";
61
+ }
62
+ if (!isCanonicalOpenRouterTarget(provider.baseUrl)) {
63
+ return "OpenRouter routing preferences require the canonical https://openrouter.ai/api/v1 baseUrl";
64
+ }
65
+ if (hasDefault) {
66
+ const error = routingPreferenceError(provider.openRouterRouting, "openRouterRouting");
67
+ if (error) return error;
68
+ }
69
+ if (hasModels) {
70
+ const routes = provider.modelOpenRouterRouting;
71
+ if (!isPlainRecord(routes)) return "modelOpenRouterRouting must be a plain object";
72
+ for (const [modelId, preference] of Object.entries(routes)) {
73
+ if (!modelId.trim() || modelId !== modelId.trim()) {
74
+ return "modelOpenRouterRouting keys must be nonblank trimmed model ids";
75
+ }
76
+ const error = routingPreferenceError(preference, `modelOpenRouterRouting.${modelId}`);
77
+ if (error) return error;
78
+ }
79
+ }
80
+ return null;
81
+ }
82
+
83
+ export function resolveOpenRouterRouting(
84
+ provider: OcxProviderConfig,
85
+ modelId: string,
86
+ ): OpenRouterProviderRouting | undefined {
87
+ if (!isCanonicalOpenRouterTarget(provider.baseUrl)) return undefined;
88
+ const modelRoutes = provider.modelOpenRouterRouting;
89
+ return modelRoutes && Object.hasOwn(modelRoutes, modelId)
90
+ ? modelRoutes[modelId]
91
+ : provider.openRouterRouting;
92
+ }
93
+
94
+ export function openRouterProviderPayload(
95
+ preference: OpenRouterProviderRouting,
96
+ ): Record<string, unknown> {
97
+ return {
98
+ ...(preference.order ? { order: [...preference.order] } : {}),
99
+ ...(preference.only ? { only: [...preference.only] } : {}),
100
+ ...(preference.allowFallbacks !== undefined ? { allow_fallbacks: preference.allowFallbacks } : {}),
101
+ };
102
+ }
@@ -0,0 +1,179 @@
1
+ import type { OcxConfig } from "../types";
2
+
3
+ export interface ProviderRewriteResult {
4
+ /** Number of references re-pointed. */
5
+ changed: number;
6
+ /**
7
+ * Sites where the destination key already held a value, left untouched. A
8
+ * non-empty list means the caller must not treat the rewrite as complete —
9
+ * merging two settings is not a decision this function can make. The function
10
+ * is NOT transactional: earlier sites are already rewritten by the time a
11
+ * collision is found, so a caller that receives collisions must discard the
12
+ * config it passed in.
13
+ */
14
+ collisions: string[];
15
+ }
16
+
17
+ /**
18
+ * Re-point every config reference from one provider id to another.
19
+ *
20
+ * Three shapes exist and the difference matters: routed model strings
21
+ * (`"<provider>/<model>"`), bare provider ids (`customModels[].provider`,
22
+ * `combos[*].targets[].provider`), and keys that ARE provider ids or routes
23
+ * (`providerContextCaps`, `claudeCode.desktopProfile.assignments`). A rewrite
24
+ * that handles only the first leaves an orphaned context cap and — worse — a
25
+ * combo target naming a provider that no longer exists, which fails validation
26
+ * in `src/combos/types.ts` and makes `loadConfig` discard the whole config.
27
+ *
28
+ * `providers[*].selectedModels` is deliberately NOT rewritten: those are
29
+ * per-provider native model ids, and upstream ids may themselves contain a
30
+ * slash, so a prefix rewrite could mangle an unrelated provider's allowlist. A
31
+ * caller that moves a provider row handles its own allowlist, where the
32
+ * destination catalog is known.
33
+ */
34
+ export function rewriteProviderReferences(config: OcxConfig, from: string, to: string): ProviderRewriteResult {
35
+ const prefix = `${from}/`;
36
+ const collisions: string[] = [];
37
+ let changed = 0;
38
+
39
+ /** Routed string: rewrite only an exact `<from>/…` prefix, never a longer id. */
40
+ const route = (value: unknown): string | undefined => {
41
+ if (typeof value !== "string" || !value.startsWith(prefix)) return undefined;
42
+ changed += 1;
43
+ return `${to}/${value.slice(prefix.length)}`;
44
+ };
45
+
46
+ /**
47
+ * Rewrite a routed-string list in place. Assigning the result unconditionally
48
+ * would add an own property with value `undefined` where the field was absent,
49
+ * which breaks the no-op contract. The key type is an explicit union rather
50
+ * than `keyof OcxConfig`: the latter also admits `customModels` and friends, so
51
+ * `map` would infer a union array that is not assignable back.
52
+ */
53
+ type RoutedListKey = "disabledModels" | "subagentModels" | "subagentModelFallback";
54
+ const routeListAt = (key: RoutedListKey): void => {
55
+ const list = config[key];
56
+ if (!list) return;
57
+ config[key] = list.map(id => route(id) ?? id);
58
+ };
59
+
60
+ const routeRecordValues = (record: Record<string, string> | undefined): void => {
61
+ if (!record) return;
62
+ for (const [key, value] of Object.entries(record)) {
63
+ const next = route(value);
64
+ if (next) record[key] = next;
65
+ }
66
+ };
67
+
68
+ if (config.defaultProvider === from) {
69
+ config.defaultProvider = to;
70
+ changed += 1;
71
+ }
72
+
73
+ routeListAt("disabledModels");
74
+ routeListAt("subagentModels");
75
+ routeListAt("subagentModelFallback");
76
+
77
+ const scalarOwners: Array<[Record<string, unknown> | undefined, string]> = [
78
+ [config as unknown as Record<string, unknown>, "injectionModel"],
79
+ [config.shadowCallIntercept as Record<string, unknown> | undefined, "model"],
80
+ [config.webSearchSidecar as Record<string, unknown> | undefined, "model"],
81
+ [config.visionSidecar as Record<string, unknown> | undefined, "model"],
82
+ [config.claudeCode as unknown as Record<string, unknown> | undefined, "model"],
83
+ [config.claudeCode as unknown as Record<string, unknown> | undefined, "smallFastModel"],
84
+ [config.claudeCode?.webSearchSidecar as Record<string, unknown> | undefined, "model"],
85
+ [config.claudeCode?.visionSidecar as Record<string, unknown> | undefined, "model"],
86
+ ];
87
+ for (const [owner, key] of scalarOwners) {
88
+ if (!owner) continue;
89
+ const next = route(owner[key]);
90
+ if (next) owner[key] = next;
91
+ }
92
+
93
+ routeRecordValues(config.claudeCode?.tierModels as Record<string, string> | undefined);
94
+ routeRecordValues(config.claudeCode?.modelMap as Record<string, string> | undefined);
95
+
96
+ // Bare provider ids.
97
+ for (const model of config.customModels ?? []) {
98
+ if (model.provider === from) {
99
+ model.provider = to;
100
+ changed += 1;
101
+ }
102
+ }
103
+ for (const combo of Object.values(config.combos ?? {})) {
104
+ for (const target of combo.targets ?? []) {
105
+ if (target.provider === from) {
106
+ target.provider = to;
107
+ changed += 1;
108
+ }
109
+ }
110
+ }
111
+
112
+ // Keys. `providerContextCaps` is KEYED by provider id — a prefix rewrite would
113
+ // silently orphan the cap — and a destination key may already be occupied.
114
+ const caps = config.providerContextCaps;
115
+ if (caps && Object.hasOwn(caps, from)) {
116
+ if (Object.hasOwn(caps, to)) {
117
+ collisions.push(`providerContextCaps.${to}`);
118
+ } else {
119
+ caps[to] = caps[from]!;
120
+ delete caps[from];
121
+ changed += 1;
122
+ }
123
+ }
124
+
125
+ // `desktopProfile` is nested and asymmetric: `assignments` is KEYED by route
126
+ // while `defaults` holds routes as VALUES.
127
+ const profile = config.claudeCode?.desktopProfile;
128
+ if (profile) {
129
+ for (const key of Object.keys(profile.assignments ?? {})) {
130
+ const next = route(key);
131
+ if (!next) continue;
132
+ if (Object.hasOwn(profile.assignments, next)) {
133
+ changed -= 1; // `route` counted it; the move did not happen.
134
+ collisions.push(`claudeCode.desktopProfile.assignments.${next}`);
135
+ continue;
136
+ }
137
+ profile.assignments[next] = profile.assignments[key]!;
138
+ delete profile.assignments[key];
139
+ }
140
+ const defaults = profile.defaults as Record<string, string | null> | undefined;
141
+ if (defaults) {
142
+ for (const [family, value] of Object.entries(defaults)) {
143
+ const next = route(value);
144
+ if (next) defaults[family] = next;
145
+ }
146
+ }
147
+ }
148
+
149
+ return { changed, collisions };
150
+ }
151
+
152
+ /**
153
+ * Drop the custom-model rows that belonged to a provider being removed.
154
+ *
155
+ * The sibling of the rename pass above. `rewriteProviderReferences` already
156
+ * carries `customModels[].provider` across a rename, so the array tracks the
157
+ * provider lifecycle — but removal used to delete only `config.providers[name]`
158
+ * and leave the rows behind. Those orphans still reach `/api/models` and the
159
+ * generated Codex catalog, which key on the row rather than on provider
160
+ * existence, so they surface as models that resolve to nothing (#1273).
161
+ *
162
+ * Only the rows are touched: the `customModelCatalogMigration` marker records
163
+ * one-time ownership of pre-marker rows and must survive removal unchanged, or
164
+ * an older binary's view of that ownership silently changes.
165
+ *
166
+ * Returns the number of rows dropped so callers can report it.
167
+ */
168
+ export function dropProviderCustomModels(config: OcxConfig, provider: string): number {
169
+ const existing = config.customModels;
170
+ if (!Array.isArray(existing) || existing.length === 0) return 0;
171
+ const kept = existing.filter(model => model.provider !== provider);
172
+ if (kept.length === existing.length) return 0;
173
+ // Match the add/remove routes: an emptied list is dropped rather than left as
174
+ // `[]`, so the `customModels` field is absent either way. Only that field —
175
+ // the `customModelCatalogMigration` marker is deliberately left in place.
176
+ if (kept.length > 0) config.customModels = kept;
177
+ else delete config.customModels;
178
+ return existing.length - kept.length;
179
+ }