@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,78 @@
1
+ import { realpathSync, statSync } from "node:fs";
2
+ import { isAbsolute, join, resolve } from "node:path";
3
+ import { expandUserPath } from "../config";
4
+ import { defaultCodexHome } from "./home";
5
+
6
+ function resolveCodexHome(): string {
7
+ const raw = process.env.CODEX_HOME?.trim();
8
+ if (raw) {
9
+ const path = resolve(expandUserPath(raw));
10
+ let stat;
11
+ try {
12
+ stat = statSync(path);
13
+ } catch (err) {
14
+ const message = err instanceof Error ? err.message : String(err);
15
+ throw new Error(`CODEX_HOME points to ${raw}, but that path could not be read: ${message}`);
16
+ }
17
+ if (!stat.isDirectory()) {
18
+ throw new Error(`CODEX_HOME points to ${raw}, but that path is not a directory`);
19
+ }
20
+ return realpathSync.native(path);
21
+ }
22
+
23
+ return defaultCodexHome();
24
+ }
25
+
26
+ export const CODEX_HOME = resolveCodexHome();
27
+ export const CODEX_CONFIG_PATH = join(CODEX_HOME, "config.toml");
28
+ export const CODEX_PROFILE_PATH = join(CODEX_HOME, "opencodex.config.toml");
29
+ export const DEFAULT_CATALOG_PATH = join(CODEX_HOME, "opencodex-catalog.json");
30
+ /**
31
+ * Catalog consumed by Codex instances launched with the Remodex profile.
32
+ *
33
+ * Keep this separate from both config.toml and Codex's private models_cache.json:
34
+ * config.toml remains user-owned, while models_cache.json is an implementation
35
+ * cache whose wrapper and invalidation semantics can change between Codex builds.
36
+ */
37
+ export const CODEX_EXTERNAL_MODELS_PATH = join(CODEX_HOME, "models.json");
38
+ export const CODEX_MODELS_CACHE_PATH = join(CODEX_HOME, "models_cache.json");
39
+
40
+ /** Runtime CODEX_HOME lookup (honors CODEX_HOME env changes after import). */
41
+ export function getCodexHome(): string {
42
+ return resolveCodexHome();
43
+ }
44
+
45
+ /** Runtime path lookup for callers that capture CODEX_HOME after module import. */
46
+ export function externalCodexModelsPath(codexHome = getCodexHome()): string {
47
+ return join(codexHome, "models.json");
48
+ }
49
+
50
+ export function tomlString(value: string): string {
51
+ return JSON.stringify(value);
52
+ }
53
+
54
+ export function parseTomlString(raw: string): string {
55
+ if (raw.startsWith("\"")) {
56
+ try {
57
+ return JSON.parse(raw) as string;
58
+ } catch {
59
+ return raw.slice(1, -1);
60
+ }
61
+ }
62
+ return raw.slice(1, -1);
63
+ }
64
+
65
+ export function readRootTomlString(content: string, key: string): string | null {
66
+ const lines = content.split("\n");
67
+ const firstTable = lines.findIndex(l => /^\s*\[/.test(l));
68
+ const rootLines = firstTable === -1 ? lines : lines.slice(0, firstTable);
69
+ for (const line of rootLines) {
70
+ const m = line.match(new RegExp(`^\\s*${key}\\s*=\\s*(\"(?:\\\\.|[^\"])*\"|'[^']*')`));
71
+ if (m) return parseTomlString(m[1]);
72
+ }
73
+ return null;
74
+ }
75
+
76
+ export function resolveCodexConfigPath(path: string): string {
77
+ return isAbsolute(path) ? path : join(CODEX_HOME, path);
78
+ }
@@ -0,0 +1,242 @@
1
+ import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
2
+ import { isAbsolute, join } from "node:path";
3
+ import { CODEX_CONFIG_PATH } from "./paths";
4
+ import { redactUserPath } from "../lib/redact";
5
+
6
+ // Mirrors codex-rs core-plugins/src/marketplace.rs MARKETPLACE_MANIFEST_RELATIVE_PATHS.
7
+ // A marketplace root "resolves" only when one of these files exists under it.
8
+ const MARKETPLACE_MANIFEST_RELATIVE_PATHS = [
9
+ ".agents/plugins/marketplace.json",
10
+ ".claude-plugin/marketplace.json",
11
+ ] as const;
12
+
13
+ const OPENAI_BUNDLED_MARKETPLACE_NAME = "openai-bundled";
14
+
15
+ // Where the Codex desktop app's bundled plugins live, relative to an install
16
+ // root. Windows app-package paths embed the app version, so the actual install
17
+ // root is discovered by scanning candidate bases (LOCALAPPDATA, etc.) rather
18
+ // than hardcoded. The bundled marketplace dir is named after the marketplace.
19
+ const BUNDLED_MARKETPLACE_LEAF = join("plugins", "bundled-marketplaces", OPENAI_BUNDLED_MARKETPLACE_NAME);
20
+ const CODEX_APP_DIR_SEGMENTS = [join("Programs", "@openai", "codex"), join("Programs", "codex"), join("@openai", "codex"), "codex"] as const;
21
+
22
+ // Plugins the issue (#43) calls out. Treated as data, not as an authoritative
23
+ // allowlist: codex-rs only allowlists chrome/computer-use, but the diagnostic
24
+ // just reports presence, so listing browser here is informational only.
25
+ const COMMON_BUNDLED_PLUGINS = ["computer-use", "browser", "chrome"] as const;
26
+
27
+ export type CodexPluginsDiagnostic =
28
+ | { applicable: false; reason: string; summary: string }
29
+ | {
30
+ applicable: true;
31
+ stale: boolean;
32
+ marketplace: {
33
+ name: string;
34
+ present: boolean;
35
+ sourceType: string | null;
36
+ source: string | null;
37
+ resolvesToManifest: boolean;
38
+ currentBundledPath: string | null;
39
+ pathMismatch: boolean;
40
+ };
41
+ bundledPlugins: Array<{ id: string; configured: boolean }>;
42
+ suggestedRepair: string | null;
43
+ summary: string;
44
+ };
45
+
46
+ /** True when the table at `[marketplaces.<name>]` exists in the config text. */
47
+ function readMarketplaceTable(configText: string, name: string): Record<string, string> | null {
48
+ // Split on CRLF or LF: config.toml on Windows (the platform this diagnostic
49
+ // targets) uses CRLF, and a leftover \r would defeat the `$`-anchored regexes.
50
+ const lines = configText.split(/\r?\n/);
51
+ const header = new RegExp(`^\\s*\\[marketplaces\\.(?:"${escapeRegExp(name)}"|${escapeRegExp(name)})\\]\\s*(?:#.*)?$`);
52
+ let start = -1;
53
+ for (let i = 0; i < lines.length; i++) {
54
+ if (header.test(lines[i] ?? "")) { start = i + 1; break; }
55
+ }
56
+ if (start === -1) return null;
57
+
58
+ const table: Record<string, string> = {};
59
+ for (let i = start; i < lines.length; i++) {
60
+ const line = lines[i] ?? "";
61
+ if (/^\s*\[/.test(line)) break; // next table starts; stop
62
+ const m = line.match(/^\s*([A-Za-z0-9_-]+)\s*=\s*("(?:\\.|[^"])*"|'[^']*'|[^#]+?)\s*(?:#.*)?$/);
63
+ if (!m) continue;
64
+ table[m[1]] = unquoteTomlValue(m[2].trim());
65
+ }
66
+ return table;
67
+ }
68
+
69
+ function unquoteTomlValue(raw: string): string {
70
+ if (raw.startsWith("\"")) {
71
+ try { return JSON.parse(raw) as string; } catch { return raw.slice(1, -1); }
72
+ }
73
+ if (raw.startsWith("'")) return raw.slice(1, -1);
74
+ return raw;
75
+ }
76
+
77
+ function escapeRegExp(value: string): string {
78
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
79
+ }
80
+
81
+ /** A directory is a bundled-marketplace root when it holds a supported manifest. */
82
+ function dirHasManifest(dir: string): boolean {
83
+ return MARKETPLACE_MANIFEST_RELATIVE_PATHS.some(rel => existsSync(join(dir, rel)));
84
+ }
85
+
86
+ /**
87
+ * Locate the bundled `openai-bundled` marketplace dir under the installed Codex
88
+ * desktop app on Windows. Windows app paths embed the app version, so we scan
89
+ * candidate install bases for a versioned app dir whose
90
+ * `plugins/bundled-marketplaces/openai-bundled` holds a manifest. Returns the
91
+ * newest matching dir (by mtime) or null. Filesystem access is injectable for
92
+ * tests so a Windows layout can be exercised on any OS.
93
+ */
94
+ export function locateCurrentBundledMarketplace(
95
+ options: {
96
+ env?: NodeJS.ProcessEnv;
97
+ listDir?: (dir: string) => string[];
98
+ isManifestRoot?: (dir: string) => boolean;
99
+ mtimeOf?: (dir: string) => number;
100
+ } = {},
101
+ ): string | null {
102
+ const env = options.env ?? process.env;
103
+ const listDir = options.listDir ?? ((dir: string) => {
104
+ try { return readdirSync(dir); } catch { return []; }
105
+ });
106
+ const isManifestRoot = options.isManifestRoot ?? dirHasManifest;
107
+ const mtimeOf = options.mtimeOf ?? ((dir: string) => {
108
+ try { return statSync(dir).mtimeMs; } catch { return 0; }
109
+ });
110
+
111
+ const bases = [env.LOCALAPPDATA, env.PROGRAMFILES, env["ProgramFiles(x86)"], env.APPDATA]
112
+ .filter((b): b is string => typeof b === "string" && b.length > 0);
113
+
114
+ const candidates: string[] = [];
115
+ for (const base of bases) {
116
+ for (const seg of CODEX_APP_DIR_SEGMENTS) {
117
+ const appRoot = join(base, seg);
118
+ // Direct (unversioned) layout.
119
+ const direct = join(appRoot, BUNDLED_MARKETPLACE_LEAF);
120
+ if (isManifestRoot(direct)) candidates.push(direct);
121
+ // Versioned layout: appRoot/<version>/plugins/bundled-marketplaces/openai-bundled
122
+ for (const child of listDir(appRoot)) {
123
+ const versioned = join(appRoot, child, BUNDLED_MARKETPLACE_LEAF);
124
+ if (isManifestRoot(versioned)) candidates.push(versioned);
125
+ }
126
+ }
127
+ }
128
+ if (candidates.length === 0) return null;
129
+ candidates.sort((a, b) => mtimeOf(b) - mtimeOf(a));
130
+ return candidates[0] ?? null;
131
+ }
132
+
133
+ /** Normalize a path for comparison: lowercase + unify separators (Windows is case-insensitive). */
134
+ function normalizePathForCompare(path: string): string {
135
+ return path.replace(/[\\/]+/g, "\\").replace(/\\+$/, "").toLowerCase();
136
+ }
137
+
138
+ /** A local marketplace `source` resolves when it holds a supported manifest. */
139
+ function sourceResolvesToManifest(source: string): boolean {
140
+ if (!isAbsolute(source)) return false;
141
+ if (!existsSync(source)) return false;
142
+ return MARKETPLACE_MANIFEST_RELATIVE_PATHS.some(rel => existsSync(join(source, rel)));
143
+ }
144
+
145
+ /**
146
+ * Read-only diagnostic for the Codex `openai-bundled` plugin marketplace.
147
+ *
148
+ * Only meaningful on Windows, where app-package paths embed the app version and
149
+ * go stale after an update. On other platforms it reports "not applicable".
150
+ * NEVER mutates config.toml, never invokes `codex plugin marketplace add`.
151
+ */
152
+ export function diagnoseCodexBundledPlugins(
153
+ options: {
154
+ platform?: NodeJS.Platform;
155
+ configPath?: string;
156
+ locateCurrent?: () => string | null;
157
+ } = {},
158
+ ): CodexPluginsDiagnostic {
159
+ const platform = options.platform ?? process.platform;
160
+ if (platform !== "win32") {
161
+ return {
162
+ applicable: false,
163
+ reason: "not_windows",
164
+ summary: "not applicable (bundled-marketplace staleness is Windows-specific)",
165
+ };
166
+ }
167
+
168
+ const configPath = options.configPath ?? CODEX_CONFIG_PATH;
169
+ let configText: string;
170
+ try {
171
+ configText = readFileSync(configPath, "utf8");
172
+ } catch {
173
+ return {
174
+ applicable: false,
175
+ reason: "config_unreadable",
176
+ summary: "not applicable (Codex config.toml not found or unreadable)",
177
+ };
178
+ }
179
+
180
+ const table = readMarketplaceTable(configText, OPENAI_BUNDLED_MARKETPLACE_NAME);
181
+ const present = table !== null;
182
+ const sourceType = table?.source_type ?? null;
183
+ const source = table?.source ?? null;
184
+ const isLocal = sourceType === "local" && !!source;
185
+ const resolvesToManifest = isLocal ? sourceResolvesToManifest(source as string) : false;
186
+
187
+ // Locate the bundled marketplace under the currently installed Codex app, so
188
+ // we can tell "registered path differs from the live app path" (the Windows
189
+ // app-update staleness signal) apart from a merely missing manifest.
190
+ const locateCurrent = options.locateCurrent ?? (() => locateCurrentBundledMarketplace());
191
+ const currentBundledPath = locateCurrent();
192
+ const pathMismatch = !!(
193
+ currentBundledPath && source && isLocal &&
194
+ normalizePathForCompare(currentBundledPath) !== normalizePathForCompare(source)
195
+ );
196
+
197
+ // Stale = a registered local bundled marketplace whose source no longer
198
+ // resolves to a manifest, OR whose registered path differs from the live
199
+ // app's bundled path (the Windows app-update signal). A missing marketplace
200
+ // is "not stale" but flagged separately by `present: false`.
201
+ const stale = present && isLocal && (!resolvesToManifest || pathMismatch);
202
+ // Present but not a usable local entry (wrong source_type or empty source):
203
+ // not "stale" in the app-update sense, but it must NOT be reported as healthy.
204
+ const malformed = present && !isLocal;
205
+
206
+ const bundledPlugins = COMMON_BUNDLED_PLUGINS.map(id => ({
207
+ id,
208
+ configured: new RegExp(`\\[plugins\\.(?:"${escapeRegExp(`${id}@${OPENAI_BUNDLED_MARKETPLACE_NAME}`)}")\\]`).test(configText),
209
+ }));
210
+
211
+ const repairTarget = currentBundledPath ?? `<current ${OPENAI_BUNDLED_MARKETPLACE_NAME} path under the installed Codex app>`;
212
+ const suggestedRepair = (stale || pathMismatch)
213
+ ? `codex plugin marketplace add ${currentBundledPath ? redactUserPath(currentBundledPath) : repairTarget}`
214
+ : null;
215
+
216
+ const summary = !present
217
+ ? `no [marketplaces.${OPENAI_BUNDLED_MARKETPLACE_NAME}] entry in Codex config`
218
+ : malformed
219
+ ? `[marketplaces.${OPENAI_BUNDLED_MARKETPLACE_NAME}] is present but not a usable local source (source_type/source missing)`
220
+ : !resolvesToManifest
221
+ ? `stale: registered ${OPENAI_BUNDLED_MARKETPLACE_NAME} source no longer resolves to a marketplace manifest`
222
+ : pathMismatch
223
+ ? `stale: registered ${OPENAI_BUNDLED_MARKETPLACE_NAME} path differs from the installed Codex app's bundled path`
224
+ : `ok: ${OPENAI_BUNDLED_MARKETPLACE_NAME} marketplace resolves`;
225
+
226
+ return {
227
+ applicable: true,
228
+ stale,
229
+ marketplace: {
230
+ name: OPENAI_BUNDLED_MARKETPLACE_NAME,
231
+ present,
232
+ sourceType,
233
+ source: source ? redactUserPath(source) : null,
234
+ resolvesToManifest,
235
+ currentBundledPath: currentBundledPath ? redactUserPath(currentBundledPath) : null,
236
+ pathMismatch,
237
+ },
238
+ bundledPlugins,
239
+ suggestedRepair,
240
+ summary,
241
+ };
242
+ }
@@ -0,0 +1,295 @@
1
+ import type { OcxAccountPoolRotationStrategy } from "../types";
2
+ import type { GenerationContext } from "../lib/state-store-sweeper";
3
+
4
+ export const POOL_KEY_CODEX = "codex";
5
+ export const POOL_KEY_ANTHROPIC = "anthropic";
6
+
7
+ interface SelectionState {
8
+ activeKey?: string;
9
+ successes: number;
10
+ currentWeights: Map<string, number>;
11
+ }
12
+
13
+ const selectionState = new Map<string, SelectionState>();
14
+ let lastReconciledGeneration = 0;
15
+
16
+ const DEFAULT_STICKY_LIMIT = 1;
17
+ const MIN_STICKY_LIMIT = 1;
18
+ const MAX_STICKY_LIMIT = 100;
19
+ const DEFAULT_STRATEGY: OcxAccountPoolRotationStrategy = "quota";
20
+ const VALID_STRATEGIES = new Set<OcxAccountPoolRotationStrategy>(["quota", "round-robin", "fill-first"]);
21
+
22
+ /** Selection order for an account with no stored preference: one flat tier. */
23
+ export const DEFAULT_ACCOUNT_PRIORITY = 0;
24
+ export const MIN_ACCOUNT_PRIORITY = -100;
25
+ export const MAX_ACCOUNT_PRIORITY = 100;
26
+
27
+ /** Strict parse for management APIs — returns null instead of defaulting. */
28
+ export function parseAccountPoolStrategy(raw: unknown): OcxAccountPoolRotationStrategy | null {
29
+ if (typeof raw === "string" && VALID_STRATEGIES.has(raw as OcxAccountPoolRotationStrategy)) {
30
+ return raw as OcxAccountPoolRotationStrategy;
31
+ }
32
+ return null;
33
+ }
34
+
35
+ /** Strict parse for management APIs — returns null instead of defaulting. */
36
+ export function parseAccountPoolStickyLimit(raw: unknown): number | null {
37
+ if (typeof raw === "number" && Number.isInteger(raw) && raw >= MIN_STICKY_LIMIT && raw <= MAX_STICKY_LIMIT) {
38
+ return raw;
39
+ }
40
+ return null;
41
+ }
42
+
43
+ export function normalizeAccountPoolStrategy(raw: unknown): OcxAccountPoolRotationStrategy {
44
+ return parseAccountPoolStrategy(raw) ?? DEFAULT_STRATEGY;
45
+ }
46
+
47
+ export function normalizeAccountPoolStickyLimit(raw: unknown): number {
48
+ return parseAccountPoolStickyLimit(raw) ?? DEFAULT_STICKY_LIMIT;
49
+ }
50
+
51
+ /** Strict parse for management APIs — returns null instead of defaulting. */
52
+ export function parseAccountPriority(raw: unknown): number | null {
53
+ if (
54
+ typeof raw === "number"
55
+ && Number.isInteger(raw)
56
+ && raw >= MIN_ACCOUNT_PRIORITY
57
+ && raw <= MAX_ACCOUNT_PRIORITY
58
+ ) {
59
+ return raw;
60
+ }
61
+ return null;
62
+ }
63
+
64
+ export function normalizeAccountPriority(raw: unknown): number {
65
+ return parseAccountPriority(raw) ?? DEFAULT_ACCOUNT_PRIORITY;
66
+ }
67
+
68
+ /**
69
+ * Narrow an already-eligible account list to the highest selection-order tier that
70
+ * still has usable quota. Priority is an *ordering* boundary layered on top of
71
+ * eligibility: it never admits an account the caller already filtered out, and it
72
+ * never keeps the pool on a tier whose every member is drained.
73
+ *
74
+ * Contract (each clause is load-bearing for "no behavior change when unconfigured"):
75
+ * - one distinct priority across `ids` (the unconfigured case) returns `ids` unchanged,
76
+ * so today's pick sequence is preserved byte for byte;
77
+ * - input order is preserved inside the returned tier, which keeps the `__main__`
78
+ * head-of-list bias and the first-index tie-break used by SWRR/lowest-usage;
79
+ * - every tier drained returns `ids` unchanged, reproducing today's
80
+ * stay-put-until-429 behavior rather than inventing a pick;
81
+ * - a `pinnedId` that is present *and* has headroom lowers the ceiling to its own
82
+ * tier, which is what makes a manual "use this now" survive round-robin and
83
+ * fill-first without any mutable selection state. A drained or absent pin is
84
+ * ignored, so the pin expires on its own once the account crosses the threshold.
85
+ */
86
+ export function selectPriorityTier(
87
+ ids: readonly string[],
88
+ priorityOf: (id: string) => number,
89
+ hasHeadroom: (id: string) => boolean,
90
+ pinnedId?: string,
91
+ ): readonly string[] {
92
+ // Readonly out as well as in: the no-change cases return the caller's own array, so a
93
+ // mutating caller would corrupt its input in exactly the cases that must not change.
94
+ const list = ids;
95
+ if (list.length <= 1) return list;
96
+
97
+ const priorities = list.map(priorityOf);
98
+ const firstPriority = priorities[0]!;
99
+ if (priorities.every(priority => priority === firstPriority)) return list;
100
+
101
+ let ceiling = Number.POSITIVE_INFINITY;
102
+ if (pinnedId !== undefined) {
103
+ const pinnedIndex = list.indexOf(pinnedId);
104
+ if (pinnedIndex >= 0 && hasHeadroom(pinnedId)) ceiling = priorities[pinnedIndex]!;
105
+ }
106
+
107
+ const tiers = [...new Set(priorities)].sort((a, b) => b - a);
108
+ for (const tier of tiers) {
109
+ if (tier > ceiling) continue;
110
+ const members = list.filter((_, index) => priorities[index] === tier);
111
+ if (members.some(hasHeadroom)) return members;
112
+ }
113
+ return list;
114
+ }
115
+
116
+ function getOrCreateState(poolKey: string): SelectionState {
117
+ let state = selectionState.get(poolKey);
118
+ if (!state) {
119
+ state = { successes: 0, currentWeights: new Map() };
120
+ selectionState.set(poolKey, state);
121
+ }
122
+ return state;
123
+ }
124
+
125
+ function cloneSelectionState(state: SelectionState): SelectionState {
126
+ return {
127
+ activeKey: state.activeKey,
128
+ successes: state.successes,
129
+ currentWeights: new Map(state.currentWeights),
130
+ };
131
+ }
132
+
133
+ function smoothWeightedIndex(ids: readonly string[], state: SelectionState): number {
134
+ let best = -1;
135
+ let bestScore = Number.NEGATIVE_INFINITY;
136
+ let total = 0;
137
+ const weight = 1;
138
+ for (let i = 0; i < ids.length; i++) {
139
+ const id = ids[i]!;
140
+ const score = (state.currentWeights.get(id) ?? 0) + weight;
141
+ state.currentWeights.set(id, score);
142
+ total += weight;
143
+ if (score > bestScore) {
144
+ best = i;
145
+ bestScore = score;
146
+ }
147
+ }
148
+ if (best >= 0) {
149
+ const key = ids[best]!;
150
+ state.currentWeights.set(key, (state.currentWeights.get(key) ?? 0) - total);
151
+ }
152
+ return best;
153
+ }
154
+
155
+ /**
156
+ * Shared pick core. Mutates `state` the same way live resolve does; callers pass
157
+ * either the live map entry or a scratch/clone for dry-run peek.
158
+ */
159
+ function pickRoundRobinFromState(
160
+ eligibleIds: readonly string[],
161
+ stickyLimit: number,
162
+ state: SelectionState,
163
+ commitSticky: boolean,
164
+ ): string | null {
165
+ if (eligibleIds.length === 0) return null;
166
+
167
+ const limit = normalizeAccountPoolStickyLimit(stickyLimit);
168
+
169
+ if (state.activeKey && eligibleIds.includes(state.activeKey)) {
170
+ return state.activeKey;
171
+ }
172
+
173
+ if (state.activeKey) {
174
+ delete state.activeKey;
175
+ state.successes = 0;
176
+ }
177
+
178
+ const index = smoothWeightedIndex(eligibleIds, state);
179
+ if (index < 0) return null;
180
+
181
+ const picked = eligibleIds[index]!;
182
+ if (commitSticky && limit > 1) {
183
+ state.activeKey = picked;
184
+ state.successes = 0;
185
+ }
186
+ return picked;
187
+ }
188
+
189
+ export function pickRoundRobinAccount(
190
+ poolKey: string,
191
+ eligibleIds: readonly string[],
192
+ stickyLimit: number,
193
+ ): string | null {
194
+ return pickRoundRobinFromState(eligibleIds, stickyLimit, getOrCreateState(poolKey), true);
195
+ }
196
+
197
+ /**
198
+ * Dry-run of {@link pickRoundRobinAccount}: returns the same account resolve would
199
+ * pick without advancing ring weights, activeKey, or successes.
200
+ */
201
+ export function peekRoundRobinAccount(
202
+ poolKey: string,
203
+ eligibleIds: readonly string[],
204
+ stickyLimit: number,
205
+ ): string | null {
206
+ const live = selectionState.get(poolKey);
207
+ const scratch = live
208
+ ? cloneSelectionState(live)
209
+ : { successes: 0, currentWeights: new Map<string, number>() };
210
+ return pickRoundRobinFromState(eligibleIds, stickyLimit, scratch, false);
211
+ }
212
+
213
+ export function notePoolRotationSuccess(
214
+ poolKey: string,
215
+ accountId: string,
216
+ stickyLimit: number,
217
+ ): void {
218
+ const limit = normalizeAccountPoolStickyLimit(stickyLimit);
219
+ const state = selectionState.get(poolKey);
220
+ if (!state) return;
221
+ if (state.activeKey !== accountId) {
222
+ state.activeKey = accountId;
223
+ state.successes = 0;
224
+ }
225
+ state.successes += 1;
226
+ if (state.successes >= limit) {
227
+ delete state.activeKey;
228
+ state.successes = 0;
229
+ }
230
+ }
231
+
232
+ export function notePoolRotationFailure(poolKey: string, accountId: string): void {
233
+ const state = selectionState.get(poolKey);
234
+ if (state?.activeKey === accountId) {
235
+ delete state.activeKey;
236
+ state.successes = 0;
237
+ }
238
+ }
239
+
240
+ /**
241
+ * Force the next sticky/RR pick onto `accountId` (manual dashboard selection).
242
+ * Clears sticky success counters and ring weights so the seeded account is held
243
+ * for the next new-session pick before ordinary rotation resumes.
244
+ */
245
+ export function seedPoolRotationAccount(poolKey: string, accountId: string): void {
246
+ const state = getOrCreateState(poolKey);
247
+ state.activeKey = accountId;
248
+ state.successes = 0;
249
+ state.currentWeights.clear();
250
+ }
251
+
252
+ export function clearPoolRotationState(poolKey?: string): void {
253
+ if (poolKey === undefined) {
254
+ selectionState.clear();
255
+ return;
256
+ }
257
+ selectionState.delete(poolKey);
258
+ }
259
+
260
+ export function reconcilePoolRotationState(context: GenerationContext): number {
261
+ if (context.generation <= lastReconciledGeneration) return 0;
262
+ const anthropicIds = new Set<string>();
263
+ for (const key of context.oauthAccountKeys) {
264
+ const separator = key.indexOf("\0");
265
+ if (separator > 0 && key.slice(0, separator) === "anthropic") {
266
+ anthropicIds.add(key.slice(separator + 1));
267
+ }
268
+ }
269
+ let removed = 0;
270
+ for (const [poolKey, state] of selectionState) {
271
+ const valid = poolKey === POOL_KEY_ANTHROPIC
272
+ ? anthropicIds
273
+ : poolKey === POOL_KEY_CODEX || poolKey.startsWith(`${POOL_KEY_CODEX}:`)
274
+ ? context.codexAccountIds
275
+ : null;
276
+ if (!valid) continue;
277
+ if (valid.size === 0) {
278
+ selectionState.delete(poolKey);
279
+ removed += 1;
280
+ continue;
281
+ }
282
+ if (state.activeKey && !valid.has(state.activeKey)) {
283
+ delete state.activeKey;
284
+ state.successes = 0;
285
+ removed += 1;
286
+ }
287
+ for (const accountId of state.currentWeights.keys()) {
288
+ if (valid.has(accountId)) continue;
289
+ state.currentWeights.delete(accountId);
290
+ removed += 1;
291
+ }
292
+ }
293
+ lastReconciledGeneration = context.generation;
294
+ return removed;
295
+ }