@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,321 @@
1
+ import { durableBunRuntime } from "../lib/bun-runtime";
2
+ import { codexAutoStartEnabled, getConfigPath, getPidPath, readConfigDiagnostics, readPid, readRuntimePort, type RuntimePortState } from "../config";
3
+ import { diagnoseCodexBundledPlugins, type CodexPluginsDiagnostic } from "../codex/plugins-doctor";
4
+ import { findLiveProxy, isOpencodexHealthz, probeHostname } from "../server/proxy-liveness";
5
+ import type { OcxConfig } from "../types";
6
+ import { diagnoseService, serviceLogPath } from "../service";
7
+ import { collectStartupHealth, type StartupHealth } from "../codex/autostart-health";
8
+ import { getCodexRoutingKind } from "../codex/inject";
9
+ import { diagnoseCodexShim } from "../codex/shim";
10
+ import { displayCodexRuntimePath, effortClampAppliesToRuntime, loadLastEffortClamp, resolveCodexRuntime } from "../codex/runtime";
11
+ import { redactSecretString, redactUserPath } from "../lib/redact";
12
+ import { collectOrcaCodexHomeDiagnostic, type OrcaCodexHomeDiagnostic } from "../codex/home";
13
+ import { grokFenceEndpointDrift, readGrokStatus } from "../grok/status";
14
+
15
+ type HealthCheck = {
16
+ ok: boolean;
17
+ url: string;
18
+ message: string;
19
+ label: string;
20
+ };
21
+
22
+ export type CliStatusJson = {
23
+ schemaVersion: 1;
24
+ proxy: {
25
+ running: boolean;
26
+ pid: number | null;
27
+ health: {
28
+ ok: boolean;
29
+ url: string;
30
+ message: string;
31
+ };
32
+ };
33
+ dashboard: { url: string };
34
+ listen: {
35
+ port: number;
36
+ hostname: string | null;
37
+ source: "runtime" | "config";
38
+ };
39
+ paths: {
40
+ config: string;
41
+ pid: string;
42
+ runtime: string;
43
+ };
44
+ runtime: {
45
+ source: string;
46
+ overrideEnv?: string;
47
+ };
48
+ codexAutostart: boolean;
49
+ startup: StartupHealth;
50
+ defaultProvider: string | null;
51
+ config: {
52
+ source: "default" | "file" | "fallback";
53
+ error: string | null;
54
+ };
55
+ service: { summary: string };
56
+ codexShim: { summary: string };
57
+ codexPlugins: CodexPluginsDiagnostic;
58
+ codexRuntime: {
59
+ path: string;
60
+ version: string | null;
61
+ source: string;
62
+ newerAvailable: { path: string; version: string | null } | null;
63
+ warning: string | null;
64
+ catalogClamp: {
65
+ active: boolean;
66
+ removedEfforts: string[];
67
+ runtimeVersion: string | null;
68
+ };
69
+ };
70
+ codexHome: OrcaCodexHomeDiagnostic;
71
+ };
72
+
73
+ export type CliStatusView = {
74
+ json: CliStatusJson;
75
+ proxyLabel: string;
76
+ healthLabel: string;
77
+ };
78
+
79
+
80
+ export type ListenTarget = {
81
+ port: number;
82
+ hostname?: string;
83
+ source: "runtime" | "config";
84
+ healthUrl: string;
85
+ dashboardUrl: string;
86
+ };
87
+
88
+ export function selectListenTarget(
89
+ config: Pick<OcxConfig, "port" | "hostname">,
90
+ pid: number | null,
91
+ runtimePort: RuntimePortState | null,
92
+ ): ListenTarget {
93
+ const currentRuntimePort = pid && runtimePort?.pid === pid ? runtimePort : null;
94
+ const port = currentRuntimePort ? currentRuntimePort.port : config.port ?? 10100;
95
+ const hostname = currentRuntimePort ? currentRuntimePort.hostname : config.hostname;
96
+ return {
97
+ port,
98
+ hostname,
99
+ source: currentRuntimePort ? "runtime" : "config",
100
+ healthUrl: `http://${probeHostname(hostname)}:${port}/healthz`,
101
+ dashboardUrl: `http://localhost:${port}/`,
102
+ };
103
+ }
104
+
105
+ /** Prefer live result (including authoritative null pid) over the on-disk pid file. */
106
+ export function resolveStatusPid(
107
+ live: { pid: number | null } | null,
108
+ pidFile: number | null,
109
+ ): number | null {
110
+ return live ? live.pid : pidFile;
111
+ }
112
+
113
+ async function checkProxyHealth(target: ListenTarget): Promise<HealthCheck> {
114
+ const url = target.healthUrl;
115
+ const controller = new AbortController();
116
+ const timer = setTimeout(() => controller.abort(), 800);
117
+ try {
118
+ const response = await fetch(url, { signal: controller.signal });
119
+ if (!response.ok) {
120
+ const message = `returned HTTP ${response.status}`;
121
+ return { ok: false, url, message, label: `${url} ${message}` };
122
+ }
123
+ const body = await response.json().catch(() => null) as { service?: unknown; status?: unknown; version?: unknown; uptime?: unknown } | null;
124
+ if (!isOpencodexHealthz(body)) {
125
+ const message = "responded, but not a Remodex proxy";
126
+ return { ok: false, url, message, label: `${url} ${message}` };
127
+ }
128
+ const version = typeof body?.version === "string" ? ` v${body.version}` : "";
129
+ const uptime = typeof body?.uptime === "number" ? `, uptime ${Math.round(body.uptime)}s` : "";
130
+ const message = `ok${version}${uptime}`;
131
+ return { ok: true, url, message, label: `${url} ${message}` };
132
+ } catch (error) {
133
+ const reason = error instanceof Error && error.name === "AbortError" ? "timed out" : "unreachable";
134
+ return { ok: false, url, message: reason, label: `${url} ${reason}` };
135
+ } finally {
136
+ clearTimeout(timer);
137
+ }
138
+ }
139
+
140
+ export async function collectStatus(): Promise<CliStatusView> {
141
+ const configDiagnostics = readConfigDiagnostics();
142
+ const config = configDiagnostics.config;
143
+ // Prefer identity-verified liveness (runtime-port + /healthz) over ocx.pid alone (#618).
144
+ // Pass the already-resolved diagnostics config so findLiveProxy does not re-load and
145
+ // warn on malformed config.json (status --json must stay stderr-clean).
146
+ const live = await findLiveProxy({
147
+ configFn: () => ({ port: config.port, hostname: config.hostname }),
148
+ });
149
+ const pidFile = readPid();
150
+ // Preserve an authoritative null from orphan/legacy liveness — do not restore pidFile.
151
+ const pid = resolveStatusPid(live, pidFile);
152
+ const listen = live
153
+ ? {
154
+ port: live.port,
155
+ hostname: live.hostname,
156
+ source: live.source,
157
+ healthUrl: `http://${probeHostname(live.hostname)}:${live.port}/healthz`,
158
+ dashboardUrl: `http://localhost:${live.port}/`,
159
+ }
160
+ : selectListenTarget(config, pidFile, pidFile ? readRuntimePort(pidFile) : null);
161
+ // findLiveProxy already identity-probed /healthz; avoid a second fetch that can race.
162
+ const health = live
163
+ ? {
164
+ ok: true,
165
+ url: listen.healthUrl,
166
+ message: `ok (pid ${live.pid ?? "unknown"})`,
167
+ label: `${listen.healthUrl} ok (live)`,
168
+ }
169
+ : await checkProxyHealth(listen);
170
+ const bunRuntime = durableBunRuntime();
171
+ const service = diagnoseService();
172
+ // A service can be registered and still not serve: the manager reports the job
173
+ // either way. `live` was already identity-probed a few lines above, so cross-check
174
+ // rather than print registration as if it were service.
175
+ const serviceSummary = service.installed && !live
176
+ ? `${service.summary} — registered but NOT serving; see ${serviceLogPath()} and re-run 'rmx service repair'`
177
+ : service.summary;
178
+ const codexShim = diagnoseCodexShim();
179
+ const codexShimSummary = codexShim.summary;
180
+ const startup = collectStartupHealth(config, {
181
+ service,
182
+ shim: codexShim,
183
+ routingKind: getCodexRoutingKind(),
184
+ });
185
+ const codexPlugins = diagnoseCodexBundledPlugins();
186
+ const resolvedRuntime = (() => {
187
+ try {
188
+ return resolveCodexRuntime();
189
+ } catch (error) {
190
+ const message = error instanceof Error ? error.message : String(error);
191
+ const redacted = redactUserPath(redactSecretString(message)).slice(0, 160);
192
+ return {
193
+ runtime: { command: "codex", version: null, source: "fallback" as const },
194
+ failures: [{
195
+ command: "codex",
196
+ source: "fallback" as const,
197
+ reason: `resolve threw: ${redacted}`,
198
+ }],
199
+ replacedConfigured: undefined,
200
+ newerAvailable: undefined,
201
+ };
202
+ }
203
+ })();
204
+ const lastClamp = loadLastEffortClamp();
205
+ const clampActive = effortClampAppliesToRuntime(lastClamp, resolvedRuntime.runtime);
206
+ const codexHome = collectOrcaCodexHomeDiagnostic();
207
+ const warningParts: string[] = [];
208
+ if (
209
+ resolvedRuntime.replacedConfigured
210
+ && resolvedRuntime.replacedConfigured.from.command !== resolvedRuntime.runtime.command
211
+ ) {
212
+ warningParts.push(
213
+ `Preferred Codex runtime is unavailable; using ${displayCodexRuntimePath(resolvedRuntime.runtime.command)} instead. Run rmx doctor for diagnosis and recovery.`,
214
+ );
215
+ } else if (
216
+ resolvedRuntime.runtime.source === "fallback"
217
+ && resolvedRuntime.failures.length > 0
218
+ && !resolvedRuntime.runtime.version
219
+ ) {
220
+ const detail = resolvedRuntime.failures[0]?.reason;
221
+ warningParts.push(
222
+ detail
223
+ ? `No validated Codex runtime found (${detail}); falling back to \`codex\`. Run rmx doctor for diagnosis and recovery.`
224
+ : "No validated Codex runtime found; falling back to `codex`. Run rmx doctor for diagnosis and recovery.",
225
+ );
226
+ }
227
+ if (resolvedRuntime.newerAvailable) {
228
+ warningParts.push("Remodex is using an older Codex binary. Run rmx doctor for diagnosis and recovery.");
229
+ }
230
+ if (clampActive) {
231
+ warningParts.push(
232
+ `Catalog clamp removed: ${lastClamp!.removedEfforts.join(", ")}. Run rmx doctor for diagnosis and recovery.`,
233
+ );
234
+ }
235
+ // A Grok fence naming a port we are not listening on is invisible everywhere else:
236
+ // grok retries the refused connection on its own side, so no request — and therefore
237
+ // no log line — ever reaches us. Surface it here, where the live port is already known.
238
+ const grokDrift = (() => {
239
+ try {
240
+ return grokFenceEndpointDrift(readGrokStatus(), health.ok ? listen.port : undefined);
241
+ } catch {
242
+ return null; // reading grok's config must never break `rmx status`
243
+ }
244
+ })();
245
+ if (grokDrift) {
246
+ warningParts.push(
247
+ `Grok Build config points at port ${grokDrift.fencePort}, but the proxy is on `
248
+ + `${grokDrift.livePort}; grok turns will retry against a closed port. Run 'rmx ensure' to repoint it.`,
249
+ );
250
+ }
251
+ const codexRuntime = {
252
+ path: displayCodexRuntimePath(resolvedRuntime.runtime.command),
253
+ version: resolvedRuntime.runtime.version,
254
+ source: resolvedRuntime.runtime.source,
255
+ newerAvailable: resolvedRuntime.newerAvailable
256
+ ? {
257
+ path: displayCodexRuntimePath(resolvedRuntime.newerAvailable.command),
258
+ version: resolvedRuntime.newerAvailable.version,
259
+ }
260
+ : null,
261
+ warning: warningParts.length > 0 ? warningParts.join(" ") : null,
262
+ catalogClamp: {
263
+ active: clampActive,
264
+ removedEfforts: clampActive ? (lastClamp?.removedEfforts ?? []) : [],
265
+ runtimeVersion: clampActive ? (lastClamp?.runtimeVersion ?? null) : null,
266
+ },
267
+ };
268
+ const proxyLabel = live
269
+ ? `running (PID ${live.pid ?? pid ?? "unknown"})`
270
+ : pid && health.ok
271
+ ? `running (PID ${pid})`
272
+ : pid
273
+ ? `PID file points to PID ${pid}, but health check failed`
274
+ : health.ok
275
+ ? "reachable, but PID file is missing or stale"
276
+ : "not running";
277
+
278
+ return {
279
+ proxyLabel,
280
+ healthLabel: health.label,
281
+ json: {
282
+ schemaVersion: 1,
283
+ proxy: {
284
+ running: Boolean(live) || Boolean(pid && health.ok),
285
+ pid: live?.pid ?? pid,
286
+ health: {
287
+ ok: health.ok,
288
+ url: health.url,
289
+ message: health.message,
290
+ },
291
+ },
292
+ dashboard: { url: listen.dashboardUrl },
293
+ listen: {
294
+ port: listen.port,
295
+ hostname: listen.hostname ?? null,
296
+ source: listen.source,
297
+ },
298
+ paths: {
299
+ config: getConfigPath(),
300
+ pid: getPidPath(),
301
+ runtime: bunRuntime.path,
302
+ },
303
+ runtime: {
304
+ source: bunRuntime.source,
305
+ ...(bunRuntime.source === "override" ? { overrideEnv: bunRuntime.overrideEnv } : {}),
306
+ },
307
+ codexAutostart: codexAutoStartEnabled(config),
308
+ startup,
309
+ defaultProvider: typeof config.defaultProvider === "string" ? config.defaultProvider : null,
310
+ config: {
311
+ source: configDiagnostics.source,
312
+ error: configDiagnostics.error,
313
+ },
314
+ service: { summary: serviceSummary },
315
+ codexShim: { summary: codexShimSummary },
316
+ codexPlugins,
317
+ codexRuntime,
318
+ codexHome,
319
+ },
320
+ };
321
+ }
@@ -0,0 +1,196 @@
1
+ import {
2
+ CliUsageError,
3
+ printData,
4
+ rejectArgs,
5
+ runCliAction,
6
+ runtimeRequest,
7
+ summaryLines,
8
+ takeBooleanOption,
9
+ takeFlag,
10
+ takeOption,
11
+ type RuntimeApiDeps,
12
+ } from "./runtime-api";
13
+
14
+ const USAGE = `Usage:
15
+ rmx system [status] [--json]
16
+ rmx system settings [--auto-start <on|off>] [--stream-mode <auto|legacy-tee|eager-relay>] [--json]
17
+ rmx system startup <health|install-service|install-shim> [--json]
18
+ rmx system diagnostics [--json]
19
+ rmx system sync [--json]
20
+ rmx system update check [--channel <latest|preview>] [--json]
21
+ rmx system update run [--channel <latest|preview>] [--restart <on|off>] --yes [--json]
22
+ rmx system update status <job-id> [--json]
23
+ rmx system desktop-update check [--channel <latest|preview>] [--json]
24
+ rmx system desktop-update run [--channel <latest|preview>] [--json]
25
+ rmx system desktop-update status [--json]`;
26
+
27
+ async function status(argv: string[], deps: RuntimeApiDeps): Promise<void> {
28
+ const args = [...argv];
29
+ const wantsJson = takeFlag(args, "--json");
30
+ rejectArgs(args, USAGE);
31
+ const [settings, startup, memory] = await Promise.all([
32
+ runtimeRequest("/api/settings", {}, deps),
33
+ runtimeRequest("/api/startup-health", {}, deps),
34
+ runtimeRequest("/api/system/memory", {}, deps),
35
+ ]);
36
+ const result = { settings, startup, memory };
37
+ printData(result, wantsJson, summaryLines(result));
38
+ }
39
+
40
+ async function settings(argv: string[], deps: RuntimeApiDeps): Promise<void> {
41
+ const args = [...argv];
42
+ const wantsJson = takeFlag(args, "--json");
43
+ const autoStart = takeBooleanOption(args, "--auto-start");
44
+ const streamMode = takeOption(args, "--stream-mode");
45
+ rejectArgs(args, USAGE);
46
+ if (autoStart === undefined && streamMode === undefined) {
47
+ const result = await runtimeRequest("/api/settings", {}, deps);
48
+ printData(result, wantsJson, summaryLines(result));
49
+ return;
50
+ }
51
+ const body = { ...(autoStart !== undefined ? { codexAutoStart: autoStart } : {}), ...(streamMode !== undefined ? { streamMode } : {}) };
52
+ const result = await runtimeRequest("/api/settings", { method: "PUT", body: JSON.stringify(body) }, deps);
53
+ printData(result, wantsJson, ["System settings updated."]);
54
+ }
55
+
56
+ async function startup(argv: string[], deps: RuntimeApiDeps): Promise<void> {
57
+ const args = [...argv];
58
+ const action = (args.shift() ?? "health").toLowerCase();
59
+ const wantsJson = takeFlag(args, "--json");
60
+ rejectArgs(args, USAGE);
61
+ if (action === "health" || action === "status") {
62
+ const result = await runtimeRequest("/api/startup-health", {}, deps);
63
+ printData(result, wantsJson, summaryLines(result));
64
+ return;
65
+ }
66
+ if (action !== "install-service" && action !== "install-shim") throw new CliUsageError("startup action must be health, install-service, or install-shim", USAGE);
67
+ const result = await runtimeRequest("/api/startup-action", { method: "POST", body: JSON.stringify({ action }) }, deps);
68
+ printData(result, wantsJson, [String((result as Record<string, unknown>).message ?? `${action} complete.`)]);
69
+ }
70
+
71
+ async function update(argv: string[], deps: RuntimeApiDeps): Promise<void> {
72
+ const args = [...argv];
73
+ const action = (args.shift() ?? "check").toLowerCase();
74
+ const wantsJson = takeFlag(args, "--json");
75
+ if (action === "status") {
76
+ const jobId = args.shift();
77
+ if (!jobId) throw new CliUsageError("update job id is required", USAGE);
78
+ rejectArgs(args, USAGE);
79
+ printData(await runtimeRequest(`/api/update/status?jobId=${encodeURIComponent(jobId)}`, {}, deps), wantsJson);
80
+ return;
81
+ }
82
+ const channel = takeOption(args, "--channel") ?? "latest";
83
+ if (channel !== "latest" && channel !== "preview") throw new CliUsageError("--channel must be latest or preview", USAGE);
84
+ if (action === "check") {
85
+ rejectArgs(args, USAGE);
86
+ printData(await runtimeRequest(`/api/update/check?tag=${channel}`, {}, deps), wantsJson);
87
+ return;
88
+ }
89
+ if (action !== "run") throw new CliUsageError(`unknown update action ${action}`, USAGE);
90
+ const restart = takeBooleanOption(args, "--restart") ?? true;
91
+ const yes = takeFlag(args, "--yes");
92
+ if (!yes) throw new CliUsageError("update run requires --yes", USAGE);
93
+ rejectArgs(args, USAGE);
94
+ const result = await runtimeRequest("/api/update/run", { method: "POST", body: JSON.stringify({ tag: channel, restart }) }, deps);
95
+ printData(result, wantsJson, [`Update started (${channel}).`]);
96
+ }
97
+
98
+ function desktopUpdateSummary(value: unknown): string[] {
99
+ if (!value || typeof value !== "object") return [`Desktop update: ${String(value)}`];
100
+ const record = value as Record<string, unknown>;
101
+ const state = record.state;
102
+ const check = record;
103
+ const lines: string[] = [];
104
+
105
+ if (typeof check.currentVersion === "string") {
106
+ lines.push(`Current version: ${check.currentVersion}`);
107
+ }
108
+ if (typeof check.latestVersion === "string") {
109
+ lines.push(`Latest version: ${check.latestVersion}`);
110
+ }
111
+ if (typeof check.phase === "string") {
112
+ lines.push(`Status: ${check.phase}`);
113
+ }
114
+ if (state && typeof state === "object" && !Array.isArray(state)) {
115
+ const stateRecord = state as Record<string, unknown>;
116
+ if (typeof stateRecord.phase === "string") lines.push(`Status: ${stateRecord.phase}`);
117
+ if (typeof stateRecord.latestVersion === "string") {
118
+ lines.push(`Latest version: ${stateRecord.latestVersion}`);
119
+ }
120
+ if (typeof stateRecord.progress === "number") {
121
+ lines.push(`Progress: ${Math.round(stateRecord.progress)}%`);
122
+ }
123
+ if (typeof stateRecord.errorCode === "string") lines.push(`Error: ${stateRecord.errorCode}`);
124
+ }
125
+ if (check.updateAvailable === true) lines.push("Update available.");
126
+ else if (check.updateAvailable === false) lines.push("No desktop update available.");
127
+ if (lines.length > 0) return lines;
128
+ return summaryLines(value);
129
+ }
130
+
131
+ async function desktopUpdate(argv: string[], deps: RuntimeApiDeps): Promise<void> {
132
+ const args = [...argv];
133
+ const action = (args.shift() ?? "check").toLowerCase();
134
+ const wantsJson = takeFlag(args, "--json");
135
+
136
+ if (action === "status") {
137
+ rejectArgs(args, USAGE);
138
+ const result = await runtimeRequest("/api/desktop-update/status", {}, deps);
139
+ printData(result, wantsJson, desktopUpdateSummary(result));
140
+ return;
141
+ }
142
+
143
+ if (action !== "check" && action !== "run") {
144
+ throw new CliUsageError(`unknown desktop-update action ${action}`, USAGE);
145
+ }
146
+
147
+ const channel = takeOption(args, "--channel") ?? "latest";
148
+ if (channel !== "latest" && channel !== "preview") {
149
+ throw new CliUsageError("--channel must be latest or preview", USAGE);
150
+ }
151
+ rejectArgs(args, USAGE);
152
+
153
+ if (action === "check") {
154
+ const result = await runtimeRequest(
155
+ `/api/desktop-update/check?channel=${encodeURIComponent(channel)}`,
156
+ {},
157
+ deps,
158
+ );
159
+ printData(result, wantsJson, desktopUpdateSummary(result));
160
+ return;
161
+ }
162
+
163
+ // Headless callers can fetch and verify a native installer, but installation
164
+ // stays restricted to the exact-origin desktop/Tauri bridge. This mirrors
165
+ // the management API contract and prevents a shell or remote dashboard from
166
+ // silently launching a platform installer.
167
+ const result = await runtimeRequest(
168
+ "/api/desktop-update/run",
169
+ {
170
+ method: "POST",
171
+ body: JSON.stringify({ channel, install: false }),
172
+ },
173
+ deps,
174
+ );
175
+ printData(result, wantsJson, [`Desktop update download started (${channel}).`]);
176
+ }
177
+
178
+ export async function handleSystemCommand(argv: string[], deps: RuntimeApiDeps = {}): Promise<number> {
179
+ return runCliAction(async () => {
180
+ const [sub = "status", ...rest] = argv;
181
+ if (sub === "status") await status(rest, deps);
182
+ else if (sub === "settings") await settings(rest, deps);
183
+ else if (sub === "startup") await startup(rest, deps);
184
+ else if (sub === "diagnostics") {
185
+ const args = [...rest]; const wantsJson = takeFlag(args, "--json"); rejectArgs(args, USAGE);
186
+ printData(await runtimeRequest("/api/diagnostics/project-config", {}, deps), wantsJson);
187
+ } else if (sub === "sync") {
188
+ const args = [...rest]; const wantsJson = takeFlag(args, "--json"); rejectArgs(args, USAGE);
189
+ printData(await runtimeRequest("/api/sync", { method: "POST" }, deps), wantsJson);
190
+ } else if (sub === "update") await update(rest, deps);
191
+ else if (sub === "desktop-update") await desktopUpdate(rest, deps);
192
+ else throw new CliUsageError(`unknown system command ${sub}`, USAGE);
193
+ });
194
+ }
195
+
196
+ export const SYSTEM_USAGE = USAGE;
@@ -0,0 +1,146 @@
1
+ import { readRuntimePort } from "../config";
2
+ import {
3
+ LOCAL_ATTESTATION_CHALLENGE_HEADER,
4
+ LOCAL_ATTESTATION_PROOF_HEADER,
5
+ createLocalAttestationChallenge,
6
+ verifyLocalAttestationProof,
7
+ } from "../lib/local-management-attestation";
8
+ import {
9
+ SYSTEM_RESTART_CAPABILITY_HEADER,
10
+ SYSTEM_RESTART_CAPABILITY_VERSION,
11
+ SYSTEM_RESTART_EXPECTED_PID_HEADER,
12
+ SYSTEM_RESTART_METHOD,
13
+ SYSTEM_RESTART_NONCE_HEADER,
14
+ SYSTEM_RESTART_PATH,
15
+ createSystemRestartCapability,
16
+ } from "../lib/system-restart-contract";
17
+ import {
18
+ findLiveProxy,
19
+ isOpencodexHealthz,
20
+ probeHostname,
21
+ type HealthzIdentity,
22
+ type LiveProxy,
23
+ } from "../server/proxy-liveness";
24
+ import type { ProxyRestartRequestOutcome } from "./tray-proxy";
25
+
26
+ export const SYSTEM_RESTART_REQUEST_TIMEOUT_MS = 5_000;
27
+ export const SYSTEM_RESTART_ATTESTATION_TIMEOUT_MS = 4_000;
28
+
29
+ export interface BoundSystemRestartDeps {
30
+ fetchImpl?: typeof fetch;
31
+ readRuntime?: typeof readRuntimePort;
32
+ findLive?: typeof findLiveProxy;
33
+ createChallenge?: () => string;
34
+ now?: () => number;
35
+ }
36
+
37
+ function rejected(code: string): ProxyRestartRequestOutcome {
38
+ return { accepted: false, uncertain: false, error: new Error(code) };
39
+ }
40
+
41
+ function uncertain(code: string): ProxyRestartRequestOutcome {
42
+ return { accepted: false, uncertain: true, error: new Error(code) };
43
+ }
44
+
45
+ function remaining(deadlineAt: number, now: () => number, cap: number): number {
46
+ return Math.max(0, Math.min(cap, deadlineAt - now()));
47
+ }
48
+
49
+ function sameRestartTarget(expected: LiveProxy, observed: LiveProxy | null): boolean {
50
+ return expected.pid !== null
51
+ && observed?.source === "runtime"
52
+ && observed.pid === expected.pid
53
+ && observed.port === expected.port;
54
+ }
55
+
56
+ /**
57
+ * Send one restart request to the exact runtime proxy observed by the caller.
58
+ *
59
+ * No reusable admin credential is sent. After the listener proves possession of
60
+ * its per-process runtime secret, the client derives a capability bound to this
61
+ * method, path, PID, and port. The expected PID is repeated so a replacement that
62
+ * wins the port between proof and POST rejects the request.
63
+ */
64
+ export async function requestBoundSystemRestart(
65
+ target: LiveProxy,
66
+ deadlineAt: number,
67
+ deps: BoundSystemRestartDeps = {},
68
+ ): Promise<ProxyRestartRequestOutcome> {
69
+ if (target.source !== "runtime" || target.pid === null) return rejected("restart_target_unattested");
70
+
71
+ const now = deps.now ?? Date.now;
72
+ const readRuntime = deps.readRuntime ?? readRuntimePort;
73
+ const runtime = readRuntime(target.pid);
74
+ if (!runtime?.attestationSecret || runtime.pid !== target.pid || runtime.port !== target.port) {
75
+ return rejected("restart_target_runtime_mismatch");
76
+ }
77
+
78
+ const attestationBudget = remaining(deadlineAt, now, SYSTEM_RESTART_ATTESTATION_TIMEOUT_MS);
79
+ if (attestationBudget <= 0) return rejected("restart_deadline_expired");
80
+
81
+ const fetchImpl = deps.fetchImpl ?? fetch;
82
+ const challenge = (deps.createChallenge ?? createLocalAttestationChallenge)();
83
+ const baseUrl = `http://${probeHostname(target.hostname)}:${target.port}`;
84
+ let proofResponse: Response;
85
+ try {
86
+ proofResponse = await fetchImpl(`${baseUrl}/healthz`, {
87
+ headers: { [LOCAL_ATTESTATION_CHALLENGE_HEADER]: challenge },
88
+ signal: AbortSignal.timeout(attestationBudget),
89
+ });
90
+ } catch {
91
+ return rejected("restart_attestation_unreachable");
92
+ }
93
+ const body = await proofResponse.json().catch(() => null) as HealthzIdentity | null;
94
+ const proof = proofResponse.headers.get(LOCAL_ATTESTATION_PROOF_HEADER);
95
+ if (
96
+ !proofResponse.ok
97
+ || !isOpencodexHealthz(body)
98
+ || body?.pid !== target.pid
99
+ || !verifyLocalAttestationProof(runtime.attestationSecret, challenge, target.pid, target.port, proof)
100
+ ) {
101
+ return rejected("restart_attestation_failed");
102
+ }
103
+ if (body.restartCapability !== SYSTEM_RESTART_CAPABILITY_VERSION) {
104
+ // A pre-update proxy accepts only the reusable management credential and cannot
105
+ // bind the operation to the attested PID. Refuse before POST rather than weakening
106
+ // the exact-process contract or replaying a stop/start transaction.
107
+ return rejected("restart_capability_unsupported");
108
+ }
109
+
110
+ let observed: LiveProxy | null;
111
+ try {
112
+ observed = await (deps.findLive ?? findLiveProxy)({ deadlineAt, nowFn: now });
113
+ } catch {
114
+ return rejected("restart_target_recheck_failed");
115
+ }
116
+ if (!sameRestartTarget(target, observed)) return rejected("restart_target_changed");
117
+
118
+ const capability = createSystemRestartCapability(
119
+ runtime.attestationSecret,
120
+ challenge,
121
+ SYSTEM_RESTART_METHOD,
122
+ SYSTEM_RESTART_PATH,
123
+ target.pid,
124
+ target.port,
125
+ );
126
+ if (!capability) return rejected("restart_capability_unavailable");
127
+
128
+ const requestBudget = remaining(deadlineAt, now, SYSTEM_RESTART_REQUEST_TIMEOUT_MS);
129
+ if (requestBudget <= 0) return rejected("restart_deadline_expired");
130
+ try {
131
+ const response = await fetchImpl(`${baseUrl}${SYSTEM_RESTART_PATH}`, {
132
+ method: SYSTEM_RESTART_METHOD,
133
+ headers: {
134
+ [SYSTEM_RESTART_EXPECTED_PID_HEADER]: String(target.pid),
135
+ [SYSTEM_RESTART_NONCE_HEADER]: challenge,
136
+ [SYSTEM_RESTART_CAPABILITY_HEADER]: capability,
137
+ },
138
+ signal: AbortSignal.timeout(requestBudget),
139
+ });
140
+ return response.ok ? { accepted: true } : rejected(`restart_request_http_${response.status}`);
141
+ } catch {
142
+ // The server may have accepted the restart before the response connection failed.
143
+ // The coordinator observes the original PID for replacement instead of replaying.
144
+ return uncertain("restart_request_outcome_unknown");
145
+ }
146
+ }