@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,239 @@
1
+ import type { OAuthController, OAuthCredentials } from "./types";
2
+ import { homedir } from "node:os";
3
+ import { join } from "node:path";
4
+ import { isAddrInUse } from "../server/ports";
5
+ import { parseCallbackInput } from "./callback-server";
6
+
7
+ const COMMAND_CODE_STUDIO_URL = "https://commandcode.ai";
8
+ const COMMAND_CODE_CALLBACK_PORT = 5959;
9
+ const LOGIN_TIMEOUT_MS = 120_000;
10
+ const CALLBACK_PATH = "/callback";
11
+
12
+ interface CommandCodeCallback {
13
+ apiKey: string;
14
+ state: string;
15
+ userId: string;
16
+ userName: string;
17
+ keyName: string;
18
+ }
19
+
20
+ interface CommandCodeLocalAuth {
21
+ apiKey?: unknown;
22
+ userId?: unknown;
23
+ }
24
+
25
+ export interface CommandCodeLoginOptions {
26
+ /** Add-account and reauthentication flows must select a fresh browser identity. */
27
+ importLocal?: "fallback" | "off";
28
+ }
29
+
30
+ export function shouldImportLocalCommandCodeAuth(options: CommandCodeLoginOptions = {}): boolean {
31
+ return options.importLocal !== "off";
32
+ }
33
+
34
+ async function importLocalCommandCodeAuth(signal?: AbortSignal): Promise<OAuthCredentials | undefined> {
35
+ if (signal?.aborted) {
36
+ throw signal.reason ?? new DOMException("Command Code login aborted", "AbortError");
37
+ }
38
+ let parsed: CommandCodeLocalAuth;
39
+ try {
40
+ parsed = JSON.parse(await Bun.file(join(homedir(), ".commandcode", "auth.json")).text()) as CommandCodeLocalAuth;
41
+ } catch {
42
+ return undefined;
43
+ }
44
+ if (typeof parsed.apiKey !== "string" || parsed.apiKey.length === 0) return undefined;
45
+ let accountId: string | undefined;
46
+ try {
47
+ const response = await fetch("https://api.commandcode.ai/alpha/whoami", {
48
+ headers: { Authorization: `Bearer ${parsed.apiKey}`, Accept: "application/json" },
49
+ signal: signal ? AbortSignal.any([signal, AbortSignal.timeout(10_000)]) : AbortSignal.timeout(10_000),
50
+ });
51
+ if (!response.ok) return undefined;
52
+ // Carry the validated whoami identity so an imported credential keeps multi-account
53
+ // semantics even when the local auth.json omits userId.
54
+ const body = (await response.json()) as { user?: { id?: unknown } };
55
+ if (typeof body.user?.id === "string" && body.user.id.length > 0) accountId = body.user.id;
56
+ } catch (error) {
57
+ if (signal?.aborted) throw signal.reason ?? new DOMException("Command Code login aborted", "AbortError");
58
+ return undefined;
59
+ }
60
+ if (!accountId && typeof parsed.userId === "string" && parsed.userId.length > 0) accountId = parsed.userId;
61
+ return {
62
+ access: parsed.apiKey,
63
+ refresh: parsed.apiKey,
64
+ expires: Number.MAX_SAFE_INTEGER,
65
+ ...(accountId ? { accountId } : {}),
66
+ source: "local-cli",
67
+ };
68
+ }
69
+
70
+ function randomState(): string {
71
+ const bytes = new Uint8Array(32);
72
+ crypto.getRandomValues(bytes);
73
+ return Buffer.from(bytes).toString("base64url");
74
+ }
75
+
76
+ export function parseCommandCodeCallback(value: unknown, expectedState: string): CommandCodeCallback {
77
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
78
+ throw new Error("Command Code callback must be an object");
79
+ }
80
+ const body = value as Record<string, unknown>;
81
+ if (body.state !== expectedState) throw new Error("Command Code OAuth state mismatch");
82
+ for (const field of ["apiKey", "userId", "userName", "keyName"] as const) {
83
+ if (typeof body[field] !== "string" || body[field].length === 0) {
84
+ throw new Error(`Command Code callback missing ${field}`);
85
+ }
86
+ }
87
+ return body as unknown as CommandCodeCallback;
88
+ }
89
+
90
+ function createCallbackServer(state: string): {
91
+ servers: Array<ReturnType<typeof Bun.serve>>;
92
+ callback: Promise<CommandCodeCallback>;
93
+ } {
94
+ let resolve!: (value: CommandCodeCallback) => void;
95
+ const callback = new Promise<CommandCodeCallback>((res) => { resolve = res; });
96
+ const fetch = async (request: Request): Promise<Response> => {
97
+ const url = new URL(request.url);
98
+ const origin = request.headers.get("origin");
99
+ const headers = new Headers({
100
+ "Content-Type": "application/json",
101
+ "Access-Control-Allow-Origin": origin === COMMAND_CODE_STUDIO_URL ? origin : COMMAND_CODE_STUDIO_URL,
102
+ "Access-Control-Allow-Methods": "POST, OPTIONS",
103
+ "Access-Control-Allow-Headers": "Content-Type",
104
+ });
105
+ if (request.method === "OPTIONS") return new Response(null, { status: 204, headers });
106
+ if (url.pathname !== CALLBACK_PATH) return Response.json({ success: false, error: "Not found" }, { status: 404, headers });
107
+ if (request.method !== "POST") return Response.json({ success: false, error: "Method not allowed" }, { status: 405, headers });
108
+ try {
109
+ const body = await request.json();
110
+ const parsed = parseCommandCodeCallback(body, state);
111
+ queueMicrotask(() => resolve(parsed));
112
+ return Response.json({ success: true }, { headers });
113
+ } catch (error) {
114
+ const message = error instanceof Error ? error.message : String(error);
115
+ return Response.json({ success: false, error: message }, { status: 400, headers });
116
+ }
117
+ };
118
+ const create = (port: number): Array<ReturnType<typeof Bun.serve>> => {
119
+ // The advertised callback host is `127.0.0.1`; on Windows `localhost` commonly resolves to `::1`
120
+ // first, so also bind the IPv6 loopback best-effort (mirrors the shared OAuthCallbackFlow).
121
+ const servers = [Bun.serve({ hostname: "127.0.0.1", port, fetch })];
122
+ try {
123
+ servers.push(Bun.serve({ hostname: "::1", port: servers[0].port, fetch }));
124
+ } catch (error) {
125
+ if (isAddrInUse(error)) {
126
+ for (const server of servers) server.stop(true);
127
+ throw error;
128
+ }
129
+ // IPv6 unsupported (EAFNOSUPPORT etc.) degrades to the IPv4-only listener.
130
+ }
131
+ return servers;
132
+ };
133
+ try {
134
+ return { servers: create(COMMAND_CODE_CALLBACK_PORT), callback };
135
+ } catch {
136
+ return { servers: create(0), callback };
137
+ }
138
+ }
139
+
140
+ /** Validate a raw pasted Command Code API key and return the validated identity. */
141
+ async function validatePastedApiKey(apiKey: string): Promise<{ userId: string; userName: string } | undefined> {
142
+ try {
143
+ const response = await fetch("https://api.commandcode.ai/alpha/whoami", {
144
+ headers: { Authorization: `Bearer ${apiKey}`, Accept: "application/json" },
145
+ signal: AbortSignal.timeout(10_000),
146
+ });
147
+ if (!response.ok) return undefined;
148
+ const body = (await response.json()) as { user?: { id?: unknown; userName?: unknown } };
149
+ const userId = body.user?.id;
150
+ const userName = body.user?.userName;
151
+ if (typeof userId !== "string" || typeof userName !== "string") return undefined;
152
+ if (!userId.trim() || !userName.trim()) return undefined;
153
+ return { userId, userName };
154
+ } catch {
155
+ return undefined;
156
+ }
157
+ }
158
+
159
+ /** Manual-paste fallback: a raw API key, or a pasted callback JSON/URL that carries `apiKey`. */
160
+ function parsePastedCommandCodeInput(input: string, expectedState: string): CommandCodeCallback | undefined {
161
+ const trimmed = input.trim();
162
+ if (!trimmed) return undefined;
163
+ if (trimmed.startsWith("{")) {
164
+ try {
165
+ return parseCommandCodeCallback(JSON.parse(trimmed) as unknown, expectedState);
166
+ } catch {
167
+ return undefined;
168
+ }
169
+ }
170
+ const parsed = parseCallbackInput(trimmed);
171
+ const apiKey = parsed.code?.trim();
172
+ if (!apiKey) return undefined;
173
+ // A URL/query-shaped paste is an authorization response and must carry a matching state,
174
+ // mirroring the shared OAuth callback flow; a stale or attacker-supplied URL from another
175
+ // session must not be accepted. Raw in-session keys are exempt (no state to compare).
176
+ if (parsed.kind !== "raw" && parsed.state !== expectedState) return undefined;
177
+ return { apiKey, state: expectedState, userId: "", userName: "", keyName: "manual" };
178
+ }
179
+
180
+ export async function loginCommandCode(ctrl: OAuthController, options: CommandCodeLoginOptions = {}): Promise<OAuthCredentials> {
181
+ if (ctrl.signal?.aborted) {
182
+ throw ctrl.signal.reason ?? new DOMException("Command Code login aborted", "AbortError");
183
+ }
184
+ if (shouldImportLocalCommandCodeAuth(options)) {
185
+ const local = await importLocalCommandCodeAuth(ctrl.signal);
186
+ if (local) {
187
+ ctrl.onProgress?.("Imported existing Command Code CLI authentication.");
188
+ return local;
189
+ }
190
+ }
191
+ const state = randomState();
192
+ let servers: Array<ReturnType<typeof Bun.serve>> = [];
193
+ let timeoutId: ReturnType<typeof setTimeout> | undefined;
194
+ try {
195
+ const created = createCallbackServer(state);
196
+ servers = created.servers;
197
+ const callbackUrl = `http://127.0.0.1:${servers[0].port}${CALLBACK_PATH}`;
198
+ const authUrl = `${COMMAND_CODE_STUDIO_URL}/studio/auth/cli?callback=${encodeURIComponent(callbackUrl)}&state=${encodeURIComponent(state)}`;
199
+ ctrl.onAuth?.({ url: authUrl, instructions: "Sign in with Command Code in the browser." });
200
+ ctrl.onProgress?.("Waiting for Command Code authentication...");
201
+ const timeout = new Promise<never>((_, reject) => {
202
+ timeoutId = setTimeout(() => reject(new Error("Command Code OAuth callback timed out")), LOGIN_TIMEOUT_MS);
203
+ ctrl.signal?.addEventListener("abort", () => { if (timeoutId) clearTimeout(timeoutId); reject(ctrl.signal?.reason); }, { once: true });
204
+ });
205
+ const manual = ctrl.onManualCodeInput
206
+ ? (async (): Promise<CommandCodeCallback> => {
207
+ while (true) {
208
+ // The loop keeps waiting until a valid paste arrives; invalid pastes re-prompt.
209
+ // Yield between iterations so an abort signal can interrupt a fast re-prompt loop.
210
+ if (ctrl.signal?.aborted) throw ctrl.signal.reason ?? new DOMException("Command Code login aborted", "AbortError");
211
+ const input = await ctrl.onManualCodeInput?.(state);
212
+ if (input === undefined) continue;
213
+ const pasted = parsePastedCommandCodeInput(input, state);
214
+ if (!pasted) continue;
215
+ const identity = await validatePastedApiKey(pasted.apiKey);
216
+ if (identity) return { ...pasted, ...identity };
217
+ await new Promise(resolve => setTimeout(resolve, 0));
218
+ }
219
+ })()
220
+ : undefined;
221
+ const result = await Promise.race([created.callback, timeout, ...(manual ? [manual] : [])]);
222
+ if (result === undefined) throw new Error("Command Code OAuth callback cancelled");
223
+ return {
224
+ access: result.apiKey,
225
+ refresh: result.apiKey,
226
+ expires: Number.MAX_SAFE_INTEGER,
227
+ accountId: result.userId,
228
+ source: "oauth",
229
+ };
230
+ } finally {
231
+ if (timeoutId) clearTimeout(timeoutId);
232
+ for (const server of servers) server.stop(true);
233
+ }
234
+ }
235
+
236
+ export async function refreshCommandCodeToken(apiKey: string): Promise<OAuthCredentials> {
237
+ if (!apiKey) throw new Error("Command Code API key missing; run rmx login command-code");
238
+ return { access: apiKey, refresh: apiKey, expires: Number.MAX_SAFE_INTEGER, source: "oauth" };
239
+ }
@@ -0,0 +1,231 @@
1
+ /**
2
+ * Cursor OAuth — PKCE poll flow. Standalone: talks directly to cursor.com / api2.cursor.sh,
3
+ * with no dependency on a local Cursor IDE/CLI install or on jawcode. Ported from jawcode
4
+ * packages/ai/src/utils/oauth/cursor.ts and adapted to Remodex's OAuthController (see kimi.ts).
5
+ *
6
+ * Security: the login URL carries only the PKCE challenge (SHA-256 of the verifier); the verifier
7
+ * is sent only to /auth/poll. Tokens and the verifier are never logged — thrown errors and progress
8
+ * messages are status/string only.
9
+ */
10
+ import { generatePKCE } from "./pkce";
11
+ import type { OAuthController, OAuthCredentials } from "./types";
12
+
13
+ const CURSOR_LOGIN_URL = "https://cursor.com/loginDeepControl";
14
+ const CURSOR_POLL_URL = "https://api2.cursor.sh/auth/poll";
15
+ const CURSOR_REFRESH_URL = "https://api2.cursor.sh/auth/exchange_user_api_key";
16
+
17
+ const POLL_MAX_ATTEMPTS = 150;
18
+ const POLL_BASE_DELAY_MS = 1000;
19
+ const POLL_MAX_DELAY_MS = 10_000;
20
+ const POLL_BACKOFF = 1.2;
21
+ const EXPIRY_SKEW_MS = 5 * 60 * 1000;
22
+ const FALLBACK_TTL_MS = 60 * 60 * 1000;
23
+
24
+ const REFRESH_TIMEOUT_MS = 15_000;
25
+ const REFRESH_ATTEMPTS = 3;
26
+ const REFRESH_RETRY_BASE_MS = 300;
27
+
28
+ export interface CursorAuthParams {
29
+ verifier: string;
30
+ challenge: string;
31
+ uuid: string;
32
+ loginUrl: string;
33
+ }
34
+
35
+ interface CursorJwtPayload {
36
+ sub?: unknown;
37
+ email?: unknown;
38
+ exp?: unknown;
39
+ }
40
+
41
+ function decodeCursorJwtPayload(token: string): CursorJwtPayload | undefined {
42
+ const parts = token.split(".");
43
+ const payload = parts[1];
44
+ if (parts.length !== 3 || !payload) return undefined;
45
+ try {
46
+ return JSON.parse(Buffer.from(payload, "base64url").toString("utf-8")) as CursorJwtPayload;
47
+ } catch {
48
+ return undefined;
49
+ }
50
+ }
51
+
52
+ /** Build OAuthCredentials from Cursor tokens, extracting stable identity from JWT `sub` for multiauth. */
53
+ export function credentialsFromCursorTokens(accessToken: string, refreshToken: string): OAuthCredentials {
54
+ const payload = decodeCursorJwtPayload(accessToken) ?? decodeCursorJwtPayload(refreshToken);
55
+ const accountId = cursorJwtIdentity(payload?.sub);
56
+ const email = cursorJwtEmail(payload?.email);
57
+ return {
58
+ access: accessToken,
59
+ refresh: refreshToken,
60
+ expires: getTokenExpiry(accessToken),
61
+ ...(accountId ? { accountId } : {}),
62
+ ...(email ? { email } : {}),
63
+ };
64
+ }
65
+
66
+ /** Coerce JWT `sub` (string or safe integer) into a stable multiauth account id. */
67
+ function cursorJwtIdentity(value: unknown): string | undefined {
68
+ if (typeof value === "string" && value.length > 0) return value;
69
+ if (typeof value === "number" && Number.isSafeInteger(value)) return String(value);
70
+ return undefined;
71
+ }
72
+
73
+ function cursorJwtEmail(value: unknown): string | undefined {
74
+ if (typeof value !== "string" || value.length === 0) return undefined;
75
+ return value.toLowerCase();
76
+ }
77
+
78
+ /** Generate PKCE params + the cursor.com deep-link login URL (challenge only — never the verifier). */
79
+ export async function generateCursorAuthParams(_opts?: { forceLogin?: boolean }): Promise<CursorAuthParams> {
80
+ const { verifier, challenge } = await generatePKCE();
81
+ const uuid = crypto.randomUUID();
82
+ // Cursor's deep-control page has no documented account-picker query; only the stable
83
+ // PKCE params are sent. forceLogin is honored only in loginCursor instructions.
84
+ const params = new URLSearchParams({ challenge, uuid, mode: "login", redirectTarget: "cli" });
85
+ return { verifier, challenge, uuid, loginUrl: `${CURSOR_LOGIN_URL}?${params.toString()}` };
86
+ }
87
+
88
+ /** Abort-aware delay (mirrors kimi.ts) — rejects if the controller signal aborts. */
89
+ function sleep(ms: number, signal?: AbortSignal): Promise<void> {
90
+ return new Promise((resolve, reject) => {
91
+ if (signal?.aborted) return reject(new Error("Cursor login cancelled"));
92
+ const timer = setTimeout(resolve, ms);
93
+ signal?.addEventListener(
94
+ "abort",
95
+ () => {
96
+ clearTimeout(timer);
97
+ reject(new Error("Cursor login cancelled"));
98
+ },
99
+ { once: true },
100
+ );
101
+ });
102
+ }
103
+
104
+ /**
105
+ * Poll cursor.com for login completion. 404 = still pending (back off), 200 = tokens.
106
+ * `baseDelayMs` is injectable so tests can avoid the real 1s cadence; production uses the default.
107
+ */
108
+ export async function pollCursorAuth(
109
+ uuid: string,
110
+ verifier: string,
111
+ signal?: AbortSignal,
112
+ baseDelayMs: number = POLL_BASE_DELAY_MS,
113
+ ): Promise<{ accessToken: string; refreshToken: string }> {
114
+ let delay = baseDelayMs;
115
+ let consecutiveErrors = 0;
116
+
117
+ for (let attempt = 0; attempt < POLL_MAX_ATTEMPTS; attempt++) {
118
+ await sleep(delay, signal);
119
+
120
+ try {
121
+ const url = `${CURSOR_POLL_URL}?uuid=${encodeURIComponent(uuid)}&verifier=${encodeURIComponent(verifier)}`;
122
+ const response = await fetch(url, { signal });
123
+
124
+ if (response.status === 404) {
125
+ consecutiveErrors = 0;
126
+ delay = Math.min(delay * POLL_BACKOFF, POLL_MAX_DELAY_MS);
127
+ continue;
128
+ }
129
+
130
+ if (response.ok) {
131
+ const data = (await response.json()) as { accessToken?: string; refreshToken?: string };
132
+ if (!data.accessToken || !data.refreshToken) {
133
+ throw new Error("Cursor auth response missing tokens");
134
+ }
135
+ return { accessToken: data.accessToken, refreshToken: data.refreshToken };
136
+ }
137
+
138
+ throw new Error(`Cursor auth poll failed: ${response.status}`);
139
+ } catch (err) {
140
+ if (signal?.aborted) throw err instanceof Error ? err : new Error("Cursor login cancelled");
141
+ consecutiveErrors++;
142
+ if (consecutiveErrors >= 3) {
143
+ throw new Error("Too many consecutive errors during Cursor auth polling");
144
+ }
145
+ delay = Math.min(delay * POLL_BACKOFF, POLL_MAX_DELAY_MS);
146
+ }
147
+ }
148
+
149
+ throw new Error("Cursor authentication polling timeout");
150
+ }
151
+
152
+ /** Run the standalone Cursor login: surface the URL via `onAuth`, then poll until approved. */
153
+ export async function loginCursor(
154
+ ctrl: OAuthController,
155
+ pollBaseDelayMs: number = POLL_BASE_DELAY_MS,
156
+ opts?: { forceLogin?: boolean },
157
+ ): Promise<OAuthCredentials> {
158
+ const { verifier, uuid, loginUrl } = await generateCursorAuthParams({ forceLogin: opts?.forceLogin === true });
159
+ ctrl.onAuth?.({
160
+ url: loginUrl,
161
+ instructions: opts?.forceLogin
162
+ ? "Log out of Cursor in the browser (or use a private window), sign in as the account you want to add, then approve and return here."
163
+ : "Approve the Cursor login in your browser, then return here.",
164
+ });
165
+ ctrl.onProgress?.("Waiting for Cursor login approval…");
166
+ const { accessToken, refreshToken } = await pollCursorAuth(uuid, verifier, ctrl.signal, pollBaseDelayMs);
167
+ return credentialsFromCursorTokens(accessToken, refreshToken);
168
+ }
169
+
170
+ function isRetryableRefreshStatus(status: number): boolean {
171
+ return status === 429 || status === 500 || status === 502 || status === 503 || status === 504;
172
+ }
173
+
174
+ function refreshRetryDelayMs(attempt: number): number {
175
+ const exp = REFRESH_RETRY_BASE_MS * 2 ** attempt;
176
+ return Math.floor(exp * (0.8 + Math.random() * 0.4));
177
+ }
178
+
179
+ function refreshTimeoutSignal(parent: AbortSignal | undefined): AbortSignal {
180
+ const timeout = AbortSignal.timeout(REFRESH_TIMEOUT_MS);
181
+ return parent ? AbortSignal.any([parent, timeout]) : timeout;
182
+ }
183
+
184
+ /**
185
+ * Exchange a refresh token for fresh credentials. Keeps the old refresh if the server omits one.
186
+ *
187
+ * Hardened with a per-attempt timeout and bounded retry on transient failures (network errors and
188
+ * 429/5xx). Non-retryable statuses (e.g. 401/403 from an expired refresh token) fail fast so the
189
+ * caller can surface a re-auth prompt. Errors never include the token value.
190
+ */
191
+ export async function refreshCursorToken(refresh: string, signal?: AbortSignal): Promise<OAuthCredentials> {
192
+ let lastError: unknown;
193
+ for (let attempt = 0; attempt < REFRESH_ATTEMPTS; attempt++) {
194
+ if (signal?.aborted) throw signal.reason ?? new Error("Cursor token refresh aborted");
195
+ let response: Response;
196
+ try {
197
+ response = await fetch(CURSOR_REFRESH_URL, {
198
+ method: "POST",
199
+ headers: { Authorization: `Bearer ${refresh}`, "Content-Type": "application/json" },
200
+ body: "{}",
201
+ signal: refreshTimeoutSignal(signal),
202
+ });
203
+ } catch (err) {
204
+ // Network/timeout error: retry unless the caller aborted or we are out of attempts.
205
+ if (signal?.aborted) throw err;
206
+ lastError = err;
207
+ if (attempt === REFRESH_ATTEMPTS - 1) break;
208
+ await new Promise(resolve => setTimeout(resolve, refreshRetryDelayMs(attempt)));
209
+ continue;
210
+ }
211
+ if (response.ok) {
212
+ const data = (await response.json()) as { accessToken?: string; refreshToken?: string };
213
+ if (!data.accessToken) throw new Error("Cursor refresh response missing access token");
214
+ return credentialsFromCursorTokens(data.accessToken, data.refreshToken || refresh);
215
+ }
216
+ if (!isRetryableRefreshStatus(response.status) || attempt === REFRESH_ATTEMPTS - 1) {
217
+ throw new Error(`Cursor token refresh failed: ${response.status}`);
218
+ }
219
+ lastError = new Error(`Cursor token refresh failed: ${response.status}`);
220
+ await response.body?.cancel().catch(() => {});
221
+ await new Promise(resolve => setTimeout(resolve, refreshRetryDelayMs(attempt)));
222
+ }
223
+ throw lastError instanceof Error ? lastError : new Error("Cursor token refresh failed");
224
+ }
225
+
226
+ /** Resolve a token's expiry (epoch ms) from its JWT `exp`, minus a 5-minute skew; ~1h fallback. */
227
+ export function getTokenExpiry(token: string): number {
228
+ const decoded = decodeCursorJwtPayload(token);
229
+ if (typeof decoded?.exp === "number") return decoded.exp * 1000 - EXPIRY_SKEW_MS;
230
+ return Date.now() + FALLBACK_TTL_MS;
231
+ }