@iislee/opencodex 2.11.0 → 2.35.0

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 (733) hide show
  1. package/AGENTS_INSTALL.md +109 -0
  2. package/README.md +117 -22
  3. package/bin/ocx.mjs +245 -88
  4. package/bin/package-main.mjs +1 -1
  5. package/gui/dist/assets/index-Be1sDpWw.css +1 -0
  6. package/gui/dist/assets/index-D4OKgUV4.js +114 -0
  7. package/gui/dist/index.html +2 -2
  8. package/gui/dist/provider-icons/alibaba-color.svg +1 -1
  9. package/gui/dist/provider-icons/antigravity-color.svg +1 -1
  10. package/gui/dist/provider-icons/claude-color.svg +1 -1
  11. package/gui/dist/provider-icons/cline-color.svg +16 -0
  12. package/gui/dist/provider-icons/cloudflare-ai-gateway-color.svg +1 -1
  13. package/gui/dist/provider-icons/commandcode-color.svg +1 -0
  14. package/gui/dist/provider-icons/copilot-color.svg +1 -1
  15. package/gui/dist/provider-icons/cursor-color.svg +1 -1
  16. package/gui/dist/provider-icons/deepseek-color.svg +1 -1
  17. package/gui/dist/provider-icons/firepass-color.svg +1 -1
  18. package/gui/dist/provider-icons/fireworks-color.svg +1 -1
  19. package/gui/dist/provider-icons/gemini-color.svg +1 -1
  20. package/gui/dist/provider-icons/github-copilot-color.svg +1 -1
  21. package/gui/dist/provider-icons/gitlab-duo-color.svg +1 -1
  22. package/gui/dist/provider-icons/grok.svg +1 -1
  23. package/gui/dist/provider-icons/groq-color.svg +1 -1
  24. package/gui/dist/provider-icons/huggingface-color.svg +1 -1
  25. package/gui/dist/provider-icons/kimi-color.svg +1 -1
  26. package/gui/dist/provider-icons/kiro-color.svg +2 -2
  27. package/gui/dist/provider-icons/lm-studio-color.svg +1 -1
  28. package/gui/dist/provider-icons/mistral-color.svg +1 -1
  29. package/gui/dist/provider-icons/moonshot-color.svg +1 -1
  30. package/gui/dist/provider-icons/nvidia-color.svg +1 -1
  31. package/gui/dist/provider-icons/ollama-color.svg +1 -1
  32. package/gui/dist/provider-icons/openai.svg +1 -1
  33. package/gui/dist/provider-icons/opencode.svg +2 -1
  34. package/gui/dist/provider-icons/openrouter-color.svg +1 -1
  35. package/gui/dist/provider-icons/pi.svg +2 -2
  36. package/gui/dist/provider-icons/qianfan-color.svg +1 -1
  37. package/gui/dist/provider-icons/qwen-portal-color.svg +1 -1
  38. package/gui/dist/provider-icons/vercel-ai-gateway-color.svg +1 -1
  39. package/gui/dist/provider-icons/vllm-color.svg +1 -1
  40. package/gui/dist/provider-icons/xiaomi-color.svg +1 -1
  41. package/package.json +21 -10
  42. package/src/adapters/anthropic-output-schema.ts +137 -0
  43. package/src/adapters/anthropic.ts +475 -62
  44. package/src/adapters/base.ts +82 -7
  45. package/src/adapters/client-fingerprint.ts +18 -12
  46. package/src/adapters/cline-pass-deepseek-v4-tool-replay.ts +69 -0
  47. package/src/adapters/command-code.ts +637 -0
  48. package/src/adapters/cursor/call-id.ts +44 -0
  49. package/src/adapters/cursor/catalog.ts +541 -0
  50. package/src/adapters/cursor/checkpoint-store.ts +308 -0
  51. package/src/adapters/cursor/cursor-errors.ts +144 -6
  52. package/src/adapters/cursor/discovery.ts +122 -14
  53. package/src/adapters/cursor/effort-map.ts +106 -4
  54. package/src/adapters/cursor/envelope-echo.ts +290 -0
  55. package/src/adapters/cursor/framing.ts +39 -0
  56. package/src/adapters/cursor/h2-pool.ts +123 -0
  57. package/src/adapters/cursor/http1-bidi.ts +361 -0
  58. package/src/adapters/cursor/images.ts +704 -0
  59. package/src/adapters/cursor/live-models.ts +180 -59
  60. package/src/adapters/cursor/live-transport.ts +623 -170
  61. package/src/adapters/cursor/message-mapper.ts +4 -1
  62. package/src/adapters/cursor/native-exec-common.ts +23 -2
  63. package/src/adapters/cursor/native-exec-desktop.ts +23 -0
  64. package/src/adapters/cursor/native-exec-fs.ts +10 -7
  65. package/src/adapters/cursor/native-exec-network.ts +1 -1
  66. package/src/adapters/cursor/native-exec-shell.ts +5 -3
  67. package/src/adapters/cursor/native-exec.ts +121 -14
  68. package/src/adapters/cursor/protobuf-events.ts +829 -11
  69. package/src/adapters/cursor/protobuf-request.ts +447 -75
  70. package/src/adapters/cursor/request-builder.ts +271 -35
  71. package/src/adapters/cursor/tool-definitions.ts +252 -12
  72. package/src/adapters/cursor/tool-result-normalize.ts +115 -0
  73. package/src/adapters/cursor/transport.ts +22 -0
  74. package/src/adapters/cursor/types.ts +48 -1
  75. package/src/adapters/cursor.ts +336 -39
  76. package/src/adapters/exec-tool-result-normalize.ts +99 -0
  77. package/src/adapters/google-antigravity-replay.ts +713 -41
  78. package/src/adapters/google-antigravity-wire.ts +48 -10
  79. package/src/adapters/google-errors.ts +44 -12
  80. package/src/adapters/google-http.ts +38 -10
  81. package/src/adapters/google-tool-schema.ts +80 -15
  82. package/src/adapters/google-truncation.ts +11 -0
  83. package/src/adapters/google.ts +742 -86
  84. package/src/adapters/identity.ts +39 -6
  85. package/src/adapters/image.ts +1 -1
  86. package/src/adapters/kiro-constants.ts +27 -0
  87. package/src/adapters/kiro-errors.ts +11 -0
  88. package/src/adapters/kiro-events.ts +19 -1
  89. package/src/adapters/kiro-thinking.ts +18 -2
  90. package/src/adapters/kiro-tools.ts +65 -17
  91. package/src/adapters/kiro.ts +270 -73
  92. package/src/adapters/mimo-free.ts +17 -0
  93. package/src/adapters/openai-chat-url.ts +11 -0
  94. package/src/adapters/openai-chat.ts +1377 -344
  95. package/src/adapters/openai-responses-url.ts +16 -0
  96. package/src/adapters/openai-responses.ts +1164 -64
  97. package/src/adapters/registry.ts +175 -0
  98. package/src/adapters/responses-tool-schema.ts +67 -0
  99. package/src/adapters/run-turn-queue.ts +36 -1
  100. package/src/adapters/tool-call-id.ts +119 -0
  101. package/src/adapters/tool-catalog-nudge.ts +105 -21
  102. package/src/adapters/xai-tool-schema.ts +436 -0
  103. package/src/adapters/xai-web-search.ts +186 -0
  104. package/src/bridge.ts +512 -92
  105. package/src/chat/inbound.ts +57 -20
  106. package/src/chat/outbound.ts +97 -33
  107. package/src/claude/agents-inject.ts +40 -10
  108. package/src/claude/context-windows.ts +37 -14
  109. package/src/claude/desktop-3p.ts +243 -9
  110. package/src/claude/gateway-cache.ts +41 -4
  111. package/src/claude/inbound.ts +72 -3
  112. package/src/claude/model-info.ts +38 -15
  113. package/src/claude/outbound.ts +88 -21
  114. package/src/cli/access.ts +46 -3
  115. package/src/cli/account-api.ts +150 -19
  116. package/src/cli/account-auth.ts +33 -6
  117. package/src/cli/account-catalog-refresh.ts +14 -0
  118. package/src/cli/account-extended.ts +648 -28
  119. package/src/cli/account-main.ts +317 -0
  120. package/src/cli/account.ts +97 -19
  121. package/src/cli/agent.ts +53 -2
  122. package/src/cli/alias.ts +66 -0
  123. package/src/cli/capabilities-command.ts +94 -0
  124. package/src/cli/capabilities.ts +496 -0
  125. package/src/cli/claude-agent-startup-sync.ts +73 -0
  126. package/src/cli/claude-desktop.ts +60 -15
  127. package/src/cli/claude.ts +129 -35
  128. package/src/cli/codex-log-guard-doctor.ts +103 -0
  129. package/src/cli/codex-shim-autorestore.ts +2 -0
  130. package/src/cli/codex-shim-readiness.ts +76 -0
  131. package/src/cli/combo.ts +8 -0
  132. package/src/cli/config-command.ts +74 -10
  133. package/src/cli/dispatch.ts +821 -0
  134. package/src/cli/doctor.ts +440 -56
  135. package/src/cli/ensure-desired-integrations.ts +152 -0
  136. package/src/cli/export-command.ts +46 -20
  137. package/src/cli/help.ts +34 -274
  138. package/src/cli/index.ts +417 -528
  139. package/src/cli/init.ts +5 -17
  140. package/src/cli/inspect.ts +230 -0
  141. package/src/cli/integrations.ts +120 -2
  142. package/src/cli/lab.ts +607 -0
  143. package/src/cli/launcher-context.ts +77 -0
  144. package/src/cli/minimax.ts +497 -0
  145. package/src/cli/models-runtime.ts +130 -2
  146. package/src/cli/models.ts +118 -16
  147. package/src/cli/observe.ts +123 -11
  148. package/src/cli/opencode.ts +4 -2
  149. package/src/cli/provider-runtime.ts +34 -3
  150. package/src/cli/provider.ts +25 -3
  151. package/src/cli/ready.ts +301 -0
  152. package/src/cli/registry.ts +476 -0
  153. package/src/cli/root.ts +86 -0
  154. package/src/cli/route-policy.ts +92 -0
  155. package/src/cli/runtime-api.ts +57 -10
  156. package/src/cli/star-prompt.ts +71 -15
  157. package/src/cli/status.ts +51 -4
  158. package/src/cli/storage.ts +234 -0
  159. package/src/cli/system-command.ts +16 -0
  160. package/src/cli/system-restart-client.ts +146 -0
  161. package/src/cli/tray-proxy.ts +153 -6
  162. package/src/cli/usage-report.ts +184 -0
  163. package/src/cli/v2.ts +137 -18
  164. package/src/cli/version-skew.ts +46 -0
  165. package/src/cli.ts +1 -1
  166. package/src/clients/config-export.ts +1442 -23
  167. package/src/clients/effective-status.ts +30 -2
  168. package/src/clients/probes/cline.ts +81 -0
  169. package/src/codex/account-label.ts +35 -1
  170. package/src/codex/account-lifecycle.ts +130 -13
  171. package/src/codex/account-namespaces.ts +49 -3
  172. package/src/codex/account-pause.ts +2 -1
  173. package/src/codex/account-priority.ts +84 -0
  174. package/src/codex/account-store.ts +29 -2
  175. package/src/codex/account-usability.ts +25 -2
  176. package/src/codex/admission.ts +256 -0
  177. package/src/codex/affinity-debug.ts +162 -0
  178. package/src/codex/app-server-processes.ts +570 -107
  179. package/src/codex/app-server-restart-service.ts +232 -0
  180. package/src/codex/auth-api.ts +893 -246
  181. package/src/codex/auth-collision.ts +5 -3
  182. package/src/codex/auth-context.ts +348 -32
  183. package/src/codex/autostart-health.ts +24 -1
  184. package/src/codex/catalog/account-models.ts +67 -0
  185. package/src/codex/catalog/aggregation.ts +86 -10
  186. package/src/codex/catalog/bundled.ts +331 -33
  187. package/src/codex/catalog/effort.ts +138 -32
  188. package/src/codex/catalog/filesystem-evidence.ts +302 -0
  189. package/src/codex/catalog/kinds.ts +2 -0
  190. package/src/codex/catalog/metadata.ts +555 -45
  191. package/src/codex/catalog/native-models.ts +75 -0
  192. package/src/codex/catalog/parsing.ts +269 -30
  193. package/src/codex/catalog/provider-fetch.ts +1626 -144
  194. package/src/codex/catalog/sync.ts +1576 -187
  195. package/src/codex/catalog-admission.ts +199 -0
  196. package/src/codex/catalog-refresh-status.ts +105 -0
  197. package/src/codex/catalog-write-serialization.ts +242 -0
  198. package/src/codex/catalog.ts +6 -3
  199. package/src/codex/codex-write-lock.ts +386 -0
  200. package/src/codex/convergence-types.ts +614 -0
  201. package/src/codex/convergence.ts +676 -0
  202. package/src/codex/coordinator-doctor.ts +332 -0
  203. package/src/codex/custom-model-catalog-migration.ts +176 -0
  204. package/src/codex/desired-state.ts +230 -0
  205. package/src/codex/desktop-app-restart.ts +355 -0
  206. package/src/codex/features.ts +636 -39
  207. package/src/codex/generation.ts +202 -0
  208. package/src/codex/history-job.ts +436 -0
  209. package/src/codex/history-lock.ts +242 -0
  210. package/src/codex/history-manifest.ts +112 -0
  211. package/src/codex/history-migration-guardian.ts +30 -24
  212. package/src/codex/history-provider.ts +1016 -235
  213. package/src/codex/history-transition.ts +105 -0
  214. package/src/codex/history-worker.ts +223 -0
  215. package/src/codex/inject-coordination.ts +373 -0
  216. package/src/codex/inject.ts +1114 -152
  217. package/src/codex/injected-marker.ts +37 -3
  218. package/src/codex/integration-record.ts +266 -0
  219. package/src/codex/internal/catalog-writer.ts +203 -0
  220. package/src/codex/internal/history-writer.ts +81 -0
  221. package/src/codex/journal.ts +66 -4
  222. package/src/codex/log-guard/inspect.ts +524 -0
  223. package/src/codex/log-guard/lock.ts +150 -0
  224. package/src/codex/log-guard/maintenance.ts +403 -0
  225. package/src/codex/log-guard/path-safety.ts +88 -0
  226. package/src/codex/log-guard/policy.ts +44 -0
  227. package/src/codex/log-guard/processes.ts +205 -0
  228. package/src/codex/log-guard/protection.ts +489 -0
  229. package/src/codex/log-guard/sqlite-errors.ts +9 -0
  230. package/src/codex/main-account-cache.ts +24 -0
  231. package/src/codex/main-account.ts +29 -1
  232. package/src/codex/management-convergence.ts +167 -0
  233. package/src/codex/model-cache.ts +56 -10
  234. package/src/codex/model-entitlements.ts +360 -0
  235. package/src/codex/native-main-admission.ts +47 -0
  236. package/src/codex/native-main-auth-temp.ts +187 -0
  237. package/src/codex/native-main-claim.ts +178 -0
  238. package/src/codex/native-main-lock-file.ts +162 -0
  239. package/src/codex/native-main-owner.ts +329 -0
  240. package/src/codex/native-profile-api.ts +247 -0
  241. package/src/codex/native-profile-manager.ts +1531 -0
  242. package/src/codex/native-profile-processes.ts +121 -0
  243. package/src/codex/native-profile-recovery.ts +99 -0
  244. package/src/codex/native-profile-stage-store.ts +387 -0
  245. package/src/codex/native-profile-startup.ts +622 -0
  246. package/src/codex/native-profile-store.ts +855 -0
  247. package/src/codex/native-profile-types.ts +120 -0
  248. package/src/codex/native-residue.ts +675 -0
  249. package/src/codex/paths.ts +80 -1
  250. package/src/codex/plan-from-token.ts +140 -0
  251. package/src/codex/plan.ts +40 -0
  252. package/src/codex/plugins-doctor.ts +1 -1
  253. package/src/codex/pool-rotation.ts +74 -4
  254. package/src/codex/project-config-warnings.ts +20 -6
  255. package/src/codex/prompt-journal.ts +352 -0
  256. package/src/codex/prompt-layers.ts +1313 -0
  257. package/src/codex/prompt-lock.ts +143 -0
  258. package/src/codex/prompt-text-probe.ts +238 -0
  259. package/src/codex/quota-rejection.ts +298 -0
  260. package/src/codex/quota.ts +264 -21
  261. package/src/codex/refresh.ts +11 -2
  262. package/src/codex/reset-credit-recovery.ts +1044 -0
  263. package/src/codex/routing.ts +514 -94
  264. package/src/codex/runtime.ts +159 -38
  265. package/src/codex/shim.ts +1065 -31
  266. package/src/codex/subagent-model-fallback.ts +437 -43
  267. package/src/codex/sync.ts +191 -2
  268. package/src/codex/transition-state.ts +720 -0
  269. package/src/codex/upstream-host-health.ts +368 -0
  270. package/src/codex/user-identity.ts +557 -0
  271. package/src/codex/warmup.ts +187 -81
  272. package/src/codex/write-coordination.ts +114 -0
  273. package/src/combos/failover.ts +47 -0
  274. package/src/combos/index.ts +4 -0
  275. package/src/combos/request.ts +32 -0
  276. package/src/combos/types.ts +91 -9
  277. package/src/compatibility/index.ts +26 -0
  278. package/src/compatibility/manifest.ts +253 -0
  279. package/src/compatibility/openai-responses.ts +121 -0
  280. package/src/config/atomic-write.ts +219 -0
  281. package/src/config/paths.ts +40 -0
  282. package/src/config/process-state.ts +309 -0
  283. package/src/config/provider-name.ts +24 -0
  284. package/src/config/provider-validation.ts +177 -0
  285. package/src/config/rebase-provenance.ts +68 -0
  286. package/src/config.ts +1713 -709
  287. package/src/generated/compatibility-version.json +3324 -0
  288. package/src/generated/{jawcode-model-metadata.ts → model-metadata.ts} +19 -17
  289. package/src/grok/inject.ts +16 -5
  290. package/src/grok/inspect.ts +45 -0
  291. package/src/grok/sync.ts +2 -2
  292. package/src/images/loop.ts +157 -33
  293. package/src/images/plan.ts +24 -13
  294. package/src/integrations/config-io.ts +269 -0
  295. package/src/integrations/journal.ts +315 -0
  296. package/src/integrations/merge.ts +135 -0
  297. package/src/integrations/mutation-flight.ts +71 -0
  298. package/src/integrations/native/ownership-preflight.ts +202 -0
  299. package/src/integrations/omp-yaml-source.ts +358 -0
  300. package/src/integrations/owned-refresh.ts +74 -0
  301. package/src/integrations/ownership-policy.ts +160 -0
  302. package/src/integrations/ownership.ts +155 -0
  303. package/src/integrations/registry.ts +166 -0
  304. package/src/integrations/serialize.ts +314 -0
  305. package/src/integrations/state.ts +433 -0
  306. package/src/integrations/store.ts +103 -0
  307. package/src/integrations/writer-lock.ts +98 -0
  308. package/src/integrations/writer.ts +715 -0
  309. package/src/lab/artifacts/sanitize.ts +586 -0
  310. package/src/lab/artifacts/secure-fs.ts +475 -0
  311. package/src/lab/artifacts/store.ts +310 -0
  312. package/src/lab/automation/budgets.ts +78 -0
  313. package/src/lab/automation/config-persistence.ts +256 -0
  314. package/src/lab/automation/constants.ts +39 -0
  315. package/src/lab/automation/cooldown.ts +103 -0
  316. package/src/lab/automation/dispatch.ts +211 -0
  317. package/src/lab/automation/index.ts +13 -0
  318. package/src/lab/automation/orchestrator.ts +499 -0
  319. package/src/lab/automation/persistence.ts +512 -0
  320. package/src/lab/automation/planner.ts +371 -0
  321. package/src/lab/automation/policy.ts +136 -0
  322. package/src/lab/automation/queue.ts +191 -0
  323. package/src/lab/automation/recovery.ts +24 -0
  324. package/src/lab/automation/route-context.ts +21 -0
  325. package/src/lab/automation/run-key.ts +44 -0
  326. package/src/lab/automation/runs-query.ts +34 -0
  327. package/src/lab/automation/types.ts +160 -0
  328. package/src/lab/conformance/assertion.ts +325 -0
  329. package/src/lab/conformance/digest.ts +22 -0
  330. package/src/lab/conformance/executor.ts +741 -0
  331. package/src/lab/conformance/fixture-provider.ts +27 -0
  332. package/src/lab/conformance/fixtures/live-v1-cases.json +175 -0
  333. package/src/lab/conformance/fixtures/protocol-v1-cases.json +461 -0
  334. package/src/lab/conformance/harness-budget.ts +47 -0
  335. package/src/lab/conformance/index.ts +5 -0
  336. package/src/lab/conformance/jcs.ts +64 -0
  337. package/src/lab/conformance/json-pointer.ts +39 -0
  338. package/src/lab/conformance/manifest.ts +180 -0
  339. package/src/lab/conformance/mcp-stub.ts +179 -0
  340. package/src/lab/conformance/negative-controls.ts +164 -0
  341. package/src/lab/conformance/observation.ts +355 -0
  342. package/src/lab/conformance/runner.ts +68 -0
  343. package/src/lab/conformance/sse-normalize.ts +59 -0
  344. package/src/lab/conformance/suite-manifest.ts +78 -0
  345. package/src/lab/conformance/types.ts +214 -0
  346. package/src/lab/constants.ts +126 -0
  347. package/src/lab/digest.ts +64 -0
  348. package/src/lab/events/errors.ts +9 -0
  349. package/src/lab/events/limits.ts +117 -0
  350. package/src/lab/events/types.ts +229 -0
  351. package/src/lab/events/validate.ts +781 -0
  352. package/src/lab/fabric/constants.ts +40 -0
  353. package/src/lab/fabric/executor.ts +492 -0
  354. package/src/lab/fabric/index.ts +80 -0
  355. package/src/lab/fabric/manifest.ts +222 -0
  356. package/src/lab/fabric/observe.ts +489 -0
  357. package/src/lab/fabric/patch.ts +79 -0
  358. package/src/lab/fabric/producer-child.ts +139 -0
  359. package/src/lab/fabric/producer-isolate.ts +276 -0
  360. package/src/lab/fabric/producer-protocol.ts +61 -0
  361. package/src/lab/fabric/scratch.ts +439 -0
  362. package/src/lab/fabric/subject.ts +106 -0
  363. package/src/lab/fabric/types.ts +134 -0
  364. package/src/lab/fabric/verifier.ts +98 -0
  365. package/src/lab/index.ts +54 -0
  366. package/src/lab/ledger/artifact-refs.ts +127 -0
  367. package/src/lab/ledger/invalidation.ts +136 -0
  368. package/src/lab/ledger/purge.ts +310 -0
  369. package/src/lab/ledger/store.ts +532 -0
  370. package/src/lab/live/credential-lease.ts +53 -0
  371. package/src/lab/live/destination.ts +155 -0
  372. package/src/lab/live/executor.ts +336 -0
  373. package/src/lab/live/inert-tools.ts +56 -0
  374. package/src/lab/live/manifest.ts +85 -0
  375. package/src/lab/live/mcp-loopback.ts +57 -0
  376. package/src/lab/live/runner.ts +19 -0
  377. package/src/lab/live/sandbox.ts +61 -0
  378. package/src/lab/live/suite-manifest.ts +41 -0
  379. package/src/lab/live/transport.ts +118 -0
  380. package/src/lab/live/types.ts +197 -0
  381. package/src/lab/observe/from-conformance.ts +301 -0
  382. package/src/lab/observe/from-live.ts +117 -0
  383. package/src/lab/paths.ts +153 -0
  384. package/src/lab/projection/rebuild.ts +495 -0
  385. package/src/lab/projection/schema.ts +135 -0
  386. package/src/lab/projection/verdicts.ts +474 -0
  387. package/src/lab/projection/verification.ts +412 -0
  388. package/src/lab/public/bundle.ts +217 -0
  389. package/src/lab/public/community-authority.ts +175 -0
  390. package/src/lab/public/community-files.ts +29 -0
  391. package/src/lab/public/community.ts +479 -0
  392. package/src/lab/public/file-safety.ts +155 -0
  393. package/src/lab/public/ids.ts +26 -0
  394. package/src/lab/public/index.ts +16 -0
  395. package/src/lab/public/mutation-lock.ts +424 -0
  396. package/src/lab/public/operator.ts +353 -0
  397. package/src/lab/public/origin-purge.ts +79 -0
  398. package/src/lab/public/origin.ts +203 -0
  399. package/src/lab/public/privacy.ts +143 -0
  400. package/src/lab/public/private-file.ts +261 -0
  401. package/src/lab/public/project.ts +124 -0
  402. package/src/lab/public/purge-test-fault.ts +21 -0
  403. package/src/lab/public/purge.ts +223 -0
  404. package/src/lab/public/registry.ts +44 -0
  405. package/src/lab/public/revocation.ts +252 -0
  406. package/src/lab/public/signature.ts +243 -0
  407. package/src/lab/public/storage.ts +105 -0
  408. package/src/lab/public/strict-json.ts +206 -0
  409. package/src/lab/public/time.ts +26 -0
  410. package/src/lab/public/types.ts +172 -0
  411. package/src/lab/public/validate.ts +391 -0
  412. package/src/lab/query/catalog.ts +101 -0
  413. package/src/lab/query/connection.ts +107 -0
  414. package/src/lab/query/constants.ts +4 -0
  415. package/src/lab/query/cursor.ts +132 -0
  416. package/src/lab/query/dto-map.ts +277 -0
  417. package/src/lab/query/errors.ts +22 -0
  418. package/src/lab/query/freshness.ts +53 -0
  419. package/src/lab/query/index.ts +45 -0
  420. package/src/lab/query/latest-observation.ts +59 -0
  421. package/src/lab/query/passive-production.ts +159 -0
  422. package/src/lab/query/queries.ts +444 -0
  423. package/src/lab/query/types.ts +266 -0
  424. package/src/lab/subject/behavior-fingerprint.ts +77 -0
  425. package/src/lab/subject/installation-salt.ts +112 -0
  426. package/src/lab/subject/protocol-subject.ts +80 -0
  427. package/src/lab/subject/route-subject.ts +74 -0
  428. package/src/lib/admin-secrets.ts +24 -0
  429. package/src/lib/app-owned-memory-stores.ts +22 -0
  430. package/src/lib/bounded-body.ts +167 -11
  431. package/src/lib/bun-runtime.ts +125 -12
  432. package/src/lib/bun-stream-caps.ts +13 -9
  433. package/src/lib/codex-restart-contract.ts +120 -0
  434. package/src/lib/config-ownership.ts +26 -2
  435. package/src/lib/destination-policy.ts +65 -1
  436. package/src/lib/errors.ts +80 -5
  437. package/src/lib/fabric-task-execution-authority.ts +7 -0
  438. package/src/lib/fabric-task-host.ts +29 -0
  439. package/src/lib/lab-activation.ts +223 -0
  440. package/src/lib/lab-live-execution-authority.ts +13 -0
  441. package/src/lib/lab-live-host.ts +30 -0
  442. package/src/lib/lab-live-pinned-sender.ts +56 -0
  443. package/src/lib/lab-live-route-production.ts +130 -0
  444. package/src/lib/lab-passive-linker-registration.ts +26 -0
  445. package/src/lib/local-management-attestation.ts +51 -0
  446. package/src/lib/local-management-capability.ts +100 -0
  447. package/src/lib/local-provider-reload-contract.ts +100 -0
  448. package/src/lib/optional-shutdown-hooks.ts +57 -0
  449. package/src/lib/package-tree-integrity.ts +101 -0
  450. package/src/lib/pinned-http.ts +145 -26
  451. package/src/lib/process-control.ts +6 -2
  452. package/src/lib/provider-outbound.ts +49 -9
  453. package/src/lib/redact.ts +419 -3
  454. package/src/lib/self-launch-argv.ts +15 -0
  455. package/src/lib/server-resource-ownership.ts +71 -0
  456. package/src/lib/service-secrets.ts +15 -0
  457. package/src/lib/shadow-call.ts +35 -4
  458. package/src/lib/sse-decoder.ts +41 -0
  459. package/src/lib/state-store-registrations.ts +10 -2
  460. package/src/lib/system-restart-contract.ts +73 -0
  461. package/src/lib/token-estimate.ts +19 -2
  462. package/src/lib/tool-argument-integers.ts +253 -0
  463. package/src/lib/translator-budget.ts +44 -0
  464. package/src/lib/upstream-http-version.ts +57 -0
  465. package/src/lib/upstream-reachability.ts +95 -0
  466. package/src/lib/upstream-retry.ts +156 -3
  467. package/src/lib/windows-atomic-replace.ts +155 -0
  468. package/src/lib/windows-elevation.ts +70 -2
  469. package/src/lib/windows-secret-acl.ts +409 -69
  470. package/src/lib/windows-service-wrappers.ts +72 -0
  471. package/src/lib/windows-text.ts +106 -0
  472. package/src/lib/windows-user-principal.ts +341 -0
  473. package/src/lib/winsw.ts +33 -5
  474. package/src/oauth/account-import/google-antigravity-adapter.ts +74 -0
  475. package/src/oauth/account-import/index.ts +15 -0
  476. package/src/oauth/account-import/parser.ts +83 -0
  477. package/src/oauth/account-import/registry.ts +18 -0
  478. package/src/oauth/account-import/service.ts +75 -0
  479. package/src/oauth/account-import/types.ts +91 -0
  480. package/src/oauth/anthropic.ts +12 -1
  481. package/src/oauth/callback-server.ts +30 -4
  482. package/src/oauth/chatgpt.ts +12 -1
  483. package/src/oauth/cline.ts +203 -0
  484. package/src/oauth/command-code.ts +239 -0
  485. package/src/oauth/cursor.ts +46 -5
  486. package/src/oauth/generic-account-failover.ts +231 -0
  487. package/src/oauth/google-antigravity.ts +35 -3
  488. package/src/oauth/health.ts +20 -12
  489. package/src/oauth/index.ts +462 -71
  490. package/src/oauth/key-providers.ts +25 -0
  491. package/src/oauth/kimi.ts +25 -3
  492. package/src/oauth/kiro.ts +95 -6
  493. package/src/oauth/local-token-detect.ts +13 -2
  494. package/src/oauth/log.ts +3 -1
  495. package/src/oauth/login-cli.ts +88 -28
  496. package/src/oauth/nous.ts +798 -0
  497. package/src/oauth/open-browser-choice.ts +26 -0
  498. package/src/oauth/store.ts +133 -26
  499. package/src/oauth/token-guardian.ts +9 -3
  500. package/src/oauth/types.ts +15 -0
  501. package/src/pi/models.ts +2 -2
  502. package/src/providers/alibaba-region-migration.ts +1 -1
  503. package/src/providers/antigravity-models.ts +521 -31
  504. package/src/providers/auto-compact-budget.ts +65 -0
  505. package/src/providers/base-url-choices.ts +10 -0
  506. package/src/providers/codex-capacity.ts +292 -0
  507. package/src/providers/command-code-efforts.ts +176 -0
  508. package/src/providers/context-cap.ts +26 -8
  509. package/src/providers/cursor-pool.ts +72 -0
  510. package/src/providers/default-aliases.ts +65 -0
  511. package/src/providers/derive.ts +281 -6
  512. package/src/providers/fastwire.ts +507 -0
  513. package/src/providers/free-directory.ts +10 -7
  514. package/src/providers/google-vertex-location.ts +14 -0
  515. package/src/providers/key-failover.ts +71 -3
  516. package/src/providers/label.ts +35 -2
  517. package/src/providers/model-discovery-limits.ts +16 -0
  518. package/src/providers/model-discovery.ts +115 -22
  519. package/src/providers/model-presets.ts +119 -0
  520. package/src/providers/model-rename-migration.ts +255 -0
  521. package/src/providers/model-rename-startup.ts +28 -0
  522. package/src/providers/new-model-policy.ts +146 -0
  523. package/src/providers/openai-sidecar.ts +72 -4
  524. package/src/providers/openai-tier-startup.ts +31 -2
  525. package/src/providers/openai-tiers.ts +119 -4
  526. package/src/providers/openai-virtual-models.ts +1 -0
  527. package/src/providers/opencode-zen-rate-limit.ts +102 -0
  528. package/src/providers/provider-id-rewrite.ts +30 -0
  529. package/src/providers/quota.ts +1379 -40
  530. package/src/providers/registry.ts +1545 -112
  531. package/src/providers/request-pacing.ts +310 -0
  532. package/src/providers/service-tier.ts +277 -0
  533. package/src/providers/slug-codec.ts +94 -6
  534. package/src/providers/static-model-discovery.ts +86 -0
  535. package/src/providers/xai-responses-opt-in.ts +15 -0
  536. package/src/providers/xai-transport.ts +32 -4
  537. package/src/reasoning-effort.ts +68 -3
  538. package/src/responses/apply-patch-envelope.ts +63 -0
  539. package/src/responses/code-mode-helper-compat.ts +50 -0
  540. package/src/responses/compaction.ts +26 -1
  541. package/src/responses/custom-tool-compat.ts +384 -0
  542. package/src/responses/hosted-tool-policy.ts +9 -0
  543. package/src/responses/namespace-tool-compat.ts +435 -0
  544. package/src/responses/parser.ts +225 -38
  545. package/src/responses/provider-continuation.ts +98 -0
  546. package/src/responses/provider-opaque-metadata.ts +73 -0
  547. package/src/responses/reasoning-envelope.ts +9 -1
  548. package/src/responses/reasoning-replay-cache.ts +504 -0
  549. package/src/responses/schema.ts +12 -2
  550. package/src/responses/spill-store.ts +75 -10
  551. package/src/responses/state.ts +659 -31
  552. package/src/responses/thought-signature-replay.ts +364 -0
  553. package/src/responses/tool-search-compat.ts +301 -0
  554. package/src/responses/truncated-stop-reason.ts +60 -0
  555. package/src/responses/turn-termination.ts +107 -0
  556. package/src/router.ts +405 -31
  557. package/src/routing/analytics.ts +379 -0
  558. package/src/routing/capability.ts +244 -0
  559. package/src/routing/compatibility/assemble.ts +73 -0
  560. package/src/routing/compatibility/behavior.ts +278 -0
  561. package/src/routing/compatibility/catalog.ts +99 -0
  562. package/src/routing/compatibility/endpoint.ts +52 -0
  563. package/src/routing/compatibility/lab-evidence-provider.ts +130 -0
  564. package/src/routing/compatibility/policy.ts +181 -0
  565. package/src/routing/compatibility/provider-slot.ts +56 -0
  566. package/src/routing/compatibility/reader.ts +110 -0
  567. package/src/routing/compatibility/subject.ts +191 -0
  568. package/src/routing/compatibility/types.ts +64 -0
  569. package/src/routing/compatibility/version.ts +104 -0
  570. package/src/routing/cost.ts +77 -0
  571. package/src/routing/evaluator.ts +495 -0
  572. package/src/routing/health.ts +412 -0
  573. package/src/routing/history/cursor.ts +43 -0
  574. package/src/routing/history/indexer.ts +605 -0
  575. package/src/routing/history/schema.ts +72 -0
  576. package/src/routing/profile-namespace.ts +15 -0
  577. package/src/routing/profile.ts +547 -0
  578. package/src/routing/quota.ts +155 -0
  579. package/src/routing/request-evidence.ts +45 -0
  580. package/src/routing/trace.ts +776 -0
  581. package/src/server/adapter-resolve.ts +2 -29
  582. package/src/server/auth-cors.ts +289 -48
  583. package/src/server/background-lifecycle.ts +182 -0
  584. package/src/server/chat-completions.ts +154 -72
  585. package/src/server/chat-native-sse.ts +331 -0
  586. package/src/server/chat-native.ts +445 -0
  587. package/src/server/claude-messages.ts +160 -44
  588. package/src/server/direct-local-http.ts +347 -0
  589. package/src/server/effort-policy.ts +18 -0
  590. package/src/server/github-copilot-responses-repair.ts +338 -0
  591. package/src/server/gui-static.ts +39 -10
  592. package/src/server/images.ts +94 -12
  593. package/src/server/index.ts +1021 -190
  594. package/src/server/lifecycle.ts +336 -14
  595. package/src/server/live.ts +136 -17
  596. package/src/server/local-management-read-client.ts +90 -0
  597. package/src/server/local-provider-reload-client.ts +137 -0
  598. package/src/server/management/agent-settings-routes.ts +433 -116
  599. package/src/server/management/api-key-usage.ts +31 -5
  600. package/src/server/management/body.ts +6 -0
  601. package/src/server/management/codex-prompt-routes.ts +570 -0
  602. package/src/server/management/combo-routes.ts +64 -25
  603. package/src/server/management/config-routes.ts +511 -51
  604. package/src/server/management/context.ts +89 -2
  605. package/src/server/management/integration-routes.ts +498 -0
  606. package/src/server/management/lab-automation-routes.ts +206 -0
  607. package/src/server/management/lab-routes.ts +563 -0
  608. package/src/server/management/logs-usage-routes.ts +127 -52
  609. package/src/server/management/model-routes.ts +461 -133
  610. package/src/server/management/model-rows.ts +167 -0
  611. package/src/server/management/native-integration-routes.ts +770 -0
  612. package/src/server/management/oauth-account-routes.ts +90 -8
  613. package/src/server/management/provider-capability-config.ts +48 -0
  614. package/src/server/management/provider-routes.ts +836 -159
  615. package/src/server/management/request-history-routes.ts +191 -0
  616. package/src/server/management/route-registry.ts +332 -0
  617. package/src/server/management/routing-analytics-routes.ts +74 -0
  618. package/src/server/management/routing-profile-routes.ts +380 -0
  619. package/src/server/management/shared.ts +27 -11
  620. package/src/server/management/sidebar-routes.ts +47 -31
  621. package/src/server/management/storage-log-guard-routes.ts +186 -0
  622. package/src/server/management/sync-response.ts +69 -0
  623. package/src/server/management/system-restart.ts +289 -33
  624. package/src/server/management/system-routes.ts +77 -0
  625. package/src/server/management/usage-summary-cache.ts +9 -1
  626. package/src/server/management/vision-sidecar-options.ts +167 -0
  627. package/src/server/management/web-search-sidecar-options.ts +120 -0
  628. package/src/server/management-api.ts +126 -23
  629. package/src/server/management-auth.ts +220 -5
  630. package/src/server/passive-route-linker.ts +66 -0
  631. package/src/server/port-reclaim.ts +1 -1
  632. package/src/server/ports.ts +41 -1
  633. package/src/server/proxy-liveness.ts +161 -10
  634. package/src/server/readiness.ts +99 -0
  635. package/src/server/relay-eager.ts +221 -54
  636. package/src/server/relay.ts +479 -87
  637. package/src/server/request-decompress.ts +113 -6
  638. package/src/server/request-log-conversation.ts +51 -0
  639. package/src/server/request-log.ts +298 -31
  640. package/src/server/responses/agent-task-recovery-cache.ts +143 -0
  641. package/src/server/responses/agent-task-recovery.ts +465 -0
  642. package/src/server/responses/codex-auth-error.ts +55 -0
  643. package/src/server/responses/collaboration.ts +239 -36
  644. package/src/server/responses/combo-stream-preflight.ts +178 -0
  645. package/src/server/responses/compact.ts +444 -72
  646. package/src/server/responses/core.ts +3579 -436
  647. package/src/server/responses/empty-completion-guard.ts +333 -0
  648. package/src/server/responses/encrypted-payload.ts +62 -39
  649. package/src/server/responses/fetch-helpers.ts +89 -99
  650. package/src/server/responses/input-admission.ts +187 -0
  651. package/src/server/responses/pacing-overload.ts +13 -0
  652. package/src/server/responses/passthrough-error.ts +33 -9
  653. package/src/server/responses/policy-fallback.ts +178 -0
  654. package/src/server/responses/responses-field-backfill.ts +343 -0
  655. package/src/server/responses/terminal-guard.ts +26 -5
  656. package/src/server/responses/upstream-error.ts +5 -0
  657. package/src/server/responses/ws-upstream.ts +381 -0
  658. package/src/server/responses-custom-tool-repair.ts +363 -0
  659. package/src/server/responses-item-id-repair.ts +54 -6
  660. package/src/server/responses-json-events.ts +90 -0
  661. package/src/server/responses-model-rewrite.ts +29 -0
  662. package/src/server/responses-reasoning-summary-rewrite.ts +178 -0
  663. package/src/server/responses-snapshot-repair.ts +621 -0
  664. package/src/server/responses-terminal-repair.ts +363 -0
  665. package/src/server/responses-tool-search-repair.ts +267 -0
  666. package/src/server/responses-undeclared-tool-guard.ts +376 -0
  667. package/src/server/responses.ts +18 -2
  668. package/src/server/search.ts +78 -13
  669. package/src/server/sse-frame-buffer.ts +319 -0
  670. package/src/server/sse-payload-rewrite.ts +110 -22
  671. package/src/server/startup-action-control.ts +8 -1
  672. package/src/server/startup-health-cache.ts +19 -1
  673. package/src/server/system-env.ts +80 -9
  674. package/src/server/ws-bridge.ts +53 -40
  675. package/src/service-manager-probe.ts +892 -0
  676. package/src/service.ts +1153 -94
  677. package/src/sidecar/auth.ts +92 -0
  678. package/src/sidecar/candidates.ts +83 -0
  679. package/src/storage/cleanup.ts +2 -2
  680. package/src/storage/policy-job.ts +14 -4
  681. package/src/storage/policy.ts +88 -23
  682. package/src/storage/scanner.ts +1 -1
  683. package/src/storage/worker-lifecycle.ts +14 -14
  684. package/src/tray/windows-tray.ps1 +83 -9
  685. package/src/tray/windows.ts +43 -16
  686. package/src/types/accounts.ts +37 -0
  687. package/src/types/config.ts +911 -0
  688. package/src/types/provider.ts +614 -0
  689. package/src/types/request.ts +397 -0
  690. package/src/types/tools.ts +236 -0
  691. package/src/types/wire.ts +80 -0
  692. package/src/types.ts +107 -1237
  693. package/src/update/index.ts +37 -23
  694. package/src/update/job.ts +445 -68
  695. package/src/update/notify.ts +12 -6
  696. package/src/update/npm-cache-preflight.d.mts +47 -0
  697. package/src/update/npm-cache-preflight.mjs +201 -0
  698. package/src/update/transactional-install.d.mts +22 -0
  699. package/src/update/transactional-install.mjs +266 -0
  700. package/src/usage/cost.ts +0 -0
  701. package/src/usage/expected-prices.ts +287 -16
  702. package/src/usage/log.ts +666 -50
  703. package/src/usage/summary.ts +388 -17
  704. package/src/usage/user-cost-overlay-reconciler.ts +313 -0
  705. package/src/usage/user-cost-overlays.ts +314 -0
  706. package/src/vision/anthropic-describe.ts +10 -6
  707. package/src/vision/backends.ts +97 -0
  708. package/src/vision/describe.ts +27 -16
  709. package/src/vision/eligibility.ts +250 -0
  710. package/src/vision/index.ts +238 -24
  711. package/src/vision/reasoning.ts +55 -0
  712. package/src/vision/routed-describe.ts +175 -0
  713. package/src/vision/timeout-bounds.ts +9 -0
  714. package/src/web-search/anthropic-executor.ts +13 -7
  715. package/src/web-search/backends.ts +108 -0
  716. package/src/web-search/exa-executor.ts +119 -0
  717. package/src/web-search/executor.ts +21 -6
  718. package/src/web-search/gemini-executor.ts +141 -0
  719. package/src/web-search/index.ts +150 -15
  720. package/src/web-search/loop.ts +284 -54
  721. package/src/web-search/parse.ts +125 -30
  722. package/src/web-search/sources.ts +60 -0
  723. package/src/web-search/xai-executor.ts +219 -0
  724. package/gui/dist/assets/index-DTpMHS4F.js +0 -67
  725. package/gui/dist/assets/index-ZNVDE3C7.css +0 -1
  726. package/gui/dist/provider-icons/antigravity.svg +0 -1
  727. package/gui/dist/provider-icons/claude.svg +0 -1
  728. package/gui/dist/provider-icons/copilot.svg +0 -1
  729. package/gui/dist/provider-icons/cursor.svg +0 -2
  730. package/gui/dist/provider-icons/gemini.svg +0 -1
  731. package/gui/dist/provider-icons/grok-color.svg +0 -1
  732. package/gui/dist/provider-icons/kiro.svg +0 -14
  733. package/src/cli/internal-dispatch.ts +0 -20
@@ -0,0 +1,155 @@
1
+ import {
2
+ closeSync,
3
+ constants as fsConstants,
4
+ fstatSync,
5
+ fsyncSync,
6
+ lstatSync,
7
+ openSync,
8
+ readFileSync,
9
+ readdirSync,
10
+ unlinkSync,
11
+ } from "node:fs";
12
+ import { basename, dirname, join } from "node:path";
13
+ import { isPrivateFileStageName } from "./private-file";
14
+ import { PublicEvidenceValidationError } from "./validate";
15
+
16
+ const O_NOFOLLOW = (fsConstants as { O_NOFOLLOW?: number }).O_NOFOLLOW ?? 0;
17
+
18
+ export interface PrivateRegularFileReadOptions {
19
+ maxBytes: number;
20
+ errorCode: string;
21
+ errorMessage: string;
22
+ sizeErrorCode?: string;
23
+ sizeErrorMessage?: string;
24
+ requireMode600?: boolean;
25
+ }
26
+
27
+ function sizeError(options: PrivateRegularFileReadOptions): PublicEvidenceValidationError {
28
+ return new PublicEvidenceValidationError(
29
+ options.sizeErrorCode ?? options.errorCode,
30
+ options.sizeErrorMessage ?? options.errorMessage,
31
+ );
32
+ }
33
+
34
+ /**
35
+ * Heal only the publication-specific hard link left behind when the final name was linked
36
+ * but the parent-directory durability check failed. The stage must be target-scoped and
37
+ * inode-identical to the final file; unrelated hard links remain and are rejected below.
38
+ */
39
+ function recoverPublishedPrivateFileStage(path: string): void {
40
+ if (process.platform === "win32") return;
41
+ const finalStats = lstatSync(path);
42
+ if (finalStats.isSymbolicLink() || !finalStats.isFile() || finalStats.nlink <= 1) return;
43
+
44
+ const dir = dirname(path);
45
+ const prefix = `.${basename(path)}.`;
46
+ const candidates: string[] = [];
47
+ for (const name of readdirSync(dir)) {
48
+ if (!name.startsWith(prefix) || !isPrivateFileStageName(name)) continue;
49
+ const stagePath = join(dir, name);
50
+ try {
51
+ const stageStats = lstatSync(stagePath);
52
+ if (
53
+ stageStats.isFile()
54
+ && !stageStats.isSymbolicLink()
55
+ && stageStats.dev === finalStats.dev
56
+ && stageStats.ino === finalStats.ino
57
+ ) {
58
+ candidates.push(stagePath);
59
+ }
60
+ } catch (error) {
61
+ if ((error as NodeJS.ErrnoException).code !== "ENOENT") throw error;
62
+ }
63
+ }
64
+ if (candidates.length === 0) return;
65
+
66
+ // The final directory entry already exists. Make that entry durable before deleting
67
+ // the recovery witness. A real fsync failure propagates and the strict read stays closed.
68
+ let dirFd: number | null = null;
69
+ try {
70
+ dirFd = openSync(dir, fsConstants.O_RDONLY);
71
+ fsyncSync(dirFd);
72
+ } finally {
73
+ if (dirFd !== null) closeSync(dirFd);
74
+ }
75
+
76
+ for (const stagePath of candidates) {
77
+ try {
78
+ const stageStats = lstatSync(stagePath);
79
+ if (
80
+ stageStats.isFile()
81
+ && !stageStats.isSymbolicLink()
82
+ && stageStats.dev === finalStats.dev
83
+ && stageStats.ino === finalStats.ino
84
+ ) {
85
+ unlinkSync(stagePath);
86
+ }
87
+ } catch (error) {
88
+ if ((error as NodeJS.ErrnoException).code !== "ENOENT") throw error;
89
+ }
90
+ }
91
+ }
92
+
93
+ function withPrivateRegularFile<T>(
94
+ path: string,
95
+ options: PrivateRegularFileReadOptions,
96
+ consume: (fd: number, size: number) => T,
97
+ ): T {
98
+ let pathStats = lstatSync(path);
99
+ if (!pathStats.isSymbolicLink() && pathStats.isFile() && pathStats.nlink > 1) {
100
+ recoverPublishedPrivateFileStage(path);
101
+ pathStats = lstatSync(path);
102
+ }
103
+ if (pathStats.isSymbolicLink() || !pathStats.isFile() || pathStats.nlink !== 1) {
104
+ throw new PublicEvidenceValidationError(options.errorCode, options.errorMessage);
105
+ }
106
+ if (pathStats.size > options.maxBytes) throw sizeError(options);
107
+
108
+ const fd = openSync(path, fsConstants.O_RDONLY | O_NOFOLLOW);
109
+ try {
110
+ const stats = fstatSync(fd);
111
+ if (
112
+ !stats.isFile()
113
+ || stats.nlink !== 1
114
+ || stats.dev !== pathStats.dev
115
+ || stats.ino !== pathStats.ino
116
+ ) {
117
+ throw new PublicEvidenceValidationError(options.errorCode, options.errorMessage);
118
+ }
119
+ if (stats.size > options.maxBytes) throw sizeError(options);
120
+ if (options.requireMode600 && process.platform !== "win32" && (stats.mode & 0o777) !== 0o600) {
121
+ throw new PublicEvidenceValidationError(options.errorCode, options.errorMessage);
122
+ }
123
+ return consume(fd, stats.size);
124
+ } finally {
125
+ closeSync(fd);
126
+ }
127
+ }
128
+
129
+ /**
130
+ * Inspect a file only after proving that the pathname and checked descriptor refer to
131
+ * the same private regular file. This keeps quota scans descriptor-bound without
132
+ * reading every cached object into memory.
133
+ */
134
+ export function privateRegularFileSize(
135
+ path: string,
136
+ options: PrivateRegularFileReadOptions,
137
+ ): number {
138
+ return withPrivateRegularFile(path, options, (_fd, size) => size);
139
+ }
140
+
141
+ /**
142
+ * Read bytes only after proving that the pathname and the consumed descriptor refer to
143
+ * the same private regular file. The lstat/dev+ino comparison keeps the protection on
144
+ * platforms where O_NOFOLLOW is unavailable instead of silently following a symlink.
145
+ */
146
+ export function readPrivateRegularFile(
147
+ path: string,
148
+ options: PrivateRegularFileReadOptions,
149
+ ): Buffer {
150
+ return withPrivateRegularFile(path, options, (fd) => {
151
+ const bytes = readFileSync(fd);
152
+ if (bytes.byteLength > options.maxBytes) throw sizeError(options);
153
+ return bytes;
154
+ });
155
+ }
@@ -0,0 +1,26 @@
1
+ import { domainHash, jcsStringify } from "../digest";
2
+
3
+ export type PublicEvidenceIdKind =
4
+ | "subject"
5
+ | "record"
6
+ | "bundle"
7
+ | "bundle_digest"
8
+ | "artifact"
9
+ | "publisher_key"
10
+ | "revocation"
11
+ | "route_registry";
12
+
13
+ const PUBLIC_EVIDENCE_DOMAIN: Record<PublicEvidenceIdKind, string> = {
14
+ subject: "ocx-lab-public:subject:v1",
15
+ record: "ocx-lab-public:record:v1",
16
+ bundle: "ocx-lab-public:bundle:v1",
17
+ bundle_digest: "ocx-lab-public:bundle-digest:v1",
18
+ artifact: "ocx-lab-public:artifact:v1",
19
+ publisher_key: "ocx-lab-public:publisher-key:v1",
20
+ revocation: "ocx-lab-public:revocation:v1",
21
+ route_registry: "ocx-lab-public:route-registry:v1",
22
+ };
23
+
24
+ export function publicEvidenceId(kind: PublicEvidenceIdKind, payload: unknown): string {
25
+ return domainHash(PUBLIC_EVIDENCE_DOMAIN[kind], jcsStringify(payload));
26
+ }
@@ -0,0 +1,16 @@
1
+ export * from "./types";
2
+ export * from "./ids";
3
+ export * from "./registry";
4
+ export * from "./validate";
5
+ export * from "./privacy";
6
+ export * from "./project";
7
+ export * from "./bundle";
8
+ export * from "./signature";
9
+ export * from "./storage";
10
+ export * from "./community-authority";
11
+ export * from "./revocation";
12
+ export * from "./community";
13
+ export * from "./strict-json";
14
+ export * from "./origin";
15
+ export * from "./operator";
16
+ export * from "./purge";
@@ -0,0 +1,424 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import {
3
+ lstatSync,
4
+ mkdirSync,
5
+ readdirSync,
6
+ renameSync,
7
+ rmSync,
8
+ unlinkSync,
9
+ writeFileSync,
10
+ } from "node:fs";
11
+ import { dirname, join } from "node:path";
12
+ import { ensureLabDirs, labCommunityDir } from "../paths";
13
+ import { readPrivateRegularFile } from "./file-safety";
14
+ import { PublicEvidenceValidationError } from "./validate";
15
+
16
+ const PUBLIC_EVIDENCE_MUTATION_LOCK_NAME = ".mutation-lock";
17
+ const PUBLIC_EVIDENCE_MUTATION_LOCK_OWNER = "owner.json";
18
+ const PUBLIC_EVIDENCE_MUTATION_LOCK_RECLAIM = ".reclaim.json";
19
+ const PUBLIC_EVIDENCE_MUTATION_LOCK_INCOMPLETE_STALE_MS = 24 * 60 * 60 * 1000;
20
+ const PUBLIC_EVIDENCE_MUTATION_LOCK_ABSOLUTE_STALE_MS = 7 * 24 * 60 * 60 * 1000;
21
+ const DETACHED_MUTATION_LOCK_RE = /^\.mutation-lock-(?:stale|release)-\d+-[0-9a-f-]{36}$/;
22
+ const MUTATION_LOCK_META_FILE_OPTIONS = {
23
+ maxBytes: 1024,
24
+ errorCode: "community_cache_lock",
25
+ errorMessage: "community cache mutation lock metadata is unsafe",
26
+ sizeErrorCode: "community_cache_lock",
27
+ sizeErrorMessage: "community cache mutation lock metadata exceeds its size bound",
28
+ requireMode600: true,
29
+ } as const;
30
+
31
+ type MutationLockOwner = {
32
+ pid: number;
33
+ token: string;
34
+ createdAt: number;
35
+ };
36
+
37
+ type MutationLockReclaim = {
38
+ pid: number;
39
+ token: string;
40
+ createdAt: number;
41
+ };
42
+
43
+ type MutationLockDirectoryIdentity = {
44
+ dev: number;
45
+ ino: number;
46
+ };
47
+
48
+ function mutationLockPath(configDir?: string): string {
49
+ return join(labCommunityDir(configDir), PUBLIC_EVIDENCE_MUTATION_LOCK_NAME);
50
+ }
51
+
52
+ function mutationLockOwnerPath(lockPath: string): string {
53
+ return join(lockPath, PUBLIC_EVIDENCE_MUTATION_LOCK_OWNER);
54
+ }
55
+
56
+ function mutationLockReclaimPath(lockPath: string): string {
57
+ return join(lockPath, PUBLIC_EVIDENCE_MUTATION_LOCK_RECLAIM);
58
+ }
59
+
60
+ function pidDefinitelyDead(pid: number): boolean {
61
+ try {
62
+ process.kill(pid, 0);
63
+ return false;
64
+ } catch (error) {
65
+ return (error as NodeJS.ErrnoException).code === "ESRCH";
66
+ }
67
+ }
68
+
69
+ function exceedsAbsoluteLockAge(createdAt: number, nowMs: number): boolean {
70
+ return nowMs - createdAt > PUBLIC_EVIDENCE_MUTATION_LOCK_ABSOLUTE_STALE_MS;
71
+ }
72
+
73
+ function readLockMetadata<T extends MutationLockOwner | MutationLockReclaim>(
74
+ path: string,
75
+ ): T | null {
76
+ try {
77
+ const bytes = readPrivateRegularFile(path, MUTATION_LOCK_META_FILE_OPTIONS);
78
+ const raw = JSON.parse(bytes.toString("utf8")) as Partial<T>;
79
+ if (
80
+ Number.isSafeInteger(raw.pid)
81
+ && Number(raw.pid) > 0
82
+ && typeof raw.token === "string"
83
+ && /^[0-9a-f-]{36}$/.test(raw.token)
84
+ && Number.isSafeInteger(raw.createdAt)
85
+ && Number(raw.createdAt) > 0
86
+ ) {
87
+ return {
88
+ pid: Number(raw.pid),
89
+ token: raw.token,
90
+ createdAt: Number(raw.createdAt),
91
+ } as T;
92
+ }
93
+ } catch {
94
+ // Incomplete metadata is handled conservatively by the age fallback where
95
+ // applicable. Normal acquisition never trusts malformed metadata.
96
+ }
97
+ return null;
98
+ }
99
+
100
+ function readMutationLockOwner(lockPath: string): MutationLockOwner | null {
101
+ return readLockMetadata<MutationLockOwner>(mutationLockOwnerPath(lockPath));
102
+ }
103
+
104
+ function readMutationLockReclaim(lockPath: string): MutationLockReclaim | null {
105
+ return readLockMetadata<MutationLockReclaim>(mutationLockReclaimPath(lockPath));
106
+ }
107
+
108
+ function assertMutationLockDirectory(lockPath: string) {
109
+ const stat = lstatSync(lockPath);
110
+ if (!stat.isDirectory() || stat.isSymbolicLink()) {
111
+ throw new PublicEvidenceValidationError(
112
+ "community_cache_lock",
113
+ "community cache mutation lock is not a directory",
114
+ );
115
+ }
116
+ return stat;
117
+ }
118
+
119
+ function sameDirectoryIdentity(
120
+ left: MutationLockDirectoryIdentity,
121
+ right: MutationLockDirectoryIdentity,
122
+ ): boolean {
123
+ return left.dev === right.dev && left.ino === right.ino;
124
+ }
125
+
126
+ function currentDirectoryIdentity(lockPath: string): MutationLockDirectoryIdentity {
127
+ const stat = assertMutationLockDirectory(lockPath);
128
+ return { dev: stat.dev, ino: stat.ino };
129
+ }
130
+
131
+ function mutationLockIsReclaimable(lockPath: string, nowMs: number): boolean {
132
+ const stat = assertMutationLockDirectory(lockPath);
133
+ const owner = readMutationLockOwner(lockPath);
134
+ if (owner) {
135
+ // A live PID is strong evidence only while the recorded ownership generation is
136
+ // reasonably recent. The absolute ceiling recovers from PID reuse after a crash.
137
+ return pidDefinitelyDead(owner.pid) || exceedsAbsoluteLockAge(owner.createdAt, nowMs);
138
+ }
139
+ // The only ownerless state is the tiny mkdir-to-owner publication window. Use
140
+ // a deliberately long fallback so a crashed acquisition can eventually heal
141
+ // without treating an ordinary pause as proof that the owner disappeared.
142
+ return nowMs - stat.mtimeMs > PUBLIC_EVIDENCE_MUTATION_LOCK_INCOMPLETE_STALE_MS;
143
+ }
144
+
145
+ function unlinkIfPresent(path: string): void {
146
+ try {
147
+ unlinkSync(path);
148
+ } catch (error) {
149
+ if ((error as NodeJS.ErrnoException).code !== "ENOENT") throw error;
150
+ }
151
+ }
152
+
153
+ function cleanupDetachedMutationLocks(lockPath: string): void {
154
+ const dir = dirname(lockPath);
155
+ for (const name of readdirSync(dir)) {
156
+ if (!DETACHED_MUTATION_LOCK_RE.test(name)) continue;
157
+ // Detached lock directories are no longer authoritative once a new canonical
158
+ // lock has been acquired. Removing only their UUID-scoped names prevents them
159
+ // from leaking storage or being mistaken for community cache objects.
160
+ rmSync(join(dir, name), { recursive: true, force: true });
161
+ }
162
+ }
163
+
164
+ function publishMutationLockOwner(
165
+ lockPath: string,
166
+ owner: MutationLockOwner,
167
+ expectedDirectory: MutationLockDirectoryIdentity,
168
+ ): void {
169
+ // Write through a unique temporary pathname first. If an ancient ownerless
170
+ // lock is reclaimed while this process was suspended, the inode check prevents
171
+ // this acquisition from publishing its owner metadata into a replacement lock.
172
+ const tempPath = join(lockPath, `.owner-${owner.token}.tmp`);
173
+ try {
174
+ writeFileSync(tempPath, JSON.stringify(owner), {
175
+ encoding: "utf8",
176
+ flag: "wx",
177
+ mode: 0o600,
178
+ });
179
+ if (!sameDirectoryIdentity(currentDirectoryIdentity(lockPath), expectedDirectory)) {
180
+ throw new PublicEvidenceValidationError(
181
+ "community_cache_lock",
182
+ "community cache mutation lock changed during owner publication",
183
+ );
184
+ }
185
+ renameSync(tempPath, mutationLockOwnerPath(lockPath));
186
+ if (!sameDirectoryIdentity(currentDirectoryIdentity(lockPath), expectedDirectory)) {
187
+ throw new PublicEvidenceValidationError(
188
+ "community_cache_lock",
189
+ "community cache mutation lock changed after owner publication",
190
+ );
191
+ }
192
+ const persisted = readMutationLockOwner(lockPath);
193
+ if (!persisted || persisted.pid !== owner.pid || persisted.token !== owner.token) {
194
+ throw new PublicEvidenceValidationError(
195
+ "community_cache_lock",
196
+ "community cache mutation lock owner publication was not durable",
197
+ );
198
+ }
199
+ } finally {
200
+ // The rename normally makes this ENOENT. If the lock pathname was replaced,
201
+ // the UUID-scoped temporary name can be removed without touching successor state.
202
+ unlinkIfPresent(tempPath);
203
+ }
204
+ }
205
+
206
+ function reclaimClaimIsRecoverable(lockPath: string, nowMs: number): boolean {
207
+ const claimPath = mutationLockReclaimPath(lockPath);
208
+ const claim = readMutationLockReclaim(lockPath);
209
+ if (claim) {
210
+ return pidDefinitelyDead(claim.pid) || exceedsAbsoluteLockAge(claim.createdAt, nowMs);
211
+ }
212
+ try {
213
+ const stat = lstatSync(claimPath);
214
+ return nowMs - stat.mtimeMs > PUBLIC_EVIDENCE_MUTATION_LOCK_INCOMPLETE_STALE_MS;
215
+ } catch (error) {
216
+ if ((error as NodeJS.ErrnoException).code === "ENOENT") return true;
217
+ throw error;
218
+ }
219
+ }
220
+
221
+ function recoverStaleReclaimClaim(lockPath: string, nowMs: number): boolean {
222
+ if (!reclaimClaimIsRecoverable(lockPath, nowMs)) return false;
223
+ const claimPath = mutationLockReclaimPath(lockPath);
224
+ const quarantinePath = join(lockPath, `.reclaim-stale-${randomUUID()}.json`);
225
+ try {
226
+ renameSync(claimPath, quarantinePath);
227
+ } catch (error) {
228
+ if ((error as NodeJS.ErrnoException).code === "ENOENT") return true;
229
+ throw error;
230
+ }
231
+ unlinkIfPresent(quarantinePath);
232
+ return true;
233
+ }
234
+
235
+ function tryAcquireReclaimClaim(
236
+ lockPath: string,
237
+ nowMs: number,
238
+ ): MutationLockReclaim | null {
239
+ for (let attempt = 0; attempt < 2; attempt += 1) {
240
+ const claim: MutationLockReclaim = {
241
+ pid: process.pid,
242
+ token: randomUUID(),
243
+ createdAt: nowMs,
244
+ };
245
+ try {
246
+ writeFileSync(mutationLockReclaimPath(lockPath), JSON.stringify(claim), {
247
+ encoding: "utf8",
248
+ flag: "wx",
249
+ mode: 0o600,
250
+ });
251
+ return claim;
252
+ } catch (error) {
253
+ const code = (error as NodeJS.ErrnoException).code;
254
+ if (code === "ENOENT") return null;
255
+ if (code !== "EEXIST") throw error;
256
+ if (!recoverStaleReclaimClaim(lockPath, nowMs)) return null;
257
+ }
258
+ }
259
+ return null;
260
+ }
261
+
262
+ function reclaimClaimStillOwned(lockPath: string, claim: MutationLockReclaim): boolean {
263
+ const current = readMutationLockReclaim(lockPath);
264
+ return current?.pid === claim.pid && current.token === claim.token;
265
+ }
266
+
267
+ function releaseReclaimClaim(lockPath: string, claim: MutationLockReclaim): void {
268
+ if (!reclaimClaimStillOwned(lockPath, claim)) return;
269
+ unlinkIfPresent(mutationLockReclaimPath(lockPath));
270
+ }
271
+
272
+ function tryReclaimMutationLock(lockPath: string, nowMs: number): boolean {
273
+ // Capture the exact stale directory before the claim write changes its mtime.
274
+ // After claiming, revalidate the inode and owner instead of reusing an age check
275
+ // that our own .reclaim.json creation would make appear fresh.
276
+ if (!mutationLockIsReclaimable(lockPath, nowMs)) return false;
277
+ const staleDirectory = currentDirectoryIdentity(lockPath);
278
+ const claim = tryAcquireReclaimClaim(lockPath, nowMs);
279
+ if (!claim) return false;
280
+
281
+ let moved = false;
282
+ try {
283
+ if (!reclaimClaimStillOwned(lockPath, claim)) return false;
284
+ if (!sameDirectoryIdentity(currentDirectoryIdentity(lockPath), staleDirectory)) return false;
285
+ const currentOwner = readMutationLockOwner(lockPath);
286
+ if (
287
+ currentOwner
288
+ && !pidDefinitelyDead(currentOwner.pid)
289
+ && !exceedsAbsoluteLockAge(currentOwner.createdAt, nowMs)
290
+ ) return false;
291
+ if (!reclaimClaimStillOwned(lockPath, claim)) return false;
292
+
293
+ const quarantinePath = join(
294
+ dirname(lockPath),
295
+ `.mutation-lock-stale-${process.pid}-${randomUUID()}`,
296
+ );
297
+ try {
298
+ // Rename the exact claimed directory away from the canonical pathname before
299
+ // deleting it. A successor can create a new lock immediately afterwards, but
300
+ // cleanup is confined to this unique quarantine path and cannot delete it.
301
+ renameSync(lockPath, quarantinePath);
302
+ moved = true;
303
+ } catch (error) {
304
+ if ((error as NodeJS.ErrnoException).code === "ENOENT") return true;
305
+ throw error;
306
+ }
307
+ rmSync(quarantinePath, { recursive: true, force: true });
308
+ return true;
309
+ } finally {
310
+ if (!moved) releaseReclaimClaim(lockPath, claim);
311
+ }
312
+ }
313
+
314
+ function discardUncommittedMutationLock(
315
+ lockPath: string,
316
+ expectedDirectory: MutationLockDirectoryIdentity,
317
+ ): void {
318
+ try {
319
+ if (!sameDirectoryIdentity(currentDirectoryIdentity(lockPath), expectedDirectory)) return;
320
+ const quarantinePath = join(
321
+ dirname(lockPath),
322
+ `.mutation-lock-release-${process.pid}-${randomUUID()}`,
323
+ );
324
+ renameSync(lockPath, quarantinePath);
325
+ rmSync(quarantinePath, { recursive: true, force: true });
326
+ } catch {
327
+ // Preserve the owner-publication error. An unrecoverable cleanup witness stays
328
+ // ownerless and can be reclaimed by the long incomplete-acquisition fallback.
329
+ }
330
+ }
331
+
332
+ function releaseMutationLock(
333
+ lockPath: string,
334
+ owner: MutationLockOwner,
335
+ expectedDirectory: MutationLockDirectoryIdentity,
336
+ ): void {
337
+ let currentDirectory: MutationLockDirectoryIdentity;
338
+ try {
339
+ currentDirectory = currentDirectoryIdentity(lockPath);
340
+ } catch (error) {
341
+ if ((error as NodeJS.ErrnoException).code === "ENOENT") return;
342
+ throw error;
343
+ }
344
+ if (!sameDirectoryIdentity(currentDirectory, expectedDirectory)) return;
345
+ const current = readMutationLockOwner(lockPath);
346
+ if (!current || current.pid !== owner.pid || current.token !== owner.token) return;
347
+
348
+ const quarantinePath = join(
349
+ dirname(lockPath),
350
+ `.mutation-lock-release-${process.pid}-${randomUUID()}`,
351
+ );
352
+ try {
353
+ renameSync(lockPath, quarantinePath);
354
+ } catch (error) {
355
+ if ((error as NodeJS.ErrnoException).code === "ENOENT") return;
356
+ throw error;
357
+ }
358
+ rmSync(quarantinePath, { recursive: true, force: true });
359
+ }
360
+
361
+ /** Serialize public-evidence mutations across CLI/server processes with ownership-safe stale recovery. */
362
+ export function withPublicEvidenceMutationLock<T>(
363
+ configDir: string | undefined,
364
+ run: () => T,
365
+ ): T {
366
+ ensureLabDirs(configDir);
367
+ const lockPath = mutationLockPath(configDir);
368
+ let owner: MutationLockOwner | null = null;
369
+ let ownedDirectory: MutationLockDirectoryIdentity | null = null;
370
+
371
+ while (true) {
372
+ try {
373
+ mkdirSync(lockPath, { mode: 0o700 });
374
+ } catch (error) {
375
+ if ((error as NodeJS.ErrnoException).code !== "EEXIST") throw error;
376
+ try {
377
+ if (tryReclaimMutationLock(lockPath, Date.now())) continue;
378
+ } catch (reclaimError) {
379
+ if ((reclaimError as NodeJS.ErrnoException).code === "ENOENT") continue;
380
+ throw reclaimError;
381
+ }
382
+ throw new PublicEvidenceValidationError("community_cache_busy", "community cache is busy");
383
+ }
384
+
385
+ const directory = currentDirectoryIdentity(lockPath);
386
+ const candidate: MutationLockOwner = {
387
+ pid: process.pid,
388
+ token: randomUUID(),
389
+ createdAt: Date.now(),
390
+ };
391
+ try {
392
+ publishMutationLockOwner(lockPath, candidate, directory);
393
+ } catch (error) {
394
+ discardUncommittedMutationLock(lockPath, directory);
395
+ throw error;
396
+ }
397
+ owner = candidate;
398
+ ownedDirectory = directory;
399
+ break;
400
+ }
401
+
402
+ try {
403
+ cleanupDetachedMutationLocks(lockPath);
404
+ return run();
405
+ } finally {
406
+ if (owner && ownedDirectory) releaseMutationLock(lockPath, owner, ownedDirectory);
407
+ }
408
+ }
409
+
410
+ /** Test-only seam for stale-owner policy. This module is not barrel-exported. */
411
+ export function publicEvidenceMutationLockIsReclaimableForTests(
412
+ configDir: string | undefined,
413
+ nowMs = Date.now(),
414
+ ): boolean {
415
+ return mutationLockIsReclaimable(mutationLockPath(configDir), nowMs);
416
+ }
417
+
418
+ /** Test-only seam for the exclusive stale-reclaimer claim. */
419
+ export function publicEvidenceTryReclaimMutationLockForTests(
420
+ configDir: string | undefined,
421
+ nowMs = Date.now(),
422
+ ): boolean {
423
+ return tryReclaimMutationLock(mutationLockPath(configDir), nowMs);
424
+ }