@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,433 @@
1
+ /**
2
+ * Dashboard memory-card drain-and-restart (#563).
3
+ *
4
+ * Longer than POST /api/stop's short drain: waits up to 60s for active turns,
5
+ * then respawns. Never runs restoreNativeCodex / stripGrokConfig — this is a
6
+ * recycle to reclaim RSS, not a teardown.
7
+ *
8
+ * Respawn policy (matches real supervisor configs in src/service.ts):
9
+ * - Supervised child (`OCX_SERVICE=1` + viable service): exit(1) so
10
+ * failure-only supervisors (systemd Restart=on-failure, WinSW onfailure,
11
+ * Task Scheduler ERRORLEVEL loop) bring the proxy back.
12
+ * - Otherwise: detached `rmx start --port <live>` (bypasses ensure's
13
+ * codexAutoStart gate), mark recycle so exit cleanup keeps injection, exit(0).
14
+ * Installed-but-stale/missing service assets are NOT treated as supervised —
15
+ * exit(1) would leave the proxy dead with `Service: installed, stale or missing
16
+ * service assets` and a /healthz timeout.
17
+ * - If detached spawn fails (sync throw or pre-start `error`): exit(1) without
18
+ * markRecycling — after drain the listen socket is already closed, so a latch
19
+ * reset cannot recover serving. Clear inherited `OCX_SERVICE` so exit cleanup
20
+ * can restore Codex/Grok fences when a stale service marker has no viable
21
+ * supervisor. Log only a stable errno code — never the raw message
22
+ * (paths in ENOENT often include the OS username).
23
+ */
24
+ import { spawn } from "node:child_process";
25
+ import {
26
+ beginShutdownDrain,
27
+ drainAndShutdown,
28
+ getActiveTurnCount,
29
+ getServerListenPort,
30
+ isDraining,
31
+ isShutdownDraining,
32
+ markRecyclingForExit,
33
+ stopServerListener,
34
+ } from "../lifecycle";
35
+ import { isServiceViable } from "../../service";
36
+ import { readRuntimePort } from "../../config";
37
+ import { withProcessRuntimeProvenance } from "../../lib/bun-runtime";
38
+ import {
39
+ MEMORY_DRAIN_RESTART_MS,
40
+ REPLACEMENT_READY_TIMEOUT_MS,
41
+ } from "../../lib/system-restart-contract";
42
+ import { findLiveProxy } from "../proxy-liveness";
43
+
44
+ export { MEMORY_DRAIN_RESTART_MS, REPLACEMENT_READY_TIMEOUT_MS } from "../../lib/system-restart-contract";
45
+ export const DEADLINE_LISTENER_STOP_TIMEOUT_MS = 5_000;
46
+ const REPLACEMENT_READY_POLL_MS = 150;
47
+
48
+ export interface ReplacementReadinessIo {
49
+ findLive?: typeof findLiveProxy;
50
+ now?: () => number;
51
+ sleep?: (ms: number) => Promise<void>;
52
+ }
53
+
54
+ export interface SystemRestartIo {
55
+ drainAndShutdown?: typeof drainAndShutdown;
56
+ /** True when a background service can actually respawn this process after exit(1). */
57
+ isServiceViable?: () => boolean;
58
+ isSupervisedServiceChild?: () => boolean;
59
+ /** Ordinary start; deadline handoff may defer health until parent exit releases OS locks. */
60
+ spawnStart?: (port?: number, waitForHealthBeforeParentExit?: boolean) => void | Promise<void>;
61
+ /** Idempotent listener close; must settle before an ordinary start is spawned. */
62
+ stopListener?: () => void | Promise<void>;
63
+ markRecycling?: () => void;
64
+ exitProcess?: (code: number) => void;
65
+ schedule?: (fn: () => void | Promise<void>, ms: number) => void;
66
+ scheduleDeadline?: (fn: () => void, ms: number) => () => void;
67
+ isDraining?: () => boolean;
68
+ isShutdownDraining?: () => boolean;
69
+ beginShutdownDrain?: () => boolean;
70
+ setDraining?: (value: boolean) => void;
71
+ getActiveTurnCount?: () => number;
72
+ listenPort?: () => number | undefined;
73
+ now?: () => number;
74
+ }
75
+
76
+ let restartIo: SystemRestartIo = {};
77
+ /** Prevents double-scheduling in the 200ms window before drainAndShutdown sets draining. */
78
+ let restartAccepted = false;
79
+
80
+ type RestartDrainOutcome = "completed" | "rejected" | "deadline";
81
+ type BoundedSettlementOutcome = "completed" | "rejected" | "deadline";
82
+
83
+ function waitForRestartDrain(
84
+ drainPromise: Promise<void>,
85
+ deadlineMs: number,
86
+ now: () => number,
87
+ scheduleDeadline: NonNullable<SystemRestartIo["scheduleDeadline"]>,
88
+ ): Promise<RestartDrainOutcome> {
89
+ const remainingMs = Math.max(0, deadlineMs - now());
90
+ if (remainingMs === 0) {
91
+ // Observe any late rejection even though orchestration is already terminal.
92
+ void drainPromise.catch(() => {});
93
+ return Promise.resolve("deadline");
94
+ }
95
+ return new Promise<RestartDrainOutcome>((resolve) => {
96
+ let settled = false;
97
+ let cancelDeadline: (() => void) | undefined;
98
+ const finish = (outcome: RestartDrainOutcome) => {
99
+ if (settled) return;
100
+ settled = true;
101
+ cancelDeadline?.();
102
+ resolve(outcome);
103
+ };
104
+ cancelDeadline = scheduleDeadline(() => finish("deadline"), remainingMs);
105
+ if (settled) cancelDeadline();
106
+ void drainPromise.then(
107
+ () => finish("completed"),
108
+ () => finish("rejected"),
109
+ );
110
+ });
111
+ }
112
+
113
+ function waitForBoundedSettlement(
114
+ promise: Promise<void>,
115
+ timeoutMs: number,
116
+ scheduleDeadline: NonNullable<SystemRestartIo["scheduleDeadline"]>,
117
+ ): Promise<BoundedSettlementOutcome> {
118
+ return new Promise<BoundedSettlementOutcome>((resolve) => {
119
+ let settled = false;
120
+ let cancelDeadline: (() => void) | undefined;
121
+ const finish = (outcome: BoundedSettlementOutcome) => {
122
+ if (settled) return;
123
+ settled = true;
124
+ cancelDeadline?.();
125
+ resolve(outcome);
126
+ };
127
+ cancelDeadline = scheduleDeadline(() => finish("deadline"), timeoutMs);
128
+ if (settled) cancelDeadline();
129
+ void promise.then(
130
+ () => finish("completed"),
131
+ () => finish("rejected"),
132
+ );
133
+ });
134
+ }
135
+
136
+ /** Test seam — reset between tests. */
137
+ export function setSystemRestartIoForTests(io: SystemRestartIo = {}): void {
138
+ restartIo = io;
139
+ restartAccepted = false;
140
+ }
141
+
142
+ function resolveListenPort(): number | undefined {
143
+ const live = getServerListenPort();
144
+ if (live) return live;
145
+ const runtime = readRuntimePort(process.pid);
146
+ if (runtime && runtime.port > 0) return runtime.port;
147
+ return undefined;
148
+ }
149
+
150
+ function isSupervisedServiceChild(io: SystemRestartIo = {}): boolean {
151
+ if (process.env.OCX_SERVICE !== "1") return false;
152
+ // Presence is not enough: stale/missing service assets report installed but will not
153
+ // respawn after exit(1). Dashboard status/recovery must fall through to detached start.
154
+ return (io.isServiceViable ?? isServiceViable)();
155
+ }
156
+
157
+ /** Stable, path-free spawn failure label for logs (never interpolate err.message). */
158
+ function spawnFailureCode(err: unknown): string {
159
+ if (err && typeof err === "object" && "code" in err) {
160
+ const code = (err as NodeJS.ErrnoException).code;
161
+ if (typeof code === "string" && code.length > 0 && code.length <= 64) return code;
162
+ }
163
+ return "spawn_failed";
164
+ }
165
+
166
+ function handoffError(code: string): NodeJS.ErrnoException {
167
+ const error = new Error(code) as NodeJS.ErrnoException;
168
+ error.code = code;
169
+ return error;
170
+ }
171
+
172
+ export async function waitForReplacementReady(
173
+ expectedPid: number | undefined,
174
+ parentPid: number,
175
+ expectedPort: number | undefined,
176
+ io: ReplacementReadinessIo = {},
177
+ ): Promise<boolean> {
178
+ const findLive = io.findLive ?? findLiveProxy;
179
+ const now = io.now ?? Date.now;
180
+ const sleep = io.sleep ?? Bun.sleep;
181
+ const deadline = now() + REPLACEMENT_READY_TIMEOUT_MS;
182
+ while (now() < deadline) {
183
+ try {
184
+ const live = await findLive({
185
+ deadlineAt: deadline,
186
+ nowFn: now,
187
+ sleepFn: sleep,
188
+ });
189
+ // A probe that began within budget can still return after it. Never accept
190
+ // delayed health as proof once the shared absolute handoff budget expired.
191
+ if (now() >= deadline) return false;
192
+ if (
193
+ live
194
+ && live.pid !== null
195
+ && live.pid !== parentPid
196
+ && (expectedPid === undefined || live.pid === expectedPid)
197
+ && (expectedPort === undefined || live.port === expectedPort)
198
+ ) {
199
+ return true;
200
+ }
201
+ } catch {
202
+ // A not-yet-bound replacement is indistinguishable from a transient
203
+ // liveness failure here; keep polling inside the one bounded window.
204
+ }
205
+ const remainingMs = deadline - now();
206
+ if (remainingMs <= 0) break;
207
+ await sleep(Math.min(REPLACEMENT_READY_POLL_MS, remainingMs));
208
+ }
209
+ return false;
210
+ }
211
+
212
+ function spawnDetachedStart(
213
+ port?: number,
214
+ waitForHealthBeforeParentExit = true,
215
+ ): Promise<void> {
216
+ const args = [process.argv[1], "start"];
217
+ const expectedPort = typeof port === "number" && Number.isFinite(port) && port > 0 && port <= 65535
218
+ ? Math.trunc(port)
219
+ : undefined;
220
+ if (expectedPort !== undefined) {
221
+ args.push("--port", String(expectedPort));
222
+ }
223
+ return new Promise<void>((resolve, reject) => {
224
+ let child: ReturnType<typeof spawn>;
225
+ try {
226
+ const env: NodeJS.ProcessEnv = { ...process.env };
227
+ delete env.OCX_SERVICE;
228
+ child = spawn(process.execPath, args, {
229
+ detached: true,
230
+ stdio: "ignore",
231
+ windowsHide: true,
232
+ env: withProcessRuntimeProvenance(env),
233
+ });
234
+ } catch (err) {
235
+ reject(err);
236
+ return;
237
+ }
238
+ let settled = false;
239
+ const cleanup = () => {
240
+ child.off("error", onError);
241
+ child.off("exit", onExit);
242
+ child.off("spawn", onSpawn);
243
+ };
244
+ const finish = (error?: unknown) => {
245
+ if (settled) return;
246
+ settled = true;
247
+ cleanup();
248
+ if (error !== undefined) {
249
+ if (child.exitCode === null && child.signalCode === null) {
250
+ try { child.kill(); } catch { /* best-effort failed-start cleanup */ }
251
+ }
252
+ try { child.unref(); } catch { /* best-effort */ }
253
+ reject(error);
254
+ return;
255
+ }
256
+ child.unref();
257
+ resolve();
258
+ };
259
+ const onError = (err: Error) => { finish(err); };
260
+ const onExit = () => { finish(handoffError("child_exit")); };
261
+ const onSpawn = () => {
262
+ if (!waitForHealthBeforeParentExit) {
263
+ // A deadline may have been caused by native-main ownership cleanup.
264
+ // Let the ordinary child survive parent exit, which releases those OS locks.
265
+ finish();
266
+ return;
267
+ }
268
+ void waitForReplacementReady(child.pid, process.pid, expectedPort).then(
269
+ ready => {
270
+ if (!ready) {
271
+ console.warn(
272
+ "Drain-and-restart replacement is still alive after the readiness window; allowing it to continue after parent exit",
273
+ );
274
+ }
275
+ // Never kill a live ordinary start at its valid reclaim boundary. Parent
276
+ // exit is the final resource release the child may still be waiting for.
277
+ finish();
278
+ },
279
+ err => finish(err),
280
+ );
281
+ };
282
+ child.once("error", onError);
283
+ child.once("exit", onExit);
284
+ child.once("spawn", onSpawn);
285
+ });
286
+ }
287
+
288
+ async function completeDeferredParentExitHandoff(
289
+ io: SystemRestartIo,
290
+ exitProcess: (code: number) => void,
291
+ port: number | undefined,
292
+ phase: "deadline" | "listener-stop fallback",
293
+ ): Promise<void> {
294
+ try {
295
+ await (io.spawnStart ?? spawnDetachedStart)(port, false);
296
+ } catch (err) {
297
+ console.warn(
298
+ `Drain-and-restart ${phase} spawn failed (${spawnFailureCode(err)}); exiting without replacement`,
299
+ );
300
+ delete process.env.OCX_SERVICE;
301
+ exitProcess(1);
302
+ return;
303
+ }
304
+ (io.markRecycling ?? markRecyclingForExit)();
305
+ exitProcess(0);
306
+ }
307
+
308
+ async function completeDeadlineRestartHandoff(
309
+ io: SystemRestartIo,
310
+ exitProcess: (code: number) => void,
311
+ port: number | undefined,
312
+ scheduleDeadline: NonNullable<SystemRestartIo["scheduleDeadline"]>,
313
+ ): Promise<void> {
314
+ const supervised = (io.isSupervisedServiceChild ?? (() => isSupervisedServiceChild(io)))();
315
+ if (supervised) {
316
+ // Failure-only supervisors ignore exit(0); intentional non-zero triggers respawn.
317
+ exitProcess(1);
318
+ return;
319
+ }
320
+
321
+ const stopPromise = Promise.resolve().then(
322
+ () => (io.stopListener ?? (() => stopServerListener()))(),
323
+ );
324
+ const stopOutcome = await waitForBoundedSettlement(
325
+ stopPromise,
326
+ DEADLINE_LISTENER_STOP_TIMEOUT_MS,
327
+ scheduleDeadline,
328
+ );
329
+ if (stopOutcome === "rejected") {
330
+ console.warn("Drain-and-restart deadline listener stop failed; continuing parent-exit handoff");
331
+ } else if (stopOutcome === "deadline") {
332
+ console.warn("Drain-and-restart deadline listener stop timed out; continuing parent-exit handoff");
333
+ }
334
+ // The ordinary child must survive parent exit: a failed/pending socket close
335
+ // or overdue cleanup is completed by process teardown, without a hidden mode.
336
+ await completeDeferredParentExitHandoff(io, exitProcess, port, "deadline");
337
+ }
338
+
339
+ /**
340
+ * Accept a drain-and-restart request. Returns immediately; the drain +
341
+ * respawn runs on a short timer so the HTTP response can flush first.
342
+ * Idempotent while already draining: returns the accepted shape again.
343
+ */
344
+ export function acceptSystemRestart(io: SystemRestartIo = restartIo): {
345
+ accepted: true;
346
+ alreadyDraining: boolean;
347
+ activeTurnCount: number;
348
+ drainTimeoutMs: number;
349
+ } {
350
+ const shutdownActive = io.isShutdownDraining
351
+ ?? io.isDraining
352
+ ?? isShutdownDraining;
353
+ const alreadyDraining = restartAccepted || shutdownActive();
354
+ const activeTurnCount = (io.getActiveTurnCount ?? getActiveTurnCount)();
355
+ const schedule = io.schedule ?? ((fn, ms) => { setTimeout(() => { void fn(); }, ms); });
356
+
357
+ if (!alreadyDraining) {
358
+ restartAccepted = true;
359
+ const now = io.now ?? Date.now;
360
+ const restartDeadlineMs = now() + MEMORY_DRAIN_RESTART_MS;
361
+ // Reject new data-plane traffic immediately (503), before the 200ms response-flush delay.
362
+ if (io.beginShutdownDrain) io.beginShutdownDrain();
363
+ else if (io.setDraining) io.setDraining(true);
364
+ else beginShutdownDrain();
365
+ schedule(async () => {
366
+ // Preserve the live binding before drainAndShutdown (or its deadline race)
367
+ // closes the listener and makes both the server ref and runtime metadata stale.
368
+ const restartPort = (io.listenPort ?? resolveListenPort)();
369
+ const drain = io.drainAndShutdown ?? drainAndShutdown;
370
+ const remainingMs = Math.max(0, restartDeadlineMs - now());
371
+ const drainPromise = Promise.resolve().then(() => drain(undefined, remainingMs));
372
+ const scheduleDeadline = io.scheduleDeadline ?? ((fn, ms) => {
373
+ const timer = setTimeout(fn, ms);
374
+ return () => clearTimeout(timer);
375
+ });
376
+ const drainOutcome = await waitForRestartDrain(drainPromise, restartDeadlineMs, now, scheduleDeadline);
377
+ const exitProcess = io.exitProcess ?? ((code: number) => { process.exit(code); });
378
+ if (drainOutcome === "deadline") {
379
+ console.warn("Drain-and-restart deadline expired; forcing terminal restart handoff");
380
+ await completeDeadlineRestartHandoff(io, exitProcess, restartPort, scheduleDeadline);
381
+ return;
382
+ }
383
+ if (drainOutcome === "rejected") {
384
+ // drainAndShutdown stops the listener in finally. Even if ancillary cleanup
385
+ // rejects, an accepted restart must still reach replacement or terminal exit.
386
+ console.warn("Drain-and-restart cleanup failed; continuing terminal restart handoff");
387
+ }
388
+ const supervised = (io.isSupervisedServiceChild ?? (() => isSupervisedServiceChild(io)))();
389
+ if (supervised) {
390
+ // Failure-only supervisors ignore exit(0); intentional non-zero triggers respawn.
391
+ (io.exitProcess ?? ((code: number) => { process.exit(code); }))(1);
392
+ return;
393
+ }
394
+ try {
395
+ await (io.stopListener ?? (() => stopServerListener()))();
396
+ } catch {
397
+ console.warn("Drain-and-restart listener stop failed; continuing parent-exit handoff");
398
+ await completeDeferredParentExitHandoff(
399
+ io,
400
+ exitProcess,
401
+ restartPort,
402
+ "listener-stop fallback",
403
+ );
404
+ return;
405
+ }
406
+ try {
407
+ // A rejected drain has uncertain cleanup ownership, so it uses the same
408
+ // parent-exit handoff as a deadline. Only a fully completed drain waits
409
+ // for replacement health in the old process.
410
+ await (io.spawnStart ?? spawnDetachedStart)(restartPort, drainOutcome === "completed");
411
+ } catch (err) {
412
+ console.warn(
413
+ `⚠️ Drain-and-restart spawn failed (${spawnFailureCode(err)}); exiting without replacement`,
414
+ );
415
+ // Listen socket is already stopped; do not markRecycling — no child to inherit fences.
416
+ // No replacement inherited the routing. Clear a stale service marker so
417
+ // this unsupervised parent restores clients after the failed handoff.
418
+ delete process.env.OCX_SERVICE;
419
+ exitProcess(1);
420
+ return;
421
+ }
422
+ (io.markRecycling ?? markRecyclingForExit)();
423
+ exitProcess(0);
424
+ }, 200);
425
+ }
426
+
427
+ return {
428
+ accepted: true,
429
+ alreadyDraining,
430
+ activeTurnCount,
431
+ drainTimeoutMs: MEMORY_DRAIN_RESTART_MS,
432
+ };
433
+ }
@@ -0,0 +1,141 @@
1
+ /**
2
+ * /api/system/* — service-process runtime/memory introspection (#314 WP3)
3
+ * and the memory-card drain-and-restart action (#563).
4
+ *
5
+ * Rides the standard management gate: every /api/* request already passed
6
+ * the independent management-auth gate + the origin check before dispatch, so these
7
+ * routes add no auth of their own. NEVER expose this data on the
8
+ * unauthenticated /healthz surface.
9
+ *
10
+ * The payload is scalar-only (numbers, enum strings, booleans): no paths, no
11
+ * tokens, no account identifiers. `external` and `arrayBuffers` keep Windows
12
+ * diagnostics honest when RSS/working-set counters under-report committed
13
+ * retention. `jscHeap` (bun:jsc heapStats) is useful context, but on Bun 1.3.14
14
+ * it is not a standalone leak discriminator. `responseState` attributes growth
15
+ * further: it is the proxy's previous_response_id continuation store, so a
16
+ * growing responseState.totalBytes under rising observed memory points at
17
+ * conversation retention rather than the runtime allocator. Spill counts,
18
+ * payload-byte totals, tombstones, and failure counters remain finite scalars;
19
+ * response ids, filenames, digests, paths, and payload content never leave the owner.
20
+ *
21
+ * `activeTurnCount` / `isDraining` are scalar lifecycle counters for the
22
+ * dashboard drain-and-restart confirm UX — never request bodies or IDs.
23
+ */
24
+ import { selectEagerPath } from "../../lib/bun-stream-caps";
25
+ import { reportedBunRuntimeSource } from "../../lib/bun-runtime";
26
+ import { getActiveTurnCount, isDraining } from "../lifecycle";
27
+ import { getActiveMemoryWatchdog, observedMemoryCounter } from "../memory-watchdog";
28
+ import { responseStateMetrics } from "../../responses/state";
29
+ import { appOwnedBytesSnapshot } from "../../lib/app-owned-memory";
30
+ import {
31
+ SYSTEM_RESTART_EXPECTED_PID_HEADER,
32
+ parseExpectedSystemRestartPid,
33
+ } from "../../lib/system-restart-contract";
34
+ import { jsonResponse } from "../auth-cors";
35
+ import { getInspectionCounters } from "../relay";
36
+ import type { ManagementContext } from "./context";
37
+ import { acceptSystemRestart } from "./system-restart";
38
+
39
+ const ENDPOINT_SAMPLE_LIMIT = 60;
40
+
41
+ export async function handleSystemRoutes(ctx: ManagementContext): Promise<Response | null> {
42
+ const { req, url, config } = ctx;
43
+ if (url.pathname === "/api/system/memory" && req.method === "GET") {
44
+ const usage = process.memoryUsage();
45
+ let jscHeap: { heapSize: number; heapCapacity: number; objectCount: number } | null = null;
46
+ try {
47
+ const { heapStats } = await import("bun:jsc");
48
+ const stats = heapStats();
49
+ jscHeap = {
50
+ heapSize: stats.heapSize,
51
+ heapCapacity: stats.heapCapacity,
52
+ objectCount: stats.objectCount,
53
+ };
54
+ } catch {
55
+ /* non-Bun tooling or unavailable introspection — omit the discriminator */
56
+ }
57
+ const watchdogInstance = getActiveMemoryWatchdog();
58
+ const observed = observedMemoryCounter({
59
+ rss: usage.rss,
60
+ external: usage.external,
61
+ arrayBuffers: usage.arrayBuffers,
62
+ });
63
+ const watchdog = watchdogInstance
64
+ ? (() => {
65
+ const snap = watchdogInstance.snapshot();
66
+ return {
67
+ warnThresholdBytes: snap.warnThresholdBytes,
68
+ lastWarnAt: snap.lastWarnAt,
69
+ observedBytes: snap.observedBytes,
70
+ observedMetric: snap.observedMetric,
71
+ samples: snap.samples.slice(-ENDPOINT_SAMPLE_LIMIT),
72
+ };
73
+ })()
74
+ : null;
75
+ const streamMode = config.streamMode ?? "auto";
76
+ /**
77
+ * No request-specific rewrite context exists on this route, so report the
78
+ * effective no-client-rewrite baseline. Individual rewrite requests still
79
+ * stay on tee even when this baseline says eager.
80
+ */
81
+ const eagerRelay = selectEagerPath(process.platform, false, streamMode);
82
+ return jsonResponse({
83
+ pid: process.pid,
84
+ bunVersion: Bun.version,
85
+ bunRevision: Bun.revision,
86
+ // Recorded at launch, not resolved now: absent means "this service predates the
87
+ // marker", which callers must report as unknown rather than guess.
88
+ bunRuntimeSource: reportedBunRuntimeSource(),
89
+ platform: process.platform,
90
+ uptimeSeconds: process.uptime(),
91
+ rss: usage.rss,
92
+ heapUsed: usage.heapUsed,
93
+ heapTotal: usage.heapTotal,
94
+ external: usage.external,
95
+ arrayBuffers: usage.arrayBuffers,
96
+ observedBytes: observed.observedBytes,
97
+ observedMetric: observed.observedMetric,
98
+ jscHeap,
99
+ responseState: responseStateMetrics(),
100
+ appOwnedBytes: appOwnedBytesSnapshot(),
101
+ inspectionCounters: getInspectionCounters(),
102
+ streamMode,
103
+ eagerRelay,
104
+ watchdog,
105
+ activeTurnCount: getActiveTurnCount(),
106
+ isDraining: isDraining(),
107
+ });
108
+ }
109
+
110
+ if (url.pathname === "/api/system/restart" && req.method === "POST") {
111
+ const expectedPid = parseExpectedSystemRestartPid(
112
+ req.headers.get(SYSTEM_RESTART_EXPECTED_PID_HEADER),
113
+ );
114
+ if (expectedPid.kind === "invalid") {
115
+ return jsonResponse({
116
+ success: false,
117
+ error: "Invalid restart target identity.",
118
+ }, 400, req, config);
119
+ }
120
+ if (expectedPid.kind === "present" && expectedPid.pid !== process.pid) {
121
+ return jsonResponse({
122
+ success: false,
123
+ error: "Restart target identity changed.",
124
+ }, 409, req, config);
125
+ }
126
+
127
+ // Longer informed drain than /api/stop; does not tear down Codex/Grok injection.
128
+ const result = acceptSystemRestart();
129
+ return jsonResponse({
130
+ success: true,
131
+ message: result.alreadyDraining
132
+ ? "Drain already in progress."
133
+ : "Draining in-flight requests, then restarting.",
134
+ activeTurnCount: result.activeTurnCount,
135
+ drainTimeoutMs: result.drainTimeoutMs,
136
+ alreadyDraining: result.alreadyDraining,
137
+ }, 202, req, config);
138
+ }
139
+
140
+ return null;
141
+ }
@@ -0,0 +1,86 @@
1
+ import { enforceAppOwnedMemoryBudget, type RetainedStoreSnapshot } from "../../lib/app-owned-memory";
2
+ import type { UsageSummary } from "../../usage/summary";
3
+
4
+ export type CachedUsageSummary = UsageSummary & {
5
+ historyTruncated: boolean;
6
+ truncatedPrefixBytes: number;
7
+ entriesTruncated: boolean;
8
+ entriesDropped: number;
9
+ };
10
+
11
+ interface UsageSummaryCacheEntry {
12
+ revisionKey: string;
13
+ expiresAt: number;
14
+ summary: CachedUsageSummary;
15
+ revisionReadAt: number;
16
+ sizeBytes: number;
17
+ }
18
+
19
+ const usageSummaryCache = new Map<string, UsageSummaryCacheEntry>();
20
+ let usageSummaryCacheBytes = 0;
21
+ let oldestUsageSummaryKey: string | undefined;
22
+ let oldestUsageSummaryAt: number | null = null;
23
+
24
+ function recomputeOldestUsageSummary(): void {
25
+ oldestUsageSummaryKey = undefined;
26
+ oldestUsageSummaryAt = null;
27
+ for (const [key, entry] of usageSummaryCache) {
28
+ const readAt = entry.revisionReadAt;
29
+ if (oldestUsageSummaryAt !== null && readAt >= oldestUsageSummaryAt) continue;
30
+ oldestUsageSummaryKey = key;
31
+ oldestUsageSummaryAt = readAt;
32
+ }
33
+ }
34
+
35
+ function deleteUsageSummaryCacheEntry(key: string): number {
36
+ const entry = usageSummaryCache.get(key);
37
+ if (!entry) return 0;
38
+ usageSummaryCache.delete(key);
39
+ usageSummaryCacheBytes = Math.max(0, usageSummaryCacheBytes - entry.sizeBytes);
40
+ if (oldestUsageSummaryKey === key) recomputeOldestUsageSummary();
41
+ return entry.sizeBytes;
42
+ }
43
+
44
+ export function getUsageSummaryCacheEntry(key: string): UsageSummaryCacheEntry | undefined {
45
+ return usageSummaryCache.get(key);
46
+ }
47
+
48
+ export function discardUsageSummaryCacheEntry(key: string): number {
49
+ return deleteUsageSummaryCacheEntry(key);
50
+ }
51
+
52
+ export function setUsageSummaryCacheEntry(
53
+ key: string,
54
+ entry: Omit<UsageSummaryCacheEntry, "sizeBytes">,
55
+ ): void {
56
+ deleteUsageSummaryCacheEntry(key);
57
+ const sizeBytes = Buffer.byteLength(JSON.stringify({ key, ...entry }), "utf8");
58
+ usageSummaryCache.set(key, { ...entry, sizeBytes });
59
+ usageSummaryCacheBytes += sizeBytes;
60
+ if (oldestUsageSummaryAt === null || entry.revisionReadAt < oldestUsageSummaryAt) {
61
+ oldestUsageSummaryKey = key;
62
+ oldestUsageSummaryAt = entry.revisionReadAt;
63
+ }
64
+ enforceAppOwnedMemoryBudget();
65
+ }
66
+
67
+ export function usageSummaryRetainedStoreSnapshot(): RetainedStoreSnapshot {
68
+ return {
69
+ count: usageSummaryCache.size,
70
+ bytes: usageSummaryCacheBytes,
71
+ evictableBytes: usageSummaryCacheBytes,
72
+ pinnedBytes: 0,
73
+ oldestAt: oldestUsageSummaryAt,
74
+ };
75
+ }
76
+
77
+ export function evictOldestUsageSummaryForBudget(): number {
78
+ return oldestUsageSummaryKey === undefined ? 0 : deleteUsageSummaryCacheEntry(oldestUsageSummaryKey);
79
+ }
80
+
81
+ export function resetUsageSummaryCacheForTests(): void {
82
+ usageSummaryCache.clear();
83
+ usageSummaryCacheBytes = 0;
84
+ oldestUsageSummaryKey = undefined;
85
+ oldestUsageSummaryAt = null;
86
+ }