@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,616 @@
1
+ import {
2
+ lstatSync,
3
+ readdirSync,
4
+ readFileSync,
5
+ renameSync,
6
+ rmdirSync,
7
+ } from "node:fs";
8
+ import { homedir } from "node:os";
9
+ import { dirname, join, resolve } from "node:path";
10
+
11
+ export const REMODEX_HOME_DIRNAME = ".remodex";
12
+ export const LEGACY_REMODEX_HOME_DIRNAME = ".opencodex";
13
+
14
+ /**
15
+ * Files that are specific enough to identify a previous Remodex state root.
16
+ *
17
+ * The migration deliberately does not move an arbitrary, user-created
18
+ * `~/.opencodex` directory. A directory is eligible only when it contains a
19
+ * known Remodex artifact, or a config.json with Remodex-shaped top-level keys.
20
+ */
21
+ export const REMODEX_STATE_EVIDENCE_FILES = [
22
+ ".opencodex-owner.json",
23
+ ".opencodex-uninstall.json",
24
+ "admin-api-token",
25
+ "android-remote.json",
26
+ "catalog-backup.json",
27
+ "codex-runtime-clamp.json",
28
+ "codex-runtime.json",
29
+ "codex-shim.json",
30
+ "desktop-runtime.log",
31
+ "desktop-update.json",
32
+ "ocx.pid",
33
+ "responses-state.json",
34
+ "runtime-port.json",
35
+ "service-api-token",
36
+ "service-provider-env.json",
37
+ "service-state.json",
38
+ "service.log",
39
+ "tray-heartbeat.json",
40
+ "tray-state.json",
41
+ "usage-debug.jsonl",
42
+ "usage.jsonl",
43
+ "update-job.json",
44
+ "winsw",
45
+ ] as const;
46
+
47
+ const CONFIG_EVIDENCE_KEYS = [
48
+ "providers",
49
+ "defaultProvider",
50
+ "clientIntegrations",
51
+ "claudeCode",
52
+ "grok",
53
+ "tokenGuardian",
54
+ "routingProfiles",
55
+ "subagentModels",
56
+ ] as const;
57
+ const MAX_EVIDENCE_CONFIG_BYTES = 256 * 1024;
58
+
59
+ type HomeStat = {
60
+ isFile(): boolean;
61
+ isDirectory(): boolean;
62
+ isSymbolicLink(): boolean;
63
+ };
64
+
65
+ export interface RemodexHomeIO {
66
+ lstat(path: string): HomeStat;
67
+ readdir(path: string): string[];
68
+ readFile(path: string): string;
69
+ rename(source: string, destination: string): void;
70
+ removeEmptyDirectory?: (path: string) => void;
71
+ }
72
+
73
+ const defaultIO: RemodexHomeIO = {
74
+ lstat: lstatSync,
75
+ readdir: path => readdirSync(path),
76
+ readFile: path => readFileSync(path, "utf8"),
77
+ rename: renameSync,
78
+ removeEmptyDirectory: rmdirSync,
79
+ };
80
+
81
+ export type DefaultRemodexHomeOutcome =
82
+ | "canonical-existing"
83
+ | "new"
84
+ | "migrated"
85
+ | "legacy-fallback"
86
+ | "collision"
87
+ | "canonical-blocked"
88
+ | "migration-deferred";
89
+
90
+ export interface DefaultRemodexHomeResolution {
91
+ readonly path: string;
92
+ readonly canonicalPath: string;
93
+ readonly legacyPath: string;
94
+ readonly outcome: DefaultRemodexHomeOutcome;
95
+ readonly legacyEvidence: boolean;
96
+ readonly warning?: string;
97
+ }
98
+
99
+ function errorCode(error: unknown): string | undefined {
100
+ return error && typeof error === "object" && "code" in error
101
+ ? String((error as { code?: unknown }).code)
102
+ : undefined;
103
+ }
104
+
105
+ function isDirectory(path: string, io: RemodexHomeIO): boolean {
106
+ try {
107
+ const stat = io.lstat(path);
108
+ return stat.isDirectory() && !stat.isSymbolicLink();
109
+ } catch {
110
+ return false;
111
+ }
112
+ }
113
+
114
+ function pathExists(path: string, io: RemodexHomeIO): boolean {
115
+ try {
116
+ io.lstat(path);
117
+ return true;
118
+ } catch {
119
+ return false;
120
+ }
121
+ }
122
+
123
+ function directoryNames(path: string, io: RemodexHomeIO): string[] | null {
124
+ try {
125
+ return io.readdir(path);
126
+ } catch {
127
+ return null;
128
+ }
129
+ }
130
+
131
+ function hasConfigEvidence(path: string, io: RemodexHomeIO): boolean {
132
+ const configPath = join(path, "config.json");
133
+ let raw: string;
134
+ try {
135
+ const stat = io.lstat(configPath);
136
+ if (!stat.isFile() || stat.isSymbolicLink()) return false;
137
+ raw = io.readFile(configPath);
138
+ } catch {
139
+ return false;
140
+ }
141
+ if (Buffer.byteLength(raw, "utf8") > MAX_EVIDENCE_CONFIG_BYTES) return false;
142
+ try {
143
+ const value = JSON.parse(raw) as unknown;
144
+ if (!value || typeof value !== "object" || Array.isArray(value)) return false;
145
+ return CONFIG_EVIDENCE_KEYS.some(key => Object.prototype.hasOwnProperty.call(value, key));
146
+ } catch {
147
+ return false;
148
+ }
149
+ }
150
+
151
+ function hasServiceAssetEvidence(path: string, io: RemodexHomeIO): boolean {
152
+ const names = directoryNames(path, io);
153
+ if (!names) return false;
154
+ return [
155
+ "service-state.json",
156
+ "opencodex-service.cmd",
157
+ "opencodex-service-launcher.vbs",
158
+ "opencodex-service-task.xml",
159
+ "winsw",
160
+ ].some(name => names.includes(name));
161
+ }
162
+
163
+ function normalizeComparablePath(path: string): string {
164
+ const normalized = resolve(path).replace(/\\/g, "/").replace(/\/+$/g, "");
165
+ return process.platform === "win32" ? normalized.toLowerCase() : normalized;
166
+ }
167
+
168
+ /**
169
+ * A legacy service is an active owner of the old root until its definition has
170
+ * been rewritten. Moving the directory underneath it would make the manager
171
+ * start a second default-root instance or lose its credentials on the next
172
+ * login. Treat the asset set as a migration boundary even when the canonical
173
+ * directory already exists.
174
+ */
175
+ function legacyServiceOwnsPath(
176
+ path: string,
177
+ legacyPath: string,
178
+ io: RemodexHomeIO,
179
+ ): boolean {
180
+ if (!hasServiceAssetEvidence(path, io)) return false;
181
+ const statePath = join(path, "service-state.json");
182
+ try {
183
+ const stat = io.lstat(statePath);
184
+ if (stat.isFile() && !stat.isSymbolicLink()) {
185
+ const parsed = JSON.parse(io.readFile(statePath)) as Record<string, unknown>;
186
+ const recorded = typeof parsed.opencodexHome === "string"
187
+ ? parsed.opencodexHome
188
+ : undefined;
189
+ if (recorded) return normalizeComparablePath(recorded) === normalizeComparablePath(legacyPath);
190
+ }
191
+ } catch {
192
+ // A malformed state file is still not permission to move a service asset.
193
+ }
194
+ return true;
195
+ }
196
+
197
+ /** Return true only for a directory with unambiguous Remodex state evidence. */
198
+ export function hasStrongRemodexEvidence(
199
+ path: string,
200
+ io: RemodexHomeIO = defaultIO,
201
+ ): boolean {
202
+ if (!isDirectory(path, io)) return false;
203
+ const names = directoryNames(path, io);
204
+ if (!names) return false;
205
+ const known = new Set<string>(REMODEX_STATE_EVIDENCE_FILES);
206
+ if (names.some(name => known.has(name))) return true;
207
+ return names.includes("config.json") && hasConfigEvidence(path, io);
208
+ }
209
+
210
+ /** True when the legacy root contains service assets that still claim ownership. */
211
+ export function hasLegacyRemodexServiceRoot(options: {
212
+ home?: string;
213
+ io?: RemodexHomeIO;
214
+ } = {}): boolean {
215
+ const io = options.io ?? defaultIO;
216
+ const home = resolve(options.home ?? homedir());
217
+ const legacyPath = join(home, LEGACY_REMODEX_HOME_DIRNAME);
218
+ return isDirectory(legacyPath, io)
219
+ && hasStrongRemodexEvidence(legacyPath, io)
220
+ && legacyServiceOwnsPath(legacyPath, legacyPath, io);
221
+ }
222
+
223
+ function nonEmptyDirectory(path: string, io: RemodexHomeIO): boolean {
224
+ const names = directoryNames(path, io);
225
+ return names === null || names.length > 0;
226
+ }
227
+
228
+ const emittedWarnings = new Set<string>();
229
+
230
+ function warningOnce(
231
+ key: string,
232
+ message: string,
233
+ warn: (message: string) => void,
234
+ ): void {
235
+ if (emittedWarnings.has(key)) return;
236
+ emittedWarnings.add(key);
237
+ warn(message);
238
+ }
239
+
240
+ /**
241
+ * Inspect whether an implicit legacy service root can be moved without changing
242
+ * the filesystem. Callers use this before stopping the owning service so a
243
+ * populated `.remodex` root cannot turn a recoverable repair into downtime.
244
+ */
245
+ export function preflightLegacyRemodexServiceMigration(options: {
246
+ home?: string;
247
+ io?: RemodexHomeIO;
248
+ warn?: (message: string) => void;
249
+ } = {}): DefaultRemodexHomeResolution {
250
+ const io = options.io ?? defaultIO;
251
+ const warn = options.warn ?? ((message: string) => console.warn(message));
252
+ const home = resolve(options.home ?? homedir());
253
+ const canonicalPath = join(home, REMODEX_HOME_DIRNAME);
254
+ const legacyPath = join(home, LEGACY_REMODEX_HOME_DIRNAME);
255
+ const canonicalDirectory = isDirectory(canonicalPath, io);
256
+ const legacyDirectory = isDirectory(legacyPath, io);
257
+ const legacyEvidence = legacyDirectory && hasStrongRemodexEvidence(legacyPath, io);
258
+
259
+ if (!legacyDirectory || !legacyEvidence || !legacyServiceOwnsPath(legacyPath, legacyPath, io)) {
260
+ return {
261
+ path: canonicalDirectory ? canonicalPath : canonicalPath,
262
+ canonicalPath,
263
+ legacyPath,
264
+ outcome: canonicalDirectory ? "canonical-existing" : "new",
265
+ legacyEvidence,
266
+ };
267
+ }
268
+
269
+ if (!pathExists(canonicalPath, io)) {
270
+ return {
271
+ path: canonicalPath,
272
+ canonicalPath,
273
+ legacyPath,
274
+ outcome: "migrated",
275
+ legacyEvidence: true,
276
+ };
277
+ }
278
+
279
+ if (!canonicalDirectory) {
280
+ const warning =
281
+ `${canonicalPath} exists but is not a real directory; Remodex will not replace it.`;
282
+ warningOnce(`${canonicalPath}:blocked`, warning, warn);
283
+ return {
284
+ path: canonicalPath,
285
+ canonicalPath,
286
+ legacyPath,
287
+ outcome: "canonical-blocked",
288
+ legacyEvidence: true,
289
+ warning,
290
+ };
291
+ }
292
+
293
+ const names = directoryNames(canonicalPath, io);
294
+ const removeEmptyDirectory = io.removeEmptyDirectory;
295
+ if (names === null || names.length > 0 || !removeEmptyDirectory) {
296
+ const warning =
297
+ `Remodex cannot move the legacy service root ${legacyPath} because `
298
+ + `the canonical directory ${canonicalPath} is already populated. `
299
+ + "No files were changed; resolve the two roots, then run `rmx service repair` again.";
300
+ warningOnce(`${canonicalPath}:service-collision`, warning, warn);
301
+ return {
302
+ path: legacyPath,
303
+ canonicalPath,
304
+ legacyPath,
305
+ outcome: "collision",
306
+ legacyEvidence: true,
307
+ warning,
308
+ };
309
+ }
310
+
311
+ return {
312
+ path: canonicalPath,
313
+ canonicalPath,
314
+ legacyPath,
315
+ outcome: "migrated",
316
+ legacyEvidence: true,
317
+ };
318
+ }
319
+
320
+ function migrateLegacyServiceRoot(
321
+ canonicalPath: string,
322
+ legacyPath: string,
323
+ io: RemodexHomeIO,
324
+ warn: (message: string) => void,
325
+ ): DefaultRemodexHomeResolution {
326
+ const preflight = preflightLegacyRemodexServiceMigration({
327
+ home: dirname(canonicalPath),
328
+ io,
329
+ warn,
330
+ });
331
+ if (preflight.outcome === "canonical-blocked" || preflight.outcome === "collision") {
332
+ return preflight;
333
+ }
334
+ if (preflight.outcome !== "migrated") {
335
+ return {
336
+ ...preflight,
337
+ path: canonicalPath,
338
+ canonicalPath,
339
+ legacyPath,
340
+ };
341
+ }
342
+
343
+ const removeEmptyDirectory = io.removeEmptyDirectory;
344
+ if (pathExists(canonicalPath, io)) {
345
+ // A previous startup can leave an empty canonical directory behind. It is
346
+ // safe to remove that empty placeholder; the read-only preflight above has
347
+ // already established that it is empty.
348
+ if (!removeEmptyDirectory) {
349
+ return {
350
+ path: legacyPath,
351
+ canonicalPath,
352
+ legacyPath,
353
+ outcome: "collision",
354
+ legacyEvidence: preflight.legacyEvidence,
355
+ warning: preflight.warning
356
+ ?? `Remodex could not remove the empty canonical directory ${canonicalPath}; no service-root migration was completed.`,
357
+ };
358
+ }
359
+ try {
360
+ removeEmptyDirectory(canonicalPath);
361
+ } catch (error) {
362
+ const code = errorCode(error);
363
+ const warning =
364
+ `Remodex could not remove the empty canonical directory ${canonicalPath}`
365
+ + (code ? ` (${code})` : "")
366
+ + "; no service-root migration was completed.";
367
+ warningOnce(`${canonicalPath}:service-collision`, warning, warn);
368
+ return {
369
+ path: legacyPath,
370
+ canonicalPath,
371
+ legacyPath,
372
+ outcome: "collision",
373
+ legacyEvidence: preflight.legacyEvidence,
374
+ warning,
375
+ };
376
+ }
377
+ }
378
+
379
+ try {
380
+ io.rename(legacyPath, canonicalPath);
381
+ return {
382
+ path: canonicalPath,
383
+ canonicalPath,
384
+ legacyPath,
385
+ outcome: "migrated",
386
+ legacyEvidence: preflight.legacyEvidence,
387
+ };
388
+ } catch (error) {
389
+ // Another Remodex process may have won the race. Only accept that outcome
390
+ // when the old service root is gone; otherwise keep using the old root.
391
+ if (isDirectory(canonicalPath, io) && !isDirectory(legacyPath, io)) {
392
+ return {
393
+ path: canonicalPath,
394
+ canonicalPath,
395
+ legacyPath,
396
+ outcome: "canonical-existing",
397
+ legacyEvidence: true,
398
+ };
399
+ }
400
+
401
+ if (isDirectory(legacyPath, io)) {
402
+ const code = errorCode(error);
403
+ const warning =
404
+ `Remodex could not move legacy service state from ${legacyPath} to ${canonicalPath}`
405
+ + (code ? ` (${code})` : "")
406
+ + ". The legacy root was left intact; retry `rmx service repair` after the service is stopped.";
407
+ warningOnce(`${canonicalPath}:service-migration-failed`, warning, warn);
408
+ return {
409
+ path: legacyPath,
410
+ canonicalPath,
411
+ legacyPath,
412
+ outcome: "legacy-fallback",
413
+ legacyEvidence: true,
414
+ warning,
415
+ };
416
+ }
417
+
418
+ return {
419
+ path: canonicalPath,
420
+ canonicalPath,
421
+ legacyPath,
422
+ outcome: "new",
423
+ legacyEvidence: true,
424
+ };
425
+ }
426
+ }
427
+
428
+ /**
429
+ * Resolve the default Remodex state root.
430
+ *
431
+ * `OPENCODEX_HOME` is handled by the caller and remains an authoritative
432
+ * explicit override. This function is only for the implicit per-user default.
433
+ *
434
+ * Migration is a same-parent directory rename, so it is atomic and never
435
+ * merges two populated roots. If Windows has a locked file and the rename
436
+ * cannot be completed, the legacy root is selected for this process so an
437
+ * installed service is not accidentally duplicated under a new empty root.
438
+ * A later process retries the migration.
439
+ */
440
+ export function resolveDefaultRemodexHome(options: {
441
+ home?: string;
442
+ io?: RemodexHomeIO;
443
+ warn?: (message: string) => void;
444
+ /** Disabled by test harnesses and read-only probes; production defaults true. */
445
+ migrate?: boolean;
446
+ /**
447
+ * Used only after the owning service has been stopped. This permits the
448
+ * legacy service root to move even though ordinary startup deliberately
449
+ * keeps it in place until its assets are rewritten.
450
+ */
451
+ forceLegacyServiceMigration?: boolean;
452
+ } = {}): DefaultRemodexHomeResolution {
453
+ const io = options.io ?? defaultIO;
454
+ const warn = options.warn ?? ((message: string) => console.warn(message));
455
+ const migrate = options.migrate ?? true;
456
+ const forceLegacyServiceMigration = options.forceLegacyServiceMigration ?? false;
457
+ const home = resolve(options.home ?? homedir());
458
+ const canonicalPath = join(home, REMODEX_HOME_DIRNAME);
459
+ const legacyPath = join(home, LEGACY_REMODEX_HOME_DIRNAME);
460
+ const canonicalDirectory = isDirectory(canonicalPath, io);
461
+ const legacyDirectory = isDirectory(legacyPath, io);
462
+
463
+ // A test process must never rename a real user's state root merely because
464
+ // one test temporarily deletes OPENCODEX_HOME.
465
+ if (!migrate) {
466
+ return {
467
+ path: canonicalPath,
468
+ canonicalPath,
469
+ legacyPath,
470
+ outcome: canonicalDirectory ? "canonical-existing" : "migration-deferred",
471
+ legacyEvidence: legacyDirectory && hasStrongRemodexEvidence(legacyPath, io),
472
+ };
473
+ }
474
+
475
+ if (canonicalDirectory) {
476
+ const legacyEvidence = hasStrongRemodexEvidence(legacyPath, io);
477
+ if (legacyDirectory && legacyServiceOwnsPath(legacyPath, legacyPath, io)) {
478
+ if (forceLegacyServiceMigration) {
479
+ return migrateLegacyServiceRoot(canonicalPath, legacyPath, io, warn);
480
+ }
481
+ const warning =
482
+ `Remodex is keeping the legacy state root ${legacyPath} because an installed `
483
+ + "service still points there. Run `rmx service repair` after closing the "
484
+ + "current proxy to move service state to the canonical .remodex directory.";
485
+ warningOnce(`${canonicalPath}:legacy-service`, warning, warn);
486
+ return {
487
+ path: legacyPath,
488
+ canonicalPath,
489
+ legacyPath,
490
+ outcome: "legacy-fallback",
491
+ legacyEvidence,
492
+ warning,
493
+ };
494
+ }
495
+ const collision = legacyDirectory && nonEmptyDirectory(legacyPath, io);
496
+ if (collision) {
497
+ const warning =
498
+ `Remodex found both ${canonicalPath} and legacy ${legacyPath}; `
499
+ + `using ${canonicalPath} and leaving the legacy directory untouched. `
500
+ + "Review the legacy directory before removing it.";
501
+ warningOnce(`${canonicalPath}:collision`, warning, warn);
502
+ return {
503
+ path: canonicalPath,
504
+ canonicalPath,
505
+ legacyPath,
506
+ outcome: "collision",
507
+ legacyEvidence,
508
+ warning,
509
+ };
510
+ }
511
+ return {
512
+ path: canonicalPath,
513
+ canonicalPath,
514
+ legacyPath,
515
+ outcome: "canonical-existing",
516
+ legacyEvidence,
517
+ };
518
+ }
519
+
520
+ if (pathExists(canonicalPath, io)) {
521
+ const warning =
522
+ `${canonicalPath} exists but is not a real directory; Remodex will not replace it.`;
523
+ warningOnce(`${canonicalPath}:blocked`, warning, warn);
524
+ return {
525
+ path: canonicalPath,
526
+ canonicalPath,
527
+ legacyPath,
528
+ outcome: "canonical-blocked",
529
+ legacyEvidence: false,
530
+ warning,
531
+ };
532
+ }
533
+
534
+ const legacyEvidence = legacyDirectory && hasStrongRemodexEvidence(legacyPath, io);
535
+ if (!legacyEvidence) {
536
+ return {
537
+ path: canonicalPath,
538
+ canonicalPath,
539
+ legacyPath,
540
+ outcome: "new",
541
+ legacyEvidence: false,
542
+ };
543
+ }
544
+
545
+ if (legacyServiceOwnsPath(legacyPath, legacyPath, io)) {
546
+ if (forceLegacyServiceMigration) {
547
+ return migrateLegacyServiceRoot(canonicalPath, legacyPath, io, warn);
548
+ }
549
+ const warning =
550
+ `Remodex found an installed service under legacy state root ${legacyPath}; `
551
+ + "it will remain there until `rmx service repair` rewrites the service safely.";
552
+ warningOnce(`${canonicalPath}:legacy-service`, warning, warn);
553
+ return {
554
+ path: legacyPath,
555
+ canonicalPath,
556
+ legacyPath,
557
+ outcome: "legacy-fallback",
558
+ legacyEvidence: true,
559
+ warning,
560
+ };
561
+ }
562
+
563
+ try {
564
+ io.rename(legacyPath, canonicalPath);
565
+ return {
566
+ path: canonicalPath,
567
+ canonicalPath,
568
+ legacyPath,
569
+ outcome: "migrated",
570
+ legacyEvidence: true,
571
+ };
572
+ } catch (error) {
573
+ // Another Remodex process may have won the race. Re-read both entries
574
+ // before deciding whether to fall back.
575
+ if (isDirectory(canonicalPath, io)) {
576
+ return {
577
+ path: canonicalPath,
578
+ canonicalPath,
579
+ legacyPath,
580
+ outcome: "canonical-existing",
581
+ legacyEvidence: true,
582
+ };
583
+ }
584
+
585
+ if (isDirectory(legacyPath, io)) {
586
+ const code = errorCode(error);
587
+ const warning =
588
+ `Remodex could not move legacy state from ${legacyPath} to ${canonicalPath}`
589
+ + (code ? ` (${code})` : "")
590
+ + ". It will continue using the legacy directory temporarily; close Remodex/Codex "
591
+ + "and try again so the migration can complete.";
592
+ warningOnce(`${canonicalPath}:migration-failed`, warning, warn);
593
+ return {
594
+ path: legacyPath,
595
+ canonicalPath,
596
+ legacyPath,
597
+ outcome: "legacy-fallback",
598
+ legacyEvidence: true,
599
+ warning,
600
+ };
601
+ }
602
+
603
+ return {
604
+ path: canonicalPath,
605
+ canonicalPath,
606
+ legacyPath,
607
+ outcome: "new",
608
+ legacyEvidence: true,
609
+ };
610
+ }
611
+ }
612
+
613
+ /** Test support for warning-memo isolation without exposing production state. */
614
+ export function clearRemodexHomeWarningMemosForTests(): void {
615
+ emittedWarnings.clear();
616
+ }
@@ -0,0 +1,55 @@
1
+ import { parseRetryAfterMs } from "../combos";
2
+ import { classifyError, parseRetryAfterFromMessage } from "./errors";
3
+
4
+ /** Small default when a retryable 429 has no upstream Retry-After (#507). */
5
+ export const DEFAULT_RETRYABLE_429_RETRY_AFTER_SEC = "2";
6
+
7
+ /**
8
+ * Validate a raw upstream Retry-After for client exposure.
9
+ * Instant-retry `"0"` is kept even though cooldown parsers reject it.
10
+ */
11
+ export function validateClientRetryAfterHeader(
12
+ value: string | null | undefined,
13
+ now: number,
14
+ ): string | undefined {
15
+ const trimmed = value?.trim();
16
+ if (!trimmed || trimmed.length > 128) return undefined;
17
+ // Instant-retry "0" is a valid client directive but rejected by cooldown parsers
18
+ // (parseRetryAfterMs requires seconds > 0). Preserve it for client headers.
19
+ if (trimmed === "0") return trimmed;
20
+ return parseRetryAfterMs(trimmed, now) !== undefined ? trimmed : undefined;
21
+ }
22
+
23
+ /**
24
+ * Pick a Retry-After value that clients (especially Codex) can back off on.
25
+ *
26
+ * Order: validated upstream header → delay embedded in the error message →
27
+ * small default for retryable rate-limit 429s. Quota-exhausted 429s get no
28
+ * default — hammering a spent quota is not a backoff problem.
29
+ *
30
+ * Pass `includeDefault: false` when the value feeds cooldown/failover metadata:
31
+ * the synthetic client fallback must not shorten combo cooldowns from 60s to 2s.
32
+ */
33
+ export function resolveClientRetryAfter(opts: {
34
+ status: number;
35
+ message?: string;
36
+ upstreamRetryAfter?: string | null;
37
+ now?: number;
38
+ includeDefault?: boolean;
39
+ }): string | undefined {
40
+ const now = opts.now ?? Date.now();
41
+ const fromHeader = validateClientRetryAfterHeader(opts.upstreamRetryAfter, now);
42
+ if (fromHeader) return fromHeader;
43
+
44
+ const message = opts.message ?? "";
45
+ const fromMessage = parseRetryAfterFromMessage(message);
46
+ if (fromMessage !== undefined) return String(fromMessage);
47
+
48
+ if (opts.includeDefault === false) return undefined;
49
+ if (opts.status !== 429) return undefined;
50
+ const classified = classifyError(429, "rate_limit_error", message || "Too Many Requests");
51
+ if (classified.type === "insufficient_quota" || classified.code === "insufficient_quota") {
52
+ return undefined;
53
+ }
54
+ return DEFAULT_RETRYABLE_429_RETRY_AFTER_SEC;
55
+ }