@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,377 @@
1
+ /**
2
+ * Source-backed routing analytics (RI-03).
3
+ *
4
+ * All metrics derive from the rebuildable request-history index
5
+ * (`routing-history.sqlite`), never from repeated full JSONL scans. The
6
+ * analysis is read-only: no routing decision, profile, or weight changes here
7
+ * (ADR-10 - no automatic self-tuning).
8
+ *
9
+ * Bounds: at most ANALYTICS_MAX_ROWS matching rows are analyzed per call; a
10
+ * larger population sets `historyTruncated: true` so readers never mistake a
11
+ * sample for the full history.
12
+ */
13
+
14
+ import type { PersistedUsageEntry, PersistedUsageAttempt } from "../usage/log";
15
+ import { estimateRequestCost, serviceTierContext } from "../usage/cost";
16
+ import { openRequestHistoryIndex, requestHistoryDb } from "./history/indexer";
17
+
18
+ export const ANALYTICS_MAX_ROWS = 50_000;
19
+ /** Default row cap for the management API (full cap remains available via `limit`). */
20
+ export const ANALYTICS_API_DEFAULT_ROWS = 5_000;
21
+
22
+ export interface RoutingAnalyticsFilters {
23
+ provider?: string;
24
+ model?: string;
25
+ profileId?: string;
26
+ surface?: string;
27
+ from?: number;
28
+ to?: number;
29
+ }
30
+
31
+ export type AnalyticsConfidence = "high" | "medium" | "low";
32
+
33
+ export interface AnalyticsBreakdownRow {
34
+ provider: string;
35
+ model: string;
36
+ accountRef?: string;
37
+ profileId?: string;
38
+ requests: number;
39
+ successes: number;
40
+ failures: number;
41
+ cancelled: number;
42
+ successRate: number | null;
43
+ p50DurationMs?: number;
44
+ estimatedCostUsdPerSuccessfulRequest?: number | null;
45
+ }
46
+
47
+ export interface AnalyticsProfileRow {
48
+ profileId: string;
49
+ profileRevision?: string;
50
+ requests: number;
51
+ successes: number;
52
+ failures: number;
53
+ fallbacks: number;
54
+ successRate: number | null;
55
+ }
56
+
57
+ export interface RoutingAnalyticsResult {
58
+ generatedAt: number;
59
+ totalRequests: number;
60
+ scannedRows: number;
61
+ historyTruncated: boolean;
62
+ confidence: AnalyticsConfidence | null;
63
+ successRate: number | null;
64
+ failureRate: number | null;
65
+ cancelledRate: number | null;
66
+ fallbackRate: number | null;
67
+ totalAttempts: number;
68
+ averageAttemptsPerRequest: number | null;
69
+ incompleteStreamRate: number | null;
70
+ cooldownTriggeringFailures: number;
71
+ durationMs: {
72
+ p50?: number;
73
+ p95?: number;
74
+ p99?: number;
75
+ sampleCount: number;
76
+ };
77
+ firstOutputMs: {
78
+ p50?: number;
79
+ p95?: number;
80
+ p99?: number;
81
+ sampleCount: number;
82
+ /** Share of scanned requests with a TTFT measurement (0..1). */
83
+ coverage: number | null;
84
+ };
85
+ estimatedCostUsdPerSuccessfulRequest: number | null;
86
+ estimatedCostUsdTotalSuccessful: number | null;
87
+ usageCoverage: number | null;
88
+ priceCoverage: number | null;
89
+ breakdown: AnalyticsBreakdownRow[];
90
+ profileBreakdown: AnalyticsProfileRow[];
91
+ }
92
+
93
+ interface ScannedRow {
94
+ provider: string;
95
+ model: string;
96
+ apiKeyId?: string | null;
97
+ profileId?: string | null;
98
+ profileRevision?: string | null;
99
+ status: number;
100
+ durationMs: number;
101
+ firstOutputMs?: number | null;
102
+ closeReason?: string | null;
103
+ terminalStatus?: string | null;
104
+ usageStatus: string;
105
+ usageJson?: string | null;
106
+ attemptCount: number;
107
+ fallback: number;
108
+ rowJson: string;
109
+ }
110
+
111
+ interface Bucket extends AnalyticsBreakdownRow {
112
+ durations: number[];
113
+ costUsdSum: number;
114
+ costRows: number;
115
+ }
116
+
117
+ const COOLDOWN_RECOVERY_KINDS = new Set([
118
+ "rate-limit-429",
119
+ "key-429",
120
+ "oauth-401",
121
+ "anthropic-oauth-429",
122
+ ]);
123
+
124
+ function percentile(sorted: number[], p: number): number | undefined {
125
+ if (sorted.length === 0) return undefined;
126
+ const index = Math.max(0, Math.ceil((p / 100) * sorted.length) - 1);
127
+ return sorted[Math.min(index, sorted.length - 1)];
128
+ }
129
+
130
+ function classifyRow(row: ScannedRow): "success" | "failure" | "cancelled" {
131
+ if (row.closeReason === "client_cancel" || row.status === 499) return "cancelled";
132
+ if (row.terminalStatus === "incomplete") return "failure";
133
+ if (row.terminalStatus && row.terminalStatus !== "completed") return "failure";
134
+ if (row.status >= 400) return "failure";
135
+ return "success";
136
+ }
137
+
138
+ function parseEntry(rowJson: string): PersistedUsageEntry | null {
139
+ try {
140
+ const parsed = JSON.parse(rowJson) as PersistedUsageEntry;
141
+ return parsed && typeof parsed === "object" && typeof parsed.requestId === "string" ? parsed : null;
142
+ } catch {
143
+ return null;
144
+ }
145
+ }
146
+
147
+ function attemptsOf(entry: PersistedUsageEntry | null): PersistedUsageAttempt[] | undefined {
148
+ return entry?.attempts;
149
+ }
150
+
151
+ function cooldownTriggering(entry: PersistedUsageEntry | null, status: number): boolean {
152
+ if (status === 429) return true;
153
+ const attempts = attemptsOf(entry) ?? [];
154
+ return attempts.some(attempt => attempt.recoveryKinds.some(kind => COOLDOWN_RECOVERY_KINDS.has(kind)));
155
+ }
156
+
157
+ function successCostUsd(
158
+ row: Pick<ScannedRow, "provider" | "model">,
159
+ entry: PersistedUsageEntry,
160
+ ): number | null {
161
+ if (!entry.usage) return null;
162
+ const estimate = estimateRequestCost({
163
+ provider: row.provider,
164
+ model: row.model,
165
+ usage: entry.usage,
166
+ usageStatus: entry.usageStatus,
167
+ serviceTier: serviceTierContext(entry),
168
+ });
169
+ return estimate ? estimate.cost.total : null;
170
+ }
171
+
172
+ export async function computeRoutingAnalytics(
173
+ filters: RoutingAnalyticsFilters,
174
+ options: { maxRows?: number } = {},
175
+ ): Promise<RoutingAnalyticsResult> {
176
+ await openRequestHistoryIndex();
177
+ const handle = requestHistoryDb();
178
+ const maxRows = Math.min(
179
+ Math.max(1, Math.trunc(options.maxRows ?? ANALYTICS_MAX_ROWS)),
180
+ ANALYTICS_MAX_ROWS,
181
+ );
182
+
183
+ const where: string[] = [];
184
+ const values: Array<string | number> = [];
185
+ const add = (clause: string, value: string | number) => {
186
+ where.push(clause);
187
+ values.push(value);
188
+ };
189
+ if (filters.provider !== undefined) add("provider = ?", filters.provider);
190
+ if (filters.model !== undefined) add("model = ?", filters.model);
191
+ if (filters.profileId !== undefined) add("profile_id = ?", filters.profileId);
192
+ if (filters.surface !== undefined) add("surface = ?", filters.surface);
193
+ if (filters.from !== undefined) add("timestamp >= ?", filters.from);
194
+ if (filters.to !== undefined) add("timestamp <= ?", filters.to);
195
+ const whereSql = where.length > 0 ? ` WHERE ${where.join(" AND ")}` : "";
196
+
197
+ const rows = handle.query(
198
+ `SELECT provider, model, api_key_id AS apiKeyId, profile_id AS profileId,
199
+ profile_revision AS profileRevision, status,
200
+ duration_ms AS durationMs, first_output_ms AS firstOutputMs,
201
+ close_reason AS closeReason, terminal_status AS terminalStatus,
202
+ usage_status AS usageStatus, usage_json AS usageJson,
203
+ attempt_count AS attemptCount, fallback, row_json AS rowJson
204
+ FROM requests${whereSql} ORDER BY timestamp DESC LIMIT ?`,
205
+ ).all(...values, maxRows + 1) as ScannedRow[];
206
+
207
+ const scanned = rows.slice(0, maxRows);
208
+ const historyTruncated = rows.length > maxRows;
209
+
210
+ let successes = 0;
211
+ let failures = 0;
212
+ let cancelled = 0;
213
+ let fallbacks = 0;
214
+ let totalAttempts = 0;
215
+ let incompleteStreams = 0;
216
+ let cooldownFailures = 0;
217
+ let usageReported = 0;
218
+ const durations: number[] = [];
219
+ const firstOutputs: number[] = [];
220
+ let costTotalUsd = 0;
221
+ let costCount = 0;
222
+
223
+ const byKey = new Map<string, Bucket>();
224
+ const byProfile = new Map<string, AnalyticsProfileRow>();
225
+
226
+ for (const row of scanned) {
227
+ const kind = classifyRow(row);
228
+ if (kind === "success") successes += 1;
229
+ else if (kind === "failure") failures += 1;
230
+ else cancelled += 1;
231
+ if (row.fallback === 1) fallbacks += 1;
232
+ totalAttempts += row.attemptCount;
233
+ if (row.terminalStatus === "incomplete") incompleteStreams += 1;
234
+ durations.push(row.durationMs);
235
+ if (row.firstOutputMs !== null && row.firstOutputMs !== undefined && row.firstOutputMs >= 0) {
236
+ firstOutputs.push(row.firstOutputMs);
237
+ }
238
+ if (row.usageStatus !== "unreported") usageReported += 1;
239
+
240
+ let rowCostUsd: number | null = null;
241
+ if (kind === "success") {
242
+ const entry = parseEntry(row.rowJson);
243
+ if (entry) {
244
+ rowCostUsd = successCostUsd(row, entry);
245
+ if (rowCostUsd !== null) {
246
+ costTotalUsd += rowCostUsd;
247
+ costCount += 1;
248
+ }
249
+ }
250
+ }
251
+
252
+ if (kind === "failure") {
253
+ const failureEntry = parseEntry(row.rowJson);
254
+ if (cooldownTriggering(failureEntry, row.status)) cooldownFailures += 1;
255
+ }
256
+
257
+ const key = `${row.provider}\0${row.model}\0${row.apiKeyId ?? ""}\0${row.profileId ?? ""}`;
258
+ let bucket: Bucket | undefined = byKey.get(key);
259
+ if (!bucket) {
260
+ bucket = {
261
+ provider: row.provider,
262
+ model: row.model,
263
+ ...(row.apiKeyId ? { accountRef: row.apiKeyId } : {}),
264
+ ...(row.profileId ? { profileId: row.profileId } : {}),
265
+ requests: 0,
266
+ successes: 0,
267
+ failures: 0,
268
+ cancelled: 0,
269
+ successRate: null,
270
+ durations: [],
271
+ costUsdSum: 0,
272
+ costRows: 0,
273
+ };
274
+ byKey.set(key, bucket);
275
+ }
276
+ bucket.requests += 1;
277
+ if (kind === "success") bucket.successes += 1;
278
+ else if (kind === "failure") bucket.failures += 1;
279
+ else bucket.cancelled += 1;
280
+ bucket.durations.push(row.durationMs);
281
+ if (rowCostUsd !== null) {
282
+ bucket.costUsdSum += rowCostUsd;
283
+ bucket.costRows += 1;
284
+ }
285
+
286
+ if (row.profileId) {
287
+ let profile = byProfile.get(row.profileId);
288
+ if (!profile) {
289
+ profile = {
290
+ profileId: row.profileId,
291
+ ...(row.profileRevision ? { profileRevision: row.profileRevision } : {}),
292
+ requests: 0,
293
+ successes: 0,
294
+ failures: 0,
295
+ fallbacks: 0,
296
+ successRate: null,
297
+ };
298
+ byProfile.set(row.profileId, profile);
299
+ }
300
+ profile.requests += 1;
301
+ if (kind === "success") profile.successes += 1;
302
+ else if (kind === "failure") profile.failures += 1;
303
+ if (row.fallback === 1) profile.fallbacks += 1;
304
+ }
305
+ }
306
+
307
+ durations.sort((a, b) => a - b);
308
+ firstOutputs.sort((a, b) => a - b);
309
+ const total = scanned.length;
310
+ const rate = (count: number): number | null => (total > 0 ? count / total : null);
311
+
312
+ const breakdown: AnalyticsBreakdownRow[] = [...byKey.values()].map(bucket => {
313
+ const sorted = bucket.durations.sort((a, b) => a - b);
314
+ const p50DurationMs = percentile(sorted, 50);
315
+ return {
316
+ provider: bucket.provider,
317
+ model: bucket.model,
318
+ ...(bucket.accountRef ? { accountRef: bucket.accountRef } : {}),
319
+ ...(bucket.profileId ? { profileId: bucket.profileId } : {}),
320
+ requests: bucket.requests,
321
+ successes: bucket.successes,
322
+ failures: bucket.failures,
323
+ cancelled: bucket.cancelled,
324
+ successRate: bucket.requests > 0 ? bucket.successes / bucket.requests : null,
325
+ ...(p50DurationMs !== undefined ? { p50DurationMs } : {}),
326
+ ...(bucket.requests > 0
327
+ ? { estimatedCostUsdPerSuccessfulRequest: bucket.costRows > 0
328
+ ? bucket.costUsdSum / bucket.costRows
329
+ : null }
330
+ : {}),
331
+ };
332
+ }).sort((a, b) => b.requests - a.requests);
333
+
334
+ const profileBreakdown: AnalyticsProfileRow[] = [...byProfile.values()].map(profile => ({
335
+ ...profile,
336
+ successRate: profile.requests > 0 ? profile.successes / profile.requests : null,
337
+ })).sort((a, b) => b.requests - a.requests);
338
+
339
+ const confidence: AnalyticsConfidence | null = total === 0
340
+ ? null
341
+ : total >= 100 ? "high" : total >= 20 ? "medium" : "low";
342
+
343
+ return {
344
+ generatedAt: Date.now(),
345
+ totalRequests: total,
346
+ scannedRows: scanned.length,
347
+ historyTruncated,
348
+ confidence,
349
+ successRate: rate(successes),
350
+ failureRate: rate(failures),
351
+ cancelledRate: rate(cancelled),
352
+ fallbackRate: rate(fallbacks),
353
+ totalAttempts,
354
+ averageAttemptsPerRequest: total > 0 ? totalAttempts / total : null,
355
+ incompleteStreamRate: rate(incompleteStreams),
356
+ cooldownTriggeringFailures: cooldownFailures,
357
+ durationMs: {
358
+ ...(percentile(durations, 50) !== undefined ? { p50: percentile(durations, 50) } : {}),
359
+ ...(percentile(durations, 95) !== undefined ? { p95: percentile(durations, 95) } : {}),
360
+ ...(percentile(durations, 99) !== undefined ? { p99: percentile(durations, 99) } : {}),
361
+ sampleCount: durations.length,
362
+ },
363
+ firstOutputMs: {
364
+ ...(percentile(firstOutputs, 50) !== undefined ? { p50: percentile(firstOutputs, 50) } : {}),
365
+ ...(percentile(firstOutputs, 95) !== undefined ? { p95: percentile(firstOutputs, 95) } : {}),
366
+ ...(percentile(firstOutputs, 99) !== undefined ? { p99: percentile(firstOutputs, 99) } : {}),
367
+ sampleCount: firstOutputs.length,
368
+ coverage: total > 0 ? firstOutputs.length / total : null,
369
+ },
370
+ estimatedCostUsdPerSuccessfulRequest: costCount > 0 ? costTotalUsd / costCount : null,
371
+ estimatedCostUsdTotalSuccessful: costCount > 0 ? costTotalUsd : null,
372
+ usageCoverage: total > 0 ? usageReported / total : null,
373
+ priceCoverage: successes > 0 ? costCount / successes : null,
374
+ breakdown,
375
+ profileBreakdown,
376
+ };
377
+ }
@@ -0,0 +1,205 @@
1
+ /**
2
+ * Candidate capability evidence for policy routing (RI-05).
3
+ *
4
+ * Evidence comes from canonical local sources only - provider config maps,
5
+ * the provider registry, the cached Codex catalog file, and the native-model
6
+ * metadata helpers. No live network fetch happens at routing time.
7
+ *
8
+ * "Unknown is not zero": any dimension without canonical evidence stays
9
+ * `undefined` (unknown) and the profile's `unknownEvidence` policy decides
10
+ * how that affects eligibility.
11
+ */
12
+
13
+ import type { OcxConfig } from "../types";
14
+ import { isCanonicalOpenAiForwardProvider } from "../providers/openai-tiers";
15
+ import { PROVIDER_REGISTRY } from "../providers/registry";
16
+ import {
17
+ nativeInputModalities,
18
+ nativeOpenAiContextWindow,
19
+ nativeParallelToolCalls,
20
+ nativeReasoningEfforts,
21
+ } from "../codex/catalog/metadata";
22
+ import { readCatalog, readCodexCatalogPath } from "../codex/catalog/parsing";
23
+ import { statSync } from "node:fs";
24
+ import type { RouteCapabilityEvidence } from "./trace";
25
+
26
+ type CatalogModelRow = {
27
+ provider: string;
28
+ id: string;
29
+ contextWindow?: number;
30
+ inputModalities?: string[];
31
+ reasoningEfforts?: string[];
32
+ capabilities?: string[];
33
+ };
34
+
35
+ /**
36
+ * Catalog rows memoized by path + mtime: the cached Codex catalog is stable
37
+ * between refreshes, and re-reading/parsing the whole file per candidate on
38
+ * the request path would multiply a synchronous disk + JSON cost by the
39
+ * profile candidate count for every policy-routed request.
40
+ */
41
+ let catalogCache: { path: string; mtimeMs: number; rows: CatalogModelRow[] } | null = null;
42
+
43
+ function cachedCatalogModels(): CatalogModelRow[] {
44
+ try {
45
+ const path = readCodexCatalogPath();
46
+ const mtimeMs = statSync(path).mtimeMs;
47
+ if (catalogCache && catalogCache.path === path && catalogCache.mtimeMs === mtimeMs) {
48
+ return catalogCache.rows;
49
+ }
50
+ const catalog = readCatalog(path);
51
+ const models = catalog?.models;
52
+ if (!Array.isArray(models)) return [];
53
+ const rows = models
54
+ .filter((model): model is Record<string, unknown> & { id: string; provider: string } =>
55
+ typeof model === "object" && model !== null && typeof model.id === "string" && typeof model.provider === "string")
56
+ .map(model => ({
57
+ provider: model.provider,
58
+ id: model.id,
59
+ ...(typeof model.contextWindow === "number" ? { contextWindow: model.contextWindow } : {}),
60
+ ...(Array.isArray(model.inputModalities)
61
+ ? { inputModalities: model.inputModalities.filter((value): value is string => typeof value === "string") }
62
+ : {}),
63
+ ...(Array.isArray(model.reasoningEfforts)
64
+ ? { reasoningEfforts: model.reasoningEfforts.filter((value): value is string => typeof value === "string") }
65
+ : {}),
66
+ ...(Array.isArray(model.capabilities)
67
+ ? { capabilities: model.capabilities.filter((value): value is string => typeof value === "string") }
68
+ : {}),
69
+ }));
70
+ catalogCache = { path, mtimeMs, rows };
71
+ return rows;
72
+ } catch {
73
+ return [];
74
+ }
75
+ }
76
+
77
+ /**
78
+ * Classify a hostname for locality evidence. `URL.hostname` keeps IPv6
79
+ * literals bracketed (`[::1]`), so strip the brackets before matching.
80
+ * Anything not positively local or private stays unknown: "unknown is not
81
+ * zero", so an unrecognized host must never assert `remoteAllowed`.
82
+ */
83
+ function classifyHostname(hostname: string): "local" | "private" | null {
84
+ const host = hostname.trim().toLowerCase().replace(/\.$/, "").replace(/^\[|\]$/g, "");
85
+ if (host === "localhost" || host.endsWith(".localhost") || host === "0.0.0.0") return "local";
86
+ if (host === "::1" || /^127\./.test(host)) return "local";
87
+ if (/^10\./.test(host)
88
+ || /^192\.168\./.test(host)
89
+ || /^169\.254\./.test(host)
90
+ || /^172\.(1[6-9]|2\d|3[01])\./.test(host)
91
+ || /^f[cd][0-9a-f]{2}:/.test(host)
92
+ || /^fe80:/.test(host)
93
+ || /^::ffff:(?:10\.|127\.|192\.168\.|169\.254\.|172\.(?:1[6-9]|2\d|3[01])\.)/.test(host)) {
94
+ return "private";
95
+ }
96
+ return null;
97
+ }
98
+
99
+ /**
100
+ * Adapters whose upstream protocol supports function/tool calling. Mirrors
101
+ * the adapter ids the resolver accepts (including the `azure` alias for
102
+ * `azure-openai`); `kiro` and `mimo-free` send/delegate tool calls.
103
+ */
104
+ const TOOL_CAPABLE_ADAPTERS = new Set([
105
+ "openai-chat",
106
+ "openai-responses",
107
+ "anthropic",
108
+ "cursor",
109
+ "google",
110
+ "azure-openai",
111
+ "azure",
112
+ "kiro",
113
+ "mimo-free",
114
+ "command-code",
115
+ ]);
116
+
117
+ function localRemoteEvidence(baseUrl: string | undefined): Pick<RouteCapabilityEvidence, "localOnly" | "remoteAllowed"> {
118
+ if (typeof baseUrl !== "string" || baseUrl.length === 0) return {};
119
+ try {
120
+ const hostname = new URL(baseUrl).hostname;
121
+ if (!hostname) return {};
122
+ const kind = classifyHostname(hostname);
123
+ if (kind === null) return {};
124
+ // Both booleans are emitted once classified: definitive negative evidence,
125
+ // so a local host cannot satisfy `require.remoteAllowed` (or vice versa)
126
+ // under `unknownEvidence.capability: "allow"`/`"penalize"`.
127
+ return kind === "local" || kind === "private"
128
+ ? { localOnly: true, remoteAllowed: false }
129
+ : { remoteAllowed: true, localOnly: false };
130
+ } catch {
131
+ return {};
132
+ }
133
+ }
134
+
135
+ /**
136
+ * Assemble canonical capability evidence for one `provider/model` candidate.
137
+ * Sources (in priority order): provider config maps, provider registry hints,
138
+ * cached Codex catalog row, native-model metadata.
139
+ */
140
+ export function candidateCapabilityEvidence(
141
+ config: OcxConfig,
142
+ providerName: string,
143
+ modelId: string,
144
+ ): RouteCapabilityEvidence {
145
+ const provider = config.providers[providerName];
146
+ const registryEntry = PROVIDER_REGISTRY.find(entry => entry.id === providerName);
147
+ const catalogRow = cachedCatalogModels().find(model => model.provider === providerName && model.id === modelId);
148
+ const isNative = providerName === "openai" && !modelId.includes("/");
149
+
150
+ const contextWindow = provider?.modelContextWindows?.[modelId]
151
+ ?? provider?.contextWindow
152
+ ?? registryEntry?.modelContextWindows?.[modelId]
153
+ ?? catalogRow?.contextWindow
154
+ ?? (isNative ? nativeOpenAiContextWindow(modelId) : undefined);
155
+
156
+ const modalities = provider?.modelInputModalities?.[modelId]
157
+ ?? registryEntry?.modelInputModalities?.[modelId]
158
+ ?? catalogRow?.inputModalities
159
+ ?? (isNative ? nativeInputModalities(modelId) : undefined);
160
+ const image = Array.isArray(modalities)
161
+ ? modalities.includes("image")
162
+ : undefined;
163
+
164
+ const capabilities = catalogRow?.capabilities ?? [];
165
+ // The catalog `capabilities` list is a positive per-model signal; a row
166
+ // without "tools" is treated as unknown, never as a negative. Without a
167
+ // catalog row the adapter protocol itself is the signal: tool-capable
168
+ // adapters run single tool calls even when the parallel-call opt-in is
169
+ // unset or false. `parallelToolCalls` stays a positive provider-level
170
+ // override.
171
+ const tools = capabilities.includes("tools")
172
+ || isNative
173
+ || (catalogRow === undefined && provider !== undefined && TOOL_CAPABLE_ADAPTERS.has(provider.adapter))
174
+ || provider?.parallelToolCalls === true
175
+ || undefined;
176
+
177
+ const reasoningEfforts = provider?.modelReasoningEfforts?.[modelId]
178
+ ?? registryEntry?.modelReasoningEfforts?.[modelId]
179
+ ?? catalogRow?.reasoningEfforts
180
+ ?? (isNative ? nativeReasoningEfforts(modelId) : undefined);
181
+
182
+ const tierSupport = provider?.supportsServiceTier
183
+ ?? registryEntry?.supportsServiceTier;
184
+ const serviceTier = tierSupport === true
185
+ ? "supported"
186
+ : tierSupport === false ? "unsupported" : "unknown";
187
+
188
+ const localRemote = localRemoteEvidence(provider?.baseUrl);
189
+ // Only emit a definitive encryptedCodexTasks value when the provider is
190
+ // present. An absent/unconfigured provider must stay unknown so
191
+ // require.encryptedCodexTasks does not fail closed on missing config.
192
+ const encryptedCodexTasks = provider === undefined
193
+ ? undefined
194
+ : isCanonicalOpenAiForwardProvider(provider);
195
+
196
+ return {
197
+ ...(typeof contextWindow === "number" ? { contextWindow } : {}),
198
+ ...(typeof image === "boolean" ? { image } : {}),
199
+ ...(typeof tools === "boolean" ? { tools } : {}),
200
+ ...(reasoningEfforts !== undefined && reasoningEfforts.length > 0 ? { reasoningEfforts } : {}),
201
+ ...(serviceTier !== "unknown" ? { serviceTier } : {}),
202
+ ...localRemote,
203
+ ...(typeof encryptedCodexTasks === "boolean" ? { encryptedCodexTasks } : {}),
204
+ };
205
+ }
@@ -0,0 +1,77 @@
1
+ /**
2
+ * Cost-aware policy scoring and limits (RI-08).
3
+ *
4
+ * Reuses the canonical price/cost normalization (`src/usage/cost.ts`).
5
+ * Evidence distinguishes estimated vs authoritative usage and registry vs
6
+ * expected prices. Unknown prices stay unknown (never free); the profile's
7
+ * `unknownEvidence.cost` policy decides how unknown evidence is handled.
8
+ *
9
+ * No billing, invoicing, or hidden budgets - a hard per-request ceiling
10
+ * (`limits.maxEstimatedCostUsd`) is evaluated deterministically.
11
+ */
12
+
13
+ import type { OcxUsage } from "../types";
14
+ import type { UsageStatus } from "../usage/log";
15
+ import { estimateRequestCost, type ServiceTierInput } from "../usage/cost";
16
+ import type { RouteCostEvidence } from "./trace";
17
+
18
+ /** Reference cost (USD) for the relative cost score when no limit is set. */
19
+ export const COST_SCORE_REFERENCE_USD = 1.0;
20
+
21
+ export interface CostEvidenceInput {
22
+ provider: string;
23
+ model: string;
24
+ usage?: OcxUsage;
25
+ usageStatus?: UsageStatus;
26
+ serviceTier?: ServiceTierInput;
27
+ limitUsd?: number;
28
+ }
29
+
30
+ /**
31
+ * Assemble cost evidence from the canonical price model. Returns unknown-ish
32
+ * evidence (`incomplete: true`, no estimate) when usage or a price is
33
+ * missing - never a fabricated zero.
34
+ */
35
+ export function costEvidenceForCandidate(input: CostEvidenceInput): RouteCostEvidence {
36
+ const limitUsd = input.limitUsd;
37
+ if (!input.usage) {
38
+ return {
39
+ ...(limitUsd !== undefined ? { limitUsd } : {}),
40
+ incomplete: true,
41
+ };
42
+ }
43
+ const estimate = estimateRequestCost({
44
+ provider: input.provider,
45
+ model: input.model,
46
+ usage: input.usage,
47
+ usageStatus: input.usageStatus ?? "estimated",
48
+ ...(input.serviceTier ? { serviceTier: input.serviceTier } : {}),
49
+ });
50
+ if (!estimate) {
51
+ return {
52
+ ...(limitUsd !== undefined ? { limitUsd } : {}),
53
+ incomplete: true,
54
+ priceSource: "unmatched",
55
+ };
56
+ }
57
+ const priceSource = estimate.price?.source ?? "registry";
58
+ return {
59
+ estimatedUsd: estimate.cost.total,
60
+ priceSource,
61
+ incomplete: estimate.estimated || priceSource === "expected",
62
+ ...(limitUsd !== undefined ? { limitUsd } : {}),
63
+ };
64
+ }
65
+
66
+ /**
67
+ * Deterministic cost score in [0,1]: cheaper is better, relative to
68
+ * `COST_SCORE_REFERENCE_USD` (or the profile limit when set). Unknown
69
+ * estimates return null so the profile's unknownEvidence policy applies.
70
+ */
71
+ export function costScore(evidence: RouteCostEvidence | undefined): number | null {
72
+ if (evidence?.estimatedUsd === undefined || !Number.isFinite(evidence.estimatedUsd)) return null;
73
+ const reference = typeof evidence.limitUsd === "number" && evidence.limitUsd > 0
74
+ ? evidence.limitUsd
75
+ : COST_SCORE_REFERENCE_USD;
76
+ return Math.max(0, Math.min(1, 1 - evidence.estimatedUsd / reference));
77
+ }