@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,512 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import {
3
+ closeSync,
4
+ existsSync,
5
+ fsyncSync,
6
+ linkSync,
7
+ openSync,
8
+ readFileSync,
9
+ unlinkSync,
10
+ writeFileSync,
11
+ } from "node:fs";
12
+ import { dirname, join } from "node:path";
13
+ import { renameAtomicFile } from "../../lib/windows-atomic-replace";
14
+ import {
15
+ ensureLabDirs,
16
+ labAutomationPolicyPath,
17
+ labAutomationRoutesPath,
18
+ labAutomationStatePath,
19
+ } from "../paths";
20
+ import { LAB_AUTOMATION_HARD_MAX } from "./constants";
21
+ import { defaultLabAutomationPolicyV1, normalizeLabAutomationPolicyV1 } from "./policy";
22
+ import type {
23
+ LabAutomationPolicyV1,
24
+ LabAutomationRoutesV1,
25
+ LabAutomationRunRecordV1,
26
+ LabAutomationStateV1,
27
+ } from "./types";
28
+ import { LabAutomationError } from "./types";
29
+
30
+ const ROUTES_KEYS = new Set(["schemaVersion", "routes"]);
31
+ const ROUTE_KEYS = new Set(["providerName", "modelId"]);
32
+ const STATE_KEYS = new Set([
33
+ "schemaVersion",
34
+ "runs",
35
+ "budgetWindowStartedAt",
36
+ "runsThisHour",
37
+ "liveRequestsThisHour",
38
+ "cooldownUntilByKey",
39
+ ]);
40
+ const RUN_KEYS = new Set([
41
+ "runId",
42
+ "runKey",
43
+ "state",
44
+ "evidenceLayer",
45
+ "suiteId",
46
+ "suiteVersion",
47
+ "suiteManifestDigest",
48
+ "scenarioId",
49
+ "scenarioVersion",
50
+ "scenarioManifestDigest",
51
+ "subjectId",
52
+ "reason",
53
+ "priority",
54
+ "eligibleAt",
55
+ "trigger",
56
+ "createdAt",
57
+ "updatedAt",
58
+ "startedAt",
59
+ "completedAt",
60
+ "terminalCode",
61
+ "providerName",
62
+ "modelId",
63
+ ]);
64
+ const RUN_STATES = new Set(["queued", "running", "completed", "blocked", "failed", "cancelled", "abandoned"]);
65
+ const TERMINAL_RUN_STATES = new Set(["completed", "blocked", "failed", "cancelled", "abandoned"]);
66
+ const RUN_REASONS = new Set([
67
+ "automation_disabled",
68
+ "layer_disabled",
69
+ "fresh",
70
+ "refresh_due",
71
+ "missing",
72
+ "cooldown",
73
+ "budget_blocked",
74
+ "already_queued",
75
+ "already_running",
76
+ "route_ineligible",
77
+ "scenario_inapplicable",
78
+ "task_background_disabled",
79
+ ]);
80
+ const STATE_LOCK_WAIT_MS = 5_000;
81
+ const LOCK_SLEEP = new Int32Array(new SharedArrayBuffer(4));
82
+
83
+ interface StateLockMeta {
84
+ pid: number;
85
+ token: string;
86
+ }
87
+
88
+ function assertClosedKeys(
89
+ value: Record<string, unknown>,
90
+ allowed: ReadonlySet<string>,
91
+ label: string,
92
+ code: "invalid_routes" | "invalid_state",
93
+ ): void {
94
+ for (const key of Object.keys(value)) {
95
+ if (!allowed.has(key)) throw new LabAutomationError(`unknown ${label} field ${key}`, code);
96
+ }
97
+ }
98
+
99
+ function assertBoundedString(
100
+ value: unknown,
101
+ field: string,
102
+ code: "invalid_routes" | "invalid_state",
103
+ max = 512,
104
+ ): string {
105
+ if (typeof value !== "string" || value.length === 0 || value.length > max) {
106
+ throw new LabAutomationError(`invalid ${field}`, code);
107
+ }
108
+ return value;
109
+ }
110
+
111
+ function assertNonNegativeInt(
112
+ value: unknown,
113
+ field: string,
114
+ code: "invalid_state",
115
+ max = Number.MAX_SAFE_INTEGER,
116
+ ): number {
117
+ if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0 || value > max) {
118
+ throw new LabAutomationError(`invalid ${field}`, code);
119
+ }
120
+ return value;
121
+ }
122
+
123
+ function atomicWriteJson(path: string, payload: unknown): void {
124
+ const dir = dirname(path);
125
+ const tmp = join(dir, `.${basename(path)}.${process.pid}.${Date.now()}.tmp`);
126
+ const text = JSON.stringify(payload);
127
+ writeFileSync(tmp, text, { encoding: "utf8", mode: 0o600 });
128
+ renameAtomicFile(tmp, path, undefined, "lab-automation");
129
+ }
130
+
131
+ function basename(path: string): string {
132
+ const idx = path.replace(/\\/g, "/").lastIndexOf("/");
133
+ return idx >= 0 ? path.slice(idx + 1) : path;
134
+ }
135
+
136
+ function readJsonFile(path: string, code: "invalid_policy" | "invalid_routes" | "invalid_state"): unknown {
137
+ if (!existsSync(path)) return undefined;
138
+ try {
139
+ const raw = readFileSync(path, "utf8");
140
+ return JSON.parse(raw) as unknown;
141
+ } catch (error) {
142
+ if (error instanceof LabAutomationError) throw error;
143
+ throw new LabAutomationError(`invalid automation JSON at ${basename(path)}`, code);
144
+ }
145
+ }
146
+
147
+ function sleepLockRetry(): void {
148
+ Atomics.wait(LOCK_SLEEP, 0, 0, 10);
149
+ }
150
+
151
+ function stateLockPath(configDir?: string): string {
152
+ return `${labAutomationStatePath(configDir)}.lock`;
153
+ }
154
+
155
+ function readStateLockMeta(lockPath: string): StateLockMeta | null {
156
+ try {
157
+ const parsed = JSON.parse(readFileSync(lockPath, "utf8")) as unknown;
158
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return null;
159
+ const row = parsed as Record<string, unknown>;
160
+ if (!Number.isSafeInteger(row.pid) || (row.pid as number) <= 0) return null;
161
+ if (typeof row.token !== "string" || row.token.length < 16 || row.token.length > 128) return null;
162
+ return { pid: row.pid as number, token: row.token };
163
+ } catch {
164
+ return null;
165
+ }
166
+ }
167
+
168
+ function pidDefinitelyDead(pid: number): boolean {
169
+ try {
170
+ process.kill(pid, 0);
171
+ return false;
172
+ } catch (error) {
173
+ const code = error && typeof error === "object" && "code" in error
174
+ ? String((error as { code?: unknown }).code)
175
+ : undefined;
176
+ return code === "ESRCH";
177
+ }
178
+ }
179
+
180
+ function releaseStateLock(lockPath: string, token: string): void {
181
+ try {
182
+ if (readStateLockMeta(lockPath)?.token === token) unlinkSync(lockPath);
183
+ } catch {
184
+ /* already released/cleaned */
185
+ }
186
+ }
187
+
188
+ function reclaimDeadStateLock(lockPath: string): boolean {
189
+ const observed = readStateLockMeta(lockPath);
190
+ if (!observed || !pidDefinitelyDead(observed.pid)) return false;
191
+ // Re-check ownership immediately before deletion. A live/paused process is never reclaimed;
192
+ // token-checked release also prevents an old owner from deleting a successor's lock.
193
+ const current = readStateLockMeta(lockPath);
194
+ if (!current || current.pid !== observed.pid || current.token !== observed.token) return false;
195
+ try {
196
+ unlinkSync(lockPath);
197
+ return true;
198
+ } catch {
199
+ return false;
200
+ }
201
+ }
202
+
203
+ function cleanupPrivateLockFile(path: string): void {
204
+ try {
205
+ unlinkSync(path);
206
+ } catch {
207
+ /* absent or already cleaned */
208
+ }
209
+ }
210
+
211
+ function acquireStateLock(configDir?: string): () => void {
212
+ ensureLabDirs(configDir);
213
+ const lockPath = stateLockPath(configDir);
214
+ const deadline = Date.now() + STATE_LOCK_WAIT_MS;
215
+ while (true) {
216
+ const token = randomUUID();
217
+ const privatePath = `${lockPath}.${process.pid}.${token}.tmp`;
218
+ let publicationAttempted = false;
219
+ try {
220
+ const fd = openSync(privatePath, "wx", 0o600);
221
+ try {
222
+ const meta: StateLockMeta = { pid: process.pid, token };
223
+ writeFileSync(fd, JSON.stringify(meta), { encoding: "utf8" });
224
+ fsyncSync(fd);
225
+ } finally {
226
+ closeSync(fd);
227
+ }
228
+
229
+ // Publish only a fully written metadata inode. A hard-link create is atomic and fails
230
+ // with EEXIST when another owner already published the canonical lock path.
231
+ publicationAttempted = true;
232
+ linkSync(privatePath, lockPath);
233
+ cleanupPrivateLockFile(privatePath);
234
+ return () => releaseStateLock(lockPath, token);
235
+ } catch (error) {
236
+ cleanupPrivateLockFile(privatePath);
237
+ const code = error && typeof error === "object" && "code" in error
238
+ ? String((error as { code?: unknown }).code)
239
+ : undefined;
240
+ // A UUID-named private file collision is not ownership contention; retry with a new token.
241
+ if (code === "EEXIST" && !publicationAttempted) continue;
242
+ if (code !== "EEXIST") throw new LabAutomationError("automation state lock failed", "state_lock_failed");
243
+ if (reclaimDeadStateLock(lockPath)) continue;
244
+ if (Date.now() >= deadline) {
245
+ throw new LabAutomationError("automation state is busy", "state_lock_busy");
246
+ }
247
+ sleepLockRetry();
248
+ }
249
+ }
250
+ }
251
+
252
+ export function loadLabAutomationPolicy(configDir?: string): LabAutomationPolicyV1 {
253
+ ensureLabDirs(configDir);
254
+ const path = labAutomationPolicyPath(configDir);
255
+ const raw = readJsonFile(path, "invalid_policy");
256
+ if (raw === undefined) return defaultLabAutomationPolicyV1();
257
+ return normalizeLabAutomationPolicyV1(raw);
258
+ }
259
+
260
+ export function saveLabAutomationPolicy(policy: LabAutomationPolicyV1, configDir?: string): void {
261
+ ensureLabDirs(configDir);
262
+ const normalized = normalizeLabAutomationPolicyV1(policy);
263
+ atomicWriteJson(labAutomationPolicyPath(configDir), normalized);
264
+ }
265
+
266
+ export function normalizeLabAutomationRoutesV1(raw: unknown): LabAutomationRoutesV1 {
267
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
268
+ throw new LabAutomationError("automation routes must be an object", "invalid_routes");
269
+ }
270
+ const obj = raw as Record<string, unknown>;
271
+ assertClosedKeys(obj, ROUTES_KEYS, "routes", "invalid_routes");
272
+ if (obj.schemaVersion !== 1) throw new LabAutomationError("unsupported routes schemaVersion", "invalid_routes");
273
+ if (!Array.isArray(obj.routes)) throw new LabAutomationError("routes must be an array", "invalid_routes");
274
+ if (obj.routes.length > LAB_AUTOMATION_HARD_MAX.maxAutomationRoutes) {
275
+ throw new LabAutomationError("too many automation routes", "invalid_routes");
276
+ }
277
+ const seen = new Set<string>();
278
+ const routes = obj.routes.map((row, index) => {
279
+ if (!row || typeof row !== "object" || Array.isArray(row)) {
280
+ throw new LabAutomationError(`invalid route row ${index}`, "invalid_routes");
281
+ }
282
+ const entry = row as Record<string, unknown>;
283
+ assertClosedKeys(entry, ROUTE_KEYS, `route ${index}`, "invalid_routes");
284
+ const providerName = assertBoundedString(entry.providerName, `providerName at ${index}`, "invalid_routes", 256);
285
+ const modelId = assertBoundedString(entry.modelId, `modelId at ${index}`, "invalid_routes", 512);
286
+ const key = `${providerName}\u0000${modelId}`;
287
+ if (seen.has(key)) throw new LabAutomationError(`duplicate automation route at ${index}`, "invalid_routes");
288
+ seen.add(key);
289
+ return Object.freeze({ providerName, modelId });
290
+ });
291
+ return Object.freeze({ schemaVersion: 1, routes: Object.freeze(routes) });
292
+ }
293
+
294
+ export function defaultLabAutomationRoutesV1(): LabAutomationRoutesV1 {
295
+ return Object.freeze({ schemaVersion: 1, routes: Object.freeze([]) });
296
+ }
297
+
298
+ export function loadLabAutomationRoutes(configDir?: string): LabAutomationRoutesV1 {
299
+ ensureLabDirs(configDir);
300
+ const raw = readJsonFile(labAutomationRoutesPath(configDir), "invalid_routes");
301
+ if (raw === undefined) return defaultLabAutomationRoutesV1();
302
+ return normalizeLabAutomationRoutesV1(raw);
303
+ }
304
+
305
+ export function saveLabAutomationRoutes(routes: LabAutomationRoutesV1, configDir?: string): void {
306
+ ensureLabDirs(configDir);
307
+ atomicWriteJson(labAutomationRoutesPath(configDir), normalizeLabAutomationRoutesV1(routes));
308
+ }
309
+
310
+ function optionalTimestamp(row: Record<string, unknown>, key: "startedAt" | "completedAt", index: number): number | undefined {
311
+ if (row[key] === undefined) return undefined;
312
+ return assertNonNegativeInt(row[key], `${key} at ${index}`, "invalid_state");
313
+ }
314
+
315
+ function normalizeRunRecord(raw: unknown, index: number): LabAutomationRunRecordV1 {
316
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
317
+ throw new LabAutomationError(`invalid run record ${index}`, "invalid_state");
318
+ }
319
+ const row = raw as Record<string, unknown>;
320
+ assertClosedKeys(row, RUN_KEYS, `run ${index}`, "invalid_state");
321
+ const state = row.state;
322
+ if (typeof state !== "string" || !RUN_STATES.has(state)) {
323
+ throw new LabAutomationError(`invalid run state at ${index}`, "invalid_state");
324
+ }
325
+ const evidenceLayer = row.evidenceLayer;
326
+ if (evidenceLayer !== "protocol_conformance"
327
+ && evidenceLayer !== "live_route_compatibility"
328
+ && evidenceLayer !== "task_effectiveness") {
329
+ throw new LabAutomationError(`invalid evidenceLayer at ${index}`, "invalid_state");
330
+ }
331
+ const trigger = row.trigger;
332
+ if (trigger !== "scheduled" && trigger !== "manual") {
333
+ throw new LabAutomationError(`invalid trigger at ${index}`, "invalid_state");
334
+ }
335
+ const reason = assertBoundedString(row.reason, `reason at ${index}`, "invalid_state", 64);
336
+ if (!RUN_REASONS.has(reason)) throw new LabAutomationError(`invalid reason at ${index}`, "invalid_state");
337
+ const runId = assertBoundedString(row.runId, `runId at ${index}`, "invalid_state", 128);
338
+ const runKey = assertBoundedString(row.runKey, `runKey at ${index}`, "invalid_state", 128);
339
+ const suiteId = assertBoundedString(row.suiteId, `suiteId at ${index}`, "invalid_state", 256);
340
+ const suiteVersion = assertBoundedString(row.suiteVersion, `suiteVersion at ${index}`, "invalid_state", 128);
341
+ const suiteManifestDigest = assertBoundedString(row.suiteManifestDigest, `suiteManifestDigest at ${index}`, "invalid_state", 256);
342
+ const scenarioId = assertBoundedString(row.scenarioId, `scenarioId at ${index}`, "invalid_state", 512);
343
+ const scenarioVersion = assertBoundedString(row.scenarioVersion, `scenarioVersion at ${index}`, "invalid_state", 128);
344
+ const scenarioManifestDigest = assertBoundedString(row.scenarioManifestDigest, `scenarioManifestDigest at ${index}`, "invalid_state", 256);
345
+ const subjectId = assertBoundedString(row.subjectId, `subjectId at ${index}`, "invalid_state", 256);
346
+ const priority = assertNonNegativeInt(row.priority, `priority at ${index}`, "invalid_state", 100);
347
+ const eligibleAt = assertNonNegativeInt(row.eligibleAt, `eligibleAt at ${index}`, "invalid_state");
348
+ const createdAt = assertNonNegativeInt(row.createdAt, `createdAt at ${index}`, "invalid_state");
349
+ const updatedAt = assertNonNegativeInt(row.updatedAt, `updatedAt at ${index}`, "invalid_state");
350
+ const startedAt = optionalTimestamp(row, "startedAt", index);
351
+ const completedAt = optionalTimestamp(row, "completedAt", index);
352
+ if (updatedAt < createdAt) throw new LabAutomationError(`updatedAt precedes createdAt at ${index}`, "invalid_state");
353
+ if (startedAt !== undefined && startedAt < createdAt) throw new LabAutomationError(`startedAt precedes createdAt at ${index}`, "invalid_state");
354
+ if (completedAt !== undefined && completedAt < createdAt) throw new LabAutomationError(`completedAt precedes createdAt at ${index}`, "invalid_state");
355
+ if (completedAt !== undefined && startedAt !== undefined && completedAt < startedAt) {
356
+ throw new LabAutomationError(`completedAt precedes startedAt at ${index}`, "invalid_state");
357
+ }
358
+ if (startedAt !== undefined && updatedAt < startedAt) throw new LabAutomationError(`updatedAt precedes startedAt at ${index}`, "invalid_state");
359
+ if (completedAt !== undefined && updatedAt < completedAt) throw new LabAutomationError(`updatedAt precedes completedAt at ${index}`, "invalid_state");
360
+ const terminalCode = row.terminalCode === undefined
361
+ ? undefined
362
+ : assertBoundedString(row.terminalCode, `terminalCode at ${index}`, "invalid_state", 256);
363
+ const providerName = row.providerName === undefined
364
+ ? undefined
365
+ : assertBoundedString(row.providerName, `providerName at ${index}`, "invalid_state", 256);
366
+ const modelId = row.modelId === undefined
367
+ ? undefined
368
+ : assertBoundedString(row.modelId, `modelId at ${index}`, "invalid_state", 512);
369
+
370
+ if (state === "queued" && (startedAt !== undefined || completedAt !== undefined || terminalCode !== undefined)) {
371
+ throw new LabAutomationError(`queued run has lifecycle terminal fields at ${index}`, "invalid_state");
372
+ }
373
+ if (state === "running" && (completedAt !== undefined || terminalCode !== undefined)) {
374
+ throw new LabAutomationError(`running run has terminal fields at ${index}`, "invalid_state");
375
+ }
376
+ if (TERMINAL_RUN_STATES.has(state) && completedAt === undefined) {
377
+ throw new LabAutomationError(`terminal run missing completedAt at ${index}`, "invalid_state");
378
+ }
379
+
380
+ return {
381
+ runId,
382
+ runKey,
383
+ state: state as LabAutomationRunRecordV1["state"],
384
+ evidenceLayer,
385
+ suiteId,
386
+ suiteVersion,
387
+ suiteManifestDigest,
388
+ scenarioId,
389
+ scenarioVersion,
390
+ scenarioManifestDigest,
391
+ subjectId,
392
+ reason: reason as LabAutomationRunRecordV1["reason"],
393
+ priority,
394
+ eligibleAt,
395
+ trigger,
396
+ createdAt,
397
+ updatedAt,
398
+ ...(startedAt !== undefined ? { startedAt } : {}),
399
+ ...(completedAt !== undefined ? { completedAt } : {}),
400
+ ...(terminalCode !== undefined ? { terminalCode } : {}),
401
+ ...(providerName !== undefined ? { providerName } : {}),
402
+ ...(modelId !== undefined ? { modelId } : {}),
403
+ };
404
+ }
405
+
406
+ function assertStateRunInvariants(runs: LabAutomationRunRecordV1[]): void {
407
+ const runIds = new Set<string>();
408
+ const activeRunKeys = new Set<string>();
409
+ for (const run of runs) {
410
+ if (runIds.has(run.runId)) throw new LabAutomationError(`duplicate runId ${run.runId}`, "invalid_state");
411
+ runIds.add(run.runId);
412
+ if (run.state !== "queued" && run.state !== "running") continue;
413
+ if (activeRunKeys.has(run.runKey)) throw new LabAutomationError(`duplicate active runKey ${run.runKey}`, "invalid_state");
414
+ activeRunKeys.add(run.runKey);
415
+ }
416
+ }
417
+
418
+ function normalizeState(raw: unknown): LabAutomationStateV1 {
419
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
420
+ throw new LabAutomationError("automation state must be an object", "invalid_state");
421
+ }
422
+ const obj = raw as Record<string, unknown>;
423
+ assertClosedKeys(obj, STATE_KEYS, "state", "invalid_state");
424
+ if (obj.schemaVersion !== 1) throw new LabAutomationError("unsupported state schemaVersion", "invalid_state");
425
+ if (!Array.isArray(obj.runs)) throw new LabAutomationError("state runs must be an array", "invalid_state");
426
+ if (obj.runs.length > LAB_AUTOMATION_HARD_MAX.maxPersistedRuns) {
427
+ throw new LabAutomationError("too many persisted runs", "invalid_state");
428
+ }
429
+ const runs = obj.runs.map((row, index) => normalizeRunRecord(row, index));
430
+ assertStateRunInvariants(runs);
431
+ const cooldownUntilByKey: Record<string, number> = {};
432
+ if (!obj.cooldownUntilByKey || typeof obj.cooldownUntilByKey !== "object" || Array.isArray(obj.cooldownUntilByKey)) {
433
+ throw new LabAutomationError("invalid cooldownUntilByKey", "invalid_state");
434
+ }
435
+ const cooldownEntries = Object.entries(obj.cooldownUntilByKey as Record<string, unknown>);
436
+ if (cooldownEntries.length > LAB_AUTOMATION_HARD_MAX.maxPersistedRuns) {
437
+ throw new LabAutomationError("too many cooldown entries", "invalid_state");
438
+ }
439
+ for (const [key, value] of cooldownEntries) {
440
+ if (key.length === 0 || key.length > 128) throw new LabAutomationError("invalid cooldown key", "invalid_state");
441
+ cooldownUntilByKey[key] = assertNonNegativeInt(value, `cooldown for ${key}`, "invalid_state");
442
+ }
443
+ return {
444
+ schemaVersion: 1,
445
+ runs,
446
+ budgetWindowStartedAt: assertNonNegativeInt(obj.budgetWindowStartedAt, "budgetWindowStartedAt", "invalid_state"),
447
+ runsThisHour: assertNonNegativeInt(
448
+ obj.runsThisHour,
449
+ "runsThisHour",
450
+ "invalid_state",
451
+ LAB_AUTOMATION_HARD_MAX.maxRunsPerHour,
452
+ ),
453
+ liveRequestsThisHour: assertNonNegativeInt(
454
+ obj.liveRequestsThisHour,
455
+ "liveRequestsThisHour",
456
+ "invalid_state",
457
+ LAB_AUTOMATION_HARD_MAX.maxLiveRequestsPerHour,
458
+ ),
459
+ cooldownUntilByKey,
460
+ };
461
+ }
462
+
463
+ export function defaultLabAutomationStateV1(now = Date.now()): LabAutomationStateV1 {
464
+ return {
465
+ schemaVersion: 1,
466
+ runs: [],
467
+ budgetWindowStartedAt: now,
468
+ runsThisHour: 0,
469
+ liveRequestsThisHour: 0,
470
+ cooldownUntilByKey: {},
471
+ };
472
+ }
473
+
474
+ function loadLabAutomationStateUnlocked(configDir?: string): LabAutomationStateV1 {
475
+ ensureLabDirs(configDir);
476
+ const raw = readJsonFile(labAutomationStatePath(configDir), "invalid_state");
477
+ if (raw === undefined) return defaultLabAutomationStateV1();
478
+ return normalizeState(raw);
479
+ }
480
+
481
+ function saveLabAutomationStateUnlocked(state: LabAutomationStateV1, configDir?: string): void {
482
+ ensureLabDirs(configDir);
483
+ atomicWriteJson(labAutomationStatePath(configDir), normalizeState(state));
484
+ }
485
+
486
+ export function loadLabAutomationState(configDir?: string): LabAutomationStateV1 {
487
+ return loadLabAutomationStateUnlocked(configDir);
488
+ }
489
+
490
+ export function saveLabAutomationState(state: LabAutomationStateV1, configDir?: string): void {
491
+ const release = acquireStateLock(configDir);
492
+ try {
493
+ saveLabAutomationStateUnlocked(state, configDir);
494
+ } finally {
495
+ release();
496
+ }
497
+ }
498
+
499
+ export function mutateLabAutomationState<T>(
500
+ configDir: string | undefined,
501
+ mutate: (state: LabAutomationStateV1) => { state: LabAutomationStateV1; value: T },
502
+ ): T {
503
+ const release = acquireStateLock(configDir);
504
+ try {
505
+ const current = loadLabAutomationStateUnlocked(configDir);
506
+ const result = mutate(current);
507
+ saveLabAutomationStateUnlocked(result.state, configDir);
508
+ return result.value;
509
+ } finally {
510
+ release();
511
+ }
512
+ }