@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,476 @@
1
+ import { loadConfig } from "../config";
2
+ import {
3
+ MAX_ACCOUNT_PRIORITY,
4
+ MIN_ACCOUNT_PRIORITY,
5
+ normalizeAccountPriority,
6
+ parseAccountPriority,
7
+ } from "../codex/pool-rotation";
8
+ import {
9
+ apiError,
10
+ apiJson,
11
+ classifyAccount,
12
+ fetchCodexRows,
13
+ fetchProviderQuotaReport,
14
+ fetchRows,
15
+ proxyUnreachable,
16
+ resolveBaseUrl,
17
+ type AccountDeps, type AccountStdin, type FamilyRows,
18
+ type ProviderQuotaDto, type ProviderQuotaReportDto,
19
+ } from "./account-api";
20
+ import {
21
+ codexCatalogRefreshPending,
22
+ warnIfCodexCatalogRefreshPending,
23
+ } from "./account-catalog-refresh";
24
+
25
+ const MAIN_ID = "__main__";
26
+ const AUTO_NOTE = "auto (no pin — lowest-usage account is selected per request)";
27
+ const EXTENDED_USAGE = `Usage:
28
+ rmx account refresh <provider> [--json]
29
+ rmx account auto-switch <provider> <on|off|status|threshold <0-100>> [--json]
30
+ rmx account alias <provider> <id|main> <display-name|-> [--json]
31
+ rmx account priority <provider> <id|main> [<-100..100|first|earlier|normal|later|last|reset>] [--json]
32
+ rmx account remove <provider> <id|main> --yes [--json]
33
+ rmx account clear-cooldown <provider> <id|main> [--json]
34
+ rmx account add-key <provider> [--label <label>] [--json]`;
35
+ const PIPE_GUIDANCE = `Pipe the API key on stdin, for example:
36
+ rmx account add-key <provider> <<< "$MY_KEY"
37
+ security find-generic-password -w <item> | rmx account add-key <provider>`;
38
+
39
+ function flag(args: string[], value: string): boolean {
40
+ const index = args.indexOf(value);
41
+ if (index < 0) return false;
42
+ args.splice(index, 1);
43
+ return true;
44
+ }
45
+
46
+ function flagValue(args: string[], value: string): { found: boolean; value?: string } {
47
+ const index = args.indexOf(value);
48
+ if (index < 0) return { found: false };
49
+ if (index + 1 >= args.length) return { found: true };
50
+ const result = args[index + 1];
51
+ args.splice(index, 2);
52
+ return { found: true, value: result };
53
+ }
54
+
55
+ function usage(message?: string): number {
56
+ if (message) console.error(message);
57
+ console.error(EXTENDED_USAGE);
58
+ return 1;
59
+ }
60
+
61
+ function configAndType(deps: AccountDeps, name: string) {
62
+ return classifyAccount(deps.loadConfigImpl?.() ?? loadConfig(), name);
63
+ }
64
+
65
+ function familyFailure(result: FamilyRows, fallback: string): number | null {
66
+ if (result.networkDown) return proxyUnreachable();
67
+ if (result.errorJson) return apiError(result.errorJson, fallback);
68
+ return null;
69
+ }
70
+
71
+ function errorText(json: Record<string, unknown> | undefined, fallback: string): string {
72
+ return typeof json?.error === "string" ? json.error : fallback;
73
+ }
74
+
75
+ function resetIso(value: number | undefined): string | null {
76
+ if (typeof value !== "number" || !Number.isFinite(value)) return null;
77
+ const date = new Date(value < 10_000_000_000 ? value * 1000 : value);
78
+ return Number.isNaN(date.getTime()) ? null : date.toISOString();
79
+ }
80
+
81
+ function refreshLine(row: FamilyRows["rows"][number]): string {
82
+ const parts = [row.id === MAIN_ID ? "main" : row.id, row.email, row.plan];
83
+ const quota = row.quota;
84
+ if (!quota || (quota.weeklyPercent === undefined && quota.monthlyPercent === undefined)) {
85
+ parts.push("quota: unknown");
86
+ } else {
87
+ if (quota.weeklyPercent !== undefined) parts.push(`weekly ${quota.weeklyPercent}%`);
88
+ const weeklyReset = resetIso(quota.weeklyResetAt);
89
+ if (weeklyReset) parts.push(`resets ${weeklyReset}`);
90
+ if (quota.monthlyPercent !== undefined) parts.push(`monthly ${quota.monthlyPercent}%`);
91
+ const monthlyReset = resetIso(quota.monthlyResetAt);
92
+ if (monthlyReset) parts.push(`resets ${monthlyReset}`);
93
+ }
94
+ if (row.needsReauth) parts.push("needs-reauth");
95
+ return parts.filter(Boolean).join(" ");
96
+ }
97
+
98
+ function quotaParts(quota: ProviderQuotaDto): string[] {
99
+ const parts: string[] = [];
100
+ const add = (label: string, percent: number | undefined, resetAt?: number) => {
101
+ if (percent === undefined) return;
102
+ parts.push(`${label} ${percent}%`);
103
+ const reset = resetIso(resetAt);
104
+ if (reset) parts.push(`resets ${reset}`);
105
+ };
106
+ add("5h", quota.fiveHourPercent, quota.fiveHourResetAt);
107
+ add("weekly", quota.weeklyPercent, quota.weeklyResetAt);
108
+ add("monthly", quota.monthlyPercent, quota.monthlyResetAt);
109
+ for (const window of quota.customWindows ?? []) add(window.label, window.percent, window.resetAt);
110
+ return parts;
111
+ }
112
+
113
+ function providerQuotaLine(name: string, report: ProviderQuotaReportDto): string {
114
+ return [name, ...quotaParts(report.quota)].join(" ");
115
+ }
116
+
117
+ export async function readStdinLine(deps: AccountDeps): Promise<string> {
118
+ const input: AccountStdin = deps.stdinImpl ?? process.stdin;
119
+ const timeoutMs = deps.stdinTimeoutMs ?? 15_000;
120
+ return await new Promise<string>((resolve, reject) => {
121
+ let buffer = "";
122
+ let settled = false;
123
+ const cleanup = () => {
124
+ clearTimeout(timer);
125
+ input.removeListener("data", onData);
126
+ input.removeListener("end", onEnd);
127
+ input.removeListener("error", onError);
128
+ };
129
+ const finish = (fn: () => void) => {
130
+ if (settled) return;
131
+ settled = true;
132
+ cleanup();
133
+ fn();
134
+ };
135
+ const onData = (chunk: unknown) => {
136
+ buffer += Buffer.isBuffer(chunk) ? chunk.toString("utf8") : String(chunk);
137
+ const newline = buffer.search(/[\r\n]/);
138
+ if (newline >= 0) finish(() => resolve(buffer.slice(0, newline).trim()));
139
+ };
140
+ const onEnd = () => finish(() => resolve(buffer.trim()));
141
+ const onError = (error: Error) => finish(() => reject(error));
142
+ const timer = setTimeout(() => finish(() => reject(new Error("timed out waiting for API key on stdin"))), timeoutMs);
143
+ input.on("data", onData);
144
+ input.on("end", onEnd);
145
+ input.on("error", onError);
146
+ });
147
+ }
148
+
149
+ export async function cmdRefresh(args: string[], deps: AccountDeps): Promise<number> {
150
+ const wantsJson = flag(args, "--json");
151
+ const name = args.shift();
152
+ if (!name || args.length) return usage();
153
+ const classified = configAndType(deps, name);
154
+ if ("error" in classified) return usage(`Error: ${classified.error}`);
155
+ const baseUrl = await resolveBaseUrl(deps);
156
+ if (!baseUrl) return proxyUnreachable();
157
+ if (classified.type !== "codex") {
158
+ const result = await fetchProviderQuotaReport(deps, baseUrl, name);
159
+ if (result.status === 0) return proxyUnreachable();
160
+ if (result.status !== 200) return apiError(result.errorJson ?? {}, `failed to refresh ${name}`);
161
+ if (wantsJson) console.log(JSON.stringify({ provider: name, report: result.report }, null, 2));
162
+ else console.log(result.report ? providerQuotaLine(name, result.report) : `no quota report available for ${name}`);
163
+ return 0;
164
+ }
165
+ const result = await fetchCodexRows(deps, baseUrl, true);
166
+ const failed = familyFailure(result, `failed to refresh ${name}`);
167
+ if (failed !== null) return failed;
168
+ if (wantsJson) console.log(JSON.stringify({ accounts: result.rows }, null, 2));
169
+ else for (const row of result.rows) console.log(refreshLine(row));
170
+ return 0;
171
+ }
172
+
173
+ export async function cmdAutoSwitch(args: string[], deps: AccountDeps): Promise<number> {
174
+ const wantsJson = flag(args, "--json");
175
+ const name = args.shift();
176
+ const action = args.shift();
177
+ if (!name || !action) return usage();
178
+ const classified = configAndType(deps, name);
179
+ if ("error" in classified || classified.type !== "codex") {
180
+ return usage("Error: auto-switch only applies to the openai Codex account pool");
181
+ }
182
+ let threshold: number | undefined;
183
+ if (action === "on" && args.length === 0) threshold = 80;
184
+ else if (action === "off" && args.length === 0) threshold = 0;
185
+ else if (action === "threshold" && args.length === 1 && /^\d+$/.test(args[0]!)) threshold = Number(args[0]);
186
+ else if (action !== "status" || args.length !== 0) return usage();
187
+ if (threshold !== undefined && (!Number.isInteger(threshold) || threshold < 0 || threshold > 100)) {
188
+ return usage("Error: threshold must be an integer 0-100");
189
+ }
190
+ const baseUrl = await resolveBaseUrl(deps);
191
+ if (!baseUrl) return proxyUnreachable();
192
+ if (action === "status") {
193
+ const response = await apiJson(deps, baseUrl, "GET", "/api/codex-auth/active");
194
+ if (response.status === 0) return proxyUnreachable();
195
+ if (response.status !== 200 || typeof response.json.autoSwitchThreshold !== "number") {
196
+ return apiError(response.json, "failed to read auto-switch status");
197
+ }
198
+ threshold = response.json.autoSwitchThreshold;
199
+ } else {
200
+ const response = await apiJson(deps, baseUrl, "PUT", "/api/codex-auth/auto-switch", { threshold });
201
+ if (response.status === 0) return proxyUnreachable();
202
+ if (response.status !== 200) return apiError(response.json, "failed to update auto-switch");
203
+ }
204
+ const enabled = threshold! > 0;
205
+ if (wantsJson) console.log(JSON.stringify({ provider: name, autoSwitchThreshold: threshold, enabled }, null, 2));
206
+ else console.log(enabled ? `auto-switch: on (threshold ${threshold}%)` : "auto-switch: off");
207
+ return 0;
208
+ }
209
+
210
+ function deletePath(type: "codex" | "oauth" | "api-key", name: string, id: string): string {
211
+ if (type === "codex") return `/api/codex-auth/accounts?id=${encodeURIComponent(id)}`;
212
+ if (type === "oauth") return `/api/oauth/accounts?provider=${encodeURIComponent(name)}&id=${encodeURIComponent(id)}`;
213
+ return `/api/providers/keys?name=${encodeURIComponent(name)}&id=${encodeURIComponent(id)}`;
214
+ }
215
+
216
+ export async function cmdRemove(args: string[], deps: AccountDeps): Promise<number> {
217
+ const wantsJson = flag(args, "--json");
218
+ const fail = (message: string): number => {
219
+ if (wantsJson) console.error(JSON.stringify({ error: message }));
220
+ else console.error(`Error: ${message}`);
221
+ return 1;
222
+ };
223
+ const confirmed = flag(args, "--yes");
224
+ const name = args.shift();
225
+ const requestedId = args.shift();
226
+ if (!name || !requestedId || args.length) return wantsJson ? fail("provider and account id are required") : usage();
227
+ if (!confirmed) {
228
+ const message = `Confirmation required. Re-run: rmx account remove ${name} ${requestedId} --yes`;
229
+ return wantsJson ? fail(message) : usage(message);
230
+ }
231
+ const classified = configAndType(deps, name);
232
+ if ("error" in classified) return wantsJson ? fail(classified.error) : usage(`Error: ${classified.error}`);
233
+ const id = classified.type === "codex" && requestedId === "main" ? MAIN_ID : requestedId;
234
+ if (classified.type === "codex" && id === MAIN_ID) return wantsJson
235
+ ? fail("the main Codex App login cannot be removed")
236
+ : usage("Error: the main Codex App login cannot be removed");
237
+ const baseUrl = await resolveBaseUrl(deps);
238
+ if (!baseUrl) return fail("Proxy not reachable. Start it with 'rmx start' or 'rmx ensure'.");
239
+ const before = await fetchRows(deps, baseUrl, name, classified.type);
240
+ if (before.networkDown) return fail("Proxy not reachable. Start it with 'rmx start' or 'rmx ensure'.");
241
+ if (before.errorJson) return fail(errorText(before.errorJson, `failed to verify ${name} before removal`));
242
+ if (!before.rows.some(row => row.id === id)) return wantsJson
243
+ ? fail(`account or key "${requestedId}" was not found`)
244
+ : usage(`Error: account or key "${requestedId}" was not found`);
245
+ const response = await apiJson(deps, baseUrl, "DELETE", deletePath(classified.type, name, id));
246
+ if (response.status === 0) return fail("Proxy not reachable. Start it with 'rmx start' or 'rmx ensure'.");
247
+ if (response.status !== 200) return fail(errorText(response.json, `failed to remove ${requestedId}`));
248
+ const catalogRefreshPending = classified.type === "codex"
249
+ && codexCatalogRefreshPending(response.json);
250
+ const after = await fetchRows(deps, baseUrl, name, classified.type);
251
+ if (after.networkDown || after.errorJson) {
252
+ const detail = after.networkDown ? "proxy not reachable" : typeof after.errorJson?.error === "string" ? after.errorJson.error : "unknown error";
253
+ return fail(`post-delete verification failed; delete may have succeeded: ${detail}`);
254
+ }
255
+ const removedActive = before.activeId === id;
256
+ const result = {
257
+ ok: true,
258
+ provider: name,
259
+ id,
260
+ removedActive,
261
+ promotedActiveId: after.activeId,
262
+ ...(classified.type === "codex" ? { catalogRefreshPending } : {}),
263
+ };
264
+ if (wantsJson) console.log(JSON.stringify(result, null, 2));
265
+ else if (classified.type === "codex" && removedActive && after.activeId === null) console.log(`openai: ${AUTO_NOTE}`);
266
+ else if (classified.type === "oauth") console.log(after.rows.length ? `${name}: active account is now ${after.activeId}` : `${name}: no accounts remaining`);
267
+ else if (classified.type === "api-key") console.log(after.rows.length ? `${name}: active key is now ${after.activeId}` : `${name}: no keys remaining`);
268
+ else console.log(`${name}: removed account ${requestedId}`);
269
+ if (!wantsJson && catalogRefreshPending) warnIfCodexCatalogRefreshPending(response.json);
270
+ return 0;
271
+ }
272
+
273
+ export async function cmdAddKey(args: string[], deps: AccountDeps): Promise<number> {
274
+ const wantsJson = flag(args, "--json");
275
+ const labelArg = flagValue(args, "--label");
276
+ const name = args.shift();
277
+ if (!name || args.length || (labelArg.found && labelArg.value === undefined)) return usage();
278
+ const classified = configAndType(deps, name);
279
+ if ("error" in classified || classified.type !== "api-key") return usage("Error: add-key only applies to API-key providers");
280
+ const input: AccountStdin = deps.stdinImpl ?? process.stdin;
281
+ if (input.isTTY) return usage(PIPE_GUIDANCE);
282
+ let key: string;
283
+ try {
284
+ key = await readStdinLine(deps);
285
+ } catch (error) {
286
+ return usage(`Error: ${error instanceof Error ? error.message : String(error)}\n${PIPE_GUIDANCE}`);
287
+ }
288
+ if (!key) return usage(`Error: API key input was empty\n${PIPE_GUIDANCE}`);
289
+ const label = labelArg.value?.trim();
290
+ const baseUrl = await resolveBaseUrl(deps);
291
+ if (!baseUrl) return proxyUnreachable();
292
+ const response = await apiJson(deps, baseUrl, "POST", "/api/providers/keys", { name, key, ...(label ? { label } : {}) });
293
+ if (response.status === 0) return proxyUnreachable();
294
+ if (response.status !== 201) return apiError(response.json, `failed to add a key for ${name}`);
295
+ const id = typeof response.json.id === "string" ? response.json.id : null;
296
+ // Redact the key inside the label BEFORE serialization — a key containing
297
+ // JSON-escaped characters (" or \) would otherwise survive the whole-output
298
+ // pass in escaped form (audit finding, Carver WP3-C).
299
+ const safeLabel = label ? label.replaceAll(key, "[redacted]") : undefined;
300
+ const result = { ok: true, id, ...(safeLabel ? { label: safeLabel } : {}) };
301
+ const output = wantsJson ? JSON.stringify(result, null, 2)
302
+ : `${name}: added API key ${id ?? ""}${safeLabel ? ` (${safeLabel})` : ""}`.trim();
303
+ console.log(output.replaceAll(key, "[redacted]"));
304
+ return 0;
305
+ }
306
+
307
+ /**
308
+ * Lift a quota cooldown on a Codex account.
309
+ *
310
+ * This is the user-facing escape from the lockout described in
311
+ * `devlog/_plan/260726_cooldown_lockout_hardening`: injected routing makes the proxy the
312
+ * only model path for Codex Desktop, so a stuck cooldown reads as "the whole app is dead".
313
+ *
314
+ * Codex accounts only. API-key pools already reset their own 429 cooldowns through key
315
+ * management (`clearKeyCooldowns`), and OAuth providers have no equivalent state here.
316
+ */
317
+ export async function cmdClearCooldown(args: string[], deps: AccountDeps): Promise<number> {
318
+ const wantsJson = flag(args, "--json");
319
+ const name = args.shift();
320
+ const requestedId = args.shift();
321
+ if (!name || !requestedId || args.length) return usage();
322
+ const classified = configAndType(deps, name);
323
+ if ("error" in classified) return usage(`Error: ${classified.error}`);
324
+ if (classified.type !== "codex") {
325
+ return usage(`Error: ${name} is not a Codex account pool; cooldown clearing applies to Codex accounts only`);
326
+ }
327
+ const id = requestedId === "main" ? MAIN_ID : requestedId;
328
+ const baseUrl = await resolveBaseUrl(deps);
329
+ if (!baseUrl) return proxyUnreachable();
330
+ const response = await apiJson(deps, baseUrl, "POST", "/api/codex-auth/accounts/clear-cooldown", { id });
331
+ if (response.status === 0) return proxyUnreachable();
332
+ if (response.status !== 200) return apiError(response.json, `failed to clear cooldown for ${requestedId}`);
333
+ const cleared = response.json?.cleared === true;
334
+ if (wantsJson) console.log(JSON.stringify({ ok: true, provider: name, id, cleared }, null, 2));
335
+ else if (cleared) console.log(`${name}: cooldown lifted for ${requestedId}`);
336
+ else console.log(`${name}: no active cooldown for ${requestedId}`);
337
+ return 0;
338
+ }
339
+
340
+ /**
341
+ * Named selection orders. The words convey sequence rather than rank because the
342
+ * pool moves down the list only when everything above it is drained — "high
343
+ * priority" would suggest the account gets more traffic, which is not what
344
+ * ordering does.
345
+ */
346
+ const PRIORITY_PRESETS: Record<string, number> = {
347
+ first: 2,
348
+ earlier: 1,
349
+ normal: 0,
350
+ later: -1,
351
+ last: -2,
352
+ };
353
+
354
+ function priorityPresetName(priority: number): string | null {
355
+ return Object.entries(PRIORITY_PRESETS).find(([, value]) => value === priority)?.[0] ?? null;
356
+ }
357
+
358
+ function formatPriority(priority: number): string {
359
+ const preset = priorityPresetName(priority);
360
+ const signed = priority > 0 ? `+${priority}` : String(priority);
361
+ return preset ? `${signed} (${preset})` : signed;
362
+ }
363
+
364
+ /** `null` = reset to the default; `undefined` = unparseable. */
365
+ function parsePriorityArgument(raw: string): number | null | undefined {
366
+ const word = raw.trim().toLowerCase();
367
+ if (word === "reset") return null;
368
+ // Own keys only: `in` also matches "constructor", "__proto__", and friends.
369
+ if (Object.hasOwn(PRIORITY_PRESETS, word)) return PRIORITY_PRESETS[word];
370
+ // The regex only rules out shapes Number() would coerce ("1e2", " 1 ", ""); the range
371
+ // itself comes from the core parser so the CLI cannot drift from what the API accepts.
372
+ if (!/^[+-]?\d+$/.test(word)) return undefined;
373
+ return parseAccountPriority(Number(word)) ?? undefined;
374
+ }
375
+
376
+ export async function cmdPriority(args: string[], deps: AccountDeps): Promise<number> {
377
+ const wantsJson = flag(args, "--json");
378
+ const name = args.shift();
379
+ const requestedId = args.shift();
380
+ const requestedPriority = args.shift();
381
+ if (!name || !requestedId || args.length) return usage();
382
+ const classified = configAndType(deps, name);
383
+ if ("error" in classified) return usage(`Error: ${classified.error}`);
384
+ if (classified.type !== "codex") {
385
+ return usage("Error: selection order only applies to the openai Codex account pool");
386
+ }
387
+ const id = requestedId === "main" ? MAIN_ID : requestedId;
388
+
389
+ // Validate before touching the network so a typo never reaches the proxy.
390
+ let priority: number | null | undefined;
391
+ if (requestedPriority !== undefined) {
392
+ priority = parsePriorityArgument(requestedPriority);
393
+ if (priority === undefined) {
394
+ return usage(`Error: selection order must be an integer ${MIN_ACCOUNT_PRIORITY}..${MAX_ACCOUNT_PRIORITY}, one of ${Object.keys(PRIORITY_PRESETS).join("/")}, or reset`);
395
+ }
396
+ }
397
+
398
+ const baseUrl = await resolveBaseUrl(deps);
399
+ if (!baseUrl) return proxyUnreachable();
400
+
401
+ // No value means "show" — a read must not rewrite what it is reporting.
402
+ if (priority === undefined) {
403
+ const result = await fetchCodexRows(deps, baseUrl);
404
+ const failed = familyFailure(result, `failed to read ${name} accounts`);
405
+ if (failed !== null) return failed;
406
+ const row = result.rows.find(candidate => candidate.id === id);
407
+ if (!row) return usage(`Error: no ${name} account ${requestedId}`);
408
+ const current = normalizeAccountPriority(row.priority);
409
+ if (wantsJson) {
410
+ console.log(JSON.stringify(
411
+ { ok: true, provider: name, id, priority: current, preset: priorityPresetName(current) },
412
+ null,
413
+ 2,
414
+ ));
415
+ } else {
416
+ console.log(`${name}: ${requestedId} selection order is ${formatPriority(current)}`);
417
+ }
418
+ return 0;
419
+ }
420
+
421
+ const response = await apiJson(deps, baseUrl, "PUT", "/api/codex-auth/accounts/priority", { id, priority });
422
+ if (response.status === 0) return proxyUnreachable();
423
+ if (response.status !== 200) return apiError(response.json, `failed to set selection order for ${requestedId}`);
424
+ const applied = typeof response.json.priority === "number" ? response.json.priority : (priority ?? 0);
425
+ if (wantsJson) {
426
+ console.log(JSON.stringify(
427
+ { ok: true, provider: name, id, priority: applied, preset: priorityPresetName(applied) },
428
+ null,
429
+ 2,
430
+ ));
431
+ } else {
432
+ console.log(`${name}: ${requestedId} selection order is now ${formatPriority(applied)}`);
433
+ }
434
+ // Not cmdUse's note: re-ordering takes effect on the next unbound request rather than
435
+ // only on new sessions, because preemption moves those requests up immediately.
436
+ console.error("Takes effect from the next unbound request; running threads keep their current account until drained.");
437
+ // The release is not optional and not conditional on the value changing, so it has to be
438
+ // stated: this route is the only way to clear a pin without immediately setting another,
439
+ // which means a write storing the order an account already had still releases it. Without
440
+ // this line that is a silent side effect of a command that looks purely declarative.
441
+ console.error('Also releases any manual "use this account now" pin, on any account.');
442
+ return 0;
443
+ }
444
+
445
+ export async function cmdAlias(args: string[], deps: AccountDeps): Promise<number> {
446
+ const wantsJson = flag(args, "--json");
447
+ const name = args.shift();
448
+ const requestedId = args.shift();
449
+ const requestedAlias = args.shift();
450
+ if (!name || !requestedId || requestedAlias === undefined || args.length) return usage();
451
+ const classified = configAndType(deps, name);
452
+ if ("error" in classified) return usage(`Error: ${classified.error}`);
453
+ const id = classified.type === "codex" && requestedId === "main" ? MAIN_ID : requestedId;
454
+ if (id === MAIN_ID) return usage("Error: the main Codex App login cannot be renamed");
455
+ const alias = requestedAlias === "-" ? "" : requestedAlias.trim();
456
+ if (alias.length > 80 || /[\x00-\x1f\x7f]/.test(alias)) return usage("Error: alias must be at most 80 printable characters");
457
+ const baseUrl = await resolveBaseUrl(deps);
458
+ if (!baseUrl) return proxyUnreachable();
459
+ const path = classified.type === "codex"
460
+ ? "/api/codex-auth/accounts/alias"
461
+ : classified.type === "oauth"
462
+ ? "/api/oauth/accounts/alias"
463
+ : "/api/providers/keys/alias";
464
+ const body = classified.type === "codex"
465
+ ? { id, alias }
466
+ : classified.type === "oauth"
467
+ ? { provider: name, accountId: id, alias }
468
+ : { name, id, alias };
469
+ const response = await apiJson(deps, baseUrl, "PUT", path, body);
470
+ if (response.status === 0) return proxyUnreachable();
471
+ if (response.status !== 200) return apiError(response.json, `failed to rename ${requestedId}`);
472
+ const result = { ok: true, provider: name, id, alias: alias || null };
473
+ if (wantsJson) console.log(JSON.stringify(result, null, 2));
474
+ else console.log(alias ? `${name}: ${requestedId} is now “${alias}”` : `${name}: cleared alias for ${requestedId}`);
475
+ return 0;
476
+ }