@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,520 @@
1
+ import { createHash } from "node:crypto";
2
+ import { enforceAppOwnedMemoryBudget } from "../lib/app-owned-memory";
3
+
4
+ /**
5
+ * Google-family thoughtSignature reasoning-replay cache.
6
+ *
7
+ * Gemini-3 interleaved thinking is stateless upstream: each model content part carries a
8
+ * `thoughtSignature` that MUST be echoed back on the matching part in the next request, or the
9
+ * upstream rejects the turn (HTTP 400). We observe signatures on the response stream, cache them
10
+ * per `model + session`, and re-inject them into the outgoing `request.contents` on the next turn.
11
+ *
12
+ * Mirrors CLIProxyAPI `internal/runtime/executor/antigravity_reasoning_replay.go` and is also used
13
+ * by Vertex with a transport/project/location-prefixed model identity. Gemini-only;
14
+ * Claude-on-Antigravity uses inline signature sanitization instead (see google-antigravity-wire).
15
+ */
16
+
17
+ interface ReplayCall {
18
+ signature: string;
19
+ sizeBytes: number;
20
+ touchedAtMs: number;
21
+ }
22
+
23
+ interface ReplayEntry {
24
+ /** thoughtSignature keyed by functionCall identity (name + canonical args). */
25
+ byCall: Map<string, ReplayCall>;
26
+ bytes: number;
27
+ expiresAtMs: number;
28
+ oldestAtMs: number | null;
29
+ }
30
+
31
+ const MIN_SIGNATURE_LEN = 16;
32
+ const REPLAY_TTL_MS = 60 * 60 * 1000; // 1h
33
+ export const ANTIGRAVITY_REPLAY_MAX_ENTRIES = 10_240;
34
+ const REPLAY_EVICT_BATCH = 128;
35
+ const REPLAY_MAX_CALLS_PER_SESSION = 256;
36
+ export const ANTIGRAVITY_REPLAY_MAX_BYTES_PER_SESSION = 2 * 1024 * 1024;
37
+ export const ANTIGRAVITY_REPLAY_MAX_TOTAL_BYTES = 64 * 1024 * 1024;
38
+ const REPLAY_MAX_SIGNATURE_BYTES = 64 * 1024;
39
+ /** Fixed 64-hex outer key length, counted once per session entry. */
40
+ const REPLAY_SESSION_KEY_BYTES = 64;
41
+
42
+ interface ReplayLimits {
43
+ maxCallsPerSession: number;
44
+ maxBytesPerSession: number;
45
+ maxSignatureBytes: number;
46
+ }
47
+
48
+ const DEFAULT_REPLAY_LIMITS: ReplayLimits = {
49
+ maxCallsPerSession: REPLAY_MAX_CALLS_PER_SESSION,
50
+ maxBytesPerSession: ANTIGRAVITY_REPLAY_MAX_BYTES_PER_SESSION,
51
+ maxSignatureBytes: REPLAY_MAX_SIGNATURE_BYTES,
52
+ };
53
+
54
+ const replayCache = new Map<string, ReplayEntry>();
55
+ const utf8 = new TextEncoder();
56
+ let replayLimits = { ...DEFAULT_REPLAY_LIMITS };
57
+ let replayBytes = 0;
58
+ let replayOldestSessionKey: string | undefined;
59
+ let replayOldestAt: number | null = null;
60
+
61
+ /**
62
+ * Fixed-size identity for a (model, sessionId) pair: SHA-256 over
63
+ * length-prefixed UTF-16 code units fed incrementally (no separator ambiguity
64
+ * — `("a\0b","c")` and `("a","b\0c")` derive different keys — and no raw
65
+ * model/session strings retained as Map keys, which the byte caps never
66
+ * counted).
67
+ */
68
+ /**
69
+ * Injective string feed for key derivation: length-prefixed in CODE UNITS,
70
+ * then each code unit as two little-endian bytes. TextEncoder/UTF-8 would
71
+ * fold lone surrogates into U+FFFD, colliding distinct strings (e.g.
72
+ * "�" and "�") into the same key.
73
+ */
74
+ function updateHashWithString(hash: ReturnType<typeof createHash>, value: string): void {
75
+ hash.update(String(value.length));
76
+ hash.update("\0");
77
+ const buf = Buffer.allocUnsafe(8192);
78
+ let offset = 0;
79
+ for (let index = 0; index < value.length; index += 1) {
80
+ buf.writeUInt16LE(value.charCodeAt(index), offset);
81
+ offset += 2;
82
+ if (offset === buf.length) {
83
+ hash.update(buf);
84
+ offset = 0;
85
+ }
86
+ }
87
+ if (offset > 0) hash.update(buf.subarray(0, offset));
88
+ }
89
+
90
+ function replayKey(model: string, sessionId: string): string {
91
+ const hash = createHash("sha256");
92
+ updateHashWithString(hash, model);
93
+ updateHashWithString(hash, sessionId);
94
+ return hash.digest("hex");
95
+ }
96
+
97
+ /** Canonical output exceeding this budget is rejected DURING the walk — the
98
+ * pre-fix path materialized an unbounded canonical string before admission. */
99
+ const REPLAY_MAX_CANONICAL_ARGS_BYTES = 64 * 1024;
100
+ const CANONICAL_OVERFLOW = Symbol("canonical-overflow");
101
+
102
+ /** Byte-identical output to the old recursive canonicalJson, written incrementally. */
103
+ /**
104
+ * Key-count pre-check: every object key costs at least 4 canonical bytes
105
+ * (two quotes, colon, separator), so a wider object ALWAYS overflows the
106
+ * canonical budget — skip the sort and the walk. Object.keys allocation
107
+ * itself is linear and irreducible in JS (there is no streaming key API),
108
+ * but it is transient and never sorted or walked past this bound.
109
+ */
110
+ const CANONICAL_MAX_KEYS_PER_OBJECT = REPLAY_MAX_CANONICAL_ARGS_BYTES / 4;
111
+
112
+ /** Test-only scan instrumentation: proves overflow aborts the walk near the
113
+ * cap instead of scanning/materializing the whole input. */
114
+ let canonicalScanUnitsForTests = 0;
115
+ export function canonicalScanUnitsForTestsValue(): number {
116
+ return canonicalScanUnitsForTests;
117
+ }
118
+ export function resetCanonicalScanUnitsForTests(): void {
119
+ canonicalScanUnitsForTests = 0;
120
+ }
121
+
122
+ const MAX_CANONICAL_DEPTH = 128;
123
+
124
+ function writeCanonicalJson(value: unknown, sink: (chunk: string) => void, depth = 0): void {
125
+ canonicalScanUnitsForTests += 1;
126
+ // Depth overflow is the same class as byte overflow: skip replay for this
127
+ // call instead of exhausting the stack on a pathological argument shape.
128
+ if (depth > MAX_CANONICAL_DEPTH) throw CANONICAL_OVERFLOW;
129
+ if (typeof value === "string") {
130
+ writeJsonStringEscaped(value, sink);
131
+ return;
132
+ }
133
+ if (value === null || typeof value !== "object") {
134
+ sink(JSON.stringify(value) ?? "null");
135
+ return;
136
+ }
137
+ if (Array.isArray(value)) {
138
+ sink("[");
139
+ for (let index = 0; index < value.length; index += 1) {
140
+ if (index > 0) sink(",");
141
+ // Array.prototype.map parity: holes produce NOTHING between the commas
142
+ // (old output `[1,,3]`), while an explicit undefined element is "null".
143
+ if (index in value) writeCanonicalJson(value[index], sink, depth + 1);
144
+ }
145
+ sink("]");
146
+ return;
147
+ }
148
+ const keys = Object.keys(value as Record<string, unknown>);
149
+ if (keys.length > CANONICAL_MAX_KEYS_PER_OBJECT) throw CANONICAL_OVERFLOW;
150
+ keys.sort();
151
+ sink("{");
152
+ keys.forEach((k, index) => {
153
+ if (index > 0) sink(",");
154
+ writeJsonStringEscaped(k, sink);
155
+ sink(":");
156
+ writeCanonicalJson((value as Record<string, unknown>)[k], sink, depth + 1);
157
+ });
158
+ sink("}");
159
+ }
160
+
161
+ /**
162
+ * JSON.stringify string escaping, streamed in small chunks so the budget can
163
+ * reject mid-string — calling JSON.stringify on a multi-MiB primitive would
164
+ * materialize its full escaped form before the sink could refuse it.
165
+ * Semantics mirror JSON.stringify for strings exactly (ES2019 JSON
166
+ * superset): quotes/backslash and control characters are escaped, LONE
167
+ * surrogates become \uXXXX, and valid surrogate pairs pass through raw.
168
+ */
169
+ function writeJsonStringEscaped(value: string, sink: (chunk: string) => void): void {
170
+ sink('"');
171
+ let buffer = "";
172
+ for (const cp of value) {
173
+ canonicalScanUnitsForTests += 1;
174
+ const code = cp.codePointAt(0)!;
175
+ let escaped: string;
176
+ if (cp === '"') escaped = '\\"';
177
+ else if (cp === "\\") escaped = "\\\\";
178
+ else if (cp === "\b") escaped = "\\b";
179
+ else if (cp === "\f") escaped = "\\f";
180
+ else if (cp === "\n") escaped = "\\n";
181
+ else if (cp === "\r") escaped = "\\r";
182
+ else if (cp === "\t") escaped = "\\t";
183
+ else if (code < 0x20) escaped = `\\u${code.toString(16).padStart(4, "0")}`;
184
+ // Lone surrogates: JSON.stringify emits \uXXXX (a raw one would decode
185
+ // back as U+FFFD and collide with real U+FFFD content).
186
+ else if (code >= 0xd800 && code <= 0xdfff) escaped = `\\u${code.toString(16).padStart(4, "0")}`;
187
+ else escaped = cp;
188
+ buffer += escaped;
189
+ if (buffer.length >= 4096) {
190
+ sink(buffer);
191
+ buffer = "";
192
+ }
193
+ }
194
+ if (buffer.length > 0) sink(buffer);
195
+ sink('"');
196
+ }
197
+
198
+ /** Bounded canonicalization: null on overflow (skip replay for that call). */
199
+ function canonicalJsonBounded(value: unknown, maxBytes: number): string | null {
200
+ let written = 0;
201
+ const parts: string[] = [];
202
+ const sink = (chunk: string) => {
203
+ written += utf8.encode(chunk).byteLength;
204
+ if (written > maxBytes) throw CANONICAL_OVERFLOW;
205
+ parts.push(chunk);
206
+ };
207
+ try {
208
+ writeCanonicalJson(value, sink);
209
+ } catch (error) {
210
+ if (error === CANONICAL_OVERFLOW) return null;
211
+ throw error;
212
+ }
213
+ return parts.join("");
214
+ }
215
+
216
+ /**
217
+ * Stable identity for a functionCall part: fixed-size SHA-256 over
218
+ * length-prefixed name + canonical args. Overflow during canonicalization
219
+ * skips replay for that call (never materializes an unbounded string); other
220
+ * canonicalization failures keep the old name-only fallback semantics.
221
+ */
222
+ function functionCallKey(name: unknown, args: unknown): string | undefined {
223
+ if (typeof name !== "string" || name.length === 0) return undefined;
224
+ let canonical: string | null;
225
+ try {
226
+ canonical = canonicalJsonBounded(args ?? {}, REPLAY_MAX_CANONICAL_ARGS_BYTES);
227
+ } catch {
228
+ canonical = "";
229
+ }
230
+ if (canonical === null) return undefined;
231
+ const hash = createHash("sha256");
232
+ updateHashWithString(hash, name);
233
+ updateHashWithString(hash, canonical);
234
+ return hash.digest("hex");
235
+ }
236
+
237
+ /** Test-only key-derivation seam: the fixed-key regression cannot go red
238
+ * through snapshot.bytes (that metric never counted raw outer keys). */
239
+ export function antigravityReplayKeyForTests(model: string, sessionId: string): string {
240
+ return replayKey(model, sessionId);
241
+ }
242
+
243
+ export function antigravityFunctionCallKeyForTests(name: unknown, args: unknown): string | undefined {
244
+ return functionCallKey(name, args);
245
+ }
246
+
247
+ /** Test-only bounded-canonicalization seam: proves mid-walk rejection without
248
+ * materializing the escaped form (allocation guard). */
249
+ export function antigravityCanonicalJsonBoundedForTests(value: unknown, maxBytes: number): string | null {
250
+ return canonicalJsonBounded(value, maxBytes);
251
+ }
252
+
253
+ /** Test-only: the ACTUAL internal session keys, so tests can prove raw
254
+ * model/session strings are never retained as Map keys. */
255
+ export function antigravityReplaySessionKeysForTests(): string[] {
256
+ return [...replayCache.keys()];
257
+ }
258
+
259
+ function extractSignature(part: Record<string, unknown>): string | undefined {
260
+ const direct = part.thoughtSignature ?? part.thought_signature;
261
+ if (typeof direct === "string" && direct.length >= MIN_SIGNATURE_LEN) return direct;
262
+ const extra = part.extra_content as { google?: { thought_signature?: unknown } } | undefined;
263
+ const nested = extra?.google?.thought_signature;
264
+ if (typeof nested === "string" && nested.length >= MIN_SIGNATURE_LEN) return nested;
265
+ return undefined;
266
+ }
267
+
268
+ function deleteReplaySession(key: string): number {
269
+ const entry = replayCache.get(key);
270
+ if (!entry) return 0;
271
+ replayCache.delete(key);
272
+ replayBytes -= entry.bytes;
273
+ if (replayOldestSessionKey === key) recomputeReplayOldestCandidate();
274
+ return entry.bytes;
275
+ }
276
+
277
+ function recomputeReplayOldestCandidate(): void {
278
+ replayOldestSessionKey = undefined;
279
+ replayOldestAt = null;
280
+ for (const [key, entry] of replayCache) {
281
+ if (entry.oldestAtMs === null || (replayOldestAt !== null && entry.oldestAtMs >= replayOldestAt)) continue;
282
+ replayOldestSessionKey = key;
283
+ replayOldestAt = entry.oldestAtMs;
284
+ }
285
+ }
286
+
287
+ function refreshReplaySessionCandidate(key: string, entry: ReplayEntry): void {
288
+ entry.oldestAtMs = entry.byCall.values().next().value?.touchedAtMs ?? null;
289
+ if (replayOldestSessionKey === key) {
290
+ recomputeReplayOldestCandidate();
291
+ return;
292
+ }
293
+ if (entry.oldestAtMs !== null && (replayOldestAt === null || entry.oldestAtMs < replayOldestAt)) {
294
+ replayOldestSessionKey = key;
295
+ replayOldestAt = entry.oldestAtMs;
296
+ }
297
+ }
298
+
299
+ function deleteExpiredReplaySessions(now: number): void {
300
+ for (const [key, entry] of replayCache) if (entry.expiresAtMs <= now) deleteReplaySession(key);
301
+ }
302
+
303
+ /**
304
+ * The lazy per-call expiry scan is O(sessions); at the 10,240-session cap
305
+ * every observe/apply would rescan the whole map — O(n²) under load. The 60s
306
+ * state-store sweeper is already the periodic expiry authority, so lazy scans
307
+ * are throttled to at most one per interval (expired entries may linger a few
308
+ * extra seconds; TTL is fuzzy at that scale by design).
309
+ */
310
+ const LAZY_SWEEP_INTERVAL_MS = 30_000;
311
+ let lastLazySweepAt = Number.NEGATIVE_INFINITY;
312
+
313
+ function deleteExpiredReplaySessionsThrottled(now: number): void {
314
+ if (now - lastLazySweepAt < LAZY_SWEEP_INTERVAL_MS) return;
315
+ lastLazySweepAt = now;
316
+ deleteExpiredReplaySessions(now);
317
+ }
318
+
319
+ export function sweepExpiredAntigravityReplay(now = Date.now()): number {
320
+ const before = replayCache.size;
321
+ deleteExpiredReplaySessions(now);
322
+ return before - replayCache.size;
323
+ }
324
+
325
+ function deleteReplayCall(entry: ReplayEntry, callKey: string): number {
326
+ const call = entry.byCall.get(callKey);
327
+ if (!call) return 0;
328
+ entry.byCall.delete(callKey);
329
+ entry.bytes -= call.sizeBytes;
330
+ replayBytes -= call.sizeBytes;
331
+ return call.sizeBytes;
332
+ }
333
+
334
+ function evictInnerCalls(entry: ReplayEntry): void {
335
+ while (
336
+ entry.byCall.size > replayLimits.maxCallsPerSession
337
+ || entry.bytes > replayLimits.maxBytesPerSession
338
+ ) {
339
+ const oldest = entry.byCall.keys().next().value;
340
+ if (oldest === undefined) break;
341
+ deleteReplayCall(entry, oldest);
342
+ }
343
+ }
344
+
345
+ function evictIfNeeded(): void {
346
+ if (replayCache.size > ANTIGRAVITY_REPLAY_MAX_ENTRIES) {
347
+ const oldest = [...replayCache.entries()]
348
+ .sort((a, b) => a[1].expiresAtMs - b[1].expiresAtMs)
349
+ .slice(0, REPLAY_EVICT_BATCH);
350
+ for (const [key] of oldest) deleteReplaySession(key);
351
+ }
352
+ while (replayBytes > ANTIGRAVITY_REPLAY_MAX_TOTAL_BYTES) {
353
+ const oldestKey = [...replayCache.entries()]
354
+ .sort((a, b) => a[1].expiresAtMs - b[1].expiresAtMs)[0]?.[0];
355
+ if (oldestKey === undefined) return;
356
+ deleteReplaySession(oldestKey);
357
+ }
358
+ }
359
+
360
+ /** Gemini/Flash/Agent use the replay cache; Claude does not (inline sanitization instead). */
361
+ export function antigravityUsesReplayCache(model: string): boolean {
362
+ return !/claude/i.test(model);
363
+ }
364
+
365
+ /**
366
+ * Observe a parsed CCA chunk's `candidates[0].content.parts` and record thought signatures keyed by
367
+ * the functionCall identity (name + args). Accumulates across the whole session so a sequential
368
+ * multi-step tool loop keeps EVERY prior call's signature, not just the latest part-index slot.
369
+ * A signature on a standalone thought part is paired with the next functionCall in the same
370
+ * array (#897); a call's own signature takes precedence and an unpaired one is dropped.
371
+ * `parts` is the already-unwrapped `response.candidates[0].content.parts`.
372
+ */
373
+ export function observeAntigravityReplay(model: string, sessionId: string, parts: unknown[]): void {
374
+ if (!antigravityUsesReplayCache(model) || !Array.isArray(parts) || parts.length === 0) return;
375
+ const now = Date.now();
376
+ deleteExpiredReplaySessionsThrottled(now);
377
+ const key = replayKey(model, sessionId);
378
+ const existing = replayCache.get(key);
379
+ const entry = existing ?? {
380
+ byCall: new Map<string, ReplayCall>(),
381
+ bytes: REPLAY_SESSION_KEY_BYTES,
382
+ expiresAtMs: 0,
383
+ oldestAtMs: null,
384
+ };
385
+ let inserted = false;
386
+ let pendingThoughtSig: string | undefined;
387
+ for (const raw of parts) {
388
+ if (!raw || typeof raw !== "object") continue;
389
+ const part = raw as Record<string, unknown>;
390
+ const sig = extractSignature(part);
391
+ const fc = part.functionCall as { name?: unknown; args?: unknown } | undefined;
392
+ if (!fc) {
393
+ // A signature on a standalone thought part pairs with the NEXT functionCall in this
394
+ // array: thought parts are stripped from replayed history, so the call part is the only
395
+ // carrier that survives (#897). Non-thought parts keep their own signature in history.
396
+ if (sig && part.thought === true) pendingThoughtSig = sig;
397
+ continue;
398
+ }
399
+ const callSig = sig ?? pendingThoughtSig; // a signature on the call part itself wins
400
+ pendingThoughtSig = undefined;
401
+ if (!callSig) continue;
402
+ const ck = functionCallKey(fc.name, fc.args);
403
+ if (!ck) continue; // only function-call signatures are replayable by identity
404
+ const signatureBytes = utf8.encode(callSig).byteLength;
405
+ const sizeBytes = utf8.encode(ck).byteLength + signatureBytes;
406
+ if (signatureBytes > replayLimits.maxSignatureBytes || sizeBytes > replayLimits.maxBytesPerSession) continue;
407
+ deleteReplayCall(entry, ck);
408
+ entry.byCall.set(ck, { signature: callSig, sizeBytes, touchedAtMs: now });
409
+ entry.bytes += sizeBytes;
410
+ replayBytes += sizeBytes;
411
+ inserted = true;
412
+ }
413
+ if (!inserted) return;
414
+ // Charge the fixed outer key only when the session is actually stored.
415
+ if (!existing) replayBytes += REPLAY_SESSION_KEY_BYTES;
416
+ evictInnerCalls(entry);
417
+ if (entry.byCall.size === 0) {
418
+ // The fixed session overhead can exceed the per-session cap on its own
419
+ // (test-sized limits): an entry holding zero calls is unusable — drop it
420
+ // instead of retaining an unevictable shell.
421
+ if (existing) deleteReplaySession(key);
422
+ else replayBytes -= REPLAY_SESSION_KEY_BYTES;
423
+ return;
424
+ }
425
+ entry.expiresAtMs = now + REPLAY_TTL_MS;
426
+ replayCache.set(key, entry);
427
+ refreshReplaySessionCandidate(key, entry);
428
+ evictIfNeeded();
429
+ enforceAppOwnedMemoryBudget();
430
+ }
431
+
432
+ /**
433
+ * Re-inject cached thought signatures into the outgoing `request.contents`, matched by functionCall
434
+ * identity across ALL model turns (not just the last one). Only fills a functionCall part that
435
+ * lacks a real signature. Returns the same array reference (mutated in place).
436
+ */
437
+ export function applyAntigravityReplay(model: string, sessionId: string, contents: unknown[]): unknown[] {
438
+ if (!antigravityUsesReplayCache(model) || !Array.isArray(contents)) return contents;
439
+ const now = Date.now();
440
+ deleteExpiredReplaySessionsThrottled(now);
441
+ const entry = replayCache.get(replayKey(model, sessionId));
442
+ if (!entry) {
443
+ return contents;
444
+ }
445
+ let touched = false;
446
+ for (const c of contents as { role?: string; parts?: unknown[] }[]) {
447
+ if (!c || typeof c !== "object" || c.role !== "model" || !Array.isArray(c.parts)) continue;
448
+ for (const raw of c.parts) {
449
+ if (!raw || typeof raw !== "object") continue;
450
+ const part = raw as Record<string, unknown>;
451
+ const fc = part.functionCall as { name?: unknown; args?: unknown } | undefined;
452
+ if (!fc) continue;
453
+ if (part.thoughtSignature !== undefined || part.thought_signature !== undefined) continue;
454
+ const ck = functionCallKey(fc.name, fc.args);
455
+ const call = ck ? entry.byCall.get(ck) : undefined;
456
+ if (call && ck) {
457
+ part.thoughtSignature = call.signature;
458
+ entry.byCall.delete(ck);
459
+ entry.byCall.set(ck, { ...call, touchedAtMs: now });
460
+ touched = true;
461
+ }
462
+ }
463
+ }
464
+ if (touched) refreshReplaySessionCandidate(replayKey(model, sessionId), entry);
465
+ return contents;
466
+ }
467
+
468
+ /** Drop the cache entry when upstream rejects a signature (clear-on-invalid). */
469
+ export function clearAntigravityReplay(model: string, sessionId: string): void {
470
+ deleteReplaySession(replayKey(model, sessionId));
471
+ }
472
+
473
+ export function antigravityReplayMetrics(): {
474
+ sessions: number;
475
+ calls: number;
476
+ totalBytes: number;
477
+ largestSessionBytes: number;
478
+ } {
479
+ let calls = 0;
480
+ let largestSessionBytes = 0;
481
+ for (const entry of replayCache.values()) {
482
+ calls += entry.byCall.size;
483
+ largestSessionBytes = Math.max(largestSessionBytes, entry.bytes);
484
+ }
485
+ return { sessions: replayCache.size, calls, totalBytes: replayBytes, largestSessionBytes };
486
+ }
487
+
488
+ export function antigravityReplayRetainedStoreSnapshot(): {
489
+ count: number;
490
+ bytes: number;
491
+ evictableBytes: number;
492
+ pinnedBytes: number;
493
+ oldestAt: number | null;
494
+ } {
495
+ return {
496
+ count: replayCache.size,
497
+ bytes: replayBytes,
498
+ evictableBytes: replayBytes,
499
+ pinnedBytes: 0,
500
+ oldestAt: replayOldestAt,
501
+ };
502
+ }
503
+
504
+ export function evictOldestAntigravityReplayForBudget(): number {
505
+ return replayOldestSessionKey === undefined ? 0 : deleteReplaySession(replayOldestSessionKey);
506
+ }
507
+
508
+ export function setAntigravityReplayLimitsForTests(limits?: Partial<ReplayLimits>): void {
509
+ __resetAntigravityReplayCache();
510
+ replayLimits = limits ? { ...DEFAULT_REPLAY_LIMITS, ...limits } : { ...DEFAULT_REPLAY_LIMITS };
511
+ }
512
+
513
+ /** Test seam. */
514
+ export function __resetAntigravityReplayCache(): void {
515
+ lastLazySweepAt = Number.NEGATIVE_INFINITY;
516
+ replayCache.clear();
517
+ replayBytes = 0;
518
+ replayOldestSessionKey = undefined;
519
+ replayOldestAt = null;
520
+ }
@@ -0,0 +1,140 @@
1
+ import { createHash } from "node:crypto";
2
+ import type { OcxContentPart, OcxParsedRequest } from "../types";
3
+ import { antigravityUserAgent } from "./client-fingerprint";
4
+
5
+ /**
6
+ * Antigravity request User-Agent. Mirrors the real Antigravity CLI UA
7
+ * (`antigravity/cli/{ver} (aidev_client; os_type=darwin; arch=arm64)`) so the request fingerprint
8
+ * matches the OAuth credential — the prior literal `"antigravity"` was a giveaway no real client
9
+ * sends. A `GOOGLE_ANTIGRAVITY_USER_AGENT` override still wins.
10
+ */
11
+ export const ANTIGRAVITY_REQUEST_UA = process.env.GOOGLE_ANTIGRAVITY_USER_AGENT || antigravityUserAgent();
12
+
13
+ /**
14
+ * Whether a stored `OcxToolCall.thoughtSignature` is a REAL upstream Gemini signature versus a
15
+ * foreign id that must not be forwarded to Gemini/Antigravity.
16
+ *
17
+ * Foreign ids that have 400'd Antigravity (`TYPE_BYTES` / Base64 decoding failed) include:
18
+ * - Responses/bridge item ids: `fc_...`, `ctc_...` (custom_tool_call), `tsc_...` (tool_search_call),
19
+ * `call_...`, `rs_...`, …
20
+ * - Anthropic tool-use ids: `toolu_...`
21
+ *
22
+ * Only real signatures may be forwarded — sending a foreign id as `thoughtSignature` breaks
23
+ * multi-turn reasoning continuity. Real signatures are opaque base64-ish blobs with no
24
+ * Responses/Anthropic id prefix.
25
+ *
26
+ * Note: do NOT reject a bare `sig_` / `sig-` prefix — existing Gemini replay fixtures and some
27
+ * upstream blobs use that shape; a deny-list entry for `sig` would drop valid continuity tokens.
28
+ */
29
+ export function isLikelyRealThoughtSignature(sig: string | undefined): boolean {
30
+ if (typeof sig !== "string" || sig.length < 16) return false;
31
+ // Reject synthetic Responses/tool-call ids and Anthropic tool-use ids (`_` or `-` separators).
32
+ if (/^(fc|ctc|tsc|call|msg|rs|resp|reasoning|item|ws|toolu|tool|func|function)[-_]/i.test(sig)) return false;
33
+ // Real Gemini thought signatures are opaque base64/base64url blobs: only [A-Za-z0-9+/_=-].
34
+ // Anything containing other characters (or whitespace) is not a real signature.
35
+ return /^[A-Za-z0-9+/_=-]+$/.test(sig);
36
+ }
37
+
38
+ function firstUserText(parsed: OcxParsedRequest): string | undefined {
39
+ for (const msg of parsed.context.messages) {
40
+ if (msg.role !== "user") continue;
41
+ if (typeof msg.content === "string") return msg.content;
42
+ const first = (msg.content as OcxContentPart[]).find(p => p.type === "text" && typeof p.text === "string");
43
+ if (first && first.type === "text") return first.text;
44
+ }
45
+ return undefined;
46
+ }
47
+
48
+ /**
49
+ * Deterministic Cloud Code Assist session id from the first user message text. Mirrors
50
+ * CLIProxyAPI `generateStableSessionID`: sha256(firstUserText) → BigEndian uint64 masked with
51
+ * 0x7FFFFFFFFFFFFFFF, prefixed with "-". Falls back to a random "-<digits>" id when there is no text.
52
+ */
53
+ export function antigravitySessionId(parsed: OcxParsedRequest): string {
54
+ // The id must be IDENTICAL on turn N and turn N+1: the replay cache observes thought signatures
55
+ // on turn N's response and re-injects them on turn N+1's request, so a changing id loses the
56
+ // association entirely. (A *shared* id does not — signatures are keyed on functionCall identity,
57
+ // name+args, so cross-conversation collisions stay harmless. Instability is the failure mode.)
58
+ //
59
+ // First-user text does not guarantee that. It is stable only while the first user message
60
+ // survives verbatim in what this adapter sees, and Codex compacts, summarises, and trims long
61
+ // histories — at which point the anchor changes mid-conversation (#1295's sibling, #1297).
62
+ //
63
+ // `_clientThreadId` is Codex's own thread identity from `x-codex-parent-thread-id`. It survives
64
+ // compaction because it does not depend on message content, which is the property first-user
65
+ // text fails to provide. Deliberately NOT `promptCacheKey`: that is arbitrary Responses input
66
+ // and is explicitly shared across conversations for some clients
67
+ // (`adapters/cursor/request-builder.ts`), so it identifies a cache cohort, not a conversation.
68
+ //
69
+ // What is NOT claimed: that Google treats this id as anything but opaque, or that upstream
70
+ // signatures are not session-bound. Only the local association is verified here.
71
+ //
72
+ // Clients that send no thread header keep the text anchor and its instability; this is a scoped
73
+ // repair, not a universal one.
74
+ const text = clientThreadAnchor(parsed) ?? firstUserText(parsed);
75
+ if (!text) return `-${Math.floor(Math.random() * 9e18).toString()}`;
76
+ const digest = createHash("sha256").update(text, "utf8").digest();
77
+ const masked = digest.readBigUInt64BE(0) & 0x7fffffffffffffffn;
78
+ return `-${masked.toString()}`;
79
+ }
80
+
81
+ /**
82
+ * Codex's stable client thread id, prefixed before hashing so it does not collide with a first
83
+ * user message equal to the bare thread id.
84
+ *
85
+ * This is a prefix, not full domain separation: a textless-anchor request whose first message is
86
+ * literally `codex-thread:<id>` still hashes the same preimage. Tagging BOTH anchor classes would
87
+ * separate them completely, but it would also change every existing text-derived id — a
88
+ * Google-visible wire value for live conversations — which is a larger blast radius than the
89
+ * collision it removes. A collision is harmless here anyway: the replay cache keys signatures on
90
+ * functionCall identity (name+args), so a shared id does not misattribute them. Instability, not
91
+ * collision, is the failure mode this function exists to prevent.
92
+ */
93
+ function clientThreadAnchor(parsed: OcxParsedRequest): string | undefined {
94
+ const threadId = parsed._clientThreadId?.trim();
95
+ return threadId ? `codex-thread:${threadId}` : undefined;
96
+ }
97
+
98
+ /** A Gemini content part as it appears in an Antigravity request body. */
99
+ interface GeminiPart {
100
+ thought?: boolean;
101
+ thoughtSignature?: string;
102
+ thought_signature?: string;
103
+ text?: string;
104
+ [key: string]: unknown;
105
+ }
106
+ interface GeminiContent {
107
+ role?: string;
108
+ parts?: GeminiPart[];
109
+ [key: string]: unknown;
110
+ }
111
+
112
+ function hasSignature(part: GeminiPart): boolean {
113
+ return typeof part.thoughtSignature === "string" && part.thoughtSignature.length > 0
114
+ || typeof part.thought_signature === "string" && part.thought_signature.length > 0;
115
+ }
116
+
117
+ /**
118
+ * Claude-on-Antigravity signature sanitization (the no-cache path). Mirrors CLIProxyAPI's
119
+ * `StripEmptySignatureThinkingBlocks` + non-model signature stripping: drop thinking parts that
120
+ * carry no valid signature (they would 400 upstream), and strip signature fields from non-model
121
+ * (user) content. Mutates and returns `contents`.
122
+ */
123
+ export function sanitizeAntigravityClaudeSignatures(contents: unknown[]): unknown[] {
124
+ if (!Array.isArray(contents)) return contents;
125
+ for (const raw of contents as GeminiContent[]) {
126
+ if (!raw || typeof raw !== "object" || !Array.isArray(raw.parts)) continue;
127
+ const isModel = raw.role === "model";
128
+ if (!isModel) {
129
+ // Non-model parts must not carry thought signatures.
130
+ for (const part of raw.parts) {
131
+ delete part.thoughtSignature;
132
+ delete part.thought_signature;
133
+ }
134
+ continue;
135
+ }
136
+ // Model turn: drop thinking blocks lacking a valid signature.
137
+ raw.parts = raw.parts.filter(part => !(part.thought === true && !hasSignature(part)));
138
+ }
139
+ return contents;
140
+ }