@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,243 @@
1
+ import {
2
+ createPrivateKey,
3
+ createPublicKey,
4
+ generateKeyPairSync,
5
+ sign as signBytes,
6
+ verify as verifyBytes,
7
+ } from "node:crypto";
8
+ import { ensureLabDirs, labPublicPublisherKeyPath } from "../paths";
9
+ import { hardenSecretPath } from "../../lib/windows-secret-acl";
10
+ import {
11
+ buildPublicEvidenceBundle,
12
+ canonicalPublicEvidenceContent,
13
+ expectedPublicBundleIdentityFromNormalized,
14
+ normalizePublicEvidenceContent,
15
+ type BuildPublicEvidenceBundleInput,
16
+ } from "./bundle";
17
+ import { validatePublicEvidenceAuthorities } from "./community-authority";
18
+ import { privateRegularFileSize, readPrivateRegularFile } from "./file-safety";
19
+ import { publicEvidenceId } from "./ids";
20
+ import { cleanupStalePrivateFileStages, publishPrivateFileExclusive } from "./private-file";
21
+ import { validatePublicEvidencePrivacy, validatePublicEvidenceRecordPrivacy } from "./privacy";
22
+ import type {
23
+ PublicEvidenceBundleV1,
24
+ PublicPublisherV1,
25
+ } from "./types";
26
+ import { PublicEvidenceValidationError } from "./validate";
27
+
28
+ const MAX_PRIVATE_KEY_BYTES = 8 * 1024;
29
+ const PRIVATE_KEY_FILE_OPTIONS = {
30
+ maxBytes: MAX_PRIVATE_KEY_BYTES,
31
+ errorCode: "public_publisher_key_unsafe",
32
+ errorMessage: "public publisher key path is not a bounded private regular file with 0600 permissions",
33
+ requireMode600: true,
34
+ } as const;
35
+
36
+ export interface PublicPublisherHandle {
37
+ publisher: PublicPublisherV1;
38
+ privateKeyPath: string;
39
+ }
40
+
41
+ function publicKeyBase64(privateKeyPem: string): string {
42
+ const publicKey = createPublicKey(privateKeyPem);
43
+ return publicKey.export({ type: "spki", format: "der" }).toString("base64");
44
+ }
45
+
46
+ function publisherForPrivateKey(privateKeyPem: string): PublicPublisherV1 {
47
+ const publicKey = publicKeyBase64(privateKeyPem);
48
+ return {
49
+ algorithm: "ed25519",
50
+ keyId: publicEvidenceId("publisher_key", { algorithm: "ed25519", publicKey }),
51
+ publicKey,
52
+ };
53
+ }
54
+
55
+ /**
56
+ * The bounded errno-shaped code from a failed ACL harden, or null when the cause
57
+ * carries none.
58
+ *
59
+ * Only the code is allowed into the message. `hardenSecretPath` already sanitizes
60
+ * its own diagnostic prose, but this error is what reaches a CI log, so what
61
+ * crosses that boundary is re-checked here rather than trusted: an errno code has
62
+ * no separator, no lowercase and a bounded length, and therefore cannot carry the
63
+ * key pathname or the username component inside it.
64
+ */
65
+ function aclFailureCode(error: unknown): string | null {
66
+ if (!(error instanceof Error) || !("code" in error)) return null;
67
+ const code = (error as NodeJS.ErrnoException).code;
68
+ return typeof code === "string" && /^[A-Z][A-Z0-9_]{1,30}$/.test(code) ? code : null;
69
+ }
70
+
71
+ function requirePublisherKeyAcl(path: string, timeoutMemoKey = path): void {
72
+ privateRegularFileSize(path, PRIVATE_KEY_FILE_OPTIONS);
73
+ let hardened: { ok: boolean };
74
+ let hardeningError: unknown;
75
+ try {
76
+ hardened = hardenSecretPath(path, { required: true, timeoutMemoKey });
77
+ } catch (error) {
78
+ hardeningError = error;
79
+ hardened = { ok: false };
80
+ }
81
+ if (!hardened.ok) {
82
+ // Name the cause in the message, not only on `cause`. Every harden failure
83
+ // reaches a CI log as this one string, and the three that occur there need
84
+ // different fixes: ETIMEDOUT is the budget, EACLIDENTITY is the effective-SID
85
+ // lookup, EICACLS is icacls refusing the path. A message identical across all
86
+ // three cannot be acted on without a Windows box to re-run it under (#2152).
87
+ const code = aclFailureCode(hardeningError);
88
+ const failure = new PublicEvidenceValidationError(
89
+ "public_publisher_key_unsafe",
90
+ code
91
+ ? `public publisher key ACL hardening did not complete (${code})`
92
+ : "public publisher key ACL hardening did not complete",
93
+ );
94
+ if (hardeningError !== undefined) {
95
+ (failure as Error & { cause?: unknown }).cause = hardeningError;
96
+ }
97
+ throw failure;
98
+ }
99
+ }
100
+
101
+ function readRestrictedPrivateKey(path: string): string {
102
+ cleanupStalePrivateFileStages(path);
103
+ // Prove the pathname is the expected private regular file before applying any
104
+ // platform ACL operation, then fail closed if Windows per-user ACL hardening
105
+ // cannot be established. The helper is a no-op success on non-Windows.
106
+ requirePublisherKeyAcl(path);
107
+ const pem = readPrivateRegularFile(path, PRIVATE_KEY_FILE_OPTIONS).toString("utf8");
108
+ const key = createPrivateKey(pem);
109
+ if (key.asymmetricKeyType !== "ed25519") {
110
+ throw new Error("public publisher key must be Ed25519");
111
+ }
112
+ return pem;
113
+ }
114
+
115
+ function createPrivateKeyFile(path: string): string {
116
+ const { privateKey } = generateKeyPairSync("ed25519", {
117
+ privateKeyEncoding: { type: "pkcs8", format: "pem" },
118
+ publicKeyEncoding: { type: "spki", format: "pem" },
119
+ });
120
+ publishPrivateFileExclusive(path, Buffer.from(privateKey, "utf8"), {
121
+ // On Windows, harden the empty stage before private key bytes are written.
122
+ // A required ACL failure therefore cannot strand secret bytes in a stage.
123
+ prepareStage: stagePath => requirePublisherKeyAcl(stagePath, path),
124
+ });
125
+ return readRestrictedPrivateKey(path);
126
+ }
127
+
128
+ export function loadExistingPublicPublisher(configDir?: string): PublicPublisherHandle | null {
129
+ const privateKeyPath = labPublicPublisherKeyPath(configDir);
130
+ try {
131
+ const privateKeyPem = readRestrictedPrivateKey(privateKeyPath);
132
+ return { publisher: publisherForPrivateKey(privateKeyPem), privateKeyPath };
133
+ } catch (error) {
134
+ if ((error as NodeJS.ErrnoException).code === "ENOENT") return null;
135
+ throw error;
136
+ }
137
+ }
138
+
139
+ export function getOrCreatePublicPublisher(configDir?: string): PublicPublisherHandle {
140
+ ensureLabDirs(configDir);
141
+ const existing = loadExistingPublicPublisher(configDir);
142
+ if (existing) return existing;
143
+ const privateKeyPath = labPublicPublisherKeyPath(configDir);
144
+ const privateKeyPem = createPrivateKeyFile(privateKeyPath);
145
+ return { publisher: publisherForPrivateKey(privateKeyPem), privateKeyPath };
146
+ }
147
+
148
+ /** Centralized descriptor-bound signing primitive for the installation publisher key. */
149
+ export function signPublicPublisherDigest(handle: PublicPublisherHandle, digestHex: string): string {
150
+ if (!/^[0-9a-f]{64}$/.test(digestHex)) {
151
+ throw new PublicEvidenceValidationError("invalid_digest", "publisher signing digest must be lowercase sha256 hex");
152
+ }
153
+ const privateKeyPem = readRestrictedPrivateKey(handle.privateKeyPath);
154
+ return signBytes(null, Buffer.from(digestHex, "hex"), createPrivateKey(privateKeyPem)).toString("base64");
155
+ }
156
+
157
+ export interface SignPublicEvidenceBundleInput extends Omit<BuildPublicEvidenceBundleInput, "publisher"> {
158
+ configDir?: string;
159
+ }
160
+
161
+ function assertLocalArtifactExportAuthority(input: SignPublicEvidenceBundleInput): void {
162
+ if (input.artifacts.length !== 0) {
163
+ throw new PublicEvidenceValidationError(
164
+ "public_artifact_authority_required",
165
+ "artifact bytes require reviewed public_export policy authority before local signing",
166
+ );
167
+ }
168
+ }
169
+
170
+ export function signPublicEvidenceBundle(input: SignPublicEvidenceBundleInput): PublicEvidenceBundleV1 {
171
+ // Validate every caller-controlled invariant before publisher identity state is touched.
172
+ assertLocalArtifactExportAuthority(input);
173
+ const normalized = normalizePublicEvidenceContent({
174
+ records: input.records,
175
+ artifacts: input.artifacts,
176
+ createdDayUtc: input.createdDayUtc,
177
+ });
178
+ validatePublicEvidenceAuthorities(normalized.records);
179
+ for (const record of normalized.records) validatePublicEvidenceRecordPrivacy(record);
180
+
181
+ const handle = getOrCreatePublicPublisher(input.configDir);
182
+ const unsigned = buildPublicEvidenceBundle({ ...normalized, publisher: handle.publisher });
183
+ validatePublicEvidencePrivacy(unsigned);
184
+ return {
185
+ ...unsigned,
186
+ signature: {
187
+ algorithm: "ed25519",
188
+ signedDigest: unsigned.bundleDigest,
189
+ signature: signPublicPublisherDigest(handle, unsigned.bundleDigest),
190
+ },
191
+ };
192
+ }
193
+
194
+ export type PublicBundleVerificationResult =
195
+ | { status: "cryptographically_valid" }
196
+ | { status: "digest_invalid" }
197
+ | { status: "signature_invalid" }
198
+ | { status: "schema_rejected" };
199
+
200
+ export function verifyPublicEvidenceBundle(bundle: PublicEvidenceBundleV1): PublicBundleVerificationResult {
201
+ try {
202
+ const raw = bundle as unknown as Record<string, unknown>;
203
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) return { status: "schema_rejected" };
204
+ const allowed = new Set([
205
+ "schemaVersion",
206
+ "exportPolicyVersion",
207
+ "bundleId",
208
+ "createdDayUtc",
209
+ "publisher",
210
+ "records",
211
+ "artifacts",
212
+ "bundleDigest",
213
+ "signature",
214
+ ]);
215
+ if (Object.keys(raw).some((key) => !allowed.has(key))) return { status: "schema_rejected" };
216
+ if (bundle.schemaVersion !== "public_evidence_bundle_v1" || bundle.exportPolicyVersion !== "public_export_policy_v1") {
217
+ return { status: "schema_rejected" };
218
+ }
219
+ if (!bundle.signature || bundle.signature.algorithm !== "ed25519") return { status: "schema_rejected" };
220
+ if (Object.keys(bundle.signature).some((key) => !["algorithm", "signedDigest", "signature"].includes(key))) {
221
+ return { status: "schema_rejected" };
222
+ }
223
+ const canonical = canonicalPublicEvidenceContent(bundle);
224
+ if (!canonical.canonical) return { status: "schema_rejected" };
225
+ const expected = expectedPublicBundleIdentityFromNormalized(canonical.normalized, bundle.publisher);
226
+ if (bundle.bundleId !== expected.bundleId || bundle.bundleDigest !== expected.bundleDigest) {
227
+ return { status: "digest_invalid" };
228
+ }
229
+ if (bundle.signature.signedDigest !== bundle.bundleDigest) return { status: "signature_invalid" };
230
+ const key = createPublicKey({
231
+ key: Buffer.from(bundle.publisher.publicKey, "base64"),
232
+ type: "spki",
233
+ format: "der",
234
+ });
235
+ if (key.asymmetricKeyType !== "ed25519") return { status: "signature_invalid" };
236
+ const signature = Buffer.from(bundle.signature.signature, "base64");
237
+ if (signature.toString("base64") !== bundle.signature.signature) return { status: "signature_invalid" };
238
+ const valid = verifyBytes(null, Buffer.from(bundle.bundleDigest, "hex"), key, signature);
239
+ return valid ? { status: "cryptographically_valid" } : { status: "signature_invalid" };
240
+ } catch {
241
+ return { status: "schema_rejected" };
242
+ }
243
+ }
@@ -0,0 +1,105 @@
1
+ import { join } from "node:path";
2
+ import { isSha256Hex, jcsStringify } from "../digest";
3
+ import { ensureLabDirs } from "../paths";
4
+ import { MAX_PUBLIC_BUNDLE_BYTES } from "./bundle";
5
+ import { validatePublicEvidenceAuthorities } from "./community-authority";
6
+ import { readPrivateRegularFile } from "./file-safety";
7
+ import { cleanupStalePrivateFileStages, publishPrivateFileExclusive } from "./private-file";
8
+ import { validatePublicEvidencePrivacy } from "./privacy";
9
+ import { parseStrictPublicJson } from "./strict-json";
10
+ import type { PublicEvidenceBundleV1 } from "./types";
11
+ import { verifyPublicEvidenceBundle } from "./signature";
12
+ import { PublicEvidenceValidationError } from "./validate";
13
+
14
+ function encodedBytes(value: string): number {
15
+ return new TextEncoder().encode(value).byteLength;
16
+ }
17
+
18
+ function bundlePath(bundleId: string, configDir?: string): string {
19
+ if (!isSha256Hex(bundleId)) throw new Error("public bundle id must be lowercase sha256 hex");
20
+ return join(ensureLabDirs(configDir).exportDir, `${bundleId}.json`);
21
+ }
22
+
23
+ function assertLocalArtifactExportAuthority(bundle: PublicEvidenceBundleV1): void {
24
+ if (bundle.artifacts.length !== 0) {
25
+ throw new PublicEvidenceValidationError(
26
+ "public_artifact_authority_required",
27
+ "artifact bytes require reviewed public_export policy authority before local export storage",
28
+ );
29
+ }
30
+ }
31
+
32
+ function readLocalExport(path: string): Buffer {
33
+ cleanupStalePrivateFileStages(path);
34
+ return readPrivateRegularFile(path, {
35
+ maxBytes: MAX_PUBLIC_BUNDLE_BYTES,
36
+ errorCode: "public_file_unsafe",
37
+ errorMessage: "public export is not a private regular file with 0600 permissions",
38
+ sizeErrorCode: "public_file_too_large",
39
+ sizeErrorMessage: "public bundle exceeds 2 MiB",
40
+ requireMode600: true,
41
+ });
42
+ }
43
+
44
+ function existingBody(path: string): string | null {
45
+ try {
46
+ return readLocalExport(path).toString("utf8");
47
+ } catch (error) {
48
+ if ((error as NodeJS.ErrnoException).code === "ENOENT") return null;
49
+ throw error;
50
+ }
51
+ }
52
+
53
+ function validateLocalBundle(bundle: PublicEvidenceBundleV1): void {
54
+ const verification = verifyPublicEvidenceBundle(bundle);
55
+ if (verification.status !== "cryptographically_valid") {
56
+ throw new PublicEvidenceValidationError(verification.status, `public bundle verification failed: ${verification.status}`);
57
+ }
58
+ assertLocalArtifactExportAuthority(bundle);
59
+ validatePublicEvidenceAuthorities(bundle.records);
60
+ validatePublicEvidencePrivacy(bundle);
61
+ }
62
+
63
+ export function storePublicEvidenceBundle(
64
+ bundle: PublicEvidenceBundleV1,
65
+ configDir?: string,
66
+ ): { path: string; created: boolean } {
67
+ validateLocalBundle(bundle);
68
+ const body = jcsStringify(bundle) + "\n";
69
+ if (encodedBytes(body) > MAX_PUBLIC_BUNDLE_BYTES) {
70
+ throw new PublicEvidenceValidationError("public_file_too_large", "public bundle exceeds 2 MiB");
71
+ }
72
+ const path = bundlePath(bundle.bundleId, configDir);
73
+ const existing = existingBody(path);
74
+ if (existing !== null) {
75
+ if (existing === body) return { path, created: false };
76
+ throw new PublicEvidenceValidationError("public_export_conflict", "public export id collision with different bytes");
77
+ }
78
+
79
+ const published = publishPrivateFileExclusive(path, Buffer.from(body, "utf8"));
80
+ if (!published.created) {
81
+ const raced = existingBody(path);
82
+ if (raced === body) return { path, created: false };
83
+ throw new PublicEvidenceValidationError("public_export_conflict", "public export id collision with different bytes");
84
+ }
85
+ return { path, created: true };
86
+ }
87
+
88
+ /** Backward-compatible local storage helper for callers that need the private path. */
89
+ export function writePublicEvidenceBundle(bundle: PublicEvidenceBundleV1, configDir?: string): string {
90
+ return storePublicEvidenceBundle(bundle, configDir).path;
91
+ }
92
+
93
+ export function readPublicEvidenceBundle(bundleId: string, configDir?: string): PublicEvidenceBundleV1 {
94
+ const bytes = readLocalExport(bundlePath(bundleId, configDir));
95
+ const raw = parseStrictPublicJson(bytes, "public export", "public_file_json");
96
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
97
+ throw new PublicEvidenceValidationError("public_file_json", "public export must contain a bundle object");
98
+ }
99
+ const parsed = raw as PublicEvidenceBundleV1;
100
+ if (parsed.bundleId !== bundleId) {
101
+ throw new PublicEvidenceValidationError("public_file_identity", "public export filename does not match bundle id");
102
+ }
103
+ validateLocalBundle(parsed);
104
+ return parsed;
105
+ }
@@ -0,0 +1,206 @@
1
+ import { PublicEvidenceValidationError } from "./validate";
2
+
3
+ const MAX_PUBLIC_JSON_BYTES = 2 * 1024 * 1024;
4
+ const MAX_PUBLIC_JSON_DEPTH = 8;
5
+ const MAX_PUBLIC_JSON_OBJECT_KEYS = 64;
6
+ const MAX_PUBLIC_JSON_ARRAY_ELEMENTS = 512;
7
+ const MAX_PUBLIC_JSON_STRING_BYTES = 384 * 1024;
8
+
9
+ function isJsonWhitespace(value: string | undefined): boolean {
10
+ return value === " " || value === "\n" || value === "\r" || value === "\t";
11
+ }
12
+
13
+ function malformedJson(code: string, message: string): never {
14
+ throw new PublicEvidenceValidationError(code, message);
15
+ }
16
+
17
+ function assertStrictPublicJsonShape(text: string, invalidCode: string): void {
18
+ let index = 0;
19
+ let depth = 0;
20
+
21
+ function invalid(message: string): never {
22
+ return malformedJson(invalidCode, message);
23
+ }
24
+
25
+ function skipWhitespace(): void {
26
+ while (isJsonWhitespace(text[index])) index += 1;
27
+ }
28
+
29
+ function parseStringToken(): string {
30
+ if (text[index] !== '"') invalid("public JSON contains an invalid string token");
31
+ const start = index;
32
+ index += 1;
33
+ let escaped = false;
34
+ while (index < text.length) {
35
+ const ch = text[index++]!;
36
+ if (escaped) {
37
+ escaped = false;
38
+ continue;
39
+ }
40
+ if (ch === "\\") {
41
+ escaped = true;
42
+ continue;
43
+ }
44
+ if (ch === '"') {
45
+ if (Buffer.byteLength(text.slice(start + 1, index - 1), "utf8") > MAX_PUBLIC_JSON_STRING_BYTES) {
46
+ invalid(`public JSON string exceeds ${MAX_PUBLIC_JSON_STRING_BYTES} bytes`);
47
+ }
48
+ try {
49
+ const decoded = JSON.parse(text.slice(start, index));
50
+ if (typeof decoded !== "string") invalid("public JSON contains an invalid string token");
51
+ return decoded;
52
+ } catch (error) {
53
+ if (error instanceof PublicEvidenceValidationError) throw error;
54
+ invalid("public JSON contains an invalid string token");
55
+ }
56
+ }
57
+ if (ch.charCodeAt(0) < 0x20) invalid("public JSON contains an invalid control character");
58
+ }
59
+ invalid("public JSON contains an unterminated string token");
60
+ }
61
+
62
+ function parseScalar(): void {
63
+ const start = index;
64
+ while (index < text.length) {
65
+ const ch = text[index];
66
+ if (ch === "," || ch === "]" || ch === "}" || isJsonWhitespace(ch)) break;
67
+ index += 1;
68
+ }
69
+ if (start === index) invalid("public JSON contains an invalid value");
70
+ try {
71
+ const parsed = JSON.parse(text.slice(start, index));
72
+ if (parsed !== null && typeof parsed === "object") invalid("public JSON contains an invalid scalar value");
73
+ } catch (error) {
74
+ if (error instanceof PublicEvidenceValidationError) throw error;
75
+ invalid("public JSON contains an invalid scalar value");
76
+ }
77
+ }
78
+
79
+ function enterContainer(): void {
80
+ depth += 1;
81
+ if (depth > MAX_PUBLIC_JSON_DEPTH) {
82
+ invalid(`public JSON nesting depth exceeds ${MAX_PUBLIC_JSON_DEPTH}`);
83
+ }
84
+ }
85
+
86
+ function parseArray(): void {
87
+ enterContainer();
88
+ try {
89
+ index += 1;
90
+ skipWhitespace();
91
+ if (text[index] === "]") {
92
+ index += 1;
93
+ return;
94
+ }
95
+ let elementCount = 0;
96
+ while (index < text.length) {
97
+ elementCount += 1;
98
+ if (elementCount > MAX_PUBLIC_JSON_ARRAY_ELEMENTS) {
99
+ invalid(`public JSON array exceeds ${MAX_PUBLIC_JSON_ARRAY_ELEMENTS} elements`);
100
+ }
101
+ parseValue();
102
+ skipWhitespace();
103
+ if (text[index] === "]") {
104
+ index += 1;
105
+ return;
106
+ }
107
+ if (text[index] !== ",") invalid("public JSON array is malformed");
108
+ index += 1;
109
+ skipWhitespace();
110
+ if (text[index] === "]") invalid("public JSON array contains a trailing comma");
111
+ }
112
+ invalid("public JSON array is unterminated");
113
+ } finally {
114
+ depth -= 1;
115
+ }
116
+ }
117
+
118
+ function parseObject(): void {
119
+ enterContainer();
120
+ try {
121
+ index += 1;
122
+ skipWhitespace();
123
+ if (text[index] === "}") {
124
+ index += 1;
125
+ return;
126
+ }
127
+ const keys = new Set<string>();
128
+ while (index < text.length) {
129
+ if (text[index] !== '"') invalid("public JSON object key must be a string");
130
+ const key = parseStringToken();
131
+ if (keys.has(key)) {
132
+ throw new PublicEvidenceValidationError("duplicate_json_key", "duplicate JSON object key");
133
+ }
134
+ keys.add(key);
135
+ if (keys.size > MAX_PUBLIC_JSON_OBJECT_KEYS) {
136
+ invalid(`public JSON object exceeds ${MAX_PUBLIC_JSON_OBJECT_KEYS} keys`);
137
+ }
138
+ skipWhitespace();
139
+ if (text[index] !== ":") invalid("public JSON object is missing a colon");
140
+ index += 1;
141
+ parseValue();
142
+ skipWhitespace();
143
+ if (text[index] === "}") {
144
+ index += 1;
145
+ return;
146
+ }
147
+ if (text[index] !== ",") invalid("public JSON object is malformed");
148
+ index += 1;
149
+ skipWhitespace();
150
+ if (text[index] === "}") invalid("public JSON object contains a trailing comma");
151
+ }
152
+ invalid("public JSON object is unterminated");
153
+ } finally {
154
+ depth -= 1;
155
+ }
156
+ }
157
+
158
+ function parseValue(): void {
159
+ skipWhitespace();
160
+ const ch = text[index];
161
+ if (ch === "{") {
162
+ parseObject();
163
+ return;
164
+ }
165
+ if (ch === "[") {
166
+ parseArray();
167
+ return;
168
+ }
169
+ if (ch === '"') {
170
+ parseStringToken();
171
+ return;
172
+ }
173
+ parseScalar();
174
+ }
175
+
176
+ skipWhitespace();
177
+ if (index === text.length) invalid("public JSON is empty");
178
+ parseValue();
179
+ skipWhitespace();
180
+ if (index !== text.length) invalid("public JSON contains trailing data");
181
+ }
182
+
183
+ export function parseStrictPublicJson(
184
+ bytes: Uint8Array,
185
+ label = "public JSON",
186
+ invalidCode = "public_json",
187
+ maxBytes = MAX_PUBLIC_JSON_BYTES,
188
+ ): unknown {
189
+ if (!Number.isSafeInteger(maxBytes) || maxBytes < 1) {
190
+ throw new PublicEvidenceValidationError(invalidCode, `${label} byte limit is invalid`);
191
+ }
192
+ if (bytes.byteLength > maxBytes) {
193
+ throw new PublicEvidenceValidationError(invalidCode, `${label} exceeds ${maxBytes} bytes`);
194
+ }
195
+ const buffer = Buffer.from(bytes);
196
+ const text = buffer.toString("utf8");
197
+ if (!Buffer.from(text, "utf8").equals(buffer)) {
198
+ throw new PublicEvidenceValidationError(invalidCode, `${label} is not valid UTF-8 JSON`);
199
+ }
200
+ assertStrictPublicJsonShape(text, invalidCode);
201
+ try {
202
+ return JSON.parse(text);
203
+ } catch {
204
+ throw new PublicEvidenceValidationError(invalidCode, `${label} is not valid JSON`);
205
+ }
206
+ }
@@ -0,0 +1,26 @@
1
+ import { PublicEvidenceValidationError } from "./validate";
2
+
3
+ /** Largest timestamp whose ISO-8601 year still fits the four-digit YYYY form. */
4
+ const MAX_PUBLIC_DAY_TIMESTAMP_MS = Date.UTC(9999, 11, 31, 23, 59, 59, 999);
5
+
6
+ /** Convert a bounded JavaScript timestamp into the public UTC day bucket. */
7
+ export function publicUtcDay(timestampMs: number): string {
8
+ if (
9
+ !Number.isInteger(timestampMs)
10
+ || timestampMs < 0
11
+ || timestampMs > MAX_PUBLIC_DAY_TIMESTAMP_MS
12
+ ) {
13
+ throw new PublicEvidenceValidationError(
14
+ "public_selection_time",
15
+ "invalid observation completion timestamp",
16
+ );
17
+ }
18
+ const date = new Date(timestampMs);
19
+ if (!Number.isFinite(date.getTime())) {
20
+ throw new PublicEvidenceValidationError(
21
+ "public_selection_time",
22
+ "invalid observation completion timestamp",
23
+ );
24
+ }
25
+ return date.toISOString().slice(0, 10);
26
+ }