@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,187 @@
1
+ import {
2
+ closeSync,
3
+ constants as fsConstants,
4
+ fstatSync,
5
+ fsyncSync,
6
+ ftruncateSync,
7
+ lstatSync,
8
+ openSync,
9
+ readdirSync,
10
+ realpathSync,
11
+ unlinkSync,
12
+ } from "node:fs";
13
+ import { dirname, join, resolve } from "node:path";
14
+
15
+ import type { NativeProfileContext } from "./native-profile-store";
16
+ import { NativeProfileError } from "./native-profile-types";
17
+
18
+ const AUTH_TEMP_NAME = /^auth\.json\.ocx\.[1-9]\d*\.[1-9]\d*\.tmp$/;
19
+ const MAX_AUTH_TEMP_RESIDUES = 128;
20
+
21
+ interface PathIdentity {
22
+ readonly dev: bigint;
23
+ readonly ino: bigint;
24
+ }
25
+
26
+ export interface NativeMainAuthTempScrubTestSeam {
27
+ /** Test-only race seam. Production never supplies this callback. */
28
+ beforeOpen?: (path: string) => void;
29
+ /** Test-only removal-failure seam. Production never supplies this callback. */
30
+ beforeUnlink?: (path: string) => void;
31
+ }
32
+
33
+ export interface NativeMainAuthTempScrubResult {
34
+ scrubbed: number;
35
+ }
36
+
37
+ function cleanupRequired(): NativeProfileError {
38
+ return new NativeProfileError(
39
+ "AUTH_TEMP_CLEANUP_REQUIRED",
40
+ "A native-main credential write residue could not be safely removed; manual cleanup is required.",
41
+ 500,
42
+ false,
43
+ true,
44
+ );
45
+ }
46
+
47
+ function errorCode(error: unknown): string | undefined {
48
+ return error && typeof error === "object" && "code" in error
49
+ ? String((error as { code?: unknown }).code)
50
+ : undefined;
51
+ }
52
+
53
+ function sameIdentity(stats: { dev: bigint; ino: bigint }, expected: PathIdentity): boolean {
54
+ return stats.dev === expected.dev && stats.ino === expected.ino;
55
+ }
56
+
57
+ function samePath(left: string, right: string): boolean {
58
+ return resolve(left) === resolve(right);
59
+ }
60
+
61
+ function inspectCanonicalParent(path: string, expected?: PathIdentity): PathIdentity {
62
+ const absolute = resolve(path);
63
+ const entry = lstatSync(absolute, { bigint: true });
64
+ if (!entry.isDirectory() || entry.isSymbolicLink()) throw cleanupRequired();
65
+ const canonical = realpathSync.native(absolute);
66
+ if (!samePath(canonical, absolute)) throw cleanupRequired();
67
+ if (expected && !sameIdentity(entry, expected)) throw cleanupRequired();
68
+ return { dev: entry.dev, ino: entry.ino };
69
+ }
70
+
71
+ function inspectExactPath(path: string, parent: string, expected?: PathIdentity): PathIdentity {
72
+ const absolute = resolve(path);
73
+ if (!samePath(dirname(absolute), parent)) throw cleanupRequired();
74
+ const entry = lstatSync(absolute, { bigint: true });
75
+ if (!entry.isFile() || entry.isSymbolicLink() || entry.nlink !== 1n) throw cleanupRequired();
76
+ const canonical = realpathSync.native(absolute);
77
+ if (!samePath(canonical, absolute) || !samePath(dirname(canonical), parent)) throw cleanupRequired();
78
+ if (expected && !sameIdentity(entry, expected)) throw cleanupRequired();
79
+ return { dev: entry.dev, ino: entry.ino };
80
+ }
81
+
82
+ function exactResidues(parent: string, parentIdentity: PathIdentity): string[] {
83
+ inspectCanonicalParent(parent, parentIdentity);
84
+ const names = readdirSync(parent).filter(name => AUTH_TEMP_NAME.test(name)).sort();
85
+ inspectCanonicalParent(parent, parentIdentity);
86
+ if (names.length > MAX_AUTH_TEMP_RESIDUES) throw cleanupRequired();
87
+ return names;
88
+ }
89
+
90
+ function assertOpenIdentity(
91
+ fd: number,
92
+ path: string,
93
+ parent: string,
94
+ parentIdentity: PathIdentity,
95
+ expected: PathIdentity,
96
+ expectedLinks: bigint,
97
+ ): void {
98
+ inspectCanonicalParent(parent, parentIdentity);
99
+ const opened = fstatSync(fd, { bigint: true });
100
+ if (
101
+ !opened.isFile()
102
+ || !sameIdentity(opened, expected)
103
+ || opened.nlink !== expectedLinks
104
+ ) throw cleanupRequired();
105
+ inspectExactPath(path, parent, expected);
106
+ inspectCanonicalParent(parent, parentIdentity);
107
+ }
108
+
109
+ function scrubOne(
110
+ path: string,
111
+ parent: string,
112
+ parentIdentity: PathIdentity,
113
+ seam: NativeMainAuthTempScrubTestSeam,
114
+ ): void {
115
+ const observed = inspectExactPath(path, parent);
116
+ inspectCanonicalParent(parent, parentIdentity);
117
+ seam.beforeOpen?.(path);
118
+
119
+ const flags = process.platform === "win32"
120
+ ? fsConstants.O_RDWR
121
+ : fsConstants.O_RDWR | fsConstants.O_NOFOLLOW;
122
+ let fd: number | undefined;
123
+ let failed = false;
124
+ try {
125
+ fd = openSync(path, flags);
126
+ assertOpenIdentity(fd, path, parent, parentIdentity, observed, 1n);
127
+
128
+ ftruncateSync(fd, 0);
129
+ fsyncSync(fd);
130
+ const truncated = fstatSync(fd, { bigint: true });
131
+ if (!sameIdentity(truncated, observed) || truncated.nlink !== 1n || truncated.size !== 0n) {
132
+ throw cleanupRequired();
133
+ }
134
+ assertOpenIdentity(fd, path, parent, parentIdentity, observed, 1n);
135
+ seam.beforeUnlink?.(path);
136
+
137
+ // The lifetime owner and exclusive claim exclude cooperative Remodex writers.
138
+ // A malicious process running as the same OS user can still race Node's final
139
+ // identity-check/unlink gap and is intentionally outside this trusted-owner boundary.
140
+ unlinkSync(path);
141
+ const unlinked = fstatSync(fd, { bigint: true });
142
+ if (!sameIdentity(unlinked, observed) || unlinked.nlink !== 0n || unlinked.size !== 0n) {
143
+ throw cleanupRequired();
144
+ }
145
+ try {
146
+ lstatSync(path);
147
+ throw cleanupRequired();
148
+ } catch (error) {
149
+ if (error instanceof NativeProfileError) throw error;
150
+ if (errorCode(error) !== "ENOENT") throw error;
151
+ }
152
+ inspectCanonicalParent(parent, parentIdentity);
153
+ } catch (error) {
154
+ failed = true;
155
+ throw error;
156
+ } finally {
157
+ if (fd !== undefined) {
158
+ try { closeSync(fd); }
159
+ catch (error) { if (!failed) throw error; }
160
+ }
161
+ }
162
+ }
163
+
164
+ /**
165
+ * Remove only crash residues created by atomicWriteFileAsync for canonical auth.json.
166
+ * The caller must hold the lifetime native-main owner and exclusive credential claim.
167
+ */
168
+ export function scrubNativeMainAuthTempResidues(
169
+ context: NativeProfileContext,
170
+ seam: NativeMainAuthTempScrubTestSeam = {},
171
+ ): NativeMainAuthTempScrubResult {
172
+ try {
173
+ const parent = resolve(context.codexHome);
174
+ const parentIdentity = inspectCanonicalParent(parent);
175
+ const names = exactResidues(parent, parentIdentity);
176
+ for (const name of names) {
177
+ scrubOne(join(parent, name), parent, parentIdentity, seam);
178
+ }
179
+ // A cooperative writer cannot create a new residue while the owner and
180
+ // exclusive claim are held. Seeing one now is ambiguous, so admission stays closed.
181
+ if (exactResidues(parent, parentIdentity).length !== 0) throw cleanupRequired();
182
+ return { scrubbed: names.length };
183
+ } catch (error) {
184
+ if (error instanceof NativeProfileError) throw error;
185
+ throw cleanupRequired();
186
+ }
187
+ }
@@ -0,0 +1,167 @@
1
+ import { join } from "node:path";
2
+
3
+ import { Database } from "bun:sqlite";
4
+
5
+ import {
6
+ assertStableLockFile,
7
+ hardenStableLockFile,
8
+ openStableLockFile,
9
+ type StableLockFile,
10
+ } from "./native-main-lock-file";
11
+ import { nativeMainOwnerFilesystemSupported } from "./native-main-owner";
12
+ import type { NativeProfileContext } from "./native-profile-store";
13
+ import { NativeProfileError } from "./native-profile-types";
14
+
15
+ export const NATIVE_MAIN_CLAIM_DB = ".opencodex-native-main.claim.sqlite";
16
+
17
+ export interface NativeMainClaimOptions {
18
+ waitMs?: number;
19
+ pollMs?: number;
20
+ hardenPath?: (path: string) => Promise<void>;
21
+ platform?: NodeJS.Platform;
22
+ env?: NodeJS.ProcessEnv;
23
+ }
24
+
25
+ const hardenedIdentities = new Map<string, string>();
26
+
27
+ export function nativeMainClaimPath(context: NativeProfileContext): string {
28
+ return join(context.codexHome, NATIVE_MAIN_CLAIM_DB);
29
+ }
30
+
31
+ function errorCode(error: unknown): string | undefined {
32
+ return error && typeof error === "object" && "code" in error
33
+ ? String((error as { code?: unknown }).code)
34
+ : undefined;
35
+ }
36
+
37
+ function isBusy(error: unknown): boolean {
38
+ const code = errorCode(error);
39
+ const message = error instanceof Error ? error.message : String(error);
40
+ return code === "SQLITE_BUSY" || code === "SQLITE_LOCKED" || /database (?:is|table is) locked/i.test(message);
41
+ }
42
+
43
+ function busyClaimError(message: string): NativeProfileError {
44
+ return new NativeProfileError("NATIVE_MAIN_CLAIM_BUSY", message, 503, true);
45
+ }
46
+
47
+ function unavailableClaimError(): NativeProfileError {
48
+ return new NativeProfileError(
49
+ "NATIVE_MAIN_CLAIM_UNAVAILABLE",
50
+ "The native-main cross-process claim is unavailable.",
51
+ 503,
52
+ true,
53
+ );
54
+ }
55
+
56
+ function mapClaimSetupError(error: unknown, busyMessage: string): NativeProfileError {
57
+ if (error instanceof NativeProfileError) return error;
58
+ return isBusy(error) ? busyClaimError(busyMessage) : unavailableClaimError();
59
+ }
60
+
61
+ async function openClaimDatabase(
62
+ context: NativeProfileContext,
63
+ options: NativeMainClaimOptions,
64
+ ): Promise<{ database: Database; file: StableLockFile }> {
65
+ const platform = options.platform ?? process.platform;
66
+ if (!nativeMainOwnerFilesystemSupported(context.codexHome, platform, options.env ?? process.env)) {
67
+ throw new NativeProfileError(
68
+ "NATIVE_MAIN_CLAIM_UNAVAILABLE",
69
+ "Native-main claims are unsupported on this CODEX_HOME filesystem.",
70
+ 503,
71
+ true,
72
+ );
73
+ }
74
+ const path = nativeMainClaimPath(context);
75
+ let file: StableLockFile | undefined;
76
+ let database: Database | undefined;
77
+ try {
78
+ file = openStableLockFile(path, platform);
79
+ const identity = `${file.dev}:${file.ino}`;
80
+ if (hardenedIdentities.get(path) !== identity) {
81
+ // The resolved platform is threaded into the DEFAULT hardener, not left to
82
+ // `hardenStableLockFile`'s own `process.platform` read. Otherwise a test
83
+ // that forces `platform` here still exercises the host's branch, and the
84
+ // production default — the thing that actually hardens a coordinator
85
+ // database — stays unproved. An audit deleted this call entirely and 89
86
+ // tests stayed green, because nearly every claim test injects `hardenPath`.
87
+ await (options.hardenPath ?? ((target: string) => hardenStableLockFile(target, platform)))(path);
88
+ assertStableLockFile(path, file);
89
+ hardenedIdentities.set(path, identity);
90
+ }
91
+ database = new Database(path, { create: true });
92
+ // Journal-mode negotiation itself may need a database lock. Disable
93
+ // SQLite's synchronous busy wait first so a contender never blocks Bun's
94
+ // event loop while the current shared holder is waiting for JS to release.
95
+ database.exec("PRAGMA busy_timeout = 0; PRAGMA locking_mode = NORMAL");
96
+ const mode = database.query<{ journal_mode: string }, []>("PRAGMA journal_mode = DELETE").get()?.journal_mode;
97
+ if (mode?.toLowerCase() !== "delete") throw new Error("native-main claim database is not in rollback-journal mode");
98
+ assertStableLockFile(path, file);
99
+ return { database, file };
100
+ } catch (error) {
101
+ try { database?.close(); } catch { /* mapped below */ }
102
+ try { file?.close(); } catch { /* mapped below */ }
103
+ throw mapClaimSetupError(error, "Native-main credentials are changing.");
104
+ }
105
+ }
106
+
107
+ function releaseClaim(database: Database | undefined, file: StableLockFile | undefined): void {
108
+ try { database?.exec("ROLLBACK"); } catch { /* close still releases the OS-backed claim */ }
109
+ try { database?.close(); } catch { /* operation already completed */ }
110
+ try { file?.close(); } catch { /* operation already completed */ }
111
+ }
112
+
113
+ export async function withNativeMainSharedClaim<T>(
114
+ context: NativeProfileContext,
115
+ operation: () => Promise<T>,
116
+ options: NativeMainClaimOptions = {},
117
+ ): Promise<T> {
118
+ let database: Database | undefined;
119
+ let file: StableLockFile | undefined;
120
+ try {
121
+ ({ database, file } = await openClaimDatabase(context, options));
122
+ database.exec("BEGIN");
123
+ // A deferred BEGIN alone owns no lock. Reading page 1 through sqlite_schema
124
+ // establishes the SHARED lock that an exclusive transition must drain.
125
+ database.query<{ rootpage: number }, []>("SELECT rootpage FROM sqlite_schema LIMIT 1").get();
126
+ assertStableLockFile(nativeMainClaimPath(context), file);
127
+ } catch (error) {
128
+ releaseClaim(database, file);
129
+ throw mapClaimSetupError(error, "Native-main credentials are changing.");
130
+ }
131
+ try {
132
+ return await operation();
133
+ } finally {
134
+ releaseClaim(database, file);
135
+ }
136
+ }
137
+
138
+ export async function withNativeMainExclusiveClaim<T>(
139
+ context: NativeProfileContext,
140
+ operation: () => Promise<T>,
141
+ options: NativeMainClaimOptions = {},
142
+ ): Promise<T> {
143
+ const deadline = Date.now() + Math.max(0, options.waitMs ?? 0);
144
+ const pollMs = Math.max(1, options.pollMs ?? 50);
145
+ for (;;) {
146
+ let database: Database | undefined;
147
+ let file: StableLockFile | undefined;
148
+ try {
149
+ ({ database, file } = await openClaimDatabase(context, options));
150
+ database.exec("BEGIN EXCLUSIVE");
151
+ assertStableLockFile(nativeMainClaimPath(context), file);
152
+ } catch (error) {
153
+ releaseClaim(database, file);
154
+ const mapped = mapClaimSetupError(error, "Native-main credentials are in use.");
155
+ if (mapped.code === "NATIVE_MAIN_CLAIM_BUSY" && Date.now() < deadline) {
156
+ await Bun.sleep(Math.min(pollMs, Math.max(1, deadline - Date.now())));
157
+ continue;
158
+ }
159
+ throw mapped;
160
+ }
161
+ try {
162
+ return await operation();
163
+ } finally {
164
+ releaseClaim(database, file);
165
+ }
166
+ }
167
+ }
@@ -0,0 +1,162 @@
1
+ import {
2
+ chmodSync,
3
+ closeSync,
4
+ constants,
5
+ existsSync,
6
+ fstatSync,
7
+ lstatSync,
8
+ openSync,
9
+ type Stats,
10
+ } from "node:fs";
11
+
12
+ import { hardenSecretPathAsync } from "../lib/windows-secret-acl";
13
+
14
+ export interface StableLockFile {
15
+ readonly fd: number;
16
+ readonly dev: number;
17
+ readonly ino: number;
18
+ close(): void;
19
+ }
20
+
21
+ export class StableLockPathUnsafeError extends Error {
22
+ constructor(message: string) {
23
+ super(message);
24
+ this.name = "StableLockPathUnsafeError";
25
+ }
26
+ }
27
+
28
+ interface StableLockEntry {
29
+ readonly fd: number;
30
+ readonly dev: number;
31
+ readonly ino: number;
32
+ refs: number;
33
+ }
34
+
35
+ // POSIX fcntl locks are process-associated: closing any raw descriptor for an
36
+ // inode can release SQLite locks held through a different descriptor in this
37
+ // process. Keep one side descriptor per canonical lock path and close it only
38
+ // after every SQLite user has closed its connection and released its reference.
39
+ const stableLockEntries = new Map<string, StableLockEntry>();
40
+
41
+ function reference(path: string, entry: StableLockEntry): StableLockFile {
42
+ let closed = false;
43
+ return {
44
+ fd: entry.fd,
45
+ dev: entry.dev,
46
+ ino: entry.ino,
47
+ close() {
48
+ if (closed) return;
49
+ closed = true;
50
+ entry.refs = Math.max(0, entry.refs - 1);
51
+ if (entry.refs !== 0) return;
52
+ if (stableLockEntries.get(path) === entry) stableLockEntries.delete(path);
53
+ closeSync(entry.fd);
54
+ },
55
+ };
56
+ }
57
+
58
+ function assertRegular(stats: Stats, path: string): void {
59
+ if (!stats.isFile() || stats.isSymbolicLink()) {
60
+ throw new StableLockPathUnsafeError(`unsafe SQLite lock path: ${path}`);
61
+ }
62
+ }
63
+
64
+ function errorCode(error: unknown): string | undefined {
65
+ return error && typeof error === "object" && "code" in error
66
+ ? String((error as { code?: unknown }).code)
67
+ : undefined;
68
+ }
69
+
70
+ function matches(handle: StableLockFile, stats: Stats): boolean {
71
+ return handle.dev === stats.dev && handle.ino === stats.ino;
72
+ }
73
+
74
+ export function openStableLockFile(path: string, platform: NodeJS.Platform = process.platform): StableLockFile {
75
+ const retained = stableLockEntries.get(path);
76
+ if (retained) {
77
+ retained.refs += 1;
78
+ const handle = reference(path, retained);
79
+ try {
80
+ assertStableLockFile(path, handle);
81
+ return handle;
82
+ } catch (error) {
83
+ handle.close();
84
+ throw error;
85
+ }
86
+ }
87
+ if (existsSync(path)) assertRegular(lstatSync(path), path);
88
+ const noFollow = platform === "win32" ? 0 : constants.O_NOFOLLOW;
89
+ const fd = openSync(path, constants.O_RDWR | constants.O_CREAT | noFollow, 0o600);
90
+ try {
91
+ const descriptor = fstatSync(fd);
92
+ assertRegular(descriptor, path);
93
+ const entry: StableLockEntry = {
94
+ fd,
95
+ dev: descriptor.dev,
96
+ ino: descriptor.ino,
97
+ refs: 1,
98
+ };
99
+ stableLockEntries.set(path, entry);
100
+ const handle = reference(path, entry);
101
+ assertStableLockFile(path, handle);
102
+ return handle;
103
+ } catch (error) {
104
+ const entry = stableLockEntries.get(path);
105
+ if (entry?.fd === fd) stableLockEntries.delete(path);
106
+ closeSync(fd);
107
+ throw error;
108
+ }
109
+ }
110
+
111
+ export function assertStableLockFile(path: string, handle: StableLockFile): void {
112
+ let pathStats: Stats;
113
+ try {
114
+ pathStats = lstatSync(path);
115
+ } catch (error) {
116
+ if (errorCode(error) === "ENOENT") {
117
+ throw new StableLockPathUnsafeError(`SQLite lock path identity changed: ${path}`);
118
+ }
119
+ throw error;
120
+ }
121
+ assertRegular(pathStats, path);
122
+ if (!matches(handle, pathStats)) {
123
+ throw new StableLockPathUnsafeError(`SQLite lock path identity changed: ${path}`);
124
+ }
125
+ }
126
+
127
+ /**
128
+ * Harden the stable lock file: chmod everywhere, per-user NTFS ACLs on Windows.
129
+ *
130
+ * The platform is a parameter rather than a direct `process.platform` read so the
131
+ * Windows branch is reachable from a test. It was not, and an audit deleted the
132
+ * whole ACL delegation without a single test noticing — the primitive underneath
133
+ * had 73 tests while the call edge that activates it had none. That is the same
134
+ * absence-as-guarantee defect one layer up: proving a mechanism works says nothing
135
+ * about whether production still calls it.
136
+ *
137
+ * `required: true` is deliberate: a failure to apply the ACL must reject rather
138
+ * than leave a coordinator database readable by other accounts.
139
+ */
140
+ export async function hardenStableLockFile(
141
+ path: string,
142
+ platform: NodeJS.Platform = process.platform,
143
+ options: { retryTimedOutOnce?: boolean } = {},
144
+ ): Promise<void> {
145
+ if (platform === "win32") {
146
+ // Best-effort here: POSIX modes are not authoritative on NTFS, and the
147
+ // required ACL hardening below is what actually decides.
148
+ try { chmodSync(path, 0o600); } catch { /* ACL below is authoritative. */ }
149
+ await hardenSecretPathAsync(path, {
150
+ required: true,
151
+ retryTimedOutOnce: options.retryTimedOutOnce,
152
+ });
153
+ return;
154
+ }
155
+ // On POSIX the mode IS the mechanism, so a failure may not be swallowed.
156
+ //
157
+ // The previous unconditional catch was a real fail-open: a coordinator
158
+ // database that already existed with permissive bits stayed permissive, and
159
+ // the caller was told the lock file had been hardened. Creation mode 0600 does
160
+ // not repair an existing file, and there is no ACL fallback outside Windows.
161
+ chmodSync(path, 0o600);
162
+ }