@iislee/opencodex 2.11.0 → 2.31.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 (675) hide show
  1. package/AGENTS_INSTALL.md +109 -0
  2. package/README.md +114 -19
  3. package/bin/ocx.mjs +164 -36
  4. package/bin/package-main.mjs +1 -1
  5. package/gui/dist/assets/index-BF38heuV.js +104 -0
  6. package/gui/dist/assets/index-DMiI18Kv.css +1 -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 +19 -10
  42. package/src/adapters/anthropic-output-schema.ts +137 -0
  43. package/src/adapters/anthropic.ts +376 -52
  44. package/src/adapters/base.ts +54 -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 +601 -0
  48. package/src/adapters/cursor/checkpoint-store.ts +303 -0
  49. package/src/adapters/cursor/cursor-errors.ts +129 -6
  50. package/src/adapters/cursor/discovery.ts +61 -4
  51. package/src/adapters/cursor/effort-map.ts +27 -3
  52. package/src/adapters/cursor/framing.ts +39 -0
  53. package/src/adapters/cursor/h2-pool.ts +123 -0
  54. package/src/adapters/cursor/http1-bidi.ts +361 -0
  55. package/src/adapters/cursor/images.ts +704 -0
  56. package/src/adapters/cursor/live-models.ts +174 -58
  57. package/src/adapters/cursor/live-transport.ts +609 -170
  58. package/src/adapters/cursor/native-exec-common.ts +23 -2
  59. package/src/adapters/cursor/native-exec-fs.ts +10 -7
  60. package/src/adapters/cursor/native-exec-network.ts +1 -1
  61. package/src/adapters/cursor/native-exec-shell.ts +0 -1
  62. package/src/adapters/cursor/native-exec.ts +101 -14
  63. package/src/adapters/cursor/protobuf-events.ts +829 -11
  64. package/src/adapters/cursor/protobuf-request.ts +383 -65
  65. package/src/adapters/cursor/request-builder.ts +237 -31
  66. package/src/adapters/cursor/tool-definitions.ts +242 -12
  67. package/src/adapters/cursor/tool-result-normalize.ts +92 -0
  68. package/src/adapters/cursor/transport.ts +22 -0
  69. package/src/adapters/cursor/types.ts +28 -1
  70. package/src/adapters/cursor.ts +133 -7
  71. package/src/adapters/google-antigravity-replay.ts +558 -34
  72. package/src/adapters/google-antigravity-wire.ts +43 -10
  73. package/src/adapters/google-http.ts +38 -10
  74. package/src/adapters/google-tool-schema.ts +80 -15
  75. package/src/adapters/google-truncation.ts +11 -0
  76. package/src/adapters/google.ts +618 -74
  77. package/src/adapters/identity.ts +39 -6
  78. package/src/adapters/kiro-errors.ts +11 -0
  79. package/src/adapters/kiro-events.ts +19 -1
  80. package/src/adapters/kiro-thinking.ts +18 -2
  81. package/src/adapters/kiro-tools.ts +10 -1
  82. package/src/adapters/kiro.ts +92 -54
  83. package/src/adapters/mimo-free.ts +17 -0
  84. package/src/adapters/openai-chat-url.ts +11 -0
  85. package/src/adapters/openai-chat.ts +1311 -336
  86. package/src/adapters/openai-responses-url.ts +16 -0
  87. package/src/adapters/openai-responses.ts +830 -56
  88. package/src/adapters/registry.ts +175 -0
  89. package/src/adapters/responses-tool-schema.ts +67 -0
  90. package/src/adapters/tool-call-id.ts +119 -0
  91. package/src/adapters/tool-catalog-nudge.ts +104 -21
  92. package/src/adapters/xai-web-search.ts +185 -0
  93. package/src/bridge.ts +428 -61
  94. package/src/chat/inbound.ts +43 -19
  95. package/src/chat/outbound.ts +82 -26
  96. package/src/claude/agents-inject.ts +32 -9
  97. package/src/claude/context-windows.ts +21 -5
  98. package/src/claude/desktop-3p.ts +243 -9
  99. package/src/claude/gateway-cache.ts +41 -4
  100. package/src/claude/inbound.ts +72 -3
  101. package/src/claude/model-info.ts +38 -15
  102. package/src/claude/outbound.ts +70 -16
  103. package/src/cli/account-api.ts +35 -1
  104. package/src/cli/account-auth.ts +33 -6
  105. package/src/cli/account-catalog-refresh.ts +14 -0
  106. package/src/cli/account-extended.ts +389 -2
  107. package/src/cli/account-main.ts +317 -0
  108. package/src/cli/account.ts +30 -6
  109. package/src/cli/agent.ts +45 -1
  110. package/src/cli/claude-agent-startup-sync.ts +73 -0
  111. package/src/cli/claude-desktop.ts +29 -4
  112. package/src/cli/claude.ts +103 -34
  113. package/src/cli/codex-log-guard-doctor.ts +103 -0
  114. package/src/cli/codex-shim-autorestore.ts +2 -0
  115. package/src/cli/codex-shim-readiness.ts +76 -0
  116. package/src/cli/combo.ts +8 -0
  117. package/src/cli/config-command.ts +74 -10
  118. package/src/cli/dispatch.ts +593 -0
  119. package/src/cli/doctor.ts +315 -43
  120. package/src/cli/ensure-desired-integrations.ts +152 -0
  121. package/src/cli/export-command.ts +46 -20
  122. package/src/cli/help.ts +20 -271
  123. package/src/cli/index.ts +378 -519
  124. package/src/cli/init.ts +4 -17
  125. package/src/cli/integrations.ts +120 -2
  126. package/src/cli/lab.ts +607 -0
  127. package/src/cli/launcher-context.ts +77 -0
  128. package/src/cli/minimax.ts +497 -0
  129. package/src/cli/models-runtime.ts +35 -2
  130. package/src/cli/models.ts +100 -14
  131. package/src/cli/observe.ts +92 -3
  132. package/src/cli/opencode.ts +4 -2
  133. package/src/cli/provider-runtime.ts +18 -1
  134. package/src/cli/provider.ts +24 -3
  135. package/src/cli/ready.ts +301 -0
  136. package/src/cli/registry.ts +437 -0
  137. package/src/cli/root.ts +86 -0
  138. package/src/cli/route-policy.ts +92 -0
  139. package/src/cli/runtime-api.ts +6 -3
  140. package/src/cli/star-prompt.ts +71 -15
  141. package/src/cli/status.ts +10 -3
  142. package/src/cli/system-restart-client.ts +146 -0
  143. package/src/cli/tray-proxy.ts +153 -6
  144. package/src/cli/v2.ts +105 -10
  145. package/src/cli.ts +1 -1
  146. package/src/clients/config-export.ts +1358 -21
  147. package/src/codex/account-label.ts +14 -1
  148. package/src/codex/account-lifecycle.ts +130 -13
  149. package/src/codex/account-namespaces.ts +49 -3
  150. package/src/codex/account-priority.ts +83 -0
  151. package/src/codex/account-store.ts +29 -2
  152. package/src/codex/account-usability.ts +25 -2
  153. package/src/codex/admission.ts +256 -0
  154. package/src/codex/affinity-debug.ts +162 -0
  155. package/src/codex/app-server-processes.ts +493 -106
  156. package/src/codex/app-server-restart-service.ts +232 -0
  157. package/src/codex/auth-api.ts +849 -242
  158. package/src/codex/auth-collision.ts +5 -3
  159. package/src/codex/auth-context.ts +345 -32
  160. package/src/codex/autostart-health.ts +8 -1
  161. package/src/codex/catalog/account-models.ts +67 -0
  162. package/src/codex/catalog/aggregation.ts +68 -10
  163. package/src/codex/catalog/bundled.ts +331 -33
  164. package/src/codex/catalog/effort.ts +121 -30
  165. package/src/codex/catalog/filesystem-evidence.ts +302 -0
  166. package/src/codex/catalog/kinds.ts +2 -0
  167. package/src/codex/catalog/metadata.ts +529 -45
  168. package/src/codex/catalog/native-models.ts +72 -0
  169. package/src/codex/catalog/parsing.ts +224 -30
  170. package/src/codex/catalog/provider-fetch.ts +1460 -134
  171. package/src/codex/catalog/sync.ts +1449 -186
  172. package/src/codex/catalog-admission.ts +199 -0
  173. package/src/codex/catalog-refresh-status.ts +105 -0
  174. package/src/codex/catalog-write-serialization.ts +242 -0
  175. package/src/codex/catalog.ts +6 -3
  176. package/src/codex/codex-write-lock.ts +384 -0
  177. package/src/codex/convergence-types.ts +614 -0
  178. package/src/codex/convergence.ts +651 -0
  179. package/src/codex/coordinator-doctor.ts +332 -0
  180. package/src/codex/custom-model-catalog-migration.ts +176 -0
  181. package/src/codex/desired-state.ts +230 -0
  182. package/src/codex/features.ts +636 -39
  183. package/src/codex/generation.ts +202 -0
  184. package/src/codex/history-job.ts +407 -0
  185. package/src/codex/history-lock.ts +242 -0
  186. package/src/codex/history-migration-guardian.ts +26 -20
  187. package/src/codex/history-provider.ts +231 -28
  188. package/src/codex/history-transition.ts +105 -0
  189. package/src/codex/history-worker.ts +220 -0
  190. package/src/codex/inject-coordination.ts +290 -0
  191. package/src/codex/inject.ts +1073 -152
  192. package/src/codex/injected-marker.ts +37 -3
  193. package/src/codex/integration-record.ts +266 -0
  194. package/src/codex/internal/catalog-writer.ts +203 -0
  195. package/src/codex/internal/history-writer.ts +80 -0
  196. package/src/codex/journal.ts +66 -4
  197. package/src/codex/log-guard/inspect.ts +506 -0
  198. package/src/codex/log-guard/lock.ts +150 -0
  199. package/src/codex/log-guard/maintenance.ts +403 -0
  200. package/src/codex/log-guard/path-safety.ts +88 -0
  201. package/src/codex/log-guard/policy.ts +44 -0
  202. package/src/codex/log-guard/processes.ts +205 -0
  203. package/src/codex/log-guard/protection.ts +489 -0
  204. package/src/codex/log-guard/sqlite-errors.ts +9 -0
  205. package/src/codex/main-account-cache.ts +24 -0
  206. package/src/codex/main-account.ts +29 -1
  207. package/src/codex/management-convergence.ts +167 -0
  208. package/src/codex/model-cache.ts +56 -10
  209. package/src/codex/model-entitlements.ts +353 -0
  210. package/src/codex/native-main-admission.ts +47 -0
  211. package/src/codex/native-main-auth-temp.ts +187 -0
  212. package/src/codex/native-main-claim.ts +178 -0
  213. package/src/codex/native-main-lock-file.ts +162 -0
  214. package/src/codex/native-main-owner.ts +329 -0
  215. package/src/codex/native-profile-api.ts +247 -0
  216. package/src/codex/native-profile-manager.ts +1531 -0
  217. package/src/codex/native-profile-processes.ts +121 -0
  218. package/src/codex/native-profile-recovery.ts +99 -0
  219. package/src/codex/native-profile-stage-store.ts +387 -0
  220. package/src/codex/native-profile-startup.ts +492 -0
  221. package/src/codex/native-profile-store.ts +855 -0
  222. package/src/codex/native-profile-types.ts +120 -0
  223. package/src/codex/native-residue.ts +682 -0
  224. package/src/codex/paths.ts +80 -1
  225. package/src/codex/plan-from-token.ts +140 -0
  226. package/src/codex/plan.ts +40 -0
  227. package/src/codex/plugins-doctor.ts +1 -1
  228. package/src/codex/pool-rotation.ts +74 -4
  229. package/src/codex/project-config-warnings.ts +20 -6
  230. package/src/codex/prompt-journal.ts +352 -0
  231. package/src/codex/prompt-layers.ts +967 -0
  232. package/src/codex/prompt-lock.ts +143 -0
  233. package/src/codex/quota-rejection.ts +298 -0
  234. package/src/codex/quota.ts +175 -13
  235. package/src/codex/refresh.ts +11 -2
  236. package/src/codex/reset-credit-recovery.ts +1044 -0
  237. package/src/codex/routing.ts +505 -94
  238. package/src/codex/runtime.ts +159 -38
  239. package/src/codex/shim.ts +1009 -28
  240. package/src/codex/subagent-model-fallback.ts +350 -35
  241. package/src/codex/sync.ts +191 -2
  242. package/src/codex/transition-state.ts +612 -0
  243. package/src/codex/upstream-host-health.ts +368 -0
  244. package/src/codex/user-identity.ts +557 -0
  245. package/src/codex/warmup.ts +187 -81
  246. package/src/codex/write-coordination.ts +114 -0
  247. package/src/combos/failover.ts +20 -0
  248. package/src/combos/index.ts +4 -0
  249. package/src/combos/request.ts +32 -0
  250. package/src/combos/types.ts +81 -9
  251. package/src/config/provider-name.ts +24 -0
  252. package/src/config.ts +1762 -140
  253. package/src/generated/compatibility-version.json +3164 -0
  254. package/src/generated/{jawcode-model-metadata.ts → model-metadata.ts} +19 -17
  255. package/src/grok/inject.ts +16 -5
  256. package/src/grok/inspect.ts +45 -0
  257. package/src/grok/sync.ts +2 -2
  258. package/src/images/loop.ts +152 -29
  259. package/src/images/plan.ts +23 -13
  260. package/src/integrations/config-io.ts +269 -0
  261. package/src/integrations/journal.ts +315 -0
  262. package/src/integrations/merge.ts +135 -0
  263. package/src/integrations/mutation-flight.ts +71 -0
  264. package/src/integrations/native/ownership-preflight.ts +202 -0
  265. package/src/integrations/omp-yaml-source.ts +358 -0
  266. package/src/integrations/owned-refresh.ts +74 -0
  267. package/src/integrations/ownership.ts +111 -0
  268. package/src/integrations/registry.ts +159 -0
  269. package/src/integrations/serialize.ts +314 -0
  270. package/src/integrations/state.ts +361 -0
  271. package/src/integrations/store.ts +103 -0
  272. package/src/integrations/writer-lock.ts +98 -0
  273. package/src/integrations/writer.ts +691 -0
  274. package/src/lab/artifacts/sanitize.ts +586 -0
  275. package/src/lab/artifacts/secure-fs.ts +475 -0
  276. package/src/lab/artifacts/store.ts +310 -0
  277. package/src/lab/automation/budgets.ts +78 -0
  278. package/src/lab/automation/config-persistence.ts +256 -0
  279. package/src/lab/automation/constants.ts +39 -0
  280. package/src/lab/automation/cooldown.ts +103 -0
  281. package/src/lab/automation/dispatch.ts +211 -0
  282. package/src/lab/automation/index.ts +13 -0
  283. package/src/lab/automation/orchestrator.ts +499 -0
  284. package/src/lab/automation/persistence.ts +512 -0
  285. package/src/lab/automation/planner.ts +371 -0
  286. package/src/lab/automation/policy.ts +136 -0
  287. package/src/lab/automation/queue.ts +191 -0
  288. package/src/lab/automation/recovery.ts +24 -0
  289. package/src/lab/automation/route-context.ts +21 -0
  290. package/src/lab/automation/run-key.ts +44 -0
  291. package/src/lab/automation/runs-query.ts +34 -0
  292. package/src/lab/automation/types.ts +160 -0
  293. package/src/lab/conformance/assertion.ts +325 -0
  294. package/src/lab/conformance/digest.ts +22 -0
  295. package/src/lab/conformance/executor.ts +741 -0
  296. package/src/lab/conformance/fixture-provider.ts +27 -0
  297. package/src/lab/conformance/fixtures/live-v1-cases.json +175 -0
  298. package/src/lab/conformance/fixtures/protocol-v1-cases.json +461 -0
  299. package/src/lab/conformance/harness-budget.ts +47 -0
  300. package/src/lab/conformance/index.ts +5 -0
  301. package/src/lab/conformance/jcs.ts +64 -0
  302. package/src/lab/conformance/json-pointer.ts +39 -0
  303. package/src/lab/conformance/manifest.ts +180 -0
  304. package/src/lab/conformance/mcp-stub.ts +179 -0
  305. package/src/lab/conformance/negative-controls.ts +164 -0
  306. package/src/lab/conformance/observation.ts +355 -0
  307. package/src/lab/conformance/runner.ts +68 -0
  308. package/src/lab/conformance/sse-normalize.ts +59 -0
  309. package/src/lab/conformance/suite-manifest.ts +78 -0
  310. package/src/lab/conformance/types.ts +214 -0
  311. package/src/lab/constants.ts +126 -0
  312. package/src/lab/digest.ts +64 -0
  313. package/src/lab/events/errors.ts +9 -0
  314. package/src/lab/events/limits.ts +117 -0
  315. package/src/lab/events/types.ts +229 -0
  316. package/src/lab/events/validate.ts +781 -0
  317. package/src/lab/fabric/constants.ts +40 -0
  318. package/src/lab/fabric/executor.ts +492 -0
  319. package/src/lab/fabric/index.ts +80 -0
  320. package/src/lab/fabric/manifest.ts +222 -0
  321. package/src/lab/fabric/observe.ts +489 -0
  322. package/src/lab/fabric/patch.ts +79 -0
  323. package/src/lab/fabric/producer-child.ts +139 -0
  324. package/src/lab/fabric/producer-isolate.ts +276 -0
  325. package/src/lab/fabric/producer-protocol.ts +61 -0
  326. package/src/lab/fabric/scratch.ts +439 -0
  327. package/src/lab/fabric/subject.ts +106 -0
  328. package/src/lab/fabric/types.ts +134 -0
  329. package/src/lab/fabric/verifier.ts +98 -0
  330. package/src/lab/index.ts +54 -0
  331. package/src/lab/ledger/artifact-refs.ts +127 -0
  332. package/src/lab/ledger/invalidation.ts +136 -0
  333. package/src/lab/ledger/purge.ts +310 -0
  334. package/src/lab/ledger/store.ts +532 -0
  335. package/src/lab/live/credential-lease.ts +53 -0
  336. package/src/lab/live/destination.ts +155 -0
  337. package/src/lab/live/executor.ts +336 -0
  338. package/src/lab/live/inert-tools.ts +56 -0
  339. package/src/lab/live/manifest.ts +85 -0
  340. package/src/lab/live/mcp-loopback.ts +57 -0
  341. package/src/lab/live/runner.ts +19 -0
  342. package/src/lab/live/sandbox.ts +61 -0
  343. package/src/lab/live/suite-manifest.ts +41 -0
  344. package/src/lab/live/transport.ts +118 -0
  345. package/src/lab/live/types.ts +197 -0
  346. package/src/lab/observe/from-conformance.ts +301 -0
  347. package/src/lab/observe/from-live.ts +117 -0
  348. package/src/lab/paths.ts +153 -0
  349. package/src/lab/projection/rebuild.ts +495 -0
  350. package/src/lab/projection/schema.ts +135 -0
  351. package/src/lab/projection/verdicts.ts +474 -0
  352. package/src/lab/projection/verification.ts +412 -0
  353. package/src/lab/public/bundle.ts +217 -0
  354. package/src/lab/public/community-authority.ts +175 -0
  355. package/src/lab/public/community-files.ts +29 -0
  356. package/src/lab/public/community.ts +479 -0
  357. package/src/lab/public/file-safety.ts +155 -0
  358. package/src/lab/public/ids.ts +26 -0
  359. package/src/lab/public/index.ts +16 -0
  360. package/src/lab/public/mutation-lock.ts +424 -0
  361. package/src/lab/public/operator.ts +353 -0
  362. package/src/lab/public/origin-purge.ts +79 -0
  363. package/src/lab/public/origin.ts +203 -0
  364. package/src/lab/public/privacy.ts +143 -0
  365. package/src/lab/public/private-file.ts +261 -0
  366. package/src/lab/public/project.ts +124 -0
  367. package/src/lab/public/purge-test-fault.ts +21 -0
  368. package/src/lab/public/purge.ts +223 -0
  369. package/src/lab/public/registry.ts +44 -0
  370. package/src/lab/public/revocation.ts +252 -0
  371. package/src/lab/public/signature.ts +243 -0
  372. package/src/lab/public/storage.ts +105 -0
  373. package/src/lab/public/strict-json.ts +206 -0
  374. package/src/lab/public/time.ts +26 -0
  375. package/src/lab/public/types.ts +172 -0
  376. package/src/lab/public/validate.ts +391 -0
  377. package/src/lab/query/catalog.ts +101 -0
  378. package/src/lab/query/connection.ts +107 -0
  379. package/src/lab/query/constants.ts +4 -0
  380. package/src/lab/query/cursor.ts +132 -0
  381. package/src/lab/query/dto-map.ts +277 -0
  382. package/src/lab/query/errors.ts +22 -0
  383. package/src/lab/query/freshness.ts +53 -0
  384. package/src/lab/query/index.ts +45 -0
  385. package/src/lab/query/latest-observation.ts +59 -0
  386. package/src/lab/query/passive-production.ts +159 -0
  387. package/src/lab/query/queries.ts +444 -0
  388. package/src/lab/query/types.ts +266 -0
  389. package/src/lab/subject/behavior-fingerprint.ts +77 -0
  390. package/src/lab/subject/installation-salt.ts +112 -0
  391. package/src/lab/subject/protocol-subject.ts +80 -0
  392. package/src/lab/subject/route-subject.ts +74 -0
  393. package/src/lib/app-owned-memory-stores.ts +22 -0
  394. package/src/lib/bounded-body.ts +153 -9
  395. package/src/lib/bun-runtime.ts +125 -12
  396. package/src/lib/bun-stream-caps.ts +13 -9
  397. package/src/lib/codex-restart-contract.ts +120 -0
  398. package/src/lib/config-ownership.ts +6 -2
  399. package/src/lib/destination-policy.ts +65 -1
  400. package/src/lib/errors.ts +44 -2
  401. package/src/lib/fabric-task-execution-authority.ts +7 -0
  402. package/src/lib/fabric-task-host.ts +29 -0
  403. package/src/lib/lab-activation.ts +223 -0
  404. package/src/lib/lab-live-execution-authority.ts +13 -0
  405. package/src/lib/lab-live-host.ts +30 -0
  406. package/src/lib/lab-live-pinned-sender.ts +56 -0
  407. package/src/lib/lab-live-route-production.ts +130 -0
  408. package/src/lib/lab-passive-linker-registration.ts +26 -0
  409. package/src/lib/local-management-attestation.ts +51 -0
  410. package/src/lib/local-management-capability.ts +100 -0
  411. package/src/lib/local-provider-reload-contract.ts +100 -0
  412. package/src/lib/optional-shutdown-hooks.ts +57 -0
  413. package/src/lib/pinned-http.ts +145 -26
  414. package/src/lib/process-control.ts +4 -1
  415. package/src/lib/provider-outbound.ts +49 -9
  416. package/src/lib/redact.ts +419 -3
  417. package/src/lib/self-launch-argv.ts +15 -0
  418. package/src/lib/server-resource-ownership.ts +71 -0
  419. package/src/lib/shadow-call.ts +35 -4
  420. package/src/lib/sse-decoder.ts +41 -0
  421. package/src/lib/state-store-registrations.ts +10 -2
  422. package/src/lib/system-restart-contract.ts +73 -0
  423. package/src/lib/token-estimate.ts +19 -2
  424. package/src/lib/tool-argument-integers.ts +202 -0
  425. package/src/lib/translator-budget.ts +44 -0
  426. package/src/lib/upstream-http-version.ts +57 -0
  427. package/src/lib/upstream-reachability.ts +95 -0
  428. package/src/lib/upstream-retry.ts +156 -3
  429. package/src/lib/windows-atomic-replace.ts +155 -0
  430. package/src/lib/windows-elevation.ts +70 -2
  431. package/src/lib/windows-secret-acl.ts +409 -69
  432. package/src/lib/windows-service-wrappers.ts +72 -0
  433. package/src/lib/windows-text.ts +106 -0
  434. package/src/lib/windows-user-principal.ts +341 -0
  435. package/src/lib/winsw.ts +33 -5
  436. package/src/oauth/account-import/google-antigravity-adapter.ts +74 -0
  437. package/src/oauth/account-import/index.ts +15 -0
  438. package/src/oauth/account-import/parser.ts +83 -0
  439. package/src/oauth/account-import/registry.ts +18 -0
  440. package/src/oauth/account-import/service.ts +75 -0
  441. package/src/oauth/account-import/types.ts +91 -0
  442. package/src/oauth/anthropic.ts +12 -1
  443. package/src/oauth/callback-server.ts +8 -2
  444. package/src/oauth/chatgpt.ts +12 -1
  445. package/src/oauth/command-code.ts +239 -0
  446. package/src/oauth/cursor.ts +46 -5
  447. package/src/oauth/google-antigravity.ts +35 -3
  448. package/src/oauth/health.ts +20 -12
  449. package/src/oauth/index.ts +398 -66
  450. package/src/oauth/key-providers.ts +16 -0
  451. package/src/oauth/kimi.ts +16 -2
  452. package/src/oauth/kiro.ts +50 -6
  453. package/src/oauth/local-token-detect.ts +11 -2
  454. package/src/oauth/log.ts +3 -1
  455. package/src/oauth/login-cli.ts +88 -28
  456. package/src/oauth/nous.ts +798 -0
  457. package/src/oauth/store.ts +119 -21
  458. package/src/oauth/token-guardian.ts +9 -3
  459. package/src/pi/models.ts +2 -2
  460. package/src/providers/alibaba-region-migration.ts +1 -1
  461. package/src/providers/antigravity-models.ts +521 -31
  462. package/src/providers/base-url-choices.ts +10 -0
  463. package/src/providers/codex-capacity.ts +292 -0
  464. package/src/providers/command-code-efforts.ts +144 -0
  465. package/src/providers/context-cap.ts +22 -5
  466. package/src/providers/cursor-pool.ts +72 -0
  467. package/src/providers/derive.ts +253 -6
  468. package/src/providers/fastwire.ts +501 -0
  469. package/src/providers/free-directory.ts +10 -7
  470. package/src/providers/google-vertex-location.ts +14 -0
  471. package/src/providers/key-failover.ts +71 -3
  472. package/src/providers/label.ts +1 -1
  473. package/src/providers/model-discovery-limits.ts +16 -0
  474. package/src/providers/model-discovery.ts +115 -22
  475. package/src/providers/model-rename-migration.ts +255 -0
  476. package/src/providers/model-rename-startup.ts +28 -0
  477. package/src/providers/openai-sidecar.ts +72 -4
  478. package/src/providers/openai-tier-startup.ts +31 -2
  479. package/src/providers/openai-tiers.ts +119 -4
  480. package/src/providers/openai-virtual-models.ts +1 -0
  481. package/src/providers/opencode-zen-rate-limit.ts +102 -0
  482. package/src/providers/provider-id-rewrite.ts +29 -0
  483. package/src/providers/quota.ts +1319 -38
  484. package/src/providers/registry.ts +1429 -111
  485. package/src/providers/request-pacing.ts +310 -0
  486. package/src/providers/service-tier.ts +277 -0
  487. package/src/providers/slug-codec.ts +42 -6
  488. package/src/providers/static-model-discovery.ts +86 -0
  489. package/src/providers/xai-responses-opt-in.ts +15 -0
  490. package/src/providers/xai-transport.ts +11 -4
  491. package/src/reasoning-effort.ts +49 -1
  492. package/src/responses/compaction.ts +26 -1
  493. package/src/responses/custom-tool-compat.ts +266 -0
  494. package/src/responses/hosted-tool-policy.ts +9 -0
  495. package/src/responses/namespace-tool-compat.ts +355 -0
  496. package/src/responses/parser.ts +220 -38
  497. package/src/responses/provider-continuation.ts +98 -0
  498. package/src/responses/provider-opaque-metadata.ts +73 -0
  499. package/src/responses/reasoning-envelope.ts +9 -1
  500. package/src/responses/reasoning-replay-cache.ts +426 -0
  501. package/src/responses/schema.ts +7 -1
  502. package/src/responses/spill-store.ts +75 -10
  503. package/src/responses/state.ts +565 -27
  504. package/src/responses/thought-signature-replay.ts +347 -0
  505. package/src/responses/tool-search-compat.ts +301 -0
  506. package/src/responses/truncated-stop-reason.ts +60 -0
  507. package/src/router.ts +366 -30
  508. package/src/routing/analytics.ts +378 -0
  509. package/src/routing/capability.ts +244 -0
  510. package/src/routing/compatibility/assemble.ts +73 -0
  511. package/src/routing/compatibility/behavior.ts +278 -0
  512. package/src/routing/compatibility/catalog.ts +99 -0
  513. package/src/routing/compatibility/endpoint.ts +52 -0
  514. package/src/routing/compatibility/lab-evidence-provider.ts +130 -0
  515. package/src/routing/compatibility/policy.ts +181 -0
  516. package/src/routing/compatibility/provider-slot.ts +56 -0
  517. package/src/routing/compatibility/reader.ts +110 -0
  518. package/src/routing/compatibility/subject.ts +191 -0
  519. package/src/routing/compatibility/types.ts +64 -0
  520. package/src/routing/compatibility/version.ts +104 -0
  521. package/src/routing/cost.ts +77 -0
  522. package/src/routing/evaluator.ts +495 -0
  523. package/src/routing/health.ts +412 -0
  524. package/src/routing/history/cursor.ts +43 -0
  525. package/src/routing/history/indexer.ts +605 -0
  526. package/src/routing/history/schema.ts +72 -0
  527. package/src/routing/profile-namespace.ts +15 -0
  528. package/src/routing/profile.ts +547 -0
  529. package/src/routing/quota.ts +145 -0
  530. package/src/routing/request-evidence.ts +45 -0
  531. package/src/routing/trace.ts +776 -0
  532. package/src/server/adapter-resolve.ts +2 -29
  533. package/src/server/auth-cors.ts +267 -46
  534. package/src/server/background-lifecycle.ts +182 -0
  535. package/src/server/chat-completions.ts +130 -56
  536. package/src/server/chat-native-sse.ts +331 -0
  537. package/src/server/chat-native.ts +426 -0
  538. package/src/server/claude-messages.ts +159 -43
  539. package/src/server/direct-local-http.ts +347 -0
  540. package/src/server/effort-policy.ts +18 -0
  541. package/src/server/github-copilot-responses-repair.ts +338 -0
  542. package/src/server/gui-static.ts +39 -10
  543. package/src/server/images.ts +94 -12
  544. package/src/server/index.ts +865 -181
  545. package/src/server/lifecycle.ts +284 -13
  546. package/src/server/live.ts +136 -17
  547. package/src/server/local-management-read-client.ts +90 -0
  548. package/src/server/local-provider-reload-client.ts +137 -0
  549. package/src/server/management/agent-settings-routes.ts +398 -103
  550. package/src/server/management/api-key-usage.ts +31 -5
  551. package/src/server/management/body.ts +6 -0
  552. package/src/server/management/combo-routes.ts +62 -24
  553. package/src/server/management/config-routes.ts +464 -51
  554. package/src/server/management/context.ts +80 -2
  555. package/src/server/management/integration-routes.ts +498 -0
  556. package/src/server/management/lab-automation-routes.ts +206 -0
  557. package/src/server/management/lab-routes.ts +563 -0
  558. package/src/server/management/logs-usage-routes.ts +101 -32
  559. package/src/server/management/model-routes.ts +189 -131
  560. package/src/server/management/model-rows.ts +163 -0
  561. package/src/server/management/native-integration-routes.ts +769 -0
  562. package/src/server/management/oauth-account-routes.ts +80 -4
  563. package/src/server/management/provider-capability-config.ts +48 -0
  564. package/src/server/management/provider-routes.ts +764 -157
  565. package/src/server/management/request-history-routes.ts +191 -0
  566. package/src/server/management/routing-analytics-routes.ts +74 -0
  567. package/src/server/management/routing-profile-routes.ts +380 -0
  568. package/src/server/management/shared.ts +27 -11
  569. package/src/server/management/sidebar-routes.ts +47 -31
  570. package/src/server/management/storage-log-guard-routes.ts +186 -0
  571. package/src/server/management/sync-response.ts +69 -0
  572. package/src/server/management/system-restart.ts +288 -32
  573. package/src/server/management/system-routes.ts +77 -0
  574. package/src/server/management/usage-summary-cache.ts +9 -1
  575. package/src/server/management/vision-sidecar-options.ts +167 -0
  576. package/src/server/management/web-search-sidecar-options.ts +120 -0
  577. package/src/server/management-api.ts +115 -14
  578. package/src/server/management-auth.ts +220 -5
  579. package/src/server/passive-route-linker.ts +66 -0
  580. package/src/server/ports.ts +41 -1
  581. package/src/server/proxy-liveness.ts +132 -5
  582. package/src/server/readiness.ts +99 -0
  583. package/src/server/relay-eager.ts +82 -42
  584. package/src/server/relay.ts +236 -76
  585. package/src/server/request-decompress.ts +113 -6
  586. package/src/server/request-log.ts +235 -22
  587. package/src/server/responses/agent-task-recovery-cache.ts +143 -0
  588. package/src/server/responses/agent-task-recovery.ts +465 -0
  589. package/src/server/responses/collaboration.ts +204 -35
  590. package/src/server/responses/compact.ts +442 -55
  591. package/src/server/responses/core.ts +2872 -331
  592. package/src/server/responses/empty-completion-guard.ts +276 -0
  593. package/src/server/responses/encrypted-payload.ts +62 -39
  594. package/src/server/responses/fetch-helpers.ts +79 -4
  595. package/src/server/responses/input-admission.ts +185 -0
  596. package/src/server/responses/pacing-overload.ts +13 -0
  597. package/src/server/responses/policy-fallback.ts +178 -0
  598. package/src/server/responses/responses-field-backfill.ts +251 -0
  599. package/src/server/responses/terminal-guard.ts +26 -5
  600. package/src/server/responses/upstream-error.ts +5 -0
  601. package/src/server/responses/ws-upstream.ts +308 -0
  602. package/src/server/responses-custom-tool-repair.ts +282 -0
  603. package/src/server/responses-item-id-repair.ts +54 -6
  604. package/src/server/responses-json-events.ts +90 -0
  605. package/src/server/responses-model-rewrite.ts +29 -0
  606. package/src/server/responses-reasoning-summary-rewrite.ts +178 -0
  607. package/src/server/responses-snapshot-repair.ts +621 -0
  608. package/src/server/responses-terminal-repair.ts +342 -0
  609. package/src/server/responses-tool-search-repair.ts +267 -0
  610. package/src/server/responses-undeclared-tool-guard.ts +153 -0
  611. package/src/server/responses.ts +18 -2
  612. package/src/server/search.ts +78 -13
  613. package/src/server/sse-frame-buffer.ts +292 -0
  614. package/src/server/sse-payload-rewrite.ts +110 -22
  615. package/src/server/startup-action-control.ts +8 -1
  616. package/src/server/startup-health-cache.ts +19 -1
  617. package/src/server/system-env.ts +80 -9
  618. package/src/server/ws-bridge.ts +39 -38
  619. package/src/service-manager-probe.ts +892 -0
  620. package/src/service.ts +1111 -90
  621. package/src/sidecar/auth.ts +92 -0
  622. package/src/sidecar/candidates.ts +83 -0
  623. package/src/storage/cleanup.ts +2 -2
  624. package/src/storage/scanner.ts +1 -1
  625. package/src/storage/worker-lifecycle.ts +14 -14
  626. package/src/tray/windows-tray.ps1 +83 -9
  627. package/src/tray/windows.ts +43 -16
  628. package/src/types/accounts.ts +37 -0
  629. package/src/types/config.ts +845 -0
  630. package/src/types/provider.ts +545 -0
  631. package/src/types/request.ts +384 -0
  632. package/src/types/tools.ts +131 -0
  633. package/src/types/wire.ts +80 -0
  634. package/src/types.ts +104 -1236
  635. package/src/update/index.ts +32 -19
  636. package/src/update/job.ts +442 -67
  637. package/src/update/notify.ts +12 -6
  638. package/src/update/npm-cache-preflight.d.mts +47 -0
  639. package/src/update/npm-cache-preflight.mjs +201 -0
  640. package/src/update/transactional-install.d.mts +22 -0
  641. package/src/update/transactional-install.mjs +259 -0
  642. package/src/usage/cost.ts +0 -0
  643. package/src/usage/expected-prices.ts +268 -16
  644. package/src/usage/log.ts +606 -41
  645. package/src/usage/summary.ts +177 -9
  646. package/src/usage/user-cost-overlay-reconciler.ts +313 -0
  647. package/src/usage/user-cost-overlays.ts +314 -0
  648. package/src/vision/anthropic-describe.ts +10 -6
  649. package/src/vision/backends.ts +97 -0
  650. package/src/vision/describe.ts +9 -3
  651. package/src/vision/eligibility.ts +250 -0
  652. package/src/vision/index.ts +238 -24
  653. package/src/vision/reasoning.ts +55 -0
  654. package/src/vision/routed-describe.ts +175 -0
  655. package/src/vision/timeout-bounds.ts +9 -0
  656. package/src/web-search/anthropic-executor.ts +13 -7
  657. package/src/web-search/backends.ts +108 -0
  658. package/src/web-search/exa-executor.ts +88 -0
  659. package/src/web-search/executor.ts +11 -3
  660. package/src/web-search/gemini-executor.ts +141 -0
  661. package/src/web-search/index.ts +150 -15
  662. package/src/web-search/loop.ts +279 -50
  663. package/src/web-search/parse.ts +125 -30
  664. package/src/web-search/sources.ts +60 -0
  665. package/src/web-search/xai-executor.ts +219 -0
  666. package/gui/dist/assets/index-DTpMHS4F.js +0 -67
  667. package/gui/dist/assets/index-ZNVDE3C7.css +0 -1
  668. package/gui/dist/provider-icons/antigravity.svg +0 -1
  669. package/gui/dist/provider-icons/claude.svg +0 -1
  670. package/gui/dist/provider-icons/copilot.svg +0 -1
  671. package/gui/dist/provider-icons/cursor.svg +0 -2
  672. package/gui/dist/provider-icons/gemini.svg +0 -1
  673. package/gui/dist/provider-icons/grok-color.svg +0 -1
  674. package/gui/dist/provider-icons/kiro.svg +0 -14
  675. package/src/cli/internal-dispatch.ts +0 -20
@@ -0,0 +1,353 @@
1
+ import { replayLabLedger } from "../ledger/store";
2
+ import { labLedgerPath } from "../paths";
3
+ import { queryLabEvents, queryLabVerdicts } from "../query";
4
+ import type { ObservationEvent } from "../events/types";
5
+ import {
6
+ importCommunityEvidenceBundle,
7
+ listCommunityEvidence,
8
+ } from "./community";
9
+ import { readPrivateRegularFile } from "./file-safety";
10
+ import { withPublicEvidenceMutationLock } from "./mutation-lock";
11
+ import { recordLocalPublicOrigin } from "./origin";
12
+ import type { ProjectPublicEvidenceRecordInput } from "./project";
13
+ import { projectPublicEvidenceRecord } from "./project";
14
+ import {
15
+ signPublicEvidenceBundle,
16
+ verifyPublicEvidenceBundle,
17
+ } from "./signature";
18
+ import { storePublicEvidenceBundle } from "./storage";
19
+ import { parseStrictPublicJson } from "./strict-json";
20
+ import { publicUtcDay } from "./time";
21
+ import { PUBLIC_EVIDENCE_BUNDLE_SCHEMA_VERSION, PUBLIC_EXPORT_POLICY_VERSION } from "./types";
22
+ import type {
23
+ PublicEvidenceBundleV1,
24
+ PublicEvidencePreviewBundleV1,
25
+ PublicEvidenceRecordV1,
26
+ PublicProjectionNotExportableReason,
27
+ } from "./types";
28
+ import { PublicEvidenceValidationError } from "./validate";
29
+
30
+ const MAX_OPERATOR_EVENTS = 256;
31
+ const MAX_PUBLIC_FILE_BYTES = 2 * 1024 * 1024;
32
+ const EMPTY_PREVIEW_DAY = "1970-01-01";
33
+ const PRIVATE_STORAGE_LOCATOR = "<private>";
34
+
35
+ export interface ProjectPublicEvidenceInput {
36
+ records: ProjectPublicEvidenceRecordInput[];
37
+ }
38
+
39
+ export function projectPublicEvidence(input: ProjectPublicEvidenceInput): {
40
+ bundle: PublicEvidencePreviewBundleV1;
41
+ excluded: Array<{ index: number; reason: PublicProjectionNotExportableReason }>;
42
+ } {
43
+ const records: PublicEvidenceRecordV1[] = [];
44
+ const excluded: Array<{ index: number; reason: PublicProjectionNotExportableReason }> = [];
45
+ let latestExportableCompletedAt: number | null = null;
46
+
47
+ input.records.forEach((recordInput, index) => {
48
+ const projected = projectPublicEvidenceRecord(recordInput);
49
+ if (projected.status !== "exportable") {
50
+ excluded.push({ index, reason: projected.reason });
51
+ return;
52
+ }
53
+ records.push(projected.record);
54
+ latestExportableCompletedAt = Math.max(
55
+ latestExportableCompletedAt ?? recordInput.observation.completedAt,
56
+ recordInput.observation.completedAt,
57
+ );
58
+ });
59
+ records.sort((a, b) => a.recordId < b.recordId ? -1 : a.recordId > b.recordId ? 1 : 0);
60
+ return {
61
+ bundle: {
62
+ schemaVersion: PUBLIC_EVIDENCE_BUNDLE_SCHEMA_VERSION,
63
+ exportPolicyVersion: PUBLIC_EXPORT_POLICY_VERSION,
64
+ createdDayUtc: latestExportableCompletedAt === null
65
+ ? EMPTY_PREVIEW_DAY
66
+ : publicUtcDay(latestExportableCompletedAt),
67
+ records,
68
+ artifacts: [],
69
+ },
70
+ excluded,
71
+ };
72
+ }
73
+
74
+ export type PublicOperatorExclusionReason =
75
+ | PublicProjectionNotExportableReason
76
+ | "event_not_found"
77
+ | "not_observation"
78
+ | "event_excluded"
79
+ | "no_canonical_verdict";
80
+
81
+ export interface PublicOperatorExclusionV1 {
82
+ selectionIndex: number;
83
+ reason: PublicOperatorExclusionReason;
84
+ }
85
+
86
+ export interface LocalPublicPreviewV1 {
87
+ bundle: PublicEvidencePreviewBundleV1;
88
+ excluded: PublicOperatorExclusionV1[];
89
+ }
90
+
91
+ export interface LocalPublicExportV1 {
92
+ bundle: PublicEvidenceBundleV1;
93
+ stored: { path: typeof PRIVATE_STORAGE_LOCATOR; created: boolean };
94
+ excluded: PublicOperatorExclusionV1[];
95
+ }
96
+
97
+ export type PublicVerificationSummaryV1 =
98
+ | { status: "cryptographically_valid"; bundleId: string; publisherKeyId: string; locallyVerified: false }
99
+ | { status: "schema_rejected" | "digest_invalid" | "signature_invalid"; locallyVerified: false };
100
+
101
+ function assertOperatorEventIds(eventIds: readonly string[]): Array<{ eventId: string; selectionIndex: number }> {
102
+ if (eventIds.length === 0 || eventIds.length > MAX_OPERATOR_EVENTS) {
103
+ throw new PublicEvidenceValidationError(
104
+ "public_selection_limit",
105
+ `public evidence selection must contain 1..${MAX_OPERATOR_EVENTS} event ids`,
106
+ );
107
+ }
108
+ const unique: Array<{ eventId: string; selectionIndex: number }> = [];
109
+ const seen = new Set<string>();
110
+ for (const [selectionIndex, eventId] of eventIds.entries()) {
111
+ if (!/^[0-9a-f]{64}$/.test(eventId)) {
112
+ throw new PublicEvidenceValidationError(
113
+ "public_selection_event_id",
114
+ "public evidence event ids must be lowercase sha256 hex",
115
+ );
116
+ }
117
+ if (seen.has(eventId)) continue;
118
+ seen.add(eventId);
119
+ unique.push({ eventId, selectionIndex });
120
+ }
121
+ return unique;
122
+ }
123
+
124
+ function projectedObservationState(
125
+ eventIds: readonly string[],
126
+ configDir?: string,
127
+ ): Map<string, { excluded: boolean }> {
128
+ const pending = new Set(eventIds);
129
+ const state = new Map<string, { excluded: boolean }>();
130
+ let cursor: string | undefined;
131
+
132
+ while (pending.size > 0) {
133
+ const page = queryLabEvents({ eventKind: "observation" }, cursor, 200, configDir);
134
+ for (const row of page.items) {
135
+ if (!pending.has(row.eventId)) continue;
136
+ state.set(row.eventId, { excluded: row.excluded });
137
+ pending.delete(row.eventId);
138
+ }
139
+ if (!page.hasMore || !page.nextCursor) break;
140
+ cursor = page.nextCursor;
141
+ }
142
+
143
+ return state;
144
+ }
145
+
146
+ function canonicalVerdictsForObservations(
147
+ observations: readonly ObservationEvent[],
148
+ configDir?: string,
149
+ ): Map<string, ProjectPublicEvidenceRecordInput["verdict"]> {
150
+ const verdictByEventId = new Map<string, ProjectPublicEvidenceRecordInput["verdict"]>();
151
+ const groups = new Map<string, {
152
+ subjectId: string;
153
+ evidenceLayer: ObservationEvent["evidenceLayer"];
154
+ suiteId: string;
155
+ observations: ObservationEvent[];
156
+ }>();
157
+
158
+ for (const observation of observations) {
159
+ const key = `${observation.subjectId}\0${observation.evidenceLayer}\0${observation.suiteId}`;
160
+ const existing = groups.get(key);
161
+ if (existing) existing.observations.push(observation);
162
+ else groups.set(key, {
163
+ subjectId: observation.subjectId,
164
+ evidenceLayer: observation.evidenceLayer,
165
+ suiteId: observation.suiteId,
166
+ observations: [observation],
167
+ });
168
+ }
169
+
170
+ for (const group of groups.values()) {
171
+ const pending = new Map(group.observations.map((observation) => [observation.eventId, observation] as const));
172
+ let cursor: string | undefined;
173
+ while (pending.size > 0) {
174
+ const page = queryLabVerdicts({
175
+ subjectId: group.subjectId,
176
+ layer: group.evidenceLayer,
177
+ suiteId: group.suiteId,
178
+ }, cursor, 200, configDir);
179
+ for (const row of page.items) {
180
+ for (const eventId of row.contributingEventIds) {
181
+ const observation = pending.get(eventId);
182
+ if (!observation) continue;
183
+ if (
184
+ row.subjectId !== observation.subjectId
185
+ || row.evidenceLayer !== observation.evidenceLayer
186
+ || row.suiteId !== observation.suiteId
187
+ || row.suiteVersion !== observation.suiteVersion
188
+ ) {
189
+ continue;
190
+ }
191
+ verdictByEventId.set(eventId, row.verdict);
192
+ pending.delete(eventId);
193
+ }
194
+ }
195
+ if (!page.hasMore || !page.nextCursor) break;
196
+ cursor = page.nextCursor;
197
+ }
198
+ }
199
+
200
+ return verdictByEventId;
201
+ }
202
+
203
+ export function previewLocalPublicEvidence(
204
+ input: { eventIds: readonly string[] },
205
+ configDir?: string,
206
+ ): LocalPublicPreviewV1 {
207
+ const selections = assertOperatorEventIds(input.eventIds);
208
+ const replay = replayLabLedger(labLedgerPath(configDir));
209
+ const byId = new Map(replay.events.map((event) => [event.eventId, event] as const));
210
+ const observationSelections: Array<{ observation: ObservationEvent; selectionIndex: number }> = [];
211
+ const excluded: PublicOperatorExclusionV1[] = [];
212
+
213
+ for (const { eventId, selectionIndex } of selections) {
214
+ const event = byId.get(eventId);
215
+ if (!event) {
216
+ excluded.push({ selectionIndex, reason: "event_not_found" });
217
+ continue;
218
+ }
219
+ if (event.eventKind !== "observation") {
220
+ excluded.push({ selectionIndex, reason: "not_observation" });
221
+ continue;
222
+ }
223
+ observationSelections.push({ observation: event, selectionIndex });
224
+ }
225
+
226
+ if (observationSelections.length === 0) {
227
+ throw new PublicEvidenceValidationError("public_selection_empty", "public evidence selection contains no observation events");
228
+ }
229
+
230
+ const projectionByEventId = projectedObservationState(
231
+ observationSelections.map(({ observation }) => observation.eventId),
232
+ configDir,
233
+ );
234
+ const candidates: Array<{ observation: ObservationEvent; selectionIndex: number }> = [];
235
+ for (const candidate of observationSelections) {
236
+ const projectedEvent = projectionByEventId.get(candidate.observation.eventId);
237
+ if (!projectedEvent) {
238
+ excluded.push({ selectionIndex: candidate.selectionIndex, reason: "event_not_found" });
239
+ continue;
240
+ }
241
+ if (projectedEvent.excluded) {
242
+ excluded.push({ selectionIndex: candidate.selectionIndex, reason: "event_excluded" });
243
+ continue;
244
+ }
245
+ candidates.push(candidate);
246
+ }
247
+
248
+ const verdictByEventId = canonicalVerdictsForObservations(
249
+ candidates.map((candidate) => candidate.observation),
250
+ configDir,
251
+ );
252
+ const projectInputs: ProjectPublicEvidenceRecordInput[] = [];
253
+ const projectSelectionIndices: number[] = [];
254
+ for (const { observation, selectionIndex } of candidates) {
255
+ const verdict = verdictByEventId.get(observation.eventId);
256
+ if (!verdict) {
257
+ excluded.push({ selectionIndex, reason: "no_canonical_verdict" });
258
+ continue;
259
+ }
260
+ projectInputs.push({ observation, verdict });
261
+ projectSelectionIndices.push(selectionIndex);
262
+ }
263
+
264
+ const projected = projectPublicEvidence({ records: projectInputs });
265
+ for (const row of projected.excluded) {
266
+ excluded.push({ selectionIndex: projectSelectionIndices[row.index]!, reason: row.reason });
267
+ }
268
+ excluded.sort((a, b) => a.selectionIndex - b.selectionIndex);
269
+ return { bundle: projected.bundle, excluded };
270
+ }
271
+
272
+ export function exportLocalPublicEvidence(
273
+ input: { eventIds: readonly string[] },
274
+ configDir?: string,
275
+ ): LocalPublicExportV1 {
276
+ const preview = previewLocalPublicEvidence(input, configDir);
277
+ if (preview.bundle.records.length === 0) {
278
+ throw new PublicEvidenceValidationError("public_export_empty", "selected events produced no exportable public evidence records");
279
+ }
280
+ const bundle = signPublicEvidenceBundle({
281
+ records: preview.bundle.records,
282
+ artifacts: preview.bundle.artifacts,
283
+ createdDayUtc: preview.bundle.createdDayUtc,
284
+ configDir,
285
+ });
286
+ return withPublicEvidenceMutationLock(configDir, () => {
287
+ // Commit purge-owned provenance first. If export publication later fails or the
288
+ // process crashes, an orphan marker is conservative and can be reclaimed later;
289
+ // the inverse state, a durable export without provenance, is not acceptable.
290
+ recordLocalPublicOrigin({ publisherKeyId: bundle.publisher.keyId, bundleId: bundle.bundleId }, configDir);
291
+ const stored = storePublicEvidenceBundle(bundle, configDir);
292
+ return {
293
+ bundle,
294
+ stored: { path: PRIVATE_STORAGE_LOCATOR, created: stored.created },
295
+ excluded: preview.excluded,
296
+ };
297
+ });
298
+ }
299
+
300
+ export function summarizePublicEvidenceVerification(raw: unknown): PublicVerificationSummaryV1 {
301
+ const result = verifyPublicEvidenceBundle(raw as PublicEvidenceBundleV1);
302
+ if (result.status !== "cryptographically_valid") {
303
+ return { status: result.status, locallyVerified: false };
304
+ }
305
+ const bundle = raw as PublicEvidenceBundleV1;
306
+ return {
307
+ status: "cryptographically_valid",
308
+ bundleId: bundle.bundleId,
309
+ publisherKeyId: bundle.publisher.keyId,
310
+ locallyVerified: false,
311
+ };
312
+ }
313
+
314
+ function readBoundedPublicFile(path: string): Buffer {
315
+ return readPrivateRegularFile(path, {
316
+ maxBytes: MAX_PUBLIC_FILE_BYTES,
317
+ errorCode: "public_file_unsafe",
318
+ errorMessage: "public evidence input must be a regular non-symlink file",
319
+ sizeErrorCode: "public_file_too_large",
320
+ sizeErrorMessage: "public evidence input exceeds 2 MiB",
321
+ });
322
+ }
323
+
324
+ function parsePublicFile(path: string): unknown {
325
+ return parseStrictPublicJson(readBoundedPublicFile(path), "public evidence input", "public_file_json");
326
+ }
327
+
328
+ export function verifyPublicEvidenceFile(path: string): PublicVerificationSummaryV1 {
329
+ return summarizePublicEvidenceVerification(parsePublicFile(path));
330
+ }
331
+
332
+ function finishCommunityImport(
333
+ stored: { path: string; created: boolean; bundleId: string; publisherKeyId: string },
334
+ ) {
335
+ const { path: _privatePath, ...imported } = stored;
336
+ return { ...imported, trustClass: "community_untrusted_v1" as const, locallyVerified: false as const };
337
+ }
338
+
339
+ export function importCommunityEvidenceFile(path: string, configDir?: string) {
340
+ return finishCommunityImport(importCommunityEvidenceBundle(readBoundedPublicFile(path), configDir));
341
+ }
342
+
343
+ export function importCommunityEvidenceValue(raw: unknown, configDir?: string) {
344
+ return finishCommunityImport(importCommunityEvidenceBundle(raw, configDir));
345
+ }
346
+
347
+ export function listCommunityEvidenceContext(configDir?: string) {
348
+ return {
349
+ evidence: listCommunityEvidence(configDir),
350
+ trustClass: "community_untrusted_v1" as const,
351
+ locallyVerified: false as const,
352
+ };
353
+ }
@@ -0,0 +1,79 @@
1
+ import { readdirSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { ensureLabDirs, labPublicOriginDir } from "../paths";
4
+ import { readPrivateRegularFile } from "./file-safety";
5
+ import { cleanupStalePrivateFileStagesInDir, isPrivateFileStageName } from "./private-file";
6
+ import { parseStrictPublicJson } from "./strict-json";
7
+
8
+ const MAX_ORIGIN_BYTES = 1024;
9
+ const ORIGIN_RE = /^origin-([0-9a-f]{64})-([0-9a-f]{64})\.json$/;
10
+
11
+ export interface PurgeOriginIdentity {
12
+ publisherKeyId: string;
13
+ bundleId: string;
14
+ }
15
+
16
+ export interface PurgeOriginRecovery {
17
+ identities: PurgeOriginIdentity[];
18
+ skipped: number;
19
+ }
20
+
21
+ /**
22
+ * Purge must salvage each provenance marker independently. A corrupt marker is untrusted
23
+ * and skipped, but it cannot hide later valid markers that are needed to classify local
24
+ * community copies after the export or publisher key is unavailable. The operational
25
+ * 1024-marker quota is deliberately not a read cutoff here: recovery must inspect every
26
+ * valid-format marker present after a race/crash instead of silently losing provenance.
27
+ */
28
+ export function recoverPublicOriginsForPurge(configDir?: string): PurgeOriginRecovery {
29
+ ensureLabDirs(configDir);
30
+ const dir = labPublicOriginDir(configDir);
31
+ cleanupStalePrivateFileStagesInDir(dir);
32
+ const names = readdirSync(dir)
33
+ .filter((name) => !isPrivateFileStageName(name) && ORIGIN_RE.test(name))
34
+ .sort();
35
+ const identities: PurgeOriginIdentity[] = [];
36
+ let skipped = 0;
37
+
38
+ for (const name of names) {
39
+ const match = ORIGIN_RE.exec(name)!;
40
+ const expected = { publisherKeyId: match[1]!, bundleId: match[2]! };
41
+ try {
42
+ const raw = parseStrictPublicJson(
43
+ readPrivateRegularFile(join(dir, name), {
44
+ maxBytes: MAX_ORIGIN_BYTES,
45
+ errorCode: "public_origin_unsafe",
46
+ errorMessage: "public origin marker is unsafe during purge",
47
+ sizeErrorCode: "public_origin_unsafe",
48
+ sizeErrorMessage: "public origin marker exceeds its size bound",
49
+ requireMode600: true,
50
+ }),
51
+ "public origin marker during purge",
52
+ "public_origin_json",
53
+ );
54
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
55
+ skipped += 1;
56
+ continue;
57
+ }
58
+ const row = raw as Record<string, unknown>;
59
+ if (
60
+ Object.keys(row).sort().join(",") !== "bundleId,publisherKeyId,schemaVersion"
61
+ || row.schemaVersion !== "public_origin_v1"
62
+ || row.publisherKeyId !== expected.publisherKeyId
63
+ || row.bundleId !== expected.bundleId
64
+ ) {
65
+ skipped += 1;
66
+ continue;
67
+ }
68
+ identities.push(expected);
69
+ } catch {
70
+ skipped += 1;
71
+ // Salvage continues with the next marker.
72
+ }
73
+ }
74
+ return { identities, skipped };
75
+ }
76
+
77
+ export function listValidPublicOriginsForPurge(configDir?: string): PurgeOriginIdentity[] {
78
+ return recoverPublicOriginsForPurge(configDir).identities;
79
+ }
@@ -0,0 +1,203 @@
1
+ import { lstatSync, readdirSync, unlinkSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { jcsStringify } from "../digest";
4
+ import { ensureLabDirs, labCommunityDir, labExportDir, labPublicOriginDir } from "../paths";
5
+ import { communityBundleFileName } from "./community-files";
6
+ import { readPrivateRegularFile } from "./file-safety";
7
+ import {
8
+ cleanupStalePrivateFileStagesInDir,
9
+ isPrivateFileStageName,
10
+ publishPrivateFileExclusive,
11
+ } from "./private-file";
12
+ import { parseStrictPublicJson } from "./strict-json";
13
+ import { PublicEvidenceValidationError } from "./validate";
14
+
15
+ // The community cache itself is capped at 512 files. Keeping twice that many origin
16
+ // markers leaves headroom for in-flight/local exports while allowing unreferenced
17
+ // provenance to be reclaimed instead of permanently locking future exports.
18
+ const MAX_ORIGINS = 1024;
19
+ const MAX_ORIGIN_BYTES = 1024;
20
+ const ORIGIN_RE = /^origin-([0-9a-f]{64})-([0-9a-f]{64})\.json$/;
21
+
22
+ export interface PublicOriginIdentityV1 {
23
+ publisherKeyId: string;
24
+ bundleId: string;
25
+ }
26
+
27
+ function originPath(identity: PublicOriginIdentityV1, configDir?: string): string {
28
+ if (!/^[0-9a-f]{64}$/.test(identity.publisherKeyId) || !/^[0-9a-f]{64}$/.test(identity.bundleId)) {
29
+ throw new PublicEvidenceValidationError("public_origin_id", "public origin identity is invalid");
30
+ }
31
+ return join(
32
+ labPublicOriginDir(configDir),
33
+ `origin-${identity.publisherKeyId}-${identity.bundleId}.json`,
34
+ );
35
+ }
36
+
37
+ function originBody(identity: PublicOriginIdentityV1): Buffer {
38
+ return Buffer.from(jcsStringify({
39
+ schemaVersion: "public_origin_v1",
40
+ publisherKeyId: identity.publisherKeyId,
41
+ bundleId: identity.bundleId,
42
+ }), "utf8");
43
+ }
44
+
45
+ function readOrigin(path: string, expected?: PublicOriginIdentityV1): PublicOriginIdentityV1 {
46
+ const bytes = readPrivateRegularFile(path, {
47
+ maxBytes: MAX_ORIGIN_BYTES,
48
+ errorCode: "public_origin_unsafe",
49
+ errorMessage: "public origin marker is not a private regular file with 0600 permissions",
50
+ sizeErrorCode: "public_origin_unsafe",
51
+ sizeErrorMessage: "public origin marker exceeds its size bound",
52
+ requireMode600: true,
53
+ });
54
+ const raw = parseStrictPublicJson(bytes, "public origin marker", "public_origin_json");
55
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
56
+ throw new PublicEvidenceValidationError("public_origin_json", "public origin marker must be an object");
57
+ }
58
+ const row = raw as Record<string, unknown>;
59
+ if (Object.keys(row).sort().join(",") !== "bundleId,publisherKeyId,schemaVersion"
60
+ || row.schemaVersion !== "public_origin_v1"
61
+ || typeof row.publisherKeyId !== "string"
62
+ || typeof row.bundleId !== "string"
63
+ || !/^[0-9a-f]{64}$/.test(row.publisherKeyId)
64
+ || !/^[0-9a-f]{64}$/.test(row.bundleId)) {
65
+ throw new PublicEvidenceValidationError("public_origin_json", "public origin marker schema is invalid");
66
+ }
67
+ const identity = { publisherKeyId: row.publisherKeyId, bundleId: row.bundleId };
68
+ if (expected && (identity.publisherKeyId !== expected.publisherKeyId || identity.bundleId !== expected.bundleId)) {
69
+ throw new PublicEvidenceValidationError("public_origin_conflict", "public origin marker identity mismatch");
70
+ }
71
+ return identity;
72
+ }
73
+
74
+ /** Marker names only. Quota accounting, reclaim, and listing must agree on this set. */
75
+ function originNames(dir: string): string[] {
76
+ cleanupStalePrivateFileStagesInDir(dir);
77
+ return readdirSync(dir)
78
+ .filter((name) => !isPrivateFileStageName(name) && ORIGIN_RE.test(name))
79
+ .sort();
80
+ }
81
+
82
+ function foreignOriginNames(dir: string): string[] {
83
+ return readdirSync(dir)
84
+ .filter((name) => !isPrivateFileStageName(name) && !ORIGIN_RE.test(name))
85
+ .sort();
86
+ }
87
+
88
+ function pathExistsConservatively(path: string): boolean {
89
+ try {
90
+ lstatSync(path);
91
+ return true;
92
+ } catch (error) {
93
+ if ((error as NodeJS.ErrnoException).code === "ENOENT") return false;
94
+ return true;
95
+ }
96
+ }
97
+
98
+ function communityBundlePath(identity: PublicOriginIdentityV1, configDir?: string): string {
99
+ return join(
100
+ labCommunityDir(configDir),
101
+ communityBundleFileName(identity.publisherKeyId, identity.bundleId),
102
+ );
103
+ }
104
+
105
+ function localExportPath(identity: PublicOriginIdentityV1, configDir?: string): string {
106
+ return join(labExportDir(configDir), `${identity.bundleId}.json`);
107
+ }
108
+
109
+ /**
110
+ * Origin markers exist to recover local provenance for community copies when the export
111
+ * or publisher key is later unavailable. A marker is reclaimable only when neither the
112
+ * exact community copy nor its matching local export still exists.
113
+ */
114
+ function reclaimUnreferencedOrigins(
115
+ dir: string,
116
+ preservePath: string,
117
+ configDir?: string,
118
+ ): void {
119
+ for (const name of originNames(dir)) {
120
+ const match = ORIGIN_RE.exec(name)!;
121
+ const path = join(dir, name);
122
+ if (path === preservePath) continue;
123
+ const identity = { publisherKeyId: match[1]!, bundleId: match[2]! };
124
+ if (pathExistsConservatively(communityBundlePath(identity, configDir))) continue;
125
+ if (pathExistsConservatively(localExportPath(identity, configDir))) continue;
126
+ try {
127
+ unlinkSync(path);
128
+ } catch (error) {
129
+ if ((error as NodeJS.ErrnoException).code !== "ENOENT") throw error;
130
+ }
131
+ }
132
+ }
133
+
134
+ export function recordLocalPublicOrigin(identity: PublicOriginIdentityV1, configDir?: string): void {
135
+ ensureLabDirs(configDir);
136
+ const dir = labPublicOriginDir(configDir);
137
+ const path = originPath(identity, configDir);
138
+ try {
139
+ readOrigin(path, identity);
140
+ return;
141
+ } catch (error) {
142
+ if (error instanceof PublicEvidenceValidationError) throw error;
143
+ if ((error as NodeJS.ErrnoException).code !== "ENOENT") throw error;
144
+ }
145
+
146
+ let names = originNames(dir);
147
+ if (names.length >= MAX_ORIGINS) {
148
+ reclaimUnreferencedOrigins(dir, path, configDir);
149
+ names = originNames(dir);
150
+ }
151
+ if (names.length >= MAX_ORIGINS) {
152
+ throw new PublicEvidenceValidationError("public_origin_bound", "public origin marker bound exceeded");
153
+ }
154
+
155
+ const bytes = originBody(identity);
156
+ const published = publishPrivateFileExclusive(path, bytes);
157
+ if (!published.created) {
158
+ readOrigin(path, identity);
159
+ return;
160
+ }
161
+
162
+ // Separate CLI processes can both observe one free slot before either publishes.
163
+ // Reclaim unreferenced history after publication, then remove only this call's marker
164
+ // if the directory still cannot converge inside the hard cap.
165
+ if (originNames(dir).length > MAX_ORIGINS) {
166
+ reclaimUnreferencedOrigins(dir, path, configDir);
167
+ if (originNames(dir).length > MAX_ORIGINS) {
168
+ try { unlinkSync(path); } catch { /* preserve the quota failure */ }
169
+ throw new PublicEvidenceValidationError("public_origin_bound", "public origin marker bound exceeded");
170
+ }
171
+ }
172
+ }
173
+
174
+ export function listLocalPublicOrigins(configDir?: string): PublicOriginIdentityV1[] {
175
+ ensureLabDirs(configDir);
176
+ const dir = labPublicOriginDir(configDir);
177
+ const names = originNames(dir);
178
+ if (names.length > MAX_ORIGINS) {
179
+ throw new PublicEvidenceValidationError("public_origin_bound", "public origin marker bound exceeded");
180
+ }
181
+ if (foreignOriginNames(dir).length > 0) {
182
+ throw new PublicEvidenceValidationError("public_origin_unsafe", "unexpected public origin marker entry");
183
+ }
184
+ const identities: PublicOriginIdentityV1[] = [];
185
+ for (const name of names) {
186
+ const match = ORIGIN_RE.exec(name)!;
187
+ const expected = { publisherKeyId: match[1]!, bundleId: match[2]! };
188
+ identities.push(readOrigin(join(dir, name), expected));
189
+ }
190
+ return identities;
191
+ }
192
+
193
+ export function clearLocalPublicOrigins(configDir?: string): void {
194
+ ensureLabDirs(configDir);
195
+ const dir = labPublicOriginDir(configDir);
196
+ cleanupStalePrivateFileStagesInDir(dir);
197
+ for (const name of readdirSync(dir)) {
198
+ if (!ORIGIN_RE.test(name)) continue;
199
+ try { unlinkSync(join(dir, name)); } catch (error) {
200
+ if ((error as NodeJS.ErrnoException).code !== "ENOENT") throw error;
201
+ }
202
+ }
203
+ }