@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,470 @@
1
+ import { execFileSync } from "node:child_process";
2
+ import { existsSync, readdirSync, readFileSync, statSync } from "node:fs";
3
+ import { homedir } from "node:os";
4
+ import { join, win32 as win32Path } from "node:path";
5
+ import type { OcxConfig } from "../types";
6
+ import { resolveTrustedWindowsSystemDirectory } from "./windows-elevation";
7
+
8
+ const ENVIRONMENT_NAME = /^[A-Za-z_][A-Za-z0-9_]*$/;
9
+ const MAX_ENVIRONMENT_FILE_BYTES = 256 * 1024;
10
+ const MAX_ENVIRONMENT_COMMAND_BYTES = 512 * 1024;
11
+ const MAX_ENVIRONMENT_VALUE_BYTES = 64 * 1024;
12
+ const MAX_ENVIRONMENT_FILES = 64;
13
+ const ENVIRONMENT_COMMAND_TIMEOUT_MS = 1_500;
14
+
15
+ type EnvironmentMap = Record<string, string | undefined>;
16
+ type EnvironmentSource = "process" | "os" | "file";
17
+
18
+ export interface ProviderEnvironmentDiscoveryOptions {
19
+ /** Test seam; production always uses process.platform. */
20
+ platform?: NodeJS.Platform;
21
+ /** Destination and highest-priority source. Defaults to process.env. */
22
+ env?: EnvironmentMap;
23
+ /** Test seam for a platform-independent fake user home. */
24
+ homeDir?: string;
25
+ /** Test seam; returns null for an unavailable or refused command. */
26
+ runCommand?: (command: string, args: readonly string[]) => string | null;
27
+ /** Test seam; production applies regular-file and size bounds before reading. */
28
+ readFile?: (path: string) => string | null;
29
+ /** Test seam for environment.d discovery. Entries must be base names. */
30
+ readDirectory?: (path: string) => readonly string[];
31
+ /** Exact persisted-source override, primarily for cross-platform tests. */
32
+ persistedFiles?: readonly string[];
33
+ /** Test seam for the Windows system directory; production uses GetSystemDirectoryW. */
34
+ resolveWindowsSystemDirectory?: () => string | null;
35
+ }
36
+
37
+ export interface ProviderEnvironmentHydrationResult {
38
+ referenced: number;
39
+ loaded: number;
40
+ /** Names are safe to report; values deliberately never leave process.env. */
41
+ loadedNames: string[];
42
+ missing: string[];
43
+ sources: Record<string, EnvironmentSource>;
44
+ }
45
+
46
+ export function environmentReferenceName(value: string | undefined): string | null {
47
+ if (!value) return null;
48
+ const braced = value.match(/^\$\{([A-Za-z_][A-Za-z0-9_]*)\}$/);
49
+ if (braced) return braced[1]!;
50
+ const bare = value.match(/^\$([A-Za-z_][A-Za-z0-9_]*)$/);
51
+ return bare ? bare[1]! : null;
52
+ }
53
+
54
+ /**
55
+ * The only OS variables Remodex is allowed to discover.
56
+ *
57
+ * Provider credentials stay as `${NAME}` references in config.json. OAuth, forward-auth, and
58
+ * local providers do not consume provider.apiKey, so an inert hand-edited value on one of those
59
+ * rows must not authorize reading an unrelated variable from the user's environment.
60
+ */
61
+ export function providerEnvironmentReferences(
62
+ config: Pick<OcxConfig, "proxy" | "providers">,
63
+ ): string[] {
64
+ const names = new Set<string>();
65
+ const add = (value: string | undefined) => {
66
+ const name = environmentReferenceName(value);
67
+ if (name && ENVIRONMENT_NAME.test(name)) names.add(name);
68
+ };
69
+ add(config.proxy);
70
+ for (const provider of Object.values(config.providers)) {
71
+ if (provider.authMode === "oauth" || provider.authMode === "forward" || provider.authMode === "local") continue;
72
+ add(provider.apiKey);
73
+ for (const entry of provider.apiKeyPool ?? []) add(entry.key);
74
+ }
75
+ return [...names].sort();
76
+ }
77
+
78
+ function nonEmpty(value: string | undefined): value is string {
79
+ return typeof value === "string" && value.trim().length > 0;
80
+ }
81
+
82
+ function validDiscoveredValue(value: string | undefined): value is string {
83
+ return nonEmpty(value)
84
+ && !value.includes("\0")
85
+ && Buffer.byteLength(value, "utf8") <= MAX_ENVIRONMENT_VALUE_BYTES;
86
+ }
87
+
88
+ function environmentValue(
89
+ env: EnvironmentMap,
90
+ name: string,
91
+ platform: NodeJS.Platform,
92
+ ): string | undefined {
93
+ const direct = env[name];
94
+ if (nonEmpty(direct)) return direct;
95
+ if (platform !== "win32") return undefined;
96
+ const key = Object.keys(env).find(candidate => candidate.toLowerCase() === name.toLowerCase());
97
+ const value = key ? env[key] : undefined;
98
+ return nonEmpty(value) ? value : undefined;
99
+ }
100
+
101
+ function defaultRunCommand(command: string, args: readonly string[]): string | null {
102
+ try {
103
+ const output = execFileSync(command, [...args], {
104
+ encoding: "utf8",
105
+ timeout: ENVIRONMENT_COMMAND_TIMEOUT_MS,
106
+ maxBuffer: MAX_ENVIRONMENT_COMMAND_BYTES,
107
+ stdio: ["ignore", "pipe", "ignore"],
108
+ windowsHide: true,
109
+ });
110
+ return typeof output === "string" ? output : null;
111
+ } catch {
112
+ return null;
113
+ }
114
+ }
115
+
116
+ function defaultReadFile(path: string): string | null {
117
+ try {
118
+ const stat = statSync(path);
119
+ if (!stat.isFile() || stat.size > MAX_ENVIRONMENT_FILE_BYTES) return null;
120
+ return readFileSync(path, "utf8");
121
+ } catch {
122
+ return null;
123
+ }
124
+ }
125
+
126
+ function defaultReadDirectory(path: string): readonly string[] {
127
+ try {
128
+ return readdirSync(path).slice(0, MAX_ENVIRONMENT_FILES);
129
+ } catch {
130
+ return [];
131
+ }
132
+ }
133
+
134
+ function decodeCString(value: string): string | null {
135
+ let decoded = "";
136
+ for (let index = 0; index < value.length; index += 1) {
137
+ const character = value[index]!;
138
+ if (character !== "\\") {
139
+ decoded += character;
140
+ continue;
141
+ }
142
+ const escaped = value[++index];
143
+ if (escaped === undefined) return null;
144
+ if (escaped === "n") decoded += "\n";
145
+ else if (escaped === "r") decoded += "\r";
146
+ else if (escaped === "t") decoded += "\t";
147
+ else if (escaped === "b") decoded += "\b";
148
+ else if (escaped === "f") decoded += "\f";
149
+ else if (escaped === "v") decoded += "\v";
150
+ else if (escaped === "a") decoded += "\u0007";
151
+ else if (escaped === "x") {
152
+ const digits = value.slice(index + 1, index + 3);
153
+ if (!/^[0-9A-Fa-f]{2}$/.test(digits)) return null;
154
+ decoded += String.fromCodePoint(Number.parseInt(digits, 16));
155
+ index += 2;
156
+ } else if (escaped === "u" || escaped === "U") {
157
+ const count = escaped === "u" ? 4 : 8;
158
+ const digits = value.slice(index + 1, index + 1 + count);
159
+ if (!new RegExp(`^[0-9A-Fa-f]{${count}}$`).test(digits)) return null;
160
+ const point = Number.parseInt(digits, 16);
161
+ if (point > 0x10ffff) return null;
162
+ decoded += String.fromCodePoint(point);
163
+ index += count;
164
+ } else if (/[0-7]/.test(escaped)) {
165
+ const tail = value.slice(index, index + 3).match(/^[0-7]{1,3}/)?.[0] ?? escaped;
166
+ decoded += String.fromCodePoint(Number.parseInt(tail, 8));
167
+ index += tail.length - 1;
168
+ } else {
169
+ decoded += escaped;
170
+ }
171
+ }
172
+ return decoded;
173
+ }
174
+
175
+ function stripUnquotedComment(value: string): string {
176
+ let quote: "'" | "\"" | null = null;
177
+ let escaped = false;
178
+ for (let index = 0; index < value.length; index += 1) {
179
+ const character = value[index]!;
180
+ if (escaped) {
181
+ escaped = false;
182
+ continue;
183
+ }
184
+ if (character === "\\" && quote !== "'") {
185
+ escaped = true;
186
+ continue;
187
+ }
188
+ if (character === "'" || character === "\"") {
189
+ if (quote === character) quote = null;
190
+ else if (quote === null) quote = character;
191
+ continue;
192
+ }
193
+ if (character === "#" && quote === null && (index === 0 || /\s/.test(value[index - 1]!))) {
194
+ return value.slice(0, index);
195
+ }
196
+ }
197
+ return value;
198
+ }
199
+
200
+ function decodeDoubleQuoted(value: string): string | null {
201
+ if (/(^|[^\\])(?:\$\(|`|\$\{?[A-Za-z_])/.test(value)) return null;
202
+ let decoded = "";
203
+ for (let index = 0; index < value.length; index += 1) {
204
+ const character = value[index]!;
205
+ if (character !== "\\") {
206
+ decoded += character;
207
+ continue;
208
+ }
209
+ const escaped = value[++index];
210
+ if (escaped === undefined) return null;
211
+ // These are the only characters whose backslash is removed inside POSIX double quotes.
212
+ decoded += ["$", "`", "\"", "\\"].includes(escaped) ? escaped : `\\${escaped}`;
213
+ }
214
+ return decoded;
215
+ }
216
+
217
+ function decodeUnquoted(value: string): string | null {
218
+ if (/(^|[^\\])(?:\$\(|`|\$\{?[A-Za-z_]|;|&&|\|\||[<>|])/.test(value)) return null;
219
+ let decoded = "";
220
+ let escaped = false;
221
+ for (const character of value) {
222
+ if (escaped) {
223
+ decoded += character;
224
+ escaped = false;
225
+ } else if (character === "\\") {
226
+ escaped = true;
227
+ } else {
228
+ decoded += character;
229
+ }
230
+ }
231
+ return escaped ? null : decoded.trim();
232
+ }
233
+
234
+ function decodeAssignmentValue(rawValue: string): string | null {
235
+ const value = stripUnquotedComment(rawValue).trim();
236
+ if (!value) return null;
237
+ let decoded: string | null;
238
+ if (value.startsWith("$'") && value.endsWith("'") && value.length >= 3) {
239
+ decoded = decodeCString(value.slice(2, -1));
240
+ } else if (value.startsWith("'") && value.endsWith("'") && value.length >= 2) {
241
+ decoded = value.slice(1, -1);
242
+ } else if (value.startsWith("\"") && value.endsWith("\"") && value.length >= 2) {
243
+ decoded = decodeDoubleQuoted(value.slice(1, -1));
244
+ } else {
245
+ decoded = decodeUnquoted(value);
246
+ }
247
+ return validDiscoveredValue(decoded ?? undefined) ? decoded : null;
248
+ }
249
+
250
+ function assignmentFromLine(line: string): { name: string; rawValue: string } | null {
251
+ const normalized = line.replace(/^\uFEFF/, "").trim();
252
+ if (!normalized || normalized.startsWith("#")) return null;
253
+
254
+ const shell = normalized.match(
255
+ /^(?:(?:export|readonly|declare\s+-x|typeset\s+-x)\s+)?([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(.+)$/,
256
+ );
257
+ if (shell) return { name: shell[1]!, rawValue: shell[2]! };
258
+
259
+ const pam = normalized.match(/^([A-Za-z_][A-Za-z0-9_]*)\s+(?:DEFAULT|OVERRIDE)=(.+)$/);
260
+ if (pam) return { name: pam[1]!, rawValue: pam[2]! };
261
+
262
+ const words = normalized.match(
263
+ /^(?:set\s+-(?:[A-Za-z]*[gxU][A-Za-z]*|[gxU]+)|setenv|launchctl\s+setenv)\s+([A-Za-z_][A-Za-z0-9_]*)\s+(.+)$/,
264
+ );
265
+ return words ? { name: words[1]!, rawValue: words[2]! } : null;
266
+ }
267
+
268
+ /** Parse direct assignments only. Shell code, substitutions, and sourced files are never run. */
269
+ export function parseEnvironmentAssignments(
270
+ content: string,
271
+ requestedNames: readonly string[],
272
+ ): Record<string, string> {
273
+ const requested = new Set(requestedNames.filter(name => ENVIRONMENT_NAME.test(name)));
274
+ const values: Record<string, string> = Object.create(null) as Record<string, string>;
275
+ if (requested.size === 0 || Buffer.byteLength(content, "utf8") > MAX_ENVIRONMENT_COMMAND_BYTES) return values;
276
+ for (const line of content.split(/\r?\n/)) {
277
+ const assignment = assignmentFromLine(line);
278
+ if (!assignment || !requested.has(assignment.name)) continue;
279
+ const value = decodeAssignmentValue(assignment.rawValue);
280
+ if (value !== null) values[assignment.name] = value;
281
+ }
282
+ return values;
283
+ }
284
+
285
+ function environmentDirectoryFiles(
286
+ directory: string,
287
+ readDirectory: (path: string) => readonly string[],
288
+ ): string[] {
289
+ return readDirectory(directory)
290
+ .filter(name => /^[A-Za-z0-9_.-]+\.(?:conf|env)$/.test(name))
291
+ .sort((left, right) => left.localeCompare(right))
292
+ .slice(0, MAX_ENVIRONMENT_FILES)
293
+ .map(name => join(directory, name));
294
+ }
295
+
296
+ function defaultPersistedFiles(
297
+ platform: NodeJS.Platform,
298
+ home: string,
299
+ readDirectory: (path: string) => readonly string[],
300
+ ): string[] {
301
+ if (platform === "win32") return [];
302
+ const files: string[] = [];
303
+ if (platform === "linux") {
304
+ files.push("/etc/environment");
305
+ for (const directory of ["/usr/lib/environment.d", "/usr/local/lib/environment.d", "/etc/environment.d"]) {
306
+ files.push(...environmentDirectoryFiles(directory, readDirectory));
307
+ }
308
+ }
309
+ files.push(join(home, ".pam_environment"));
310
+ files.push(...environmentDirectoryFiles(join(home, ".config", "environment.d"), readDirectory));
311
+ files.push(
312
+ join(home, ".profile"),
313
+ join(home, ".bash_profile"),
314
+ join(home, ".bash_login"),
315
+ join(home, ".bashrc"),
316
+ join(home, ".zshenv"),
317
+ join(home, ".zprofile"),
318
+ join(home, ".zshrc"),
319
+ join(home, ".config", "fish", "config.fish"),
320
+ );
321
+ return files.slice(0, MAX_ENVIRONMENT_FILES);
322
+ }
323
+
324
+ function systemExecutable(candidates: readonly string[], fallback: string): string {
325
+ return candidates.find(existsSync) ?? fallback;
326
+ }
327
+
328
+ function parseWindowsRegistryValue(output: string, requestedName: string): string | null {
329
+ for (const line of output.split(/\r?\n/)) {
330
+ const columns = line.trim().split(/\s{2,}/);
331
+ if (columns.length < 3 || columns[0]?.toLowerCase() !== requestedName.toLowerCase()) continue;
332
+ if (!/^REG_(?:SZ|EXPAND_SZ)$/i.test(columns[1]!)) continue;
333
+ const value = columns.slice(2).join(" ");
334
+ if (validDiscoveredValue(value)) return value;
335
+ }
336
+ return null;
337
+ }
338
+
339
+ function discoverOsValues(
340
+ names: readonly string[],
341
+ platform: NodeJS.Platform,
342
+ runCommand: (command: string, args: readonly string[]) => string | null,
343
+ resolveWindowsSystemDirectory?: () => string | null,
344
+ ): Record<string, string> {
345
+ const values: Record<string, string> = Object.create(null) as Record<string, string>;
346
+ if (names.length === 0) return values;
347
+
348
+ if (platform === "linux") {
349
+ const systemctl = systemExecutable(["/usr/bin/systemctl", "/bin/systemctl"], "systemctl");
350
+ const output = runCommand(systemctl, ["--user", "show-environment"]);
351
+ if (output) Object.assign(values, parseEnvironmentAssignments(output, names));
352
+ return values;
353
+ }
354
+
355
+ if (platform === "darwin") {
356
+ const launchctl = systemExecutable(["/bin/launchctl", "/usr/bin/launchctl"], "launchctl");
357
+ for (const name of names) {
358
+ const output = runCommand(launchctl, ["getenv", name]);
359
+ const value = output?.replace(/[\r\n]+$/, "");
360
+ if (validDiscoveredValue(value)) values[name] = value;
361
+ }
362
+ return values;
363
+ }
364
+
365
+ if (platform === "win32") {
366
+ // SystemRoot/WINDIR are caller-controlled environment variables. Never use
367
+ // them to select an executable that reads credentials; resolve System32
368
+ // through the OS API and fail closed when that API is unavailable.
369
+ let systemDirectory: string | null;
370
+ try {
371
+ systemDirectory = resolveWindowsSystemDirectory
372
+ ? resolveWindowsSystemDirectory()
373
+ : resolveTrustedWindowsSystemDirectory();
374
+ } catch {
375
+ return values;
376
+ }
377
+ if (!systemDirectory?.trim()) return values;
378
+ const reg = win32Path.join(systemDirectory, "reg.exe");
379
+ const roots = [
380
+ "HKCU\\Environment",
381
+ "HKLM\\SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment",
382
+ ];
383
+ for (const name of names) {
384
+ for (const root of roots) {
385
+ const output = runCommand(reg, ["query", root, "/v", name]);
386
+ const value = output ? parseWindowsRegistryValue(output, name) : null;
387
+ if (!value) continue;
388
+ values[name] = value;
389
+ break; // User environment wins over the machine environment.
390
+ }
391
+ }
392
+ }
393
+ return values;
394
+ }
395
+
396
+ /**
397
+ * Resolve configured provider/proxy references from the current process, the OS user environment,
398
+ * and safely parsed persisted user files, in that order. Only process.env is mutated. No value is
399
+ * written to Remodex/Codex configuration or returned to callers.
400
+ */
401
+ export function hydrateProviderEnvironment(
402
+ config: Pick<OcxConfig, "proxy" | "providers">,
403
+ options: ProviderEnvironmentDiscoveryOptions = {},
404
+ ): ProviderEnvironmentHydrationResult {
405
+ const platform = options.platform ?? process.platform;
406
+ const env = options.env ?? process.env;
407
+ const names = providerEnvironmentReferences(config);
408
+ const sources: Record<string, EnvironmentSource> = Object.create(null) as Record<string, EnvironmentSource>;
409
+ const unresolved: string[] = [];
410
+ for (const name of names) {
411
+ if (environmentValue(env, name, platform)) sources[name] = "process";
412
+ else unresolved.push(name);
413
+ }
414
+
415
+ const runCommand = options.runCommand ?? defaultRunCommand;
416
+ const osValues = discoverOsValues(
417
+ unresolved,
418
+ platform,
419
+ runCommand,
420
+ options.resolveWindowsSystemDirectory,
421
+ );
422
+ const afterOs: string[] = [];
423
+ for (const name of unresolved) {
424
+ const value = osValues[name];
425
+ if (validDiscoveredValue(value)) {
426
+ env[name] = value;
427
+ sources[name] = "os";
428
+ } else {
429
+ afterOs.push(name);
430
+ }
431
+ }
432
+
433
+ const readFile = options.readFile ?? defaultReadFile;
434
+ const readDirectory = options.readDirectory ?? defaultReadDirectory;
435
+ const home = options.homeDir ?? homedir();
436
+ const persistedFiles = options.persistedFiles
437
+ ? [...options.persistedFiles]
438
+ : defaultPersistedFiles(platform, home, readDirectory);
439
+ const fileValues: Record<string, string> = Object.create(null) as Record<string, string>;
440
+ if (afterOs.length > 0) {
441
+ for (const path of persistedFiles.slice(0, MAX_ENVIRONMENT_FILES)) {
442
+ const content = readFile(path);
443
+ if (content === null || Buffer.byteLength(content, "utf8") > MAX_ENVIRONMENT_FILE_BYTES) continue;
444
+ Object.assign(fileValues, parseEnvironmentAssignments(content, afterOs));
445
+ }
446
+ }
447
+
448
+ const missing: string[] = [];
449
+ const loadedNames: string[] = [];
450
+ for (const name of afterOs) {
451
+ const value = fileValues[name];
452
+ if (!validDiscoveredValue(value)) {
453
+ missing.push(name);
454
+ continue;
455
+ }
456
+ env[name] = value;
457
+ sources[name] = "file";
458
+ }
459
+ for (const name of names) {
460
+ if (sources[name] === "os" || sources[name] === "file") loadedNames.push(name);
461
+ }
462
+
463
+ return {
464
+ referenced: names.length,
465
+ loaded: loadedNames.length,
466
+ loadedNames,
467
+ missing,
468
+ sources,
469
+ };
470
+ }
@@ -0,0 +1,203 @@
1
+ import type { OcxProviderConfig } from "../types";
2
+ import {
3
+ assessUrlDestination,
4
+ DestinationDnsResolutionError,
5
+ providerAllowsPrivateNetwork,
6
+ providerDestinationConfigError,
7
+ resolvePublicAddresses,
8
+ } from "./destination-policy";
9
+ import { pinnedHttpGet, pinnedHttpPost } from "./pinned-http";
10
+ import { outboundProxyConfigured } from "./proxy-env";
11
+ import { publicProviderBaseUrl } from "./provider-url";
12
+
13
+ type ProviderGetInit = Omit<RequestInit, "body" | "method" | "redirect">;
14
+ type ProviderPostInit = ProviderGetInit & { body: string };
15
+ type ProviderOutboundConfig = Pick<OcxProviderConfig, "baseUrl" | "allowPrivateNetwork"> & {
16
+ fetch?: typeof globalThis.fetch;
17
+ };
18
+ export interface ProviderOutboundDependencies {
19
+ resolveAddresses?: typeof resolvePublicAddresses;
20
+ pinnedGet?: typeof pinnedHttpGet;
21
+ pinnedPost?: typeof pinnedHttpPost;
22
+ }
23
+
24
+ export class ProviderOutboundPolicyError extends Error {
25
+ override readonly name = "ProviderOutboundPolicyError";
26
+ }
27
+
28
+ function pickPinnedAddress(addresses: Array<{ address: string; family: number }>): { address: string; family: number } {
29
+ return addresses.find(address => address.family === 4) ?? addresses[0]!;
30
+ }
31
+
32
+ function configuredProxyFor(): boolean {
33
+ return outboundProxyConfigured();
34
+ }
35
+
36
+ function normalizeProxyHostname(hostname: string): string {
37
+ const normalized = hostname.trim().toLowerCase().replace(/\.+$/, "");
38
+ return normalized.startsWith("[") && normalized.endsWith("]")
39
+ ? normalized.slice(1, -1)
40
+ : normalized;
41
+ }
42
+
43
+ function noProxyMatches(url: URL): boolean {
44
+ const raw = process.env.NO_PROXY ?? process.env.no_proxy ?? "";
45
+ const hostname = normalizeProxyHostname(url.hostname);
46
+ const port = url.port || (url.protocol === "https:" ? "443" : "80");
47
+ for (const rawEntry of raw.split(",")) {
48
+ let entry = rawEntry.trim().toLowerCase();
49
+ if (!entry) continue;
50
+ if (entry === "*") return true;
51
+ entry = entry.replace(/^https?:\/\//, "").split("/", 1)[0]!;
52
+
53
+ let entryHost = entry;
54
+ let entryPort = "";
55
+ const bracketed = /^\[([^\]]+)](?::(\d+))?$/.exec(entry);
56
+ if (bracketed) {
57
+ entryHost = bracketed[1]!;
58
+ entryPort = bracketed[2] ?? "";
59
+ } else if ((entry.match(/:/g)?.length ?? 0) === 1) {
60
+ const separator = entry.lastIndexOf(":");
61
+ const possiblePort = entry.slice(separator + 1);
62
+ if (/^\d+$/.test(possiblePort)) {
63
+ entryHost = entry.slice(0, separator);
64
+ entryPort = possiblePort;
65
+ }
66
+ }
67
+ if (entryPort && entryPort !== port) continue;
68
+ entryHost = normalizeProxyHostname(entryHost.replace(/^\*?\./, ""));
69
+ if (!entryHost) continue;
70
+ if (hostname === entryHost || hostname.endsWith(`.${entryHost}`)) return true;
71
+ }
72
+ return false;
73
+ }
74
+
75
+ let proxyBoundaryWarned = false;
76
+ let proxyDnsDegradationWarned = false;
77
+
78
+ function warnProxyBoundaryOnce(): void {
79
+ if (proxyBoundaryWarned) return;
80
+ proxyBoundaryWarned = true;
81
+ console.warn(
82
+ "[Remodex] Provider outbound proxy mode preserves Bun proxy/NO_PROXY routing and validates "
83
+ + "the URL plus available local DNS results; the final route and peer cannot be pinned locally.",
84
+ );
85
+ }
86
+
87
+ function warnProxyDnsDegradationOnce(): void {
88
+ if (proxyDnsDegradationWarned) return;
89
+ proxyDnsDegradationWarned = true;
90
+ console.warn(
91
+ "[Remodex] Local DNS could not resolve a proxied provider hostname; continuing after URL/literal checks. "
92
+ + "The proxy-selected peer cannot be verified or pinned locally.",
93
+ );
94
+ }
95
+
96
+ export async function providerRedirectError(response: Response, requestUrl: string): Promise<string | null> {
97
+ if (response.status < 300 || response.status >= 400) return null;
98
+ try { await response.body?.cancel(); } catch { /* ignore cancellation failures */ }
99
+ const location = response.headers.get("location");
100
+ let target = "the final upstream URL";
101
+ if (location) {
102
+ try { target = publicProviderBaseUrl(new URL(location, requestUrl).toString()); } catch { /* keep fallback */ }
103
+ }
104
+ return `provider returned ${response.status} redirect to ${target}; configure the final provider URL directly`;
105
+ }
106
+
107
+ async function providerOutboundRequest(
108
+ name: string,
109
+ provider: ProviderOutboundConfig,
110
+ url: string,
111
+ method: "GET" | "POST",
112
+ init: ProviderGetInit | ProviderPostInit,
113
+ dependencies: ProviderOutboundDependencies = {},
114
+ ): Promise<Response> {
115
+ const postUrl = method === "POST" ? new URL(url) : undefined;
116
+ if (postUrl?.protocol !== undefined && postUrl.protocol !== "https:") {
117
+ throw new ProviderOutboundPolicyError("provider POST URL must use HTTPS");
118
+ }
119
+ if (provider.fetch) {
120
+ // A caller-owned executor cannot be peer-pinned here. This branch keeps literal/config
121
+ // checks and redirect blocking, but does not provide the resolved-address guarantees of
122
+ // the built-in transport. Main-request migration must define that executor contract first.
123
+ const assessment = assessUrlDestination(url);
124
+ if (assessment?.kind === "metadata" || assessment?.kind === "link-local" || assessment?.kind === "unspecified") {
125
+ throw new ProviderOutboundPolicyError(`provider URL targets ${assessment.detail}`);
126
+ }
127
+ // Registry defaults count here too, not just the operator flag: a stock Ollama entry is
128
+ // local by definition and previously passed config validation only to be refused at the
129
+ // fetch (#758). Metadata/link-local/unspecified were already rejected above.
130
+ const allowPrivate = providerAllowsPrivateNetwork(name, provider);
131
+ if (!allowPrivate) {
132
+ const destinationError = providerDestinationConfigError(name, {
133
+ baseUrl: url,
134
+ allowPrivateNetwork: false,
135
+ });
136
+ if (destinationError) throw new ProviderOutboundPolicyError(destinationError);
137
+ }
138
+ return provider.fetch(url, { ...init, method, redirect: "manual" });
139
+ }
140
+ const parsed = postUrl ?? new URL(url);
141
+ const proxyConfigured = configuredProxyFor();
142
+ const resolveAddresses = dependencies.resolveAddresses ?? resolvePublicAddresses;
143
+ const pinnedGet = dependencies.pinnedGet ?? pinnedHttpGet;
144
+ const pinnedPost = dependencies.pinnedPost ?? pinnedHttpPost;
145
+ const allowPrivate = providerAllowsPrivateNetwork(name, provider);
146
+ let resolved: Awaited<ReturnType<typeof resolvePublicAddresses>>;
147
+ try {
148
+ resolved = await resolveAddresses(url, {
149
+ context: "provider URL",
150
+ allowPrivateNetwork: allowPrivate,
151
+ });
152
+ } catch (error) {
153
+ const dnsResolutionFailed = error instanceof DestinationDnsResolutionError
154
+ || (error instanceof Error && error.name === "DestinationDnsResolutionError");
155
+ if (!dnsResolutionFailed) {
156
+ throw new ProviderOutboundPolicyError(error instanceof Error ? error.message : "provider destination was blocked");
157
+ }
158
+ if (!proxyConfigured) throw error;
159
+ warnProxyBoundaryOnce();
160
+ warnProxyDnsDegradationOnce();
161
+ return globalThis.fetch(url, { ...init, method, redirect: "manual" });
162
+ }
163
+ if (proxyConfigured && !resolved.privateNetwork) {
164
+ warnProxyBoundaryOnce();
165
+ return globalThis.fetch(url, { ...init, method, redirect: "manual" });
166
+ }
167
+ if (proxyConfigured && resolved.privateNetwork && !noProxyMatches(parsed)) {
168
+ const hostname = normalizeProxyHostname(parsed.hostname);
169
+ throw new Error(
170
+ `provider URL resolves to a private-network destination; add ${hostname} to NO_PROXY before using allowPrivateNetwork with an outbound proxy`,
171
+ );
172
+ }
173
+ const requestOptions = {
174
+ headers: init.headers,
175
+ rejectUnauthorized: true,
176
+ context: "provider response",
177
+ };
178
+ const pinned = pickPinnedAddress(resolved.addresses);
179
+ if (method === "POST") {
180
+ return pinnedPost(url, pinned, (init as ProviderPostInit).body, init.signal ?? undefined, requestOptions);
181
+ }
182
+ return pinnedGet(url, pinned, init.signal ?? undefined, requestOptions);
183
+ }
184
+
185
+ export async function providerOutboundGet(
186
+ name: string,
187
+ provider: ProviderOutboundConfig,
188
+ url: string,
189
+ init: ProviderGetInit = {},
190
+ dependencies: ProviderOutboundDependencies = {},
191
+ ): Promise<Response> {
192
+ return providerOutboundRequest(name, provider, url, "GET", init, dependencies);
193
+ }
194
+
195
+ export async function providerOutboundPost(
196
+ name: string,
197
+ provider: ProviderOutboundConfig,
198
+ url: string,
199
+ init: ProviderPostInit,
200
+ dependencies: ProviderOutboundDependencies = {},
201
+ ): Promise<Response> {
202
+ return providerOutboundRequest(name, provider, url, "POST", init, dependencies);
203
+ }
@@ -0,0 +1,14 @@
1
+ /** Strip credentials and non-routing URL components before displaying a provider URL. */
2
+ export function publicProviderBaseUrl(baseUrl: string): string {
3
+ try {
4
+ const parsed = new URL(baseUrl.trim());
5
+ if (parsed.protocol !== "http:" && parsed.protocol !== "https:") return "(invalid URL)";
6
+ parsed.username = "";
7
+ parsed.password = "";
8
+ parsed.search = "";
9
+ parsed.hash = "";
10
+ return parsed.toString().replace(/\/$/, baseUrl.endsWith("/") ? "/" : "");
11
+ } catch {
12
+ return "(invalid URL)";
13
+ }
14
+ }