@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,253 @@
1
+ /**
2
+ * `application/vnd.amazon.eventstream` decoder.
3
+ *
4
+ * Ported from jawcode `packages/ai/src/providers/aws-eventstream.ts` (verbatim logic).
5
+ * Foundational dependency for AWS-eventstream providers: kiro (CodeWhisperer
6
+ * GenerateAssistantResponse) and amazon-bedrock (Converse). Self-contained — only
7
+ * uses Buffer / DataView / TextDecoder (Bun + Node compatible).
8
+ *
9
+ * Wire format (all integers big-endian):
10
+ *
11
+ * [total length u32]
12
+ * [headers length u32]
13
+ * [prelude CRC32 u32] <- CRC over the first 8 bytes
14
+ * [headers headers_length]
15
+ * [payload total_length - headers_length - 16]
16
+ * [message CRC32 u32] <- CRC over the entire message minus the trailing 4 bytes
17
+ *
18
+ * Headers: a sequence of `[name_len u8][name utf8][value_type u8][value …]`.
19
+ */
20
+
21
+ const PRELUDE_LEN = 8;
22
+ const PRELUDE_CRC_LEN = 4;
23
+ const MESSAGE_CRC_LEN = 4;
24
+ const HEADER_BLOCK_OFFSET = PRELUDE_LEN + PRELUDE_CRC_LEN;
25
+ const MIN_MESSAGE_LEN = HEADER_BLOCK_OFFSET + MESSAGE_CRC_LEN;
26
+ const MAX_MESSAGE_LEN = 16 * 1024 * 1024;
27
+ const MAX_HEADERS_LEN = 128 * 1024;
28
+
29
+ export interface EventStreamMessage {
30
+ /** Header casing is preserved verbatim (e.g. `:event-type`, `:message-type`). */
31
+ headers: Record<string, string>;
32
+ payload: Uint8Array;
33
+ }
34
+
35
+ /** CRC32 (IEEE / zlib polynomial 0xEDB88320), matches `@aws-crypto/crc32`. */
36
+ const CRC_TABLE = (() => {
37
+ const t = new Uint32Array(256);
38
+ for (let i = 0; i < 256; i++) {
39
+ let c = i;
40
+ for (let k = 0; k < 8; k++) c = c & 1 ? 0xedb88320 ^ (c >>> 1) : c >>> 1;
41
+ t[i] = c >>> 0;
42
+ }
43
+ return t;
44
+ })();
45
+
46
+ export function crc32(bytes: Uint8Array, seed = 0): number {
47
+ let c = (seed ^ 0xffffffff) >>> 0;
48
+ for (let i = 0; i < bytes.length; i++) c = (CRC_TABLE[(c ^ bytes[i]) & 0xff] ^ (c >>> 8)) >>> 0;
49
+ return (c ^ 0xffffffff) >>> 0;
50
+ }
51
+
52
+ /**
53
+ * Decode a single, fully buffered eventstream message. Throws if the framing is
54
+ * malformed or either CRC mismatches.
55
+ */
56
+ export function decodeMessage(frame: Uint8Array): EventStreamMessage {
57
+ if (frame.length < MIN_MESSAGE_LEN) throw new Error("eventstream: frame too short");
58
+ const view = new DataView(frame.buffer, frame.byteOffset, frame.byteLength);
59
+ const total = view.getUint32(0, false);
60
+ if (total !== frame.length) throw new Error(`eventstream: framed length ${total} != buffer ${frame.length}`);
61
+ if (total > MAX_MESSAGE_LEN) throw new Error(`eventstream: total length ${total} exceeds maximum`);
62
+ const headersLen = view.getUint32(4, false);
63
+ const preludeCrc = view.getUint32(8, false);
64
+ const computedPreludeCrc = crc32(frame.subarray(0, PRELUDE_LEN));
65
+ if (computedPreludeCrc !== preludeCrc) throw new Error("eventstream: prelude CRC mismatch");
66
+ if (headersLen > MAX_HEADERS_LEN) throw new Error(`eventstream: headers length ${headersLen} exceeds maximum`);
67
+ if (headersLen > total - MIN_MESSAGE_LEN) throw new Error("eventstream: headers length exceeds frame payload");
68
+ const msgCrc = view.getUint32(total - MESSAGE_CRC_LEN, false);
69
+ const computedMsgCrc = crc32(frame.subarray(0, total - MESSAGE_CRC_LEN));
70
+ if (computedMsgCrc !== msgCrc) throw new Error("eventstream: message CRC mismatch");
71
+
72
+ const headersBytes = frame.subarray(HEADER_BLOCK_OFFSET, HEADER_BLOCK_OFFSET + headersLen);
73
+ const payload = frame.subarray(HEADER_BLOCK_OFFSET + headersLen, total - MESSAGE_CRC_LEN);
74
+ return { headers: parseHeaders(headersBytes), payload };
75
+ }
76
+
77
+ function parseHeaders(buf: Uint8Array): Record<string, string> {
78
+ const out: Record<string, string> = {};
79
+ const view = new DataView(buf.buffer, buf.byteOffset, buf.byteLength);
80
+ const decoder = new TextDecoder();
81
+ let p = 0;
82
+ const need = (n: number, label: string) => {
83
+ if (p + n > buf.length) throw new Error(`eventstream: truncated header ${label}`);
84
+ };
85
+ while (p < buf.length) {
86
+ need(1, "name length");
87
+ const nameLen = view.getUint8(p);
88
+ p += 1;
89
+ need(nameLen, "name");
90
+ const name = decoder.decode(buf.subarray(p, p + nameLen));
91
+ p += nameLen;
92
+ need(1, "type");
93
+ const type = view.getUint8(p);
94
+ p += 1;
95
+ switch (type) {
96
+ case 0: // bool true
97
+ out[name] = "true";
98
+ break;
99
+ case 1: // bool false
100
+ out[name] = "false";
101
+ break;
102
+ case 2: // byte
103
+ need(1, "byte value");
104
+ out[name] = String(view.getInt8(p));
105
+ p += 1;
106
+ break;
107
+ case 3: // short
108
+ need(2, "short value");
109
+ out[name] = String(view.getInt16(p, false));
110
+ p += 2;
111
+ break;
112
+ case 4: // integer
113
+ need(4, "integer value");
114
+ out[name] = String(view.getInt32(p, false));
115
+ p += 4;
116
+ break;
117
+ case 5: // long — decimal string to avoid precision loss
118
+ need(8, "long value");
119
+ out[name] = bigIntFromBytes(buf.subarray(p, p + 8)).toString();
120
+ p += 8;
121
+ break;
122
+ case 6: {
123
+ // byte array — base64 for safe transport
124
+ need(2, "byte-array length");
125
+ const len = view.getUint16(p, false);
126
+ p += 2;
127
+ need(len, "byte-array value");
128
+ out[name] = Buffer.from(buf.buffer, buf.byteOffset + p, len).toString("base64");
129
+ p += len;
130
+ break;
131
+ }
132
+ case 7: {
133
+ // string
134
+ need(2, "string length");
135
+ const len = view.getUint16(p, false);
136
+ p += 2;
137
+ need(len, "string value");
138
+ out[name] = decoder.decode(buf.subarray(p, p + len));
139
+ p += len;
140
+ break;
141
+ }
142
+ case 8: // timestamp (ms since epoch as i64)
143
+ need(8, "timestamp value");
144
+ out[name] = new Date(Number(bigIntFromBytes(buf.subarray(p, p + 8)))).toISOString();
145
+ p += 8;
146
+ break;
147
+ case 9: {
148
+ // uuid
149
+ need(16, "uuid value");
150
+ const u = buf.subarray(p, p + 16);
151
+ const hex: string[] = [];
152
+ for (let i = 0; i < 16; i++) hex.push(u[i].toString(16).padStart(2, "0"));
153
+ out[name] =
154
+ `${hex.slice(0, 4).join("")}-${hex.slice(4, 6).join("")}-${hex.slice(6, 8).join("")}-${hex.slice(8, 10).join("")}-${hex.slice(10, 16).join("")}`;
155
+ p += 16;
156
+ break;
157
+ }
158
+ default:
159
+ throw new Error(`eventstream: unknown header value type ${type}`);
160
+ }
161
+ }
162
+ return out;
163
+ }
164
+
165
+ function bigIntFromBytes(b: Uint8Array): bigint {
166
+ let v = 0n;
167
+ for (let i = 0; i < b.length; i++) v = (v << 8n) | BigInt(b[i]);
168
+ // sign-extend (two's complement)
169
+ if (b.length === 8 && b[0] & 0x80) v -= 1n << 64n;
170
+ return v;
171
+ }
172
+
173
+ /**
174
+ * Async generator that consumes a `ReadableStream<Uint8Array>` (a fetch response
175
+ * body) and yields fully-framed messages, handling arbitrary chunk boundaries.
176
+ */
177
+ export async function* decodeEventStream(source: ReadableStream<Uint8Array>): AsyncGenerator<EventStreamMessage> {
178
+ const reader = source.getReader();
179
+ let buf: Uint8Array = new Uint8Array(0);
180
+ try {
181
+ while (true) {
182
+ const { value, done } = await reader.read();
183
+ if (value && value.length > 0) buf = buf.length === 0 ? value : Buffer.concat([buf, value]);
184
+ let offset = 0;
185
+ while (buf.length - offset >= 4) {
186
+ const dv = new DataView(buf.buffer, buf.byteOffset + offset, buf.length - offset);
187
+ const total = dv.getUint32(0, false);
188
+ if (total < MIN_MESSAGE_LEN) throw new Error(`eventstream: total length ${total} below minimum`);
189
+ if (total > MAX_MESSAGE_LEN) throw new Error(`eventstream: total length ${total} exceeds maximum`);
190
+ if (buf.length - offset >= HEADER_BLOCK_OFFSET) {
191
+ const headersLen = dv.getUint32(4, false);
192
+ const preludeCrc = dv.getUint32(8, false);
193
+ const computedPreludeCrc = crc32(buf.subarray(offset, offset + PRELUDE_LEN));
194
+ if (computedPreludeCrc !== preludeCrc) throw new Error("eventstream: prelude CRC mismatch");
195
+ if (headersLen > MAX_HEADERS_LEN) throw new Error(`eventstream: headers length ${headersLen} exceeds maximum`);
196
+ }
197
+ if (buf.length - offset < total) break;
198
+ const frame = buf.subarray(offset, offset + total);
199
+ yield decodeMessage(frame);
200
+ offset += total;
201
+ }
202
+ if (offset > 0) buf = buf.slice(offset);
203
+ if (buf.length > MAX_MESSAGE_LEN) throw new Error(`eventstream: buffered frame exceeds maximum ${MAX_MESSAGE_LEN}`);
204
+ if (done) break;
205
+ }
206
+ if (buf.length > 0) throw new Error("eventstream: truncated message at end of stream");
207
+ } finally {
208
+ // Early termination (consumer break/return, turn abort, or an HTTP/2 mid-body reset) can leave
209
+ // an in-flight `reader.read()` pending when this generator's `finally` runs. Releasing the lock
210
+ // does NOT settle that orphaned read — Bun then surfaces it as an off-path
211
+ // `unhandledRejection: TypeError: null is not an object` that no caller try/catch can intercept.
212
+ // Cancel first (settles the pending read + closes the body), then release. On a clean `done`
213
+ // finish the read is already settled, so cancel() is a harmless no-op.
214
+ try {
215
+ await reader.cancel();
216
+ } catch {
217
+ /* body already errored/closed — nothing to cancel */
218
+ }
219
+ try {
220
+ reader.releaseLock();
221
+ } catch {
222
+ /* lock already released by cancel() on some runtimes */
223
+ }
224
+ }
225
+ }
226
+
227
+ /** Build a single eventstream frame (string headers only) — used by tests and fixtures. */
228
+ export function encodeMessage(headers: Record<string, string>, payload: Uint8Array): Uint8Array {
229
+ const enc = new TextEncoder();
230
+ const headerParts: Uint8Array[] = [];
231
+ for (const [name, value] of Object.entries(headers)) {
232
+ const nameBytes = enc.encode(name);
233
+ const valueBytes = enc.encode(value);
234
+ const head = new Uint8Array(1 + nameBytes.length + 1 + 2);
235
+ const hv = new DataView(head.buffer);
236
+ hv.setUint8(0, nameBytes.length);
237
+ head.set(nameBytes, 1);
238
+ hv.setUint8(1 + nameBytes.length, 7); // string type
239
+ hv.setUint16(1 + nameBytes.length + 1, valueBytes.length, false);
240
+ headerParts.push(head, valueBytes);
241
+ }
242
+ const headersBytes = Buffer.concat(headerParts.map(p => Buffer.from(p)));
243
+ const total = HEADER_BLOCK_OFFSET + headersBytes.length + payload.length + MESSAGE_CRC_LEN;
244
+ const frame = new Uint8Array(total);
245
+ const dv = new DataView(frame.buffer);
246
+ dv.setUint32(0, total, false);
247
+ dv.setUint32(4, headersBytes.length, false);
248
+ dv.setUint32(8, crc32(frame.subarray(0, PRELUDE_LEN)), false);
249
+ frame.set(headersBytes, HEADER_BLOCK_OFFSET);
250
+ frame.set(payload, HEADER_BLOCK_OFFSET + headersBytes.length);
251
+ dv.setUint32(total - MESSAGE_CRC_LEN, crc32(frame.subarray(0, total - MESSAGE_CRC_LEN)), false);
252
+ return frame;
253
+ }
@@ -0,0 +1,341 @@
1
+ /**
2
+ * Application Default Credentials (ADC) resolution for Vertex AI.
3
+ *
4
+ * Direct WebCrypto + REST implementation (no `google-auth-library`). Sources, in priority order:
5
+ * 1. `GOOGLE_APPLICATION_CREDENTIALS` env → file with `type: "service_account"` (RS256 JWT
6
+ * exchange) or `type: "authorized_user"` (refresh-token exchange).
7
+ * 2. gcloud user ADC (`CLOUDSDK_CONFIG`, else `%APPDATA%\gcloud` on Windows, else
8
+ * `~/.config/gcloud`) `application_default_credentials.json` (authorized_user flow).
9
+ * 3. GCE / Cloud Run metadata server.
10
+ *
11
+ * Tokens are cached per source key and refreshed `GOOGLE_VERTEX_REFRESH_SKEW_MS` (default 60s)
12
+ * before expiry. Concurrent callers waiting on a refresh share one in-flight promise.
13
+ *
14
+ * Security: never logs the access token, private key, or refresh token.
15
+ */
16
+
17
+ import { Buffer } from "node:buffer";
18
+ import * as os from "node:os";
19
+ import * as path from "node:path";
20
+ import { readFileSync, existsSync, statSync } from "node:fs";
21
+ import {
22
+ captureConfigGeneration,
23
+ sweepExpiredOnWrite,
24
+ type GenerationContext,
25
+ } from "./state-store-sweeper";
26
+
27
+ /** Injectable fetch (tests pass a mock); defaults to the global fetch. */
28
+ export type FetchImpl = typeof fetch;
29
+
30
+ const OAUTH_TOKEN_URL = "https://oauth2.googleapis.com/token";
31
+ const METADATA_TOKEN_URL = "http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token";
32
+ const CLOUD_PLATFORM_SCOPE = "https://www.googleapis.com/auth/cloud-platform";
33
+ const JWT_BEARER_GRANT = "urn:ietf:params:oauth:grant-type:jwt-bearer";
34
+
35
+ const TOKEN_TIMEOUT_MS = 15_000;
36
+ const TOKEN_ATTEMPTS = 3;
37
+ const TOKEN_RETRY_BASE_MS = 300;
38
+
39
+ interface CachedToken {
40
+ token: string;
41
+ expiresAtMs: number;
42
+ }
43
+
44
+ interface ServiceAccountCredentials {
45
+ type: "service_account";
46
+ client_email: string;
47
+ private_key: string;
48
+ private_key_id?: string;
49
+ }
50
+
51
+ interface AuthorizedUserCredentials {
52
+ type: "authorized_user";
53
+ client_id: string;
54
+ client_secret: string;
55
+ refresh_token: string;
56
+ }
57
+
58
+ type AdcFileCredentials = ServiceAccountCredentials | AuthorizedUserCredentials;
59
+
60
+ interface TokenResponse {
61
+ access_token: string;
62
+ expires_in: number;
63
+ token_type?: string;
64
+ }
65
+
66
+ const tokenCache = new Map<string, CachedToken>();
67
+ const inflight = new Map<string, Promise<string>>();
68
+ let lastReconciledGeneration = 0;
69
+ let liveSources = new Set<string>();
70
+
71
+ export function sweepExpiredGcpAdcTokens(now = Date.now()): number {
72
+ const skew = getRefreshSkewMs();
73
+ let removed = 0;
74
+ for (const [source, cached] of tokenCache) {
75
+ if (cached.expiresAtMs - skew > now) continue;
76
+ tokenCache.delete(source);
77
+ removed += 1;
78
+ }
79
+ return removed;
80
+ }
81
+
82
+ export function reconcileGcpAdcTokens(context: GenerationContext): number {
83
+ if (context.generation <= lastReconciledGeneration) return 0;
84
+ const currentSource = currentAdcSourceKey();
85
+ let removed = 0;
86
+ for (const source of tokenCache.keys()) {
87
+ if (source === currentSource) continue;
88
+ tokenCache.delete(source);
89
+ removed += 1;
90
+ }
91
+ liveSources = new Set([currentSource]);
92
+ lastReconciledGeneration = context.generation;
93
+ return removed;
94
+ }
95
+
96
+ function getRefreshSkewMs(): number {
97
+ const raw = Number(process.env.GOOGLE_VERTEX_REFRESH_SKEW_MS);
98
+ return Number.isFinite(raw) && raw > 0 ? raw : 60_000;
99
+ }
100
+
101
+ /** gcloud config dir, matching the SDK's own resolution order. */
102
+ function gcloudConfigDir(): string {
103
+ const explicit = process.env.CLOUDSDK_CONFIG?.trim();
104
+ if (explicit) return explicit;
105
+ if (process.platform === "win32" && process.env.APPDATA) {
106
+ return path.join(process.env.APPDATA, "gcloud");
107
+ }
108
+ return path.join(os.homedir(), ".config", "gcloud");
109
+ }
110
+
111
+ function userAdcPath(): string {
112
+ return path.join(gcloudConfigDir(), "application_default_credentials.json");
113
+ }
114
+
115
+ /**
116
+ * A content-freshness fingerprint for a credential file, so an in-place rewrite (e.g.
117
+ * `gcloud auth application-default login`, or a rotated service-account key at the same path)
118
+ * changes the cache key and invalidates the stale token. Falls back to the bare path when stat fails.
119
+ */
120
+ function fileSourceTag(prefix: string, filePath: string): string {
121
+ try {
122
+ const st = statSync(filePath);
123
+ return `${prefix}:${filePath}:${st.size}:${Math.floor(st.mtimeMs)}`;
124
+ } catch {
125
+ return `${prefix}:${filePath}`;
126
+ }
127
+ }
128
+
129
+ function readJsonFile<T>(filePath: string): T | undefined {
130
+ if (!existsSync(filePath)) return undefined;
131
+ return JSON.parse(readFileSync(filePath, "utf8")) as T;
132
+ }
133
+
134
+ function loadAdcCredentials(): { source: string; creds: AdcFileCredentials } | undefined {
135
+ const gacPath = process.env.GOOGLE_APPLICATION_CREDENTIALS;
136
+ if (gacPath) {
137
+ const creds = readJsonFile<AdcFileCredentials>(gacPath);
138
+ if (!creds) throw new Error(`GOOGLE_APPLICATION_CREDENTIALS points to a missing file: ${gacPath}`);
139
+ return { source: fileSourceTag("gac", gacPath), creds };
140
+ }
141
+ const userPath = userAdcPath();
142
+ const creds = readJsonFile<AdcFileCredentials>(userPath);
143
+ if (creds) return { source: fileSourceTag("user", userPath), creds };
144
+ return undefined;
145
+ }
146
+
147
+ /**
148
+ * The cache key for the source the NEXT resolve would use, computed cheaply (no network). Lets the
149
+ * cache return a token only when it still matches the active credential source, so an in-process
150
+ * change to GOOGLE_APPLICATION_CREDENTIALS (or the user ADC file) does not keep serving a stale
151
+ * token from a different source. Falls back to "metadata" when no file/env ADC is present.
152
+ */
153
+ function currentAdcSourceKey(): string {
154
+ const gacPath = process.env.GOOGLE_APPLICATION_CREDENTIALS;
155
+ if (gacPath) return fileSourceTag("gac", gacPath);
156
+ const userPath = userAdcPath();
157
+ if (existsSync(userPath)) return fileSourceTag("user", userPath);
158
+ return "metadata";
159
+ }
160
+
161
+ function base64UrlEncode(bytes: Uint8Array | string): string {
162
+ const buf = typeof bytes === "string" ? Buffer.from(bytes, "utf8") : Buffer.from(bytes);
163
+ return buf.toString("base64url");
164
+ }
165
+
166
+ function pemToPkcs8(pem: string): ArrayBuffer {
167
+ const body = pem
168
+ .replace(/-----BEGIN [^-]+-----/g, "")
169
+ .replace(/-----END [^-]+-----/g, "")
170
+ .replace(/\s+/g, "");
171
+ if (!body) throw new Error("Invalid PEM: empty body");
172
+ const buf = Buffer.from(body, "base64");
173
+ return buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength) as ArrayBuffer;
174
+ }
175
+
176
+ async function signJwtRs256(claims: Record<string, unknown>, privateKeyPem: string, keyId?: string): Promise<string> {
177
+ const header: Record<string, unknown> = { alg: "RS256", typ: "JWT" };
178
+ if (keyId) header.kid = keyId;
179
+ const payload = `${base64UrlEncode(JSON.stringify(header))}.${base64UrlEncode(JSON.stringify(claims))}`;
180
+ const key = await globalThis.crypto.subtle.importKey(
181
+ "pkcs8",
182
+ pemToPkcs8(privateKeyPem),
183
+ { name: "RSASSA-PKCS1-v1_5", hash: "SHA-256" },
184
+ false,
185
+ ["sign"],
186
+ );
187
+ const signature = new Uint8Array(
188
+ await globalThis.crypto.subtle.sign("RSASSA-PKCS1-v1_5", key, new TextEncoder().encode(payload)),
189
+ );
190
+ return `${payload}.${base64UrlEncode(signature)}`;
191
+ }
192
+
193
+ function tokenRetryDelayMs(attempt: number): number {
194
+ const exp = TOKEN_RETRY_BASE_MS * 2 ** attempt;
195
+ return Math.floor(exp * (0.8 + Math.random() * 0.4));
196
+ }
197
+
198
+ function isRetryableTokenStatus(status: number): boolean {
199
+ return status === 429 || status === 500 || status === 502 || status === 503 || status === 504;
200
+ }
201
+
202
+ function tokenTimeoutSignal(parent: AbortSignal | undefined): AbortSignal {
203
+ const timeout = AbortSignal.timeout(TOKEN_TIMEOUT_MS);
204
+ return parent ? AbortSignal.any([parent, timeout]) : timeout;
205
+ }
206
+
207
+ /**
208
+ * Exchange a grant for a Google access token, hardened with a per-attempt timeout + bounded retry
209
+ * on transient failures (network errors and 429/5xx). Non-retryable statuses (e.g. 400/401 from a
210
+ * bad grant) fail fast. The error message carries only the status code, never the response body
211
+ * (which can leak grant/account details) or the token/key.
212
+ */
213
+ async function postForToken(body: URLSearchParams, signal: AbortSignal | undefined, fetchImpl: FetchImpl): Promise<TokenResponse> {
214
+ let lastError: unknown;
215
+ for (let attempt = 0; attempt < TOKEN_ATTEMPTS; attempt++) {
216
+ if (signal?.aborted) throw signal.reason ?? new Error("Google OAuth token exchange aborted");
217
+ let response: Response;
218
+ try {
219
+ response = await fetchImpl(OAUTH_TOKEN_URL, {
220
+ method: "POST",
221
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
222
+ body: body.toString(),
223
+ signal: tokenTimeoutSignal(signal),
224
+ });
225
+ } catch (err) {
226
+ if (signal?.aborted) throw err;
227
+ lastError = err;
228
+ if (attempt === TOKEN_ATTEMPTS - 1) break;
229
+ await new Promise(resolve => setTimeout(resolve, tokenRetryDelayMs(attempt)));
230
+ continue;
231
+ }
232
+ if (response.ok) return (await response.json()) as TokenResponse;
233
+ if (!isRetryableTokenStatus(response.status) || attempt === TOKEN_ATTEMPTS - 1) {
234
+ throw new Error(`Google OAuth token exchange failed (${response.status})`);
235
+ }
236
+ lastError = new Error(`Google OAuth token exchange failed (${response.status})`);
237
+ await response.body?.cancel().catch(() => {});
238
+ await new Promise(resolve => setTimeout(resolve, tokenRetryDelayMs(attempt)));
239
+ }
240
+ throw lastError instanceof Error ? lastError : new Error("Google OAuth token exchange failed");
241
+ }
242
+
243
+ async function exchangeJwtForToken(creds: ServiceAccountCredentials, signal: AbortSignal | undefined, fetchImpl: FetchImpl): Promise<TokenResponse> {
244
+ const now = Math.floor(Date.now() / 1000);
245
+ const assertion = await signJwtRs256(
246
+ { iss: creds.client_email, scope: CLOUD_PLATFORM_SCOPE, aud: OAUTH_TOKEN_URL, exp: now + 3600, iat: now },
247
+ creds.private_key,
248
+ creds.private_key_id,
249
+ );
250
+ return postForToken(new URLSearchParams({ grant_type: JWT_BEARER_GRANT, assertion }), signal, fetchImpl);
251
+ }
252
+
253
+ async function exchangeRefreshToken(creds: AuthorizedUserCredentials, signal: AbortSignal | undefined, fetchImpl: FetchImpl): Promise<TokenResponse> {
254
+ return postForToken(
255
+ new URLSearchParams({
256
+ client_id: creds.client_id,
257
+ client_secret: creds.client_secret,
258
+ refresh_token: creds.refresh_token,
259
+ grant_type: "refresh_token",
260
+ }),
261
+ signal,
262
+ fetchImpl,
263
+ );
264
+ }
265
+
266
+ async function fetchMetadataToken(signal: AbortSignal | undefined, fetchImpl: FetchImpl): Promise<TokenResponse | undefined> {
267
+ const timeout = AbortSignal.timeout(2000);
268
+ const combined = signal ? AbortSignal.any([signal, timeout]) : timeout;
269
+ try {
270
+ const response = await fetchImpl(METADATA_TOKEN_URL, {
271
+ method: "GET",
272
+ headers: { "Metadata-Flavor": "Google" },
273
+ signal: combined,
274
+ });
275
+ if (!response.ok) return undefined;
276
+ return (await response.json()) as TokenResponse;
277
+ } catch {
278
+ return undefined;
279
+ }
280
+ }
281
+
282
+ async function resolveAccessTokenUncached(signal: AbortSignal | undefined, fetchImpl: FetchImpl): Promise<{ source: string; token: TokenResponse }> {
283
+ const adc = loadAdcCredentials();
284
+ if (adc) {
285
+ const token = adc.creds.type === "service_account"
286
+ ? await exchangeJwtForToken(adc.creds, signal, fetchImpl)
287
+ : await exchangeRefreshToken(adc.creds, signal, fetchImpl);
288
+ return { source: adc.source, token };
289
+ }
290
+ const metadata = await fetchMetadataToken(signal, fetchImpl);
291
+ if (metadata) return { source: "metadata", token: metadata };
292
+ throw new Error(
293
+ "Vertex AI requires Application Default Credentials. Set GOOGLE_APPLICATION_CREDENTIALS, run `gcloud auth application-default login`, or run on a GCE/Cloud Run instance with a service account.",
294
+ );
295
+ }
296
+
297
+ /** Returns a Bearer access token for the `Authorization` header on Vertex AI calls (cached + refreshed). */
298
+ export async function getVertexAccessToken(options?: { signal?: AbortSignal; fetch?: FetchImpl }): Promise<string> {
299
+ const fetchImpl = options?.fetch ?? globalThis.fetch.bind(globalThis);
300
+ const skew = getRefreshSkewMs();
301
+ const now = Date.now();
302
+
303
+ // Only serve a cached token that matches the source the next resolve would actually use; prune
304
+ // expired or now-stale (different-source) entries so a credential-source change is honored.
305
+ const expectedSource = currentAdcSourceKey();
306
+ const writerGeneration = captureConfigGeneration();
307
+ for (const [source, cached] of tokenCache) {
308
+ if (source === expectedSource && cached.expiresAtMs - skew > now) return cached.token;
309
+ if (cached.expiresAtMs - skew <= now) tokenCache.delete(source);
310
+ }
311
+
312
+ // Dedup in-flight fetches PER source, not globally: if the credential source changes while a
313
+ // fetch is in flight, a new caller must not reuse the old source's promise (cross-source bleed).
314
+ const cacheKey = expectedSource;
315
+ const existing = inflight.get(cacheKey);
316
+ if (existing) return existing;
317
+
318
+ const promise = (async () => {
319
+ try {
320
+ const { source, token } = await resolveAccessTokenUncached(options?.signal, fetchImpl);
321
+ const expiresAtMs = Date.now() + Math.max(0, token.expires_in * 1000);
322
+ if (writerGeneration >= lastReconciledGeneration || liveSources.has(source)) {
323
+ tokenCache.set(source, { token: token.access_token, expiresAtMs });
324
+ sweepExpiredOnWrite(Date.now());
325
+ }
326
+ return token.access_token;
327
+ } finally {
328
+ inflight.delete(cacheKey);
329
+ }
330
+ })();
331
+ inflight.set(cacheKey, promise);
332
+ return promise;
333
+ }
334
+
335
+ /** Test seam: restores complete process-local token and reconciliation state. */
336
+ export function __resetVertexTokenCache(): void {
337
+ tokenCache.clear();
338
+ inflight.clear();
339
+ lastReconciledGeneration = 0;
340
+ liveSources = new Set();
341
+ }
@@ -0,0 +1,58 @@
1
+ /** In-memory ring buffer of multi-agent guidance-injection / effort-cap log lines.
2
+ *
3
+ * Injection debug lines were previously console-only, so the GUI had an "Injection log"
4
+ * toggle with nothing to display. This buffer mirrors the provider debug buffer so the
5
+ * management API and GUI can tail injection lines the same way. Callers keep their own
6
+ * `isInjectionDebugEnabled()` guard; this module only stores what it is given. */
7
+
8
+ import type { DebugLogEntry } from "./debug-log-buffer";
9
+ import { retainedUtf8Bytes, truncateRetainedUtf8 } from "./admission";
10
+ import { enforceAppOwnedMemoryBudget } from "./app-owned-memory";
11
+
12
+ const MAX_LINES = 2_000;
13
+ const MAX_DEBUG_LINE_BYTES = 16 * 1024;
14
+ const buffer: DebugLogEntry[] = [];
15
+ let nextSeq = 1;
16
+ let bufferBytes = 0;
17
+
18
+ function removeOldestEntry(): number {
19
+ const entry = buffer.shift();
20
+ if (!entry) return 0;
21
+ const bytes = retainedUtf8Bytes(entry.line);
22
+ bufferBytes -= bytes;
23
+ return bytes;
24
+ }
25
+
26
+ /** Append a line to the injection buffer and echo it to the server console. */
27
+ export function injectionDebugLog(line: string): void {
28
+ const retainedLine = truncateRetainedUtf8(line, MAX_DEBUG_LINE_BYTES);
29
+ const entry: DebugLogEntry = { seq: nextSeq++, at: Date.now(), line: retainedLine };
30
+ buffer.push(entry);
31
+ bufferBytes += retainedUtf8Bytes(retainedLine);
32
+ while (buffer.length > MAX_LINES) removeOldestEntry();
33
+ enforceAppOwnedMemoryBudget();
34
+ console.log(line);
35
+ }
36
+
37
+ export function getInjectionDebugLogEntries(options?: { after?: number; limit?: number }): DebugLogEntry[] {
38
+ const after = options?.after ?? 0;
39
+ const limit = options?.limit ?? 500;
40
+ const filtered = after > 0 ? buffer.filter(entry => entry.seq > after) : buffer;
41
+ if (filtered.length <= limit) return filtered;
42
+ return filtered.slice(-limit);
43
+ }
44
+
45
+ export function injectionBufferMetrics(): { entries: number; bytes: number; oldestAt: number | null } {
46
+ return { entries: buffer.length, bytes: bufferBytes, oldestAt: buffer[0]?.at ?? null };
47
+ }
48
+
49
+ export function evictOldestInjectionEntryForBudget(): number {
50
+ return removeOldestEntry();
51
+ }
52
+
53
+ /** Test isolation. */
54
+ export function resetInjectionDebugLogBufferForTests(): void {
55
+ buffer.length = 0;
56
+ bufferBytes = 0;
57
+ nextSeq = 1;
58
+ }