@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,358 @@
1
+ /**
2
+ * Source-preserving mutation for one plain block-map YAML fragment.
3
+ *
4
+ * Shared client settings are not ours to re-render. This scanner accepts only
5
+ * the small, unambiguous source shape we can patch byte-for-byte around the
6
+ * owned leaf. Every candidate is parsed again and compared with the complete
7
+ * expected document; unsupported YAML fails closed and never falls back to a
8
+ * whole-document serializer.
9
+ */
10
+ import { renderYaml } from "./serialize";
11
+
12
+ interface SourceLine {
13
+ start: number;
14
+ end: number;
15
+ body: string;
16
+ }
17
+
18
+ interface LocatedEntry {
19
+ lines: readonly SourceLine[];
20
+ index: number;
21
+ indent: number;
22
+ endIndex: number;
23
+ }
24
+
25
+ interface MissingEntry {
26
+ lines: readonly SourceLine[];
27
+ missingDepth: number;
28
+ indent: number;
29
+ insertAt: number;
30
+ }
31
+
32
+ type LocatedPath = { kind: "existing"; entry: LocatedEntry } | { kind: "missing"; entry: MissingEntry };
33
+
34
+ export type YamlFragmentMutation =
35
+ | { kind: "upsert"; value: unknown }
36
+ | { kind: "remove"; createdContainers: readonly string[] };
37
+
38
+ export type OmpYamlMutation =
39
+ | { kind: "upsert"; value: unknown }
40
+ | { kind: "remove"; removeEmptyProviders: boolean };
41
+
42
+ function sourceLines(text: string): SourceLine[] {
43
+ const lines: SourceLine[] = [];
44
+ const matcher = /[^\r\n]*(?:\r\n|\n|$)/gu;
45
+ for (const match of text.matchAll(matcher)) {
46
+ const raw = match[0];
47
+ if (raw.length === 0) continue;
48
+ const start = match.index;
49
+ const body = raw.endsWith("\r\n")
50
+ ? raw.slice(0, -2)
51
+ : raw.endsWith("\n") ? raw.slice(0, -1) : raw;
52
+ lines.push({ start, end: start + raw.length, body });
53
+ }
54
+ return lines;
55
+ }
56
+
57
+ function leadingSpaces(line: string): number | null {
58
+ const leading = line.match(/^[ \t]*/u)?.[0] ?? "";
59
+ return leading.includes("\t") ? null : leading.length;
60
+ }
61
+
62
+ function isBlank(line: string): boolean {
63
+ return line.trim().length === 0;
64
+ }
65
+
66
+ function isComment(line: string): boolean {
67
+ return line.trimStart().startsWith("#");
68
+ }
69
+
70
+ function hasInlineComment(line: string): boolean {
71
+ return line.includes("#");
72
+ }
73
+
74
+ function regexpEscape(value: string): string {
75
+ return value.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&");
76
+ }
77
+
78
+ function isPlainBlockKey(line: string, indent: number, key: string): boolean {
79
+ const spaces = leadingSpaces(line);
80
+ if (spaces !== indent) return false;
81
+ const rest = line.slice(indent);
82
+ return new RegExp(`^${regexpEscape(key)}:[ ]*(?:#.*)?$`, "u").test(rest);
83
+ }
84
+
85
+ function containerEnd(lines: readonly SourceLine[], start: number, indent: number): number | null {
86
+ for (let index = start + 1; index < lines.length; index += 1) {
87
+ const body = lines[index]!.body;
88
+ const spaces = leadingSpaces(body);
89
+ if (spaces === null) return null;
90
+ if (isBlank(body)) continue;
91
+ if (isComment(body)) {
92
+ if (spaces <= indent) return index;
93
+ continue;
94
+ }
95
+ if (spaces <= indent) return index;
96
+ }
97
+ return lines.length;
98
+ }
99
+
100
+ function childEnd(
101
+ lines: readonly SourceLine[],
102
+ start: number,
103
+ parentEnd: number,
104
+ indent: number,
105
+ ): number | null {
106
+ for (let index = start + 1; index < parentEnd; index += 1) {
107
+ const body = lines[index]!.body;
108
+ const spaces = leadingSpaces(body);
109
+ if (spaces === null) return null;
110
+ // Blank lines and same-level comments remain outside our replacement.
111
+ // Deeper comments belong to the leaf and would be destroyed, so refuse.
112
+ if (isBlank(body)) return index;
113
+ if (isComment(body)) return spaces <= indent ? index : null;
114
+ if (spaces <= indent) return index;
115
+ if (hasInlineComment(body)) return null;
116
+ }
117
+ return parentEnd;
118
+ }
119
+
120
+ function canonicalValue(value: unknown): unknown {
121
+ if (Array.isArray(value)) return value.map(canonicalValue);
122
+ if (value && typeof value === "object") {
123
+ return Object.fromEntries(
124
+ Object.entries(value as Record<string, unknown>)
125
+ .sort(([left], [right]) => left.localeCompare(right))
126
+ .map(([key, child]) => [key, canonicalValue(child)]),
127
+ );
128
+ }
129
+ return value;
130
+ }
131
+
132
+ function semanticallyMatches(text: string, expected: unknown): boolean {
133
+ try {
134
+ const parsed = text.trim().length === 0 ? {} : Bun.YAML.parse(text);
135
+ return JSON.stringify(canonicalValue(parsed)) === JSON.stringify(canonicalValue(expected));
136
+ } catch {
137
+ return false;
138
+ }
139
+ }
140
+
141
+ function lineEnding(text: string): "\n" | "\r\n" {
142
+ return text.includes("\r\n") ? "\r\n" : "\n";
143
+ }
144
+
145
+ function readPath(doc: unknown, path: readonly string[]): unknown {
146
+ let cursor = doc;
147
+ for (const key of path) {
148
+ if (cursor === null || typeof cursor !== "object" || Array.isArray(cursor)) return undefined;
149
+ cursor = (cursor as Record<string, unknown>)[key];
150
+ if (cursor === undefined) return undefined;
151
+ }
152
+ return cursor;
153
+ }
154
+
155
+ function isPlainRecord(value: unknown): value is Record<string, unknown> {
156
+ return value !== null && typeof value === "object" && !Array.isArray(value);
157
+ }
158
+
159
+ function immediateIndent(
160
+ lines: readonly SourceLine[],
161
+ start: number,
162
+ end: number,
163
+ parentIndent: number,
164
+ ): number | null {
165
+ let indent: number | null = null;
166
+ for (let index = start; index < end; index += 1) {
167
+ const body = lines[index]!.body;
168
+ const spaces = leadingSpaces(body);
169
+ if (spaces === null) return null;
170
+ if (isBlank(body) || isComment(body) || spaces <= parentIndent) continue;
171
+ indent = indent === null ? spaces : Math.min(indent, spaces);
172
+ }
173
+ return indent ?? parentIndent + 2;
174
+ }
175
+
176
+ /** Locate a path only when every present segment is a plain block-map key. */
177
+ function locatePath(text: string, parsed: unknown, path: readonly string[]): LocatedPath | null {
178
+ if (path.length === 0 || !isPlainRecord(parsed)) return null;
179
+ const lines = sourceLines(text);
180
+ if (lines.some(line => leadingSpaces(line.body) === null)) return null;
181
+
182
+ let rangeStart = 0;
183
+ let rangeEnd = lines.length;
184
+ let parentIndent = -2;
185
+ const prefix: string[] = [];
186
+ for (let depth = 0; depth < path.length; depth += 1) {
187
+ const indent = depth === 0 ? 0 : immediateIndent(lines, rangeStart, rangeEnd, parentIndent);
188
+ if (indent === null) return null;
189
+ const matches: number[] = [];
190
+ for (let index = rangeStart; index < rangeEnd; index += 1) {
191
+ if (isPlainBlockKey(lines[index]!.body, indent, path[depth]!)) matches.push(index);
192
+ }
193
+ if (matches.length > 1) return null;
194
+ prefix.push(path[depth]!);
195
+ if (matches.length === 0) {
196
+ // The parser saw this key through syntax we do not patch (quoted/flow,
197
+ // merge aliases, or an ambiguous indentation shape).
198
+ if (readPath(parsed, prefix) !== undefined) return null;
199
+ const insertAt = rangeEnd < lines.length ? lines[rangeEnd]!.start : text.length;
200
+ return { kind: "missing", entry: { lines, missingDepth: depth, indent, insertAt } };
201
+ }
202
+
203
+ const index = matches[0]!;
204
+ const end = containerEnd(lines, index, indent);
205
+ if (end === null) return null;
206
+ if (depth === path.length - 1) {
207
+ if (hasInlineComment(lines[index]!.body)) return null;
208
+ const leafEnd = childEnd(lines, index, end, indent);
209
+ if (leafEnd === null) return null;
210
+ return { kind: "existing", entry: { lines, index, indent, endIndex: leafEnd } };
211
+ }
212
+ if (!isPlainRecord(readPath(parsed, prefix))) return null;
213
+ rangeStart = index + 1;
214
+ rangeEnd = end;
215
+ parentIndent = indent;
216
+ }
217
+ return null;
218
+ }
219
+
220
+ function nestedValue(path: readonly string[], value: unknown): Record<string, unknown> {
221
+ let nested: unknown = value;
222
+ for (let index = path.length - 1; index >= 0; index -= 1) nested = { [path[index]!]: nested };
223
+ return nested as Record<string, unknown>;
224
+ }
225
+
226
+ function rendered(value: unknown, indent: number, eol: "\n" | "\r\n"): string {
227
+ return renderYaml(value as Record<string, unknown>, indent).replaceAll("\n", eol);
228
+ }
229
+
230
+ function preserveFinalNewline(candidate: string, original: string, eol: "\n" | "\r\n"): string {
231
+ if (original.length > 0 && !original.endsWith("\n") && candidate.endsWith(eol)) {
232
+ return candidate.slice(0, -eol.length);
233
+ }
234
+ return candidate;
235
+ }
236
+
237
+ function upsertSource(
238
+ text: string,
239
+ parsed: unknown,
240
+ path: readonly string[],
241
+ value: unknown,
242
+ ): string | null {
243
+ const located = locatePath(text, parsed, path);
244
+ if (located === null) return null;
245
+ const eol = lineEnding(text);
246
+ if (located.kind === "existing") {
247
+ const { lines, index, indent, endIndex } = located.entry;
248
+ const startOffset = lines[index]!.start;
249
+ const endOffset = endIndex < lines.length ? lines[endIndex]!.start : text.length;
250
+ const candidate = `${text.slice(0, startOffset)}${rendered({ [path[path.length - 1]!]: value }, indent, eol)}${text.slice(endOffset)}`;
251
+ return preserveFinalNewline(candidate, text, eol);
252
+ }
253
+
254
+ const { missingDepth, indent, insertAt } = located.entry;
255
+ const prefix = insertAt > 0 && !text.slice(0, insertAt).endsWith("\n") ? eol : "";
256
+ const insertion = rendered(nestedValue(path.slice(missingDepth), value), indent, eol);
257
+ const candidate = `${text.slice(0, insertAt)}${prefix}${insertion}${text.slice(insertAt)}`;
258
+ return preserveFinalNewline(candidate, text, eol);
259
+ }
260
+
261
+ function removeExactPath(text: string, path: readonly string[], requireEmpty: boolean): string | null {
262
+ let parsed: unknown;
263
+ try {
264
+ parsed = text.trim().length === 0 ? {} : Bun.YAML.parse(text);
265
+ } catch {
266
+ return null;
267
+ }
268
+ const located = locatePath(text, parsed, path);
269
+ if (located === null || located.kind !== "existing") return null;
270
+ const { lines, index, endIndex } = located.entry;
271
+ const startOffset = lines[index]!.start;
272
+ const endOffset = endIndex < lines.length ? lines[endIndex]!.start : text.length;
273
+ if (requireEmpty) {
274
+ const sourceBody = text.slice(lines[index]!.end, endOffset);
275
+ if (sourceBody.trim().length > 0) return null;
276
+ }
277
+ return `${text.slice(0, startOffset)}${text.slice(endOffset)}`;
278
+ }
279
+
280
+ function planSourceRemoval(
281
+ text: string,
282
+ path: readonly string[],
283
+ createdContainers: readonly string[],
284
+ ): { text: string; prunedContainers: string[] } | null {
285
+ let next = removeExactPath(text, path, false);
286
+ if (next === null) return null;
287
+ const created = new Set(createdContainers);
288
+ const prunedContainers: string[] = [];
289
+ for (let depth = path.length - 1; depth >= 1; depth -= 1) {
290
+ const containerPath = path.slice(0, depth);
291
+ const encoded = containerPath.join("\u0000");
292
+ if (!created.has(encoded)) continue;
293
+ const pruned = removeExactPath(next, containerPath, true);
294
+ // A user-added sibling/comment makes this ancestor source-owned now. Keep
295
+ // it (and every parent) while still removing our leaf.
296
+ if (pruned === null) break;
297
+ next = pruned;
298
+ prunedContainers.push(encoded);
299
+ }
300
+ return { text: next, prunedContainers };
301
+ }
302
+
303
+ /** Containers whose source ranges are still empty and safe to prune. */
304
+ export function sourcePrunableYamlContainers(
305
+ text: string,
306
+ path: readonly string[],
307
+ createdContainers: readonly string[],
308
+ ): readonly string[] | null {
309
+ return planSourceRemoval(text, path, createdContainers)?.prunedContainers ?? null;
310
+ }
311
+
312
+ function removeSource(
313
+ text: string,
314
+ path: readonly string[],
315
+ createdContainers: readonly string[],
316
+ ): string | null {
317
+ return planSourceRemoval(text, path, createdContainers)?.text ?? null;
318
+ }
319
+
320
+ /**
321
+ * Patch one arbitrary plain block-map path, preserving every other byte.
322
+ */
323
+ export function patchYamlFragmentSource(
324
+ text: string,
325
+ path: readonly string[],
326
+ mutation: YamlFragmentMutation,
327
+ expected: unknown,
328
+ ): string | null {
329
+ let parsed: unknown;
330
+ try {
331
+ parsed = text.trim().length === 0 ? {} : Bun.YAML.parse(text);
332
+ } catch {
333
+ return null;
334
+ }
335
+ const patched = mutation.kind === "upsert"
336
+ ? upsertSource(text, parsed, path, mutation.value)
337
+ : removeSource(text, path, mutation.createdContainers);
338
+ return patched !== null && semanticallyMatches(patched, expected) ? patched : null;
339
+ }
340
+
341
+ /** Backward-compatible OMP wrapper around the generic path patcher. */
342
+ export function patchOmpYamlSource(
343
+ text: string,
344
+ mutation: OmpYamlMutation,
345
+ expected: unknown,
346
+ ): string | null {
347
+ return patchYamlFragmentSource(
348
+ text,
349
+ ["providers", "opencodex"],
350
+ mutation.kind === "upsert"
351
+ ? mutation
352
+ : {
353
+ kind: "remove",
354
+ createdContainers: mutation.removeEmptyProviders ? ["providers"] : [],
355
+ },
356
+ expected,
357
+ );
358
+ }
@@ -0,0 +1,74 @@
1
+ /**
2
+ * Refresh a file integration only when OpenCodex already owns its block.
3
+ *
4
+ * This is the safe bridge between an implicit operation such as `ocx sync`
5
+ * and the explicit integration writer. An implicit sync may update a block
6
+ * the user previously enabled, but it must never claim an unowned block,
7
+ * recreate one the user removed, or overwrite edits made after our write.
8
+ */
9
+ import type { ExportModel } from "../clients/config-export";
10
+ import type { OcxConfig } from "../types";
11
+ import type { IntegrationIO } from "./config-io";
12
+ import type { IntegrationClientId } from "./registry";
13
+ import { runIntegrationMutationFlight } from "./mutation-flight";
14
+ import { createIntegrationStateStore, type IntegrationStateStore } from "./store";
15
+ import {
16
+ refreshIntegrationCoordinated,
17
+ type CoordinatedIntegrationOptions,
18
+ } from "./writer";
19
+
20
+ export interface OwnedIntegrationRefreshInput {
21
+ clientId: IntegrationClientId;
22
+ /** Lazy in `ocx sync`, so an unowned client does not even load the catalog. */
23
+ models: readonly ExportModel[] | (() => Promise<readonly ExportModel[]>);
24
+ config: OcxConfig;
25
+ port: number;
26
+ env?: NodeJS.ProcessEnv;
27
+ home?: string;
28
+ store?: IntegrationStateStore;
29
+ io?: IntegrationIO;
30
+ }
31
+
32
+ export interface OwnedIntegrationRefreshOutcome {
33
+ readonly client: IntegrationClientId;
34
+ readonly ok: boolean;
35
+ readonly changed?: boolean;
36
+ readonly reason?: string;
37
+ }
38
+
39
+ /**
40
+ * Returns `null` when the client has never been connected by OpenCodex.
41
+ * Callers use that distinction to report "left alone" rather than "skipped".
42
+ */
43
+ export async function refreshOwnedIntegration(
44
+ input: OwnedIntegrationRefreshInput,
45
+ options?: CoordinatedIntegrationOptions,
46
+ ): Promise<OwnedIntegrationRefreshOutcome | null> {
47
+ const store = input.store ?? createIntegrationStateStore();
48
+
49
+ // The ownership record is the user's durable opt-in. Do this check before
50
+ // reading or classifying the target so an implicit sync can never turn an
51
+ // unowned provider block into one of ours.
52
+ const record = store.readRecords()[input.clientId];
53
+ if (!record || record.clientId !== input.clientId) return null;
54
+
55
+ const { models: suppliedModels, ...rest } = input;
56
+ const models = typeof suppliedModels === "function"
57
+ ? await suppliedModels()
58
+ : suppliedModels;
59
+ const bound = { ...rest, models, store };
60
+ const result = await runIntegrationMutationFlight(
61
+ input.clientId,
62
+ "refresh",
63
+ input.io?.now ?? Date.now,
64
+ () => refreshIntegrationCoordinated(bound, options),
65
+ );
66
+ return result.ok
67
+ ? {
68
+ client: input.clientId,
69
+ ok: true,
70
+ changed: result.changed,
71
+ ...(result.state === "absent" ? { reason: result.message } : {}),
72
+ }
73
+ : { client: input.clientId, ok: false, reason: result.message };
74
+ }
@@ -0,0 +1,160 @@
1
+ /**
2
+ * Client-scoped exceptions to strict managed-fragment ownership.
3
+ *
4
+ * Most clients must preserve every byte represented by their managed
5
+ * contribution. A client that persists runtime-derived fields back into an
6
+ * OpenCodex-owned fragment needs a narrower contract: name the exact paths it
7
+ * may rewrite, then fingerprint everything else. Keeping that policy here
8
+ * prevents a client quirk from weakening the shared classifier.
9
+ */
10
+ import {
11
+ OPENCODE_PROVIDER_ID,
12
+ type ManagedContribution,
13
+ type ManagedFragment,
14
+ } from "../clients/config-export";
15
+ import { canonicalContribution, fingerprint, semanticContribution } from "./ownership";
16
+
17
+ type JsonObject = Record<string, unknown>;
18
+
19
+ function isObject(value: unknown): value is JsonObject {
20
+ return typeof value === "object" && value !== null && !Array.isArray(value);
21
+ }
22
+
23
+ function pathStartsWith(path: readonly string[], prefix: readonly string[]): boolean {
24
+ return prefix.length <= path.length && prefix.every((part, index) => path[index] === part);
25
+ }
26
+
27
+ /** Delete one nested object member and prune only the empty ancestors created by that deletion. */
28
+ function deletePath(root: unknown, path: readonly string[]): void {
29
+ if (!isObject(root) || path.length === 0) return;
30
+ const parents: Array<{ parent: JsonObject; key: string }> = [];
31
+ let cursor: JsonObject = root;
32
+ for (let index = 0; index < path.length - 1; index += 1) {
33
+ const key = path[index]!;
34
+ const next = cursor[key];
35
+ if (!isObject(next)) return;
36
+ parents.push({ parent: cursor, key });
37
+ cursor = next;
38
+ }
39
+ delete cursor[path[path.length - 1]!];
40
+ for (let index = parents.length - 1; index >= 0; index -= 1) {
41
+ if (Object.keys(cursor).length > 0) break;
42
+ const { parent, key } = parents[index]!;
43
+ delete parent[key];
44
+ cursor = parent;
45
+ }
46
+ }
47
+
48
+ function cloneFragment(fragment: ManagedFragment): ManagedFragment {
49
+ return {
50
+ path: [...fragment.path],
51
+ value: structuredClone(fragment.value),
52
+ };
53
+ }
54
+
55
+ /**
56
+ * Paths a client is documented to derive after OpenCodex writes its block.
57
+ *
58
+ * ZCode 3.8.1 persists reasoning and output defaults for every generated
59
+ * model. It may also fill a context default when OpenCodex intentionally
60
+ * omitted one; an authoritative context emitted by OpenCodex remains
61
+ * protected and is never listed here.
62
+ */
63
+ export function refreshablePathsOf(
64
+ contribution: ManagedContribution,
65
+ ): readonly (readonly string[])[] {
66
+ if (contribution.clientId !== "zcode") return [];
67
+ const fragment = contribution.fragments.find(candidate => (
68
+ candidate.path.length === 2
69
+ && candidate.path[0] === "provider"
70
+ && candidate.path[1] === OPENCODE_PROVIDER_ID
71
+ ));
72
+ if (!fragment || !isObject(fragment.value) || !isObject(fragment.value.models)) return [];
73
+
74
+ const paths: string[][] = [];
75
+ for (const modelId of Object.keys(fragment.value.models).sort()) {
76
+ const entry = fragment.value.models[modelId];
77
+ if (!isObject(entry)) continue;
78
+ const base = [...fragment.path, "models", modelId];
79
+ paths.push([...base, "reasoning"]);
80
+ paths.push([...base, "limit", "output"]);
81
+ const limit = entry.limit;
82
+ if (!isObject(limit) || typeof limit.context !== "number") {
83
+ paths.push([...base, "limit", "context"]);
84
+ }
85
+ }
86
+ return paths;
87
+ }
88
+
89
+ export function validRefreshablePaths(
90
+ contribution: ManagedContribution,
91
+ value: unknown,
92
+ ): value is readonly (readonly string[])[] {
93
+ if (contribution.clientId !== "zcode" || !Array.isArray(value) || value.length === 0) {
94
+ return false;
95
+ }
96
+ const fragment = contribution.fragments.find(candidate => (
97
+ candidate.path.length === 2
98
+ && candidate.path[0] === "provider"
99
+ && candidate.path[1] === OPENCODE_PROVIDER_ID
100
+ ));
101
+ if (!fragment || !isObject(fragment.value) || !isObject(fragment.value.models)) return false;
102
+
103
+ const modelIds = new Set(Object.keys(fragment.value.models));
104
+ const seen = new Set<string>();
105
+ return value.every(path => {
106
+ if (!Array.isArray(path) || !path.every(part => typeof part === "string")) return false;
107
+ const modelId = path[3];
108
+ const isReasoning = path.length === 5 && path[4] === "reasoning";
109
+ const isLimitDefault = path.length === 6
110
+ && path[4] === "limit"
111
+ && (path[5] === "output" || path[5] === "context");
112
+ const key = path.join("\u0000");
113
+ if (
114
+ path[0] !== "provider"
115
+ || path[1] !== OPENCODE_PROVIDER_ID
116
+ || path[2] !== "models"
117
+ || typeof modelId !== "string"
118
+ || !modelIds.has(modelId)
119
+ || (!isReasoning && !isLimitDefault)
120
+ || seen.has(key)
121
+ ) return false;
122
+ seen.add(key);
123
+ return true;
124
+ });
125
+ }
126
+
127
+ function contributionWithoutRefreshablePaths(
128
+ contribution: ManagedContribution,
129
+ refreshablePaths: readonly (readonly string[])[],
130
+ ): ManagedContribution {
131
+ const fragments = contribution.fragments.map(cloneFragment);
132
+ for (const refreshablePath of refreshablePaths) {
133
+ for (const fragment of fragments) {
134
+ if (!pathStartsWith(refreshablePath, fragment.path)) continue;
135
+ deletePath(fragment.value, refreshablePath.slice(fragment.path.length));
136
+ break;
137
+ }
138
+ }
139
+ return { ...contribution, fragments };
140
+ }
141
+
142
+ /** Fingerprint a contribution after removing only its explicitly refreshable paths. */
143
+ export function protectedContributionFingerprint(
144
+ contribution: ManagedContribution,
145
+ refreshablePaths: readonly (readonly string[])[],
146
+ ): string {
147
+ return fingerprint(canonicalContribution(
148
+ contributionWithoutRefreshablePaths(contribution, refreshablePaths),
149
+ ));
150
+ }
151
+
152
+ /** Semantic protected fingerprint that ignores JSON object-key order only. */
153
+ export function semanticProtectedContributionFingerprint(
154
+ contribution: ManagedContribution,
155
+ refreshablePaths: readonly (readonly string[])[],
156
+ ): string {
157
+ return fingerprint(semanticContribution(
158
+ contributionWithoutRefreshablePaths(contribution, refreshablePaths),
159
+ ));
160
+ }