@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,36 @@
1
+ import type { IncomingMeta, ProviderAdapter } from "./base";
2
+ import type { OcxParsedRequest, OcxProviderConfig } from "../types";
3
+ import { createResponsesPassthroughAdapter } from "./openai-responses";
4
+
5
+ export function createAzureAdapter(provider: OcxProviderConfig): ProviderAdapter & { passthrough: true } {
6
+ const inner = createResponsesPassthroughAdapter({
7
+ ...provider,
8
+ baseUrl: provider.baseUrl,
9
+ });
10
+
11
+ return {
12
+ ...inner,
13
+ name: "azure-openai",
14
+
15
+ async buildRequest(parsed: OcxParsedRequest, incoming: IncomingMeta) {
16
+ if (provider.authMode === "forward") {
17
+ throw new Error("azure-openai does not support forward auth mode");
18
+ }
19
+ if (typeof provider.apiKey !== "string" || provider.apiKey.trim() === "") {
20
+ throw new Error("azure-openai requires a non-empty apiKey");
21
+ }
22
+
23
+ const request = await inner.buildRequest(parsed, incoming);
24
+ const unresolvedPlaceholder = request.url.match(/\{[^}]*\}/)?.[0] ?? request.url.match(/[{}]/)?.[0];
25
+ if (unresolvedPlaceholder) {
26
+ throw new Error(`azure-openai baseUrl contains unresolved ${unresolvedPlaceholder} — set your real resource URL`);
27
+ }
28
+
29
+ const headers = { ...request.headers };
30
+ headers["api-key"] = provider.apiKey;
31
+ delete headers["Authorization"];
32
+ // The inner adapter always targets Azure's v1 API here, which needs no api-version query.
33
+ return { ...request, headers };
34
+ },
35
+ };
36
+ }
@@ -0,0 +1,83 @@
1
+ import type { AdapterEvent, OcxParsedRequest } from "../types";
2
+ import type { TranslatorBudget } from "../lib/translator-budget";
3
+
4
+ /** Metadata about the caller's incoming request, for auth-forwarding adapters. */
5
+ export interface IncomingMeta {
6
+ headers: Headers;
7
+ translatorBudget: TranslatorBudget;
8
+ abortSignal?: AbortSignal;
9
+ /**
10
+ * Image-normalization ladder bias for upstream-413 tightened retries: every image
11
+ * starts one tier lower (devlog/260714_image_normalization_pipeline/030). Only the
12
+ * anthropic adapter consumes it; others ignore it.
13
+ */
14
+ imageTierBias?: number;
15
+ }
16
+
17
+ export interface ProviderAdapter {
18
+ name: string;
19
+
20
+ /**
21
+ * Convert an already-read provider HTTP error into client-safe text. This hook must be pure and
22
+ * return fully redacted output: callers may pass untrusted provider headers and payload text.
23
+ */
24
+ formatErrorBody?(status: number, headers: Headers, payloadText: string): string;
25
+
26
+ /**
27
+ * Build the upstream request. May be async: adapters that resolve a short-lived credential
28
+ * (e.g. Vertex AI ADC token) return a Promise. Sync adapters return the object directly; callers
29
+ * must `await` the result (awaiting a non-Promise is a no-op).
30
+ */
31
+ buildRequest(parsed: OcxParsedRequest, incoming: IncomingMeta): AdapterRequest | Promise<AdapterRequest>;
32
+
33
+ fetchResponse?(request: AdapterRequest, ctx?: AdapterFetchContext): Promise<Response>;
34
+
35
+ parseStream(response: Response, budget: TranslatorBudget): AsyncGenerator<AdapterEvent>;
36
+ parseResponse?(response: Response, budget: TranslatorBudget): Promise<AdapterEvent[]>;
37
+ runTurn?(
38
+ parsed: OcxParsedRequest,
39
+ incoming: IncomingMeta,
40
+ emit: (event: AdapterEvent) => void,
41
+ ): Promise<void>;
42
+ }
43
+
44
+ export interface AdapterRequest {
45
+ url: string;
46
+ method: string;
47
+ headers: Record<string, string>;
48
+ body: string;
49
+ /** Releases observation of a serialized request body after its final fetch attempt settles. */
50
+ releaseBodyObservation?: () => void;
51
+ /** Exact reasoning parameter emitted by the adapter, for request-log diagnostics only. */
52
+ reasoningLog?:
53
+ | {
54
+ effectiveEffort: string;
55
+ wireField: "reasoning.enabled";
56
+ wireValue: boolean;
57
+ }
58
+ | {
59
+ effectiveEffort: string;
60
+ wireField: "thinking_budget";
61
+ wireValue: number;
62
+ }
63
+ | {
64
+ effectiveEffort: string;
65
+ wireField: "reasoning_effort" | "reasoning.effort" | "thinking.type";
66
+ wireValue: string;
67
+ };
68
+ usageLog?: {
69
+ inputTokens?: number;
70
+ estimated?: boolean;
71
+ };
72
+ }
73
+
74
+ export interface AdapterFetchContext {
75
+ /** Remains attached to the returned response body after the response headers arrive. */
76
+ abortSignal?: AbortSignal;
77
+ /** Deadline for receiving response headers on each attempt, not for consuming the response body. */
78
+ timeoutMs?: number;
79
+ /** Return final non-2xx responses untouched so the caller can own the error-body read. */
80
+ returnRawErrors?: boolean;
81
+ /** Whether the upstream response will be consumed as a stream; adapters may select low-latency transport settings. */
82
+ stream?: boolean;
83
+ }
@@ -0,0 +1,59 @@
1
+ /**
2
+ * First-party client fingerprints.
3
+ *
4
+ * Routed OAuth providers reject — or quietly flag — requests whose header signature doesn't match
5
+ * the real first-party client that minted the token. Sending a valid OAuth token with an empty
6
+ * header set (or a giveaway literal UA like "antigravity") is a non-first-party signature. These
7
+ * constants mirror the headers the real Claude Code CLI and Antigravity CLI send, so the proxy's
8
+ * request fingerprint matches the credential.
9
+ *
10
+ * Pinned versions live HERE (single source) so they're trivial to bump. Values that need a live
11
+ * manifest fetch (Antigravity auto-updater) or a cryptographic billing signature (Claude cch) are
12
+ * intentionally NOT modeled — those are brittle and a wrong guess does more harm than the gap.
13
+ */
14
+ import { createHash } from "node:crypto";
15
+
16
+ // ── Claude Code CLI (matches Claude Code 2.1.63 / @anthropic-ai/sdk 0.74.0) ──
17
+ export const CLAUDE_CODE_HEADERS: Record<string, string> = {
18
+ "X-App": "cli",
19
+ "X-Stainless-Retry-Count": "0",
20
+ "X-Stainless-Runtime": "node",
21
+ "X-Stainless-Lang": "js",
22
+ "X-Stainless-Timeout": "600",
23
+ "X-Stainless-Arch": process.arch,
24
+ "X-Stainless-OS": process.platform,
25
+ "X-Stainless-Package-Version": "0.74.0",
26
+ "X-Stainless-Runtime-Version": process.version.slice(1),
27
+ };
28
+
29
+ /**
30
+ * Stable per-credential session id, matching Claude Code's `X-Claude-Code-Session-Id`. Real Claude
31
+ * Code keeps one session id per CLI session; we derive a deterministic UUIDv4-shaped id from the
32
+ * OAuth token so it stays stable across a conversation's turns without persisting state. The token
33
+ * itself never leaves this function (only its hash drives the id).
34
+ */
35
+ export function claudeCodeSessionId(token: string | undefined): string {
36
+ const seed = token && token.length > 0 ? token : "opencodex-anon";
37
+ const h = createHash("sha256").update(`claude-code-session:${seed}`, "utf8").digest("hex");
38
+ // Shape the hash into a v4-looking UUID (version nibble 4, variant nibble 8-b).
39
+ const variant = ((parseInt(h[16], 16) & 0x3) | 0x8).toString(16);
40
+ return `${h.slice(0, 8)}-${h.slice(8, 12)}-4${h.slice(13, 16)}-${variant}${h.slice(17, 20)}-${h.slice(20, 32)}`;
41
+ }
42
+
43
+ // ── Antigravity CLI ──
44
+ /** Pinned fallback Antigravity CLI version (real client fetches a manifest; we pin to avoid the network dependency). */
45
+ export const ANTIGRAVITY_CLI_VERSION = "1.0.13";
46
+ const ANTIGRAVITY_CLI_CLIENT_NAME = "aidev_client";
47
+ const ANTIGRAVITY_CLI_PLATFORM = "darwin/arm64";
48
+ /** Secondary Google API client UA the Antigravity client library reports. */
49
+ export const ANTIGRAVITY_GOOG_API_CLIENT_UA = "google-api-nodejs-client/10.3.0";
50
+
51
+ /**
52
+ * The real Antigravity CLI User-Agent, e.g.
53
+ * `antigravity/cli/1.0.13 (aidev_client; os_type=darwin; arch=arm64)`.
54
+ * A `GOOGLE_ANTIGRAVITY_USER_AGENT` override (set by the caller) takes precedence upstream.
55
+ */
56
+ export function antigravityUserAgent(version = ANTIGRAVITY_CLI_VERSION): string {
57
+ const [osType, arch] = ANTIGRAVITY_CLI_PLATFORM.split("/");
58
+ return `antigravity/cli/${version} (${ANTIGRAVITY_CLI_CLIENT_NAME}; os_type=${osType}; arch=${arch})`;
59
+ }
@@ -0,0 +1,453 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { execFile as execFileCallback } from "node:child_process";
3
+ import { promisify } from "node:util";
4
+ import { opendir } from "node:fs/promises";
5
+ import type { AdapterEvent, OcxContentPart, OcxMessage, OcxParsedRequest, OcxProviderConfig, OcxTool, OcxUsage } from "../types";
6
+ import { isAllowedToolChoice, namespacedToolName, resolveToolChoiceWireName, toolAllowedByChoice, toolChoiceAliases } from "../types";
7
+ import type { AdapterFetchContext, AdapterRequest, ProviderAdapter } from "./base";
8
+ import type { TranslatorBudget } from "../lib/translator-budget";
9
+ import { readBoundedResponseBody } from "../lib/bounded-body";
10
+ import { configuredReasoningEfforts } from "../reasoning-effort";
11
+ import { commandCodeReasoningEfforts, refreshCommandCodeReasoningEfforts } from "../providers/command-code-efforts";
12
+ import { identifyRoutedModel } from "./identity";
13
+ import { buildNonOpenAIToolCatalogNudgeForTools } from "./tool-catalog-nudge";
14
+ import { parseDataUrl } from "./image";
15
+
16
+ // Retain the short ids emitted by the first local integration. New requests use the live catalog's
17
+ // provider-native IDs directly; this map is compatibility-only and is not a model fallback list.
18
+ const COMMAND_CODE_MODEL_ALIASES: Readonly<Record<string, string>> = {
19
+ "deepseek-v4-flash": "deepseek/deepseek-v4-flash",
20
+ "kimi-k3": "moonshotai/Kimi-K3",
21
+ "glm-5.2": "zai-org/GLM-5.2",
22
+ };
23
+
24
+ /** Flatten tool-result content for the text-only wire output, keeping an `[image]` marker per image part in content order. */
25
+ function toolResultText(content: string | OcxContentPart[]): string {
26
+ if (typeof content === "string") return content;
27
+ return content.map(part => (part.type === "text" ? part.text : "[image]")).join("");
28
+ }
29
+
30
+ /** Best-effort media type from a remote https URL extension, e.g. image/png. */
31
+ function mediaTypeFromUrl(url: string): string | undefined {
32
+ const ext = url.split(/[?#]/)[0]!.match(/\.([a-zA-Z0-9]+)$/)?.[1]?.toLowerCase();
33
+ if (!ext) return undefined;
34
+ const known: Record<string, string> = {
35
+ png: "image/png", jpg: "image/jpeg", jpeg: "image/jpeg", gif: "image/gif", webp: "image/webp", bmp: "image/bmp",
36
+ };
37
+ return known[ext];
38
+ }
39
+
40
+ /** Wire image part: `{ type, image, mediaType? }` per the /alpha/generate ModelMessage schema. */
41
+ function wireImagePart(imageUrl: string): Record<string, unknown> {
42
+ const parsed = parseDataUrl(imageUrl);
43
+ const mediaType = parsed?.mediaType ?? mediaTypeFromUrl(imageUrl);
44
+ return { type: "image", image: imageUrl, ...(mediaType ? { mediaType } : {}) };
45
+ }
46
+
47
+ function wireMessages(messages: OcxMessage[]): Array<Record<string, unknown>> {
48
+ const out: Array<Record<string, unknown>> = [];
49
+ for (const message of messages) {
50
+ if (message.role === "assistant") {
51
+ const content: Array<Record<string, unknown>> = [];
52
+ for (const part of message.content) {
53
+ if (part.type === "text") content.push({ type: "text", text: part.text });
54
+ else if (part.type === "thinking") content.push({ type: "reasoning", text: part.thinking });
55
+ else content.push({ type: "tool-call", toolCallId: part.id, toolName: namespacedToolName(part.namespace, part.name), input: part.arguments });
56
+ }
57
+ out.push({ role: "assistant", content });
58
+ continue;
59
+ }
60
+ if (message.role === "toolResult") {
61
+ out.push({ role: "tool", content: [{
62
+ type: "tool-result",
63
+ toolCallId: message.toolCallId,
64
+ toolName: namespacedToolName(message.toolNamespace, message.toolName),
65
+ output: { type: message.isError ? "error-text" : "text", value: toolResultText(message.content) },
66
+ }] });
67
+ // The proprietary wire's tool-result output is text-only; image parts returned by a
68
+ // tool (e.g. Codex view_image) cannot live inside it. Carry them in a follow-up user
69
+ // message using the same image encoding as the user branch so the bytes reach the model.
70
+ const images = typeof message.content === "string" ? [] : message.content.filter(part => part.type === "image");
71
+ if (images.length > 0) {
72
+ out.push({ role: "user", content: images.map(part => wireImagePart((part as { imageUrl: string }).imageUrl)) });
73
+ }
74
+ continue;
75
+ }
76
+ const content: Array<Record<string, unknown>> = [];
77
+ if (typeof message.content === "string") content.push({ type: "text", text: message.content });
78
+ else for (const part of message.content) {
79
+ if (part.type === "text") content.push({ type: "text", text: part.text });
80
+ else content.push(wireImagePart(part.imageUrl));
81
+ }
82
+ out.push({ role: "user", content });
83
+ }
84
+ return out;
85
+ }
86
+
87
+ function visibleTools(parsed: OcxParsedRequest): OcxTool[] {
88
+ const choice = parsed.options.toolChoice;
89
+ if (choice === "none") return [];
90
+ const tools = parsed.context.tools ?? [];
91
+ if (isAllowedToolChoice(choice)) {
92
+ const allowed = new Set(choice.allowedTools);
93
+ return tools.filter(tool => toolAllowedByChoice(tool, allowed));
94
+ }
95
+ if (choice && typeof choice !== "string") {
96
+ return tools.filter(tool => toolChoiceAliases(tool).includes(choice.name));
97
+ }
98
+ return tools;
99
+ }
100
+
101
+ function toolChoiceInstruction(parsed: OcxParsedRequest): string | undefined {
102
+ const choice = parsed.options.toolChoice;
103
+ if (choice === "required" || (isAllowedToolChoice(choice) && choice.mode === "required")) {
104
+ return "Tool choice is required for this turn. Make at least one call from the advertised tool catalog before answering.";
105
+ }
106
+ if (choice && typeof choice !== "string" && !isAllowedToolChoice(choice)) {
107
+ // Resolve the forced name (bare, namespace__name, or namespace.name) to the advertised
108
+ // wire name so the instruction names a tool that is actually in the catalog.
109
+ const wireName = resolveToolChoiceWireName(parsed.context.tools, choice.name);
110
+ return `Tool choice is required for this turn. Call the advertised tool named ${wireName} before answering.`;
111
+ }
112
+ return undefined;
113
+ }
114
+
115
+ function wireTools(tools: OcxTool[]): Array<Record<string, unknown>> {
116
+ return tools.map(tool => ({
117
+ name: namespacedToolName(tool.namespace, tool.name),
118
+ description: tool.description,
119
+ input_schema: tool.parameters,
120
+ }));
121
+ }
122
+
123
+ function currentWorkingDirectory(): string | undefined {
124
+ try { return process.cwd(); } catch { return undefined; }
125
+ }
126
+
127
+ /** Cap the workspace listing so a large directory does not ship every entry name upstream. */
128
+ const MAX_WORKSPACE_STRUCTURE_ENTRIES = 64;
129
+ /** Cap how many recent commit subjects the config carries. */
130
+ const MAX_RECENT_COMMITS = 8;
131
+ /** Cap each recent commit entry to keep the request bounded even for long subjects. */
132
+ const MAX_RECENT_COMMIT_LENGTH = 512;
133
+ /** Cap the git status text sent upstream. */
134
+ const MAX_GIT_STATUS_LENGTH = 2048;
135
+ /** Keep collected workspace/git metadata fresh for this long (ms) so repeated requests reuse it. */
136
+ const WORKSPACE_METADATA_TTL_MS = 30_000;
137
+
138
+ /** Derive a bounded project slug from the working directory for the `x-project-slug` header. */
139
+ function projectSlug(cwd: string): string {
140
+ return cwd.replace(/[^a-zA-Z0-9]+/g, "-").replace(/^-|-$/g, "").toLowerCase().slice(0, 64) || "workspace";
141
+ }
142
+
143
+ interface GitWorkspaceInfo {
144
+ isGitRepo: boolean;
145
+ currentBranch: string;
146
+ mainBranch: string;
147
+ gitStatus: string;
148
+ recentCommits: string[];
149
+ }
150
+
151
+ const workspaceMetadataCache = new Map<string, { collectedAt: number; value: GitWorkspaceInfo }>();
152
+
153
+ const execFile = promisify(execFileCallback);
154
+
155
+ /** Best-effort git metadata for the upstream config contract; every read fails safe and stays off the event loop. */
156
+ async function gitWorkspaceInfo(cwd: string | undefined): Promise<GitWorkspaceInfo> {
157
+ const fallback: GitWorkspaceInfo = { isGitRepo: false, currentBranch: "", mainBranch: "", gitStatus: "", recentCommits: [] };
158
+ if (!cwd) return fallback;
159
+ const cached = workspaceMetadataCache.get(cwd);
160
+ if (cached && Date.now() - cached.collectedAt < WORKSPACE_METADATA_TTL_MS) return cached.value;
161
+ const run = async (args: string[]): Promise<string> => {
162
+ try {
163
+ const { stdout } = await execFile("git", args, { cwd, encoding: "utf8", timeout: 2000, windowsHide: true });
164
+ return stdout.trim();
165
+ } catch {
166
+ return "";
167
+ }
168
+ };
169
+ const root = await run(["rev-parse", "--show-toplevel"]);
170
+ const value = root
171
+ ? {
172
+ isGitRepo: true,
173
+ currentBranch: (await run(["rev-parse", "--abbrev-ref", "HEAD"])) || "HEAD",
174
+ mainBranch: (await run(["symbolic-ref", "--short", "refs/remotes/origin/HEAD"])).replace(/^origin\//, "") || (await run(["rev-parse", "--abbrev-ref", "HEAD"])) || "",
175
+ gitStatus: (await run(["status", "--porcelain"])).slice(0, MAX_GIT_STATUS_LENGTH),
176
+ recentCommits: (await run(["log", "--oneline", `-${MAX_RECENT_COMMITS}`]))
177
+ .split("\n")
178
+ .filter(Boolean)
179
+ .slice(0, MAX_RECENT_COMMITS)
180
+ .map(commit => commit.slice(0, MAX_RECENT_COMMIT_LENGTH)),
181
+ }
182
+ : fallback;
183
+ workspaceMetadataCache.set(cwd, { collectedAt: Date.now(), value });
184
+ return value;
185
+ }
186
+
187
+ async function commandCodeConfig(cwd: string | undefined): Promise<Record<string, unknown>> {
188
+ let structure: string[] = [];
189
+ if (cwd) {
190
+ try {
191
+ // Iterate and stop after the cap instead of materializing every entry: a directory with a
192
+ // huge number of names must not stall the request path for 64 metadata rows.
193
+ const dir = await opendir(cwd);
194
+ try {
195
+ for await (const entry of dir) {
196
+ if (entry.name.startsWith(".")) continue;
197
+ structure.push(entry.name);
198
+ if (structure.length >= MAX_WORKSPACE_STRUCTURE_ENTRIES) break;
199
+ }
200
+ } finally {
201
+ await dir.close().catch(() => undefined);
202
+ }
203
+ } catch { /* workspace metadata is optional */ }
204
+ }
205
+ const git = await gitWorkspaceInfo(cwd);
206
+ return {
207
+ ...(cwd ? { workingDir: cwd } : {}),
208
+ date: new Date().toISOString().slice(0, 10),
209
+ environment: process.platform,
210
+ structure,
211
+ ...git,
212
+ };
213
+ }
214
+
215
+ function usage(value: unknown): OcxUsage | undefined {
216
+ if (!value || typeof value !== "object" || Array.isArray(value)) return undefined;
217
+ const row = value as Record<string, unknown>;
218
+ const inputTokens = typeof row.inputTokens === "number" ? row.inputTokens : 0;
219
+ const outputTokens = typeof row.outputTokens === "number" ? row.outputTokens : 0;
220
+ const details = row.inputTokenDetails && typeof row.inputTokenDetails === "object" && !Array.isArray(row.inputTokenDetails)
221
+ ? row.inputTokenDetails as Record<string, unknown> : {};
222
+ const cachedInputTokens = typeof details.cacheReadTokens === "number" ? details.cacheReadTokens : undefined;
223
+ const cacheCreationInputTokens = typeof details.cacheWriteTokens === "number" ? details.cacheWriteTokens : undefined;
224
+ return {
225
+ inputTokens, outputTokens, totalTokens: inputTokens + outputTokens,
226
+ ...(cachedInputTokens !== undefined ? { cachedInputTokens, cacheReadInputTokens: cachedInputTokens } : {}),
227
+ ...(cacheCreationInputTokens !== undefined ? { cacheCreationInputTokens } : {}),
228
+ };
229
+ }
230
+
231
+ function eventError(value: unknown): string {
232
+ if (typeof value === "string" && value) return value;
233
+ if (value && typeof value === "object" && !Array.isArray(value)) {
234
+ const message = (value as Record<string, unknown>).message;
235
+ if (typeof message === "string" && message) return message;
236
+ }
237
+ return "Command Code stream error";
238
+ }
239
+
240
+ async function*ndjson(response: Response, budget: TranslatorBudget): AsyncGenerator<Record<string, unknown>> {
241
+ if (!response.body) throw new Error("Command Code response body missing");
242
+ const reader = response.body.getReader();
243
+ const decoder = new TextDecoder();
244
+ const encoder = new TextEncoder();
245
+ let buffer = "";
246
+ let bufferBytes = 0;
247
+ try {
248
+ for (;;) {
249
+ const { value, done } = await reader.read();
250
+ const next = buffer + decoder.decode(value, { stream: !done });
251
+ const nextBytes = encoder.encode(next).byteLength;
252
+ const reservation = budget.reserveTransient(nextBytes, { kind: "live_transient" });
253
+ buffer = next;
254
+ reservation.commitRetained();
255
+ budget.releaseRetained(bufferBytes, { kind: "live_transient" });
256
+ bufferBytes = nextBytes;
257
+ let newline = buffer.indexOf("\n");
258
+ while (newline >= 0) {
259
+ const line = buffer.slice(0, newline).trim(); buffer = buffer.slice(newline + 1);
260
+ if (line) { try { yield JSON.parse(stripEventFrame(line)) as Record<string, unknown>; } catch { /* ignore non-events */ } }
261
+ newline = buffer.indexOf("\n");
262
+ }
263
+ const residualBytes = encoder.encode(buffer).byteLength;
264
+ const residualReservation = budget.reserveTransient(residualBytes, { kind: "live_transient" });
265
+ residualReservation.commitRetained();
266
+ budget.releaseRetained(bufferBytes, { kind: "live_transient" });
267
+ bufferBytes = residualBytes;
268
+ if (done) break;
269
+ }
270
+ const final = buffer.trim();
271
+ if (final) { try { yield JSON.parse(stripEventFrame(final)) as Record<string, unknown>; } catch { /* ignore */ } }
272
+ } finally {
273
+ budget.releaseRetained(bufferBytes, { kind: "live_transient" });
274
+ try { await reader.cancel(); } catch { /* already closed */ }
275
+ reader.releaseLock();
276
+ }
277
+ }
278
+
279
+ /** The endpoint is newline-delimited JSON; defensively strip an SSE `data:` frame if the gateway ever switches shapes. */
280
+ function stripEventFrame(line: string): string {
281
+ return line.startsWith("data:") ? line.slice("data:".length).trim() : line;
282
+ }
283
+
284
+ function isReasoningEffortRejection(status: number, payload: string): boolean {
285
+ return (status === 400 || status === 422) && /reasoning[_ -]?effort|unsupported effort|invalid effort/i.test(payload);
286
+ }
287
+
288
+ function requestWithoutReasoningEffort(request: AdapterRequest): AdapterRequest | undefined {
289
+ try {
290
+ const body = JSON.parse(request.body) as { params?: Record<string, unknown> };
291
+ if (!body.params?.reasoning_effort) return undefined;
292
+ delete body.params.reasoning_effort;
293
+ return { ...request, body: JSON.stringify(body), reasoningLog: undefined };
294
+ } catch {
295
+ return undefined;
296
+ }
297
+ }
298
+
299
+ async function fetchCommandCode(request: AdapterRequest, ctx: AdapterFetchContext | undefined, executor: typeof globalThis.fetch): Promise<Response> {
300
+ const timeout = new AbortController();
301
+ const timer = setTimeout(() => timeout.abort(new DOMException("Timeout elapsed", "TimeoutError")), ctx?.timeoutMs ?? 200_000);
302
+ const callerSignal = ctx?.abortSignal ?? new AbortController().signal;
303
+ try {
304
+ return await executor(request.url, {
305
+ method: request.method,
306
+ headers: request.headers,
307
+ body: request.body,
308
+ redirect: "manual",
309
+ signal: AbortSignal.any([callerSignal, timeout.signal]),
310
+ });
311
+ } finally {
312
+ clearTimeout(timer);
313
+ }
314
+ }
315
+
316
+ function supportedCommandCodeEffort(provider: OcxProviderConfig, modelId: string, requested: string | undefined): string | undefined {
317
+ if (!requested || requested === "none") return undefined;
318
+ // Compatibility ids (deepseek-v4-flash / glm-5.2) must resolve to their canonical
319
+ // Command Code id before the effort lookup, or legacy requests silently lose the
320
+ // reasoning effort because the official table is keyed by the canonical ids.
321
+ const canonicalId = COMMAND_CODE_MODEL_ALIASES[modelId] ?? modelId;
322
+ const supported = commandCodeReasoningEfforts(canonicalId) ?? configuredReasoningEfforts(provider, canonicalId);
323
+ if (!supported) return undefined;
324
+ // Command Code's official profiles describe xhigh and ultra as the CLI labels that map to
325
+ // the wire value `max`; preserve that mapping without advertising a synthetic tier.
326
+ const wire = (requested === "xhigh" || requested === "ultra") && supported.includes("max") ? "max" : requested;
327
+ return supported.includes(wire) ? wire : undefined;
328
+ }
329
+
330
+ export function createCommandCodeAdapter(provider: OcxProviderConfig): ProviderAdapter {
331
+ const executor = (provider as OcxProviderConfig & { fetch?: typeof globalThis.fetch }).fetch ?? globalThis.fetch;
332
+ return {
333
+ name: "command-code",
334
+ async buildRequest(parsed: OcxParsedRequest): Promise<AdapterRequest> {
335
+ if (!provider.apiKey) throw new Error("Command Code credential missing — run rmx login command-code");
336
+ const cwd = currentWorkingDirectory();
337
+ const tools = visibleTools(parsed);
338
+ const toolNudge = buildNonOpenAIToolCatalogNudgeForTools(tools, parsed.options.toolChoice);
339
+ const choiceInstruction = toolChoiceInstruction(parsed);
340
+ const system = identifyRoutedModel([
341
+ ...(parsed.context.systemPrompt ?? []),
342
+ ...(toolNudge ? [toolNudge] : []),
343
+ ...(choiceInstruction ? [choiceInstruction] : []),
344
+ ].join("\n\n"), parsed.modelId);
345
+ const reasoningEffort = supportedCommandCodeEffort(provider, parsed.modelId, parsed.options.reasoning);
346
+ const body = {
347
+ config: await commandCodeConfig(cwd), memory: "", taste: null, skills: null,
348
+ permissionMode: "standard", mode: "agent",
349
+ params: {
350
+ model: COMMAND_CODE_MODEL_ALIASES[parsed.modelId] ?? parsed.modelId,
351
+ messages: wireMessages(parsed.context.messages),
352
+ tools: wireTools(tools),
353
+ system,
354
+ max_tokens: parsed.options.maxOutputTokens ?? provider.defaultMaxOutputTokens ?? 64_000,
355
+ // The proprietary /alpha/generate endpoint is NDJSON-stream-only; the proxy converts
356
+ // the buffered/streamed events to the client's requested shape (parsed.stream).
357
+ stream: true,
358
+ ...(parsed.options.temperature !== undefined ? { temperature: parsed.options.temperature } : {}),
359
+ ...(reasoningEffort ? { reasoning_effort: reasoningEffort } : {}),
360
+ },
361
+ };
362
+ const headers: Record<string, string> = {
363
+ Authorization: `Bearer ${provider.apiKey}`,
364
+ "Content-Type": "application/json",
365
+ "User-Agent": "cli",
366
+ "x-command-code-version": provider.commandCodeVersion ?? "0.52.1",
367
+ "x-cli-environment": "production",
368
+ "x-taste-learning": "false",
369
+ "x-co-flag": "false",
370
+ "x-session-id": randomUUID(),
371
+ };
372
+ if (cwd) headers["x-project-slug"] = projectSlug(cwd);
373
+ return {
374
+ url: `${provider.baseUrl.replace(/\/$/, "")}/alpha/generate`, method: "POST",
375
+ headers,
376
+ body: JSON.stringify(body),
377
+ ...(reasoningEffort ? { reasoningLog: { effectiveEffort: reasoningEffort, wireField: "reasoning_effort" as const, wireValue: reasoningEffort } } : {}),
378
+ };
379
+ },
380
+ async fetchResponse(request: AdapterRequest, ctx?: AdapterFetchContext): Promise<Response> {
381
+ const response = await fetchCommandCode(request, ctx, executor);
382
+ if (response.ok) return response;
383
+ const currentEffort = (() => {
384
+ try { return (JSON.parse(request.body) as { params?: { reasoning_effort?: unknown } }).params?.reasoning_effort; } catch { return undefined; }
385
+ })();
386
+ if (typeof currentEffort !== "string") return response;
387
+ let body = "";
388
+ try {
389
+ const observed = await readBoundedResponseBody(response.clone(), { signal: ctx?.abortSignal, maxBytes: 8 * 1024 });
390
+ if (!observed.displaySafe) return response;
391
+ body = observed.text;
392
+ } catch { return response; }
393
+ if (!isReasoningEffortRejection(response.status, body)) return response;
394
+ const modelId = (() => {
395
+ try { return (JSON.parse(request.body) as { params?: { model?: unknown } }).params?.model; } catch { return undefined; }
396
+ })();
397
+ if (typeof modelId !== "string") return response;
398
+ const refreshed = await refreshCommandCodeReasoningEfforts(modelId, executor);
399
+ if (!refreshed || refreshed.includes(currentEffort)) return response;
400
+ const retry = requestWithoutReasoningEffort(request);
401
+ if (!retry) return response;
402
+ try { void response.body?.cancel(); } catch { /* already closed */ }
403
+ return fetchCommandCode(retry, ctx, executor);
404
+ },
405
+ async *parseStream(response: Response, budget: TranslatorBudget): AsyncGenerator<AdapterEvent> {
406
+ let sawFinish = false;
407
+ for await (const event of ndjson(response, budget)) {
408
+ switch (event.type) {
409
+ case "text-delta": if (typeof event.text === "string") yield { type: "text_delta", text: event.text }; break;
410
+ case "reasoning-delta": if (typeof event.text === "string") yield { type: "thinking_delta", thinking: event.text }; break;
411
+ case "tool-call": {
412
+ const id = typeof event.toolCallId === "string" ? event.toolCallId : randomUUID();
413
+ const name = typeof event.toolName === "string" ? event.toolName : "tool";
414
+ const input = event.input ?? event.args ?? {};
415
+ const argumentsText = typeof input === "string" ? input : JSON.stringify(input);
416
+ yield { type: "tool_call_start", id, name };
417
+ budget.openCall(id);
418
+ try {
419
+ const reservation = budget.reserveTransient(new TextEncoder().encode(argumentsText).byteLength, { kind: "tool_args", callId: id });
420
+ reservation.commitRetained();
421
+ yield { type: "tool_call_delta", arguments: argumentsText };
422
+ yield { type: "tool_call_end" };
423
+ } finally {
424
+ budget.closeCall(id);
425
+ }
426
+ break;
427
+ }
428
+ case "finish-step":
429
+ case "finish": {
430
+ // Both events are terminal on the current wire; streams commonly carry both, so
431
+ // only the first one emits the done. finish-step carries `usage`; finish may carry
432
+ // `totalUsage` (current flows) or `usage`.
433
+ if (sawFinish) break;
434
+ sawFinish = true;
435
+ const usageValue = event.totalUsage ?? event.usage;
436
+ const stopReason = typeof event.rawFinishReason === "string" ? event.rawFinishReason : typeof event.finishReason === "string" ? event.finishReason : undefined;
437
+ yield { type: "done", usage: usage(usageValue), stopReason };
438
+ break;
439
+ }
440
+ case "error": yield { type: "error", message: eventError(event.error), status: 502 }; break;
441
+ }
442
+ }
443
+ // A stream that ends without a finish event still needs a terminal done so the
444
+ // server does not wait on an adapter that silently stopped emitting.
445
+ if (!sawFinish) yield { type: "done", usage: undefined, stopReason: undefined };
446
+ },
447
+ async parseResponse(response: Response, budget: TranslatorBudget): Promise<AdapterEvent[]> {
448
+ const events: AdapterEvent[] = [];
449
+ for await (const event of this.parseStream(response, budget)) events.push(event);
450
+ return events;
451
+ },
452
+ };
453
+ }
@@ -0,0 +1,38 @@
1
+ import { fromBinary, toBinary, toJson } from "@bufbuild/protobuf";
2
+ import { ValueSchema } from "@bufbuild/protobuf/wkt";
3
+ import { textDecoder } from "./native-exec-common";
4
+
5
+ function parseJsonText(text: string): unknown {
6
+ try {
7
+ return JSON.parse(text);
8
+ } catch {
9
+ return text;
10
+ }
11
+ }
12
+
13
+ function sameBytes(a: Uint8Array, b: Uint8Array): boolean {
14
+ if (a.length !== b.length) return false;
15
+ for (let i = 0; i < a.length; i++) {
16
+ if (a[i] !== b[i]) return false;
17
+ }
18
+ return true;
19
+ }
20
+
21
+ export function decodeCursorArgValue(value: Uint8Array): unknown {
22
+ try {
23
+ const parsed = fromBinary(ValueSchema, value);
24
+ if (!sameBytes(toBinary(ValueSchema, parsed), value)) throw new Error("not canonical protobuf Value bytes");
25
+ const jsonValue = toJson(ValueSchema, parsed);
26
+ return typeof jsonValue === "string" ? parseJsonText(jsonValue) : jsonValue;
27
+ } catch {
28
+ return parseJsonText(textDecoder.decode(value));
29
+ }
30
+ }
31
+
32
+ export function decodeCursorArgsMap(args: { [key: string]: Uint8Array } | undefined): Record<string, unknown> {
33
+ const out: Record<string, unknown> = {};
34
+ for (const [key, value] of Object.entries(args ?? {})) {
35
+ out[key] = decodeCursorArgValue(value);
36
+ }
37
+ return out;
38
+ }