@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,565 @@
1
+ import { existsSync, readFileSync } from "node:fs";
2
+ import { codexExecInvocation } from "../codex/exec-invocation";
3
+ import { CODEX_PROFILE_PATH } from "../codex/paths";
4
+ import { resolveCodexRuntime } from "../codex/runtime";
5
+
6
+ const DEFAULT_CODEX_APP_SERVER_PORT = 10106;
7
+ const START_TIMEOUT_MS = 12_000;
8
+ const REQUEST_TIMEOUT_MS = 30_000;
9
+
10
+ const APP_SERVER_PROFILE_KEYS = new Set([
11
+ "model_provider",
12
+ "openai_base_url",
13
+ "model_catalog_json",
14
+ "service_tier",
15
+ "features.fast_mode",
16
+ "model_providers.opencodex.name",
17
+ "model_providers.opencodex.base_url",
18
+ "model_providers.opencodex.wire_api",
19
+ "model_providers.opencodex.requires_openai_auth",
20
+ "model_providers.opencodex.supports_websockets",
21
+ "model_providers.opencodex.env_http_headers.x-opencodex-api-key",
22
+ ]);
23
+
24
+ function record(value: unknown): Record<string, unknown> | null {
25
+ return value !== null && typeof value === "object" && !Array.isArray(value)
26
+ ? value as Record<string, unknown>
27
+ : null;
28
+ }
29
+
30
+ function flattenProfile(
31
+ value: Record<string, unknown>,
32
+ prefix: string[],
33
+ output: Array<{ key: string; value: unknown }>,
34
+ ): void {
35
+ for (const [segment, child] of Object.entries(value)) {
36
+ const path = [...prefix, segment];
37
+ const childRecord = record(child);
38
+ if (childRecord) {
39
+ flattenProfile(childRecord, path, output);
40
+ continue;
41
+ }
42
+ output.push({ key: path.join("."), value: child });
43
+ }
44
+ }
45
+
46
+ function configTomlLiteral(value: unknown): string {
47
+ if (typeof value === "string") return JSON.stringify(value);
48
+ if (typeof value === "boolean") return value ? "true" : "false";
49
+ if (typeof value === "number" && Number.isFinite(value)) return String(value);
50
+ throw new Error("Remodex Codex profile contains an unsupported config value");
51
+ }
52
+
53
+ /**
54
+ * Current Codex builds do not accept `--profile` on `app-server`. Project the
55
+ * generated profile's small, non-secret allowlist through app-server's supported
56
+ * `--config key=value` surface instead. This has the same overlay effect without
57
+ * changing the user's base config.toml or putting a credential value in argv.
58
+ */
59
+ export function codexAppServerProfileOverrideArgs(profileContent: string): string[] {
60
+ let parsed: Record<string, unknown>;
61
+ try {
62
+ const document = record(Bun.TOML.parse(profileContent.replace(/^\uFEFF/, "")));
63
+ if (!document) throw new Error("profile root is not a TOML table");
64
+ parsed = document;
65
+ } catch {
66
+ throw new Error("Could not parse the generated Remodex Codex profile");
67
+ }
68
+
69
+ const leaves: Array<{ key: string; value: unknown }> = [];
70
+ flattenProfile(parsed, [], leaves);
71
+ const values = new Map(leaves.map(entry => [entry.key, entry.value]));
72
+ const provider = values.get("model_provider");
73
+ const hasLoopbackRoute = provider === "openai"
74
+ && typeof values.get("openai_base_url") === "string";
75
+ const hasNamedRoute = provider === "opencodex"
76
+ && typeof values.get("model_providers.opencodex.base_url") === "string"
77
+ && values.get("model_providers.opencodex.wire_api") === "responses";
78
+ if (!hasLoopbackRoute && !hasNamedRoute) {
79
+ throw new Error("Generated Remodex Codex profile does not contain a complete proxy route");
80
+ }
81
+
82
+ const args: string[] = [];
83
+ for (const { key, value } of leaves) {
84
+ if (!APP_SERVER_PROFILE_KEYS.has(key)) {
85
+ throw new Error(`Generated Remodex Codex profile contains unsupported key ${JSON.stringify(key)}`);
86
+ }
87
+ if (
88
+ key === "model_providers.opencodex.env_http_headers.x-opencodex-api-key"
89
+ && (typeof value !== "string" || !/^[A-Za-z_][A-Za-z0-9_]*$/.test(value))
90
+ ) {
91
+ throw new Error("Generated Remodex Codex profile contains an invalid API-auth environment reference");
92
+ }
93
+ args.push("--config", `${key}=${configTomlLiteral(value)}`);
94
+ }
95
+ return args;
96
+ }
97
+
98
+ function installedProfileContent(): string | null {
99
+ if (!existsSync(CODEX_PROFILE_PATH)) return null;
100
+ return readFileSync(CODEX_PROFILE_PATH, "utf8");
101
+ }
102
+
103
+ /**
104
+ * Arguments for the private Codex app-server used by Remodex's external clients.
105
+ * The generated v2 profile keeps the user's base config/provider untouched. Its
106
+ * values are forwarded as one-off config overrides because app-server itself
107
+ * does not currently accept Codex's `--profile` selector.
108
+ */
109
+ export function remodexCodexAppServerArgs(
110
+ port: number,
111
+ profileContent: string | null = installedProfileContent(),
112
+ ): string[] {
113
+ return [
114
+ ...(profileContent === null ? [] : codexAppServerProfileOverrideArgs(profileContent)),
115
+ "--enable",
116
+ "goals",
117
+ "app-server",
118
+ "--listen",
119
+ `ws://127.0.0.1:${port}`,
120
+ ];
121
+ }
122
+
123
+ export type CodexJsonRpcMessage = Record<string, unknown> & {
124
+ id?: string | number;
125
+ method?: string;
126
+ params?: unknown;
127
+ result?: unknown;
128
+ error?: { code?: number; message?: string };
129
+ };
130
+
131
+ export interface AndroidCodexClient {
132
+ request<T = unknown>(method: string, params?: unknown, timeoutMs?: number): Promise<T>;
133
+ respond(id: string | number, result: unknown): void;
134
+ reject(id: string | number, code: number, message: string): void;
135
+ subscribe(listener: (message: CodexJsonRpcMessage) => void): () => void;
136
+ close(): void;
137
+ /**
138
+ * `false` means the transport can no longer accept a request. Older test
139
+ * doubles may omit the field, so callers must treat `undefined` as unknown.
140
+ */
141
+ readonly connected?: boolean;
142
+ readonly closed: Promise<void>;
143
+ }
144
+
145
+ export class AndroidCodexConnectionError extends Error {
146
+ constructor(
147
+ message: string,
148
+ readonly requestMayHaveBeenSent: boolean,
149
+ ) {
150
+ super(message);
151
+ this.name = "AndroidCodexConnectionError";
152
+ }
153
+ }
154
+
155
+ const SAFE_DISCONNECT_RETRY_METHODS = new Set([
156
+ "fs/readDirectory",
157
+ "fuzzyFileSearch",
158
+ "model/list",
159
+ "plugin/installed",
160
+ "plugin/list",
161
+ "skills/list",
162
+ "thread/list",
163
+ "thread/read",
164
+ "thread/turns/list",
165
+ ]);
166
+
167
+ function connectionFailure(error: unknown): boolean {
168
+ if (error instanceof AndroidCodexConnectionError) return true;
169
+ const message = error instanceof Error ? error.message : String(error);
170
+ return /codex task server.*(?:closed|disconnect|connection|connected|failed)|websocket.*(?:closed|disconnect|connection|failed)/iu
171
+ .test(message);
172
+ }
173
+
174
+ function frameText(data: unknown): string | null {
175
+ if (typeof data === "string") return data;
176
+ if (data instanceof ArrayBuffer) return new TextDecoder().decode(data);
177
+ if (ArrayBuffer.isView(data)) {
178
+ return new TextDecoder().decode(
179
+ new Uint8Array(data.buffer, data.byteOffset, data.byteLength),
180
+ );
181
+ }
182
+ return null;
183
+ }
184
+
185
+ class CodexAppServerSocket implements AndroidCodexClient {
186
+ private nextId = 1;
187
+ private readonly pending = new Map<number, {
188
+ resolve: (value: unknown) => void;
189
+ reject: (error: Error) => void;
190
+ timer: ReturnType<typeof setTimeout>;
191
+ }>();
192
+ private readonly listeners = new Set<(message: CodexJsonRpcMessage) => void>();
193
+ private readonly closedResolve: () => void;
194
+ private didClose = false;
195
+ readonly closed: Promise<void>;
196
+
197
+ private constructor(private readonly socket: WebSocket) {
198
+ let resolveClosed = () => {};
199
+ this.closed = new Promise<void>(resolve => { resolveClosed = resolve; });
200
+ this.closedResolve = resolveClosed;
201
+ socket.addEventListener("message", event => this.onMessage(event.data));
202
+ socket.addEventListener("close", () => this.onClosed("Codex task server disconnected"));
203
+ socket.addEventListener("error", () => this.onClosed("Codex task server connection failed"));
204
+ }
205
+
206
+ static async connect(url: string): Promise<CodexAppServerSocket> {
207
+ const socket = new WebSocket(url);
208
+ await new Promise<void>((resolve, reject) => {
209
+ let settled = false;
210
+ const finish = (callback: () => void): void => {
211
+ if (settled) return;
212
+ settled = true;
213
+ clearTimeout(timer);
214
+ callback();
215
+ };
216
+ const timer = setTimeout(() => {
217
+ finish(() => {
218
+ try { socket.close(); } catch { /* connection already failed */ }
219
+ reject(new Error("Codex task server connection timed out"));
220
+ });
221
+ }, 5_000);
222
+ socket.addEventListener("open", () => finish(resolve), { once: true });
223
+ socket.addEventListener("error", () => finish(() => {
224
+ reject(new Error("Could not connect to the Codex task server"));
225
+ }), { once: true });
226
+ });
227
+ const client = new CodexAppServerSocket(socket);
228
+ await client.request("initialize", {
229
+ clientInfo: { name: "Remodex Android Remote", version: "1" },
230
+ capabilities: {
231
+ experimentalApi: true,
232
+ requestAttestation: false,
233
+ optOutNotificationMethods: [],
234
+ },
235
+ });
236
+ client.send({ method: "initialized" });
237
+ return client;
238
+ }
239
+
240
+ get connected(): boolean {
241
+ return !this.didClose && this.socket.readyState === WebSocket.OPEN;
242
+ }
243
+
244
+ request<T = unknown>(method: string, params: unknown = {}, timeoutMs = REQUEST_TIMEOUT_MS): Promise<T> {
245
+ const id = this.nextId++;
246
+ return new Promise<T>((resolve, reject) => {
247
+ const timer = setTimeout(() => {
248
+ this.pending.delete(id);
249
+ reject(new Error(`Codex request timed out: ${method}`));
250
+ }, timeoutMs);
251
+ this.pending.set(id, {
252
+ resolve: value => resolve(value as T),
253
+ reject,
254
+ timer,
255
+ });
256
+ try {
257
+ this.send({ id, method, params });
258
+ } catch (error) {
259
+ clearTimeout(timer);
260
+ this.pending.delete(id);
261
+ reject(error instanceof AndroidCodexConnectionError
262
+ ? error
263
+ : new AndroidCodexConnectionError(
264
+ error instanceof Error ? error.message : String(error),
265
+ false,
266
+ ));
267
+ }
268
+ });
269
+ }
270
+
271
+ respond(id: string | number, result: unknown): void {
272
+ this.send({ id, result });
273
+ }
274
+
275
+ reject(id: string | number, code: number, message: string): void {
276
+ this.send({ id, error: { code, message } });
277
+ }
278
+
279
+ subscribe(listener: (message: CodexJsonRpcMessage) => void): () => void {
280
+ this.listeners.add(listener);
281
+ return () => this.listeners.delete(listener);
282
+ }
283
+
284
+ close(): void {
285
+ try { this.socket.close(1000, "Remodex stopping"); } catch { /* already closed */ }
286
+ this.onClosed("Codex task server connection closed");
287
+ }
288
+
289
+ private send(message: CodexJsonRpcMessage): void {
290
+ if (this.socket.readyState !== WebSocket.OPEN) {
291
+ throw new AndroidCodexConnectionError("Codex task server is not connected", false);
292
+ }
293
+ this.socket.send(JSON.stringify({ jsonrpc: "2.0", ...message }));
294
+ }
295
+
296
+ private onMessage(data: unknown): void {
297
+ const text = frameText(data);
298
+ if (!text || text.length > 16 * 1024 * 1024) return;
299
+ let message: CodexJsonRpcMessage;
300
+ try {
301
+ message = JSON.parse(text) as CodexJsonRpcMessage;
302
+ } catch {
303
+ return;
304
+ }
305
+ if (typeof message.id === "number" && !message.method) {
306
+ const pending = this.pending.get(message.id);
307
+ if (!pending) return;
308
+ this.pending.delete(message.id);
309
+ clearTimeout(pending.timer);
310
+ if (message.error) {
311
+ pending.reject(new Error(message.error.message || "Codex task request failed"));
312
+ } else {
313
+ pending.resolve(message.result);
314
+ }
315
+ return;
316
+ }
317
+ for (const listener of this.listeners) listener(message);
318
+ }
319
+
320
+ private onClosed(message: string): void {
321
+ if (this.didClose) return;
322
+ this.didClose = true;
323
+ for (const pending of this.pending.values()) {
324
+ clearTimeout(pending.timer);
325
+ pending.reject(new AndroidCodexConnectionError(message, true));
326
+ }
327
+ this.pending.clear();
328
+ this.closedResolve();
329
+ }
330
+ }
331
+
332
+ async function taskServerReady(port: number): Promise<boolean> {
333
+ try {
334
+ const response = await fetch(`http://127.0.0.1:${port}/readyz`, {
335
+ signal: AbortSignal.timeout(750),
336
+ });
337
+ return response.ok;
338
+ } catch {
339
+ return false;
340
+ }
341
+ }
342
+
343
+ async function waitUntilReady(port: number, child: Bun.Subprocess): Promise<void> {
344
+ const deadline = Date.now() + START_TIMEOUT_MS;
345
+ while (Date.now() < deadline) {
346
+ if (await taskServerReady(port)) return;
347
+ const exit = await Promise.race([
348
+ child.exited.then(code => ({ code })),
349
+ new Promise<null>(resolve => setTimeout(() => resolve(null), 150)),
350
+ ]);
351
+ if (exit) throw new Error(`Codex task server exited during startup (code ${exit.code})`);
352
+ }
353
+ throw new Error("Codex task server did not become ready");
354
+ }
355
+
356
+ export type AndroidCodexRuntimeStatus = {
357
+ connected: boolean;
358
+ port: number;
359
+ ownedProcess: boolean;
360
+ error?: string;
361
+ };
362
+
363
+ export class AndroidCodexRuntime {
364
+ private child: Bun.Subprocess | null = null;
365
+ private socket: AndroidCodexClient | null = null;
366
+ private socketUnsubscribe: (() => void) | null = null;
367
+ private facade: AndroidCodexClient | null = null;
368
+ private facadeClosedResolve: (() => void) | null = null;
369
+ private readonly listeners = new Set<(message: CodexJsonRpcMessage) => void>();
370
+ private connectFlight: Promise<AndroidCodexClient> | null = null;
371
+ private ownedProcess = false;
372
+ private error: string | undefined;
373
+ private lifecycleRevision = 0;
374
+ private stopFlight: Promise<void> | null = null;
375
+
376
+ constructor(private readonly port = DEFAULT_CODEX_APP_SERVER_PORT) {}
377
+
378
+ status(): AndroidCodexRuntimeStatus {
379
+ return {
380
+ connected: this.socket?.connected !== false && this.socket !== null,
381
+ port: this.port,
382
+ ownedProcess: this.ownedProcess,
383
+ ...(this.error ? { error: this.error } : {}),
384
+ };
385
+ }
386
+
387
+ async start(): Promise<AndroidCodexClient> {
388
+ if (this.stopFlight) throw new Error("Codex task runtime is stopping");
389
+ const facade = this.facade ?? this.createFacade();
390
+ await this.ensureSocket();
391
+ return facade;
392
+ }
393
+
394
+ private createFacade(): AndroidCodexClient {
395
+ let resolveClosed = () => {};
396
+ const closed = new Promise<void>(resolve => { resolveClosed = resolve; });
397
+ const thisRuntime = this;
398
+ const facade: AndroidCodexClient = {
399
+ request: <T = unknown>(method: string, params?: unknown, timeoutMs?: number) => {
400
+ if (this.facade !== facade || this.stopFlight) {
401
+ return Promise.reject(new Error("Codex task client is closed"));
402
+ }
403
+ return this.request<T>(method, params, timeoutMs);
404
+ },
405
+ respond: (id, result) => {
406
+ if (this.facade !== facade || this.stopFlight) throw new Error("Codex task client is closed");
407
+ this.requireSocket().respond(id, result);
408
+ },
409
+ reject: (id, code, message) => {
410
+ if (this.facade !== facade || this.stopFlight) throw new Error("Codex task client is closed");
411
+ this.requireSocket().reject(id, code, message);
412
+ },
413
+ subscribe: listener => {
414
+ if (this.facade !== facade || this.stopFlight) return () => {};
415
+ this.listeners.add(listener);
416
+ return () => this.listeners.delete(listener);
417
+ },
418
+ close: () => {
419
+ if (this.facade === facade) void this.stop();
420
+ },
421
+ get connected() {
422
+ return facade === thisRuntime.facade && thisRuntime.status().connected;
423
+ },
424
+ closed,
425
+ };
426
+ this.facade = facade;
427
+ this.facadeClosedResolve = resolveClosed;
428
+ return facade;
429
+ }
430
+
431
+ private async request<T>(
432
+ method: string,
433
+ params?: unknown,
434
+ timeoutMs?: number,
435
+ ): Promise<T> {
436
+ const socket = await this.ensureSocket();
437
+ try {
438
+ return await socket.request<T>(method, params, timeoutMs);
439
+ } catch (error) {
440
+ if (!connectionFailure(error)) throw error;
441
+ this.dropSocket(socket, true);
442
+ const canRetry = error instanceof AndroidCodexConnectionError
443
+ ? !error.requestMayHaveBeenSent || SAFE_DISCONNECT_RETRY_METHODS.has(method)
444
+ : SAFE_DISCONNECT_RETRY_METHODS.has(method);
445
+ if (!canRetry) throw error;
446
+ return (await this.ensureSocket()).request<T>(method, params, timeoutMs);
447
+ }
448
+ }
449
+
450
+ private requireSocket(): AndroidCodexClient {
451
+ if (!this.socket || this.socket.connected === false) {
452
+ throw new AndroidCodexConnectionError("Codex task server is not connected", false);
453
+ }
454
+ return this.socket;
455
+ }
456
+
457
+ private async ensureSocket(): Promise<AndroidCodexClient> {
458
+ if (this.socket?.connected !== false && this.socket) return this.socket;
459
+ if (this.socket) this.dropSocket(this.socket, false);
460
+ if (this.connectFlight) return this.connectFlight;
461
+ const revision = this.lifecycleRevision;
462
+ const flight = this.connectSocket(revision);
463
+ this.connectFlight = flight;
464
+ try {
465
+ return await flight;
466
+ } finally {
467
+ if (this.connectFlight === flight) this.connectFlight = null;
468
+ }
469
+ }
470
+
471
+ private async connectSocket(revision: number): Promise<AndroidCodexClient> {
472
+ this.error = undefined;
473
+ try {
474
+ if (!(await taskServerReady(this.port))) {
475
+ await this.stopOwnedProcess();
476
+ const runtime = resolveCodexRuntime({ discoverAlternatives: false }).runtime;
477
+ const invocation = codexExecInvocation(
478
+ runtime.command || "codex",
479
+ remodexCodexAppServerArgs(this.port),
480
+ );
481
+ const child = Bun.spawn([invocation.file, ...invocation.args], {
482
+ stdin: "ignore",
483
+ stdout: "ignore",
484
+ stderr: "ignore",
485
+ windowsHide: true,
486
+ ...(invocation.options.windowsVerbatimArguments
487
+ ? { windowsVerbatimArguments: true }
488
+ : {}),
489
+ });
490
+ this.child = child;
491
+ this.ownedProcess = true;
492
+ void child.exited.then(() => {
493
+ if (this.child !== child) return;
494
+ this.child = null;
495
+ this.ownedProcess = false;
496
+ });
497
+ await waitUntilReady(this.port, child);
498
+ }
499
+ const socket = await CodexAppServerSocket.connect(`ws://127.0.0.1:${this.port}`);
500
+ if (revision !== this.lifecycleRevision) {
501
+ socket.close();
502
+ throw new Error("Codex task runtime stopped during startup");
503
+ }
504
+ this.socket = socket;
505
+ this.socketUnsubscribe = socket.subscribe(message => {
506
+ for (const listener of this.listeners) listener(message);
507
+ });
508
+ void socket.closed.then(() => this.dropSocket(socket, false));
509
+ this.error = undefined;
510
+ return socket;
511
+ } catch (error) {
512
+ this.error = error instanceof Error ? error.message : String(error);
513
+ await this.stopOwnedProcess();
514
+ throw error;
515
+ }
516
+ }
517
+
518
+ async stop(): Promise<void> {
519
+ if (this.stopFlight) return this.stopFlight;
520
+ const flight = this.stopRuntime();
521
+ this.stopFlight = flight;
522
+ try {
523
+ await flight;
524
+ } finally {
525
+ if (this.stopFlight === flight) this.stopFlight = null;
526
+ }
527
+ }
528
+
529
+ private async stopRuntime(): Promise<void> {
530
+ this.lifecycleRevision += 1;
531
+ const connecting = this.connectFlight;
532
+ if (connecting) await connecting.catch(() => undefined);
533
+ const socket = this.socket;
534
+ if (socket) this.dropSocket(socket, true);
535
+ await this.stopOwnedProcess();
536
+ this.listeners.clear();
537
+ this.facadeClosedResolve?.();
538
+ this.facadeClosedResolve = null;
539
+ this.facade = null;
540
+ this.error = undefined;
541
+ }
542
+
543
+ private dropSocket(socket: AndroidCodexClient, close: boolean): void {
544
+ if (this.socket !== socket) return;
545
+ this.socketUnsubscribe?.();
546
+ this.socketUnsubscribe = null;
547
+ this.socket = null;
548
+ if (close) {
549
+ try { socket.close(); } catch { /* already disconnected */ }
550
+ }
551
+ }
552
+
553
+ private async stopOwnedProcess(): Promise<void> {
554
+ const child = this.child;
555
+ this.child = null;
556
+ if (child && this.ownedProcess) {
557
+ try { child.kill(); } catch { /* already exited */ }
558
+ await Promise.race([
559
+ child.exited.catch(() => -1),
560
+ new Promise(resolve => setTimeout(resolve, 1_000)),
561
+ ]);
562
+ }
563
+ this.ownedProcess = false;
564
+ }
565
+ }