@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,51 @@
1
+ import { createHmac, randomBytes, timingSafeEqual } from "node:crypto";
2
+
3
+ export const LOCAL_ATTESTATION_CHALLENGE_HEADER = "x-opencodex-attestation-challenge";
4
+ export const LOCAL_ATTESTATION_PROOF_HEADER = "x-opencodex-attestation-proof";
5
+
6
+ const BASE64URL_256 = /^[A-Za-z0-9_-]{43}$/;
7
+
8
+ export function isLocalAttestationSecret(value: unknown): value is string {
9
+ return typeof value === "string" && BASE64URL_256.test(value);
10
+ }
11
+
12
+ export function createLocalAttestationSecret(): string {
13
+ return randomBytes(32).toString("base64url");
14
+ }
15
+
16
+ export function createLocalAttestationChallenge(): string {
17
+ return randomBytes(32).toString("base64url");
18
+ }
19
+
20
+ function attestationPayload(challenge: string, pid: number, port: number): string | null {
21
+ if (!BASE64URL_256.test(challenge)) return null;
22
+ if (!Number.isSafeInteger(pid) || pid <= 0) return null;
23
+ if (!Number.isInteger(port) || port <= 0 || port > 65535) return null;
24
+ return `opencodex-local-management-v1\n${challenge}\n${pid}\n${port}`;
25
+ }
26
+
27
+ export function createLocalAttestationProof(
28
+ secret: string,
29
+ challenge: string,
30
+ pid: number,
31
+ port: number,
32
+ ): string | null {
33
+ if (!isLocalAttestationSecret(secret)) return null;
34
+ const payload = attestationPayload(challenge, pid, port);
35
+ if (!payload) return null;
36
+ return createHmac("sha256", secret).update(payload).digest("base64url");
37
+ }
38
+
39
+ export function verifyLocalAttestationProof(
40
+ secret: string,
41
+ challenge: string,
42
+ pid: number,
43
+ port: number,
44
+ proof: string | null,
45
+ ): boolean {
46
+ const expected = createLocalAttestationProof(secret, challenge, pid, port);
47
+ if (!expected || !proof || !BASE64URL_256.test(proof)) return false;
48
+ const expectedBytes = Buffer.from(expected);
49
+ const actualBytes = Buffer.from(proof);
50
+ return expectedBytes.length === actualBytes.length && timingSafeEqual(expectedBytes, actualBytes);
51
+ }
@@ -0,0 +1,25 @@
1
+ import { spawn } from "node:child_process";
2
+ import { existsSync } from "node:fs";
3
+ import { join } from "node:path";
4
+
5
+ function windowsRundll32(): string {
6
+ const windowsRoot = process.env.SystemRoot || process.env.WINDIR || "C:\\Windows";
7
+ const candidate = join(windowsRoot, "System32", "rundll32.exe");
8
+ return existsSync(candidate) ? candidate : "rundll32";
9
+ }
10
+
11
+ export function openUrl(url: string): void {
12
+ if (!/^https?:\/\//i.test(url)) return;
13
+ const cmd =
14
+ process.platform === "darwin" ? "open"
15
+ : process.platform === "win32" ? windowsRundll32()
16
+ : "xdg-open";
17
+ const args = process.platform === "win32"
18
+ ? ["url.dll,FileProtocolHandler", url]
19
+ : [url];
20
+ const child = spawn(cmd, args, { detached: true, stdio: "ignore", shell: false });
21
+ // Headless hosts (no xdg-open) emit ENOENT as an async 'error' event; without a
22
+ // listener that is an uncaught exception that kills the whole proxy/login flow.
23
+ child.on("error", () => {});
24
+ child.unref();
25
+ }
@@ -0,0 +1,182 @@
1
+ import http, { type IncomingMessage, type RequestOptions } from "node:http";
2
+ import https from "node:https";
3
+
4
+ export type PinnedAddress = { address: string; family: number };
5
+
6
+ export interface PinnedHttpRequestOptions {
7
+ headers?: HeadersInit;
8
+ maxBytes?: number;
9
+ idleTimeoutMs?: number;
10
+ rejectUnauthorized?: boolean;
11
+ context?: string;
12
+ }
13
+
14
+ /** @deprecated Use {@link PinnedHttpRequestOptions}. */
15
+ export type PinnedHttpGetOptions = PinnedHttpRequestOptions;
16
+
17
+ function pinnedHttpRequest(
18
+ url: string,
19
+ pinned: PinnedAddress,
20
+ method: "GET" | "POST",
21
+ body: string | undefined,
22
+ signal?: AbortSignal,
23
+ options?: PinnedHttpRequestOptions,
24
+ ): Promise<Response> {
25
+ const parsed = new URL(url);
26
+ if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
27
+ throw new Error(`${options?.context ?? "request"} must use HTTP or HTTPS, got ${parsed.protocol}`);
28
+ }
29
+ const context = options?.context ?? "request";
30
+ const idleTimeoutMs = options?.idleTimeoutMs ?? 60_000;
31
+ const maxBytes = options?.maxBytes;
32
+ const headers = new Headers(options?.headers);
33
+ headers.set("host", parsed.host);
34
+ if (body !== undefined && !headers.has("content-length")) {
35
+ headers.set("content-length", String(Buffer.byteLength(body)));
36
+ }
37
+ const requestHeaders: Record<string, string> = {};
38
+ headers.forEach((value, key) => { requestHeaders[key] = value; });
39
+
40
+ return new Promise<Response>((resolve, reject) => {
41
+ if (signal?.aborted) {
42
+ reject(signal.reason instanceof Error ? signal.reason : new Error("aborted"));
43
+ return;
44
+ }
45
+
46
+ let settled = false;
47
+ const fail = (error: unknown) => {
48
+ try { req.destroy(); } catch { /* ignore */ }
49
+ if (settled) return;
50
+ settled = true;
51
+ reject(error instanceof Error ? error : new Error(String(error)));
52
+ };
53
+ const requestOptions: RequestOptions & { servername?: string } = {
54
+ protocol: parsed.protocol,
55
+ hostname: parsed.hostname,
56
+ port: parsed.port || (parsed.protocol === "https:" ? 443 : 80),
57
+ path: `${parsed.pathname}${parsed.search}`,
58
+ method,
59
+ headers: requestHeaders,
60
+ ...(parsed.protocol === "https:"
61
+ ? {
62
+ servername: parsed.hostname,
63
+ rejectUnauthorized: options?.rejectUnauthorized ?? true,
64
+ }
65
+ : {}),
66
+ lookup(_hostname, lookupOptions, callback) {
67
+ const opts = typeof lookupOptions === "function" ? undefined : lookupOptions;
68
+ const cb = typeof lookupOptions === "function" ? lookupOptions : callback;
69
+ if (!cb) return;
70
+ if (opts && typeof opts === "object" && "all" in opts && opts.all) {
71
+ (cb as (error: NodeJS.ErrnoException | null, addresses: PinnedAddress[]) => void)(
72
+ null,
73
+ [{ address: pinned.address, family: pinned.family }],
74
+ );
75
+ return;
76
+ }
77
+ (cb as (error: NodeJS.ErrnoException | null, address: string, family: 4 | 6) => void)(
78
+ null,
79
+ pinned.address,
80
+ pinned.family as 4 | 6,
81
+ );
82
+ },
83
+ };
84
+
85
+ const onResponse = (response: IncomingMessage) => {
86
+ const status = response.statusCode ?? 0;
87
+ const responseHeaders = new Headers();
88
+ for (const [key, value] of Object.entries(response.headers)) {
89
+ if (value === undefined || value === null) continue;
90
+ if (Array.isArray(value)) {
91
+ for (const item of value) responseHeaders.append(key, String(item));
92
+ } else {
93
+ responseHeaders.set(key, String(value));
94
+ }
95
+ }
96
+
97
+ if (status < 200 || status >= 300) {
98
+ try { response.destroy(); } catch { /* ignore */ }
99
+ try { req.destroy(); } catch { /* ignore */ }
100
+ if (settled) return;
101
+ settled = true;
102
+ resolve(new Response(null, { status, headers: responseHeaders }));
103
+ return;
104
+ }
105
+
106
+ let received = 0;
107
+ const stream = new ReadableStream<Uint8Array>({
108
+ start(controller) {
109
+ response.setTimeout(idleTimeoutMs, () => {
110
+ const error = new Error(`${context} stalled`);
111
+ fail(error);
112
+ try { controller.error(error); } catch { /* closed */ }
113
+ });
114
+ response.on("data", (chunk: Buffer | string) => {
115
+ const buffer = typeof chunk === "string" ? Buffer.from(chunk) : chunk;
116
+ received += buffer.byteLength;
117
+ if (maxBytes !== undefined && received > maxBytes) {
118
+ const error = new Error(`${context} exceeds ${maxBytes} byte cap`);
119
+ fail(error);
120
+ try { controller.error(error); } catch { /* closed */ }
121
+ return;
122
+ }
123
+ try { controller.enqueue(buffer); } catch { /* closed */ }
124
+ });
125
+ response.on("end", () => {
126
+ try { controller.close(); } catch { /* closed */ }
127
+ });
128
+ response.on("error", (error: Error) => {
129
+ fail(error);
130
+ try { controller.error(error); } catch { /* closed */ }
131
+ });
132
+ },
133
+ cancel() {
134
+ req.destroy();
135
+ },
136
+ });
137
+
138
+ if (settled) return;
139
+ settled = true;
140
+ resolve(new Response(stream, { status, headers: responseHeaders }));
141
+ };
142
+
143
+ const requestFn = parsed.protocol === "https:" ? https.request : http.request;
144
+ const req = requestFn(requestOptions, onResponse);
145
+ const onAbort = () => fail(signal?.reason instanceof Error ? signal.reason : new Error("aborted"));
146
+ signal?.addEventListener("abort", onAbort, { once: true });
147
+ req.setTimeout(idleTimeoutMs, () => fail(new Error(`${context} timed out`)));
148
+ req.on("error", error => {
149
+ signal?.removeEventListener("abort", onAbort);
150
+ fail(error);
151
+ });
152
+ req.on("close", () => signal?.removeEventListener("abort", onAbort));
153
+ req.end(body);
154
+ });
155
+ }
156
+
157
+ /**
158
+ * GET a URL through one previously validated address. The original hostname
159
+ * remains authoritative for Host, SNI, and certificate verification.
160
+ */
161
+ export function pinnedHttpGet(
162
+ url: string,
163
+ pinned: PinnedAddress,
164
+ signal?: AbortSignal,
165
+ options?: PinnedHttpRequestOptions,
166
+ ): Promise<Response> {
167
+ return pinnedHttpRequest(url, pinned, "GET", undefined, signal, options);
168
+ }
169
+
170
+ /**
171
+ * POST a string body through one previously validated address. The original
172
+ * hostname remains authoritative for Host, SNI, and certificate verification.
173
+ */
174
+ export function pinnedHttpPost(
175
+ url: string,
176
+ pinned: PinnedAddress,
177
+ body: string,
178
+ signal?: AbortSignal,
179
+ options?: PinnedHttpRequestOptions,
180
+ ): Promise<Response> {
181
+ return pinnedHttpRequest(url, pinned, "POST", body, signal, options);
182
+ }
@@ -0,0 +1,20 @@
1
+ export function maskEmail(value: string | null | undefined): string | null {
2
+ if (!value) return null;
3
+ const at = value.indexOf("@");
4
+ if (at <= 0) return value;
5
+ const local = value.slice(0, at);
6
+ const domain = value.slice(at + 1);
7
+ if (!domain) return value;
8
+ if (local.length === 1) return `*@${domain}`;
9
+ if (local.length === 2) return `${local[0]}*@${domain}`;
10
+ return `${local[0]}***${local[local.length - 1]}@${domain}`;
11
+ }
12
+
13
+ export function maskAccountId(value: string | null | undefined): string | null {
14
+ if (!value) return null;
15
+ const id = value.trim();
16
+ if (!id) return null;
17
+ // Short IDs would disclose the entire identifier via the suffix; use a non-identifying placeholder.
18
+ if (id.length <= 4) return "account-…";
19
+ return `account-…${id.slice(-4)}`;
20
+ }
@@ -0,0 +1,168 @@
1
+ import { execFileSync } from "node:child_process";
2
+ import { loadConfig, readRuntimePort } from "../config";
3
+ import { configuredAdminToken } from "./admin-secrets";
4
+
5
+ export function isProcessAlive(pid: number): boolean {
6
+ try {
7
+ process.kill(pid, 0);
8
+ return true;
9
+ } catch {
10
+ return false;
11
+ }
12
+ }
13
+
14
+ export function waitForExit(pid: number, timeoutMs: number): boolean {
15
+ const deadline = Date.now() + timeoutMs;
16
+ const marker = new Int32Array(new SharedArrayBuffer(4));
17
+ while (Date.now() < deadline) {
18
+ if (!isProcessAlive(pid)) return true;
19
+ Atomics.wait(marker, 0, 0, 50);
20
+ }
21
+ return !isProcessAlive(pid);
22
+ }
23
+
24
+ /** Injectable seams so the graceful-stop flow is unit-testable without a live proxy. */
25
+ export interface GracefulStopIo {
26
+ fetchFn?: typeof fetch;
27
+ readRuntime?: (pid: number) => { port: number; hostname?: string } | null;
28
+ waitExit?: (pid: number, timeoutMs: number) => boolean;
29
+ env?: Record<string, string | undefined>;
30
+ exitTimeoutMs?: number;
31
+ }
32
+
33
+ /**
34
+ * Host to POST /api/stop against: follow the recorded bind hostname when it names a
35
+ * concrete address (a proxy bound to ::1 or a LAN IP is unreachable on 127.0.0.1);
36
+ * loopback aliases and wildcard binds all answer on IPv4 loopback.
37
+ */
38
+ export function gracefulStopHost(hostname: string | undefined): string {
39
+ const trimmed = (hostname ?? "").trim();
40
+ const lower = trimmed.toLowerCase();
41
+ if (!trimmed || lower === "localhost" || trimmed === "127.0.0.1" || trimmed === "0.0.0.0" || trimmed === "::" || trimmed === "[::]") {
42
+ return "127.0.0.1";
43
+ }
44
+ if (lower === "::1" || lower === "[::1]") return "[::1]";
45
+ if (trimmed.startsWith("[") && trimmed.endsWith("]")) return trimmed;
46
+ return trimmed.includes(":") ? `[${trimmed}]` : trimmed;
47
+ }
48
+
49
+ /**
50
+ * Outcome of a graceful stop attempt. `"refused"` is distinct from failure: the proxy answered
51
+ * that it must NOT be stopped from here, so callers must not escalate to a forced kill.
52
+ */
53
+ export type GracefulStopResult = boolean | "refused";
54
+
55
+ /** A proxy declined shutdown because a service under another home owns it (HTTP 409). */
56
+ export class ProxyOwnershipRefusedError extends Error {}
57
+
58
+ /**
59
+ * Ask a running proxy to stop itself via the management API (`POST /api/stop`), which
60
+ * drains in-flight turns, restores native Codex, and cleans its pid/runtime files.
61
+ * This is the only way to get a GRACEFUL stop on Windows, where the POSIX
62
+ * SIGTERM-then-SIGKILL ladder does not exist and `taskkill /F` gives the proxy no
63
+ * chance to run its shutdown handlers. Returns false when the proxy can't be reached
64
+ * or doesn't exit in time — callers fall back to {@link killProxy}. Returns `"refused"`
65
+ * when the proxy declines the stop (HTTP 409), which callers must NOT force past.
66
+ */
67
+ export async function stopProxyGracefully(pid: number, io: GracefulStopIo = {}): Promise<GracefulStopResult> {
68
+ const readRuntime = io.readRuntime ?? readRuntimePort;
69
+ const runtime = readRuntime(pid);
70
+ if (!runtime?.port) return false;
71
+ const env = io.env ?? process.env;
72
+ const headers: Record<string, string> = {};
73
+ const token = configuredAdminToken(env.OPENCODEX_HOME?.trim() || undefined, env as NodeJS.ProcessEnv);
74
+ if (token) headers["x-opencodex-api-key"] = token;
75
+ const fetchFn = io.fetchFn ?? fetch;
76
+ try {
77
+ const res = await fetchFn(`http://${gracefulStopHost(runtime.hostname)}:${runtime.port}/api/stop`, {
78
+ method: "POST",
79
+ headers,
80
+ // Hung proxies with many CLOSE_WAIT clients can be slow to accept; give them
81
+ // longer than a health poll so we prefer drain over taskkill /F.
82
+ signal: AbortSignal.timeout(io.exitTimeoutMs ? Math.min(io.exitTimeoutMs, 10_000) : 10_000),
83
+ });
84
+ // 409 is the proxy REFUSING to stop (a service installed under another home owns it and
85
+ // would respawn it anyway). That is a policy answer, not a dead endpoint — escalating to
86
+ // SIGTERM here would run the daemon's cleanup and strip shared config out from under the
87
+ // still-running service. Report the refusal instead of forcing.
88
+ if (res.status === 409) return "refused";
89
+ if (!res.ok) return false;
90
+ } catch {
91
+ return false;
92
+ }
93
+ const waitExit = io.waitExit ?? waitForExit;
94
+ // Honor the server's own drain window: /api/stop answers 200 first, then drains for
95
+ // config.shutdownTimeoutMs. Waiting less than that hard-kills mid-drain.
96
+ const exitTimeoutMs = io.exitTimeoutMs ?? drainDeadlineMs();
97
+ return waitExit(pid, exitTimeoutMs);
98
+ }
99
+
100
+ function drainDeadlineMs(): number {
101
+ try {
102
+ return (loadConfig().shutdownTimeoutMs ?? 5000) + 3000;
103
+ } catch {
104
+ return 8000;
105
+ }
106
+ }
107
+
108
+ /** Graceful-first stop: management-API drain, then the platform kill ladder. */
109
+ export async function stopProxy(pid: number): Promise<void> {
110
+ if (!isProcessAlive(pid)) return;
111
+ const runtime = readRuntimePort(pid);
112
+ const graceful = await stopProxyGracefully(pid);
113
+ if (graceful === "refused") {
114
+ // The proxy refused on purpose (foreign service owns it). Forcing would strip shared
115
+ // config while that service keeps the proxy alive.
116
+ throw new ProxyOwnershipRefusedError(
117
+ "The running proxy refused to stop: a service installed under a different "
118
+ + "CODEX_HOME/OPENCODEX_HOME owns it. Run the stop from that home.",
119
+ );
120
+ }
121
+ if (graceful) {
122
+ await waitForStoppedPort(runtime, pid);
123
+ return;
124
+ }
125
+ killProxy(pid);
126
+ await waitForStoppedPort(runtime, pid);
127
+ }
128
+
129
+ /** After stop/kill, wait for the former listen port to become bindable (Windows drain). */
130
+ async function waitForStoppedPort(
131
+ runtime: { port: number; hostname?: string } | null | undefined,
132
+ stoppedPid?: number,
133
+ ): Promise<void> {
134
+ if (!runtime?.port) return;
135
+ try {
136
+ const { reclaimListenPort } = await import("../server/port-reclaim");
137
+ await reclaimListenPort(runtime.port, runtime.hostname ?? "127.0.0.1", {
138
+ timeoutMs: 15_000,
139
+ intervalMs: 100,
140
+ scanIntervalMs: 500,
141
+ // Only the process we just stopped — never kill a newly started twin proxy.
142
+ killOcxHolders: !!(stoppedPid && stoppedPid > 0),
143
+ onlyKillPids: stoppedPid && stoppedPid > 0 ? [stoppedPid] : [],
144
+ });
145
+ } catch {
146
+ /* best-effort — callers that need a hard guarantee reclaim again before bind */
147
+ }
148
+ }
149
+
150
+ export function killProxy(pid: number): void {
151
+ if (!isProcessAlive(pid)) return;
152
+ if (process.platform === "win32") {
153
+ // Windows process.kill(SIGTERM/SIGINT) is TerminateProcess — not a graceful signal.
154
+ // Graceful drain happens only via stopProxyGracefully() (POST /api/stop). This path
155
+ // is the hard fallback: taskkill /T /F so the process tree exits (ghost LISTEN /
156
+ // CLOSE_WAIT are then cleared by reclaimListenPort / SetTcpEntry).
157
+ const taskkill = `${process.env.SystemRoot ?? "C:\\Windows"}\\System32\\taskkill.exe`;
158
+ try {
159
+ execFileSync(taskkill, ["/PID", String(pid), "/T", "/F"], { stdio: "pipe", windowsHide: true });
160
+ } catch (err) {
161
+ if (isProcessAlive(pid)) throw err;
162
+ }
163
+ } else {
164
+ process.kill(pid, "SIGTERM");
165
+ if (!waitForExit(pid, 5000)) process.kill(pid, "SIGKILL");
166
+ }
167
+ if (!waitForExit(pid, 5000)) throw new Error(`process ${pid} did not exit`);
168
+ }