@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
@@ -1,9 +1,29 @@
1
1
  import type { OcxConfig } from "../../types";
2
+ import type { NativeProfileApiDeps } from "../../codex/native-profile-api";
3
+ import type { CodexLogGuardProtectionDeps } from "../../codex/log-guard/protection";
4
+ import type { CodexLogGuardMaintenanceDeps } from "../../codex/log-guard/maintenance";
5
+ import type { StartupHealth } from "../../codex/autostart-health";
2
6
  import type { StartupInstallAction } from "../startup-action-control";
7
+ import type { ManagementPrincipal } from "../management-auth";
8
+ import type { CatalogModel } from "../../codex/catalog";
9
+ import type { Paths as CodexPromptPaths } from "../../codex/prompt-layers";
10
+ import type { injectGrokConfig } from "../../grok/inject";
11
+ import type { removeDesktop3pStandardPivot, writeDesktop3pConfig } from "../../claude/desktop-3p";
12
+ import type { RuntimePortState } from "../../config/process-state";
13
+ import type { CatalogDisposition, ConvergeCodex } from "../../codex/convergence-types";
14
+ import type {
15
+ performCodexRestart,
16
+ readCodexAppServerState,
17
+ } from "../../codex/app-server-restart-service";
3
18
 
4
19
  export interface ManagementApiDeps {
20
+ /** Platform seam for capability projections; does not alter host-level startup behavior. */
21
+ platform?: NodeJS.Platform;
5
22
  toggleCodexMultiAgentV2?: (enabled: boolean) => void;
6
- refreshCodexCatalog?: () => Promise<void>;
23
+ toggleDefaultModeRequestUserInput?: (enabled: boolean) => void;
24
+ createManagementConvergeCodex?: (config: Readonly<OcxConfig>) => ConvergeCodex;
25
+ /** Startup-health seam keeps route tests from launching platform probes. */
26
+ getCachedStartupHealth?: (config: Pick<OcxConfig, "codexAutoStart">) => Promise<StartupHealth>;
7
27
  /**
8
28
  * Persistence seam for route-level tests. Production leaves this unset and uses
9
29
  * `saveConfigPreservingClaudeCode`; tests that pass an in-memory fixture config
@@ -11,6 +31,28 @@ export interface ManagementApiDeps {
11
31
  * OPENCODEX_HOME (incident: devlog 260730.../070).
12
32
  */
13
33
  saveConfigPreservingClaudeCode?: (config: OcxConfig) => void;
34
+ /**
35
+ * Catalog seam for the Grok toggle (WP2, devlog 260803_integrations_toggle_all
36
+ * Rev 3 N2). Production leaves this unset and the route dynamic-imports the
37
+ * real one — a static import would close a cycle with management-api.ts.
38
+ * Tests stub it to orphan the fixture file mid-fetch (the r7 recheck test).
39
+ */
40
+ fetchAllModels?: (config: OcxConfig) => Promise<CatalogModel[]>;
41
+ /**
42
+ * Writer seam for the Grok toggle: lets a test place the file in any state
43
+ * between the pre-write recheck and the write itself (the r8 post-inspection
44
+ * tests). Production leaves this unset and uses the real writer.
45
+ */
46
+ injectGrokConfig?: typeof injectGrokConfig;
47
+ /** Desktop mutation seams keep route tests inside temporary config libraries. */
48
+ removeDesktop3pStandardPivot?: typeof removeDesktop3pStandardPivot;
49
+ writeDesktop3pConfig?: typeof writeDesktop3pConfig;
50
+ /**
51
+ * Runtime-state seam: the fence must name the host/port the RUNNING process
52
+ * bound (agent-settings-routes.ts:99-103 pattern), and a test must not depend
53
+ * on the developer's real runtime state file.
54
+ */
55
+ readRuntimePort?: (pid: number) => RuntimePortState | null;
14
56
  clearThreadAccountMap?: () => void;
15
57
  clearProviderQuotaCache?: () => void;
16
58
  primeCodexPoolQuotas?: (config: OcxConfig, reason: string) => Promise<void> | void;
@@ -18,6 +60,42 @@ export interface ManagementApiDeps {
18
60
  action: StartupInstallAction,
19
61
  options?: { repair?: boolean },
20
62
  ) => Promise<{ message: string }>;
63
+ /**
64
+ * Native-main profile persistence seam for server-boundary tests. Production
65
+ * leaves this unset, so the route creates its normal NativeProfileManager.
66
+ */
67
+ /**
68
+ * Codex app-server restart seam (devlog/_fin/260815_gui_codex_restart).
69
+ * Grouped rather than three separate fields: the route is an adapter over one
70
+ * service, and a route test that could not stub it would really terminate the
71
+ * developer's own Codex app-servers.
72
+ */
73
+ codexRestartService?: {
74
+ readState: typeof readCodexAppServerState;
75
+ performRestart: typeof performCodexRestart;
76
+ };
77
+ nativeProfileApi?: NativeProfileApiDeps;
78
+ /**
79
+ * Log Guard mutation seam. Production leaves this unset and therefore uses the
80
+ * owner-verified process enumerator, trusted L namespace and real config store.
81
+ * Route tests inject all three so they cannot depend on local Codex processes
82
+ * or create lock/config state outside the fixture.
83
+ */
84
+ codexLogGuardProtectionDeps?: CodexLogGuardProtectionDeps;
85
+ /**
86
+ * Log Guard maintenance seam. Production reuses the same fail-closed process
87
+ * enumerator and L namespace as Protect; route tests keep all maintenance
88
+ * state inside their temporary Codex home.
89
+ */
90
+ codexLogGuardMaintenanceDeps?: CodexLogGuardMaintenanceDeps;
91
+ /**
92
+ * Prompt-layer path seam. Production leaves this unset and
93
+ * `src/codex/prompt-layers.ts` resolves the real CODEX_HOME. A route test
94
+ * that could not inject paths would read AND WRITE the developer's live
95
+ * ~/.codex/config.toml — the same class of incident
96
+ * `saveConfigPreservingClaudeCode` above exists to prevent.
97
+ */
98
+ codexPromptPaths?: CodexPromptPaths;
21
99
  }
22
100
 
23
101
 
@@ -26,6 +104,15 @@ export interface ManagementContext {
26
104
  url: URL;
27
105
  config: OcxConfig;
28
106
  deps: ManagementApiDeps;
29
- refreshCodexCatalogBestEffort: () => Promise<void>;
107
+ /**
108
+ * Which credential authorized this request, resolved by the auth gate before
109
+ * dispatch. Routes that spend the USER's identity (not just the proxy's) must
110
+ * branch on this instead of on request headers: the admin token is readable by
111
+ * anything running as the user, so a token holder can forge any header a route
112
+ * might otherwise treat as browser evidence. Undefined only in direct-dispatch
113
+ * tests, which are treated as the untrusted `admin-token` case.
114
+ */
115
+ principal?: ManagementPrincipal;
116
+ convergeCodexCatalog: () => Promise<CatalogDisposition>;
30
117
  syncClaudeAgentDefsBestEffort: () => Promise<void>;
31
118
  }
@@ -0,0 +1,498 @@
1
+ /**
2
+ * Management routes for the client-integration toggle.
3
+ *
4
+ * This module is an HTTP adapter and nothing more: every policy decision —
5
+ * what counts as ownership, when a mutation is refused, what gets journaled —
6
+ * belongs to src/integrations/writer.ts. Duplicating any of it here is how the
7
+ * API and the writer would start disagreeing about what happened to a file.
8
+ *
9
+ * Design of record: devlog/_fin/260802_client_toggle_api/040_wp4_management_api.md.
10
+ */
11
+ import { readFileSync } from "node:fs";
12
+ import type { IntegrationIO } from "../../integrations/config-io";
13
+ import { matchesOperationResult } from "../../integrations/journal";
14
+ import {
15
+ INTEGRATION_CLIENT_IDS,
16
+ isIntegrationClientId,
17
+ type IntegrationClientId,
18
+ } from "../../integrations/registry";
19
+ import { readIntegrationState } from "../../integrations/state";
20
+ import { createIntegrationStateStore, type IntegrationStateStore } from "../../integrations/store";
21
+ import {
22
+ applyIntegrationCoordinated,
23
+ disableIntegrationCoordinated,
24
+ restoreIntegrationCoordinated,
25
+ type IntegrationRestoreInput,
26
+ type IntegrationWriteInput,
27
+ type WriteRefused,
28
+ } from "../../integrations/writer";
29
+ import { IntegrationWriterLockBusyError, type IntegrationWriterLockSeams } from "../../integrations/writer-lock";
30
+ import {
31
+ INTEGRATION_MUTATION_TERMINAL_MS,
32
+ IntegrationMutationBusyError,
33
+ runIntegrationMutationFlight,
34
+ setIntegrationMutationFlightTestHook,
35
+ } from "../../integrations/mutation-flight";
36
+ import { jsonResponse } from "../auth-cors";
37
+ import { readManagementJsonBody, rethrowManagementBodyTooLarge } from "./body";
38
+ import type { ManagementContext } from "./context";
39
+ import { loadExportModels } from "./model-rows";
40
+
41
+
42
+ const INTEGRATION_ROUTE_PREFIX = "/api/client-integrations/";
43
+ export { INTEGRATION_MUTATION_TERMINAL_MS };
44
+
45
+ type IntegrationStateRecord = Awaited<ReturnType<typeof readIntegrationState>>;
46
+ type ApplyResult = Awaited<ReturnType<typeof applyIntegrationCoordinated>>;
47
+ type DisableResult = Awaited<ReturnType<typeof disableIntegrationCoordinated>>;
48
+ type RestoreResult = Awaited<ReturnType<typeof restoreIntegrationCoordinated>>;
49
+
50
+ export type IntegrationStateEnvelope = {
51
+ clientId: IntegrationClientId;
52
+ } & IntegrationStateRecord;
53
+
54
+ export interface IntegrationStateListEnvelope {
55
+ clients: IntegrationStateEnvelope[];
56
+ }
57
+
58
+ export type IntegrationToggleEnvelope =
59
+ | ({ clientId: IntegrationClientId } & ApplyResult)
60
+ | ({ clientId: IntegrationClientId } & DisableResult);
61
+
62
+ export type IntegrationRestoreEnvelope = {
63
+ clientId: IntegrationClientId;
64
+ } & RestoreResult;
65
+
66
+ export interface IntegrationJournalEnvelope {
67
+ operations: IntegrationJournalRow[];
68
+ }
69
+
70
+ export interface IntegrationJournalRow {
71
+ opId: string;
72
+ clientId: IntegrationClientId;
73
+ kind: "apply" | "disable" | "refresh" | "restore";
74
+ at: string;
75
+ configPath: string;
76
+ snapshot: "none" | "stored" | "expired";
77
+ undoable: boolean;
78
+ }
79
+
80
+ export interface IntegrationToggleBody {
81
+ enabled: boolean;
82
+ }
83
+
84
+ export interface IntegrationRestoreBody {
85
+ opId: string;
86
+ confirmDrift?: boolean;
87
+ }
88
+
89
+ let integrationMutationTestHooks: {
90
+ io?: IntegrationIO;
91
+ lockSeams?: IntegrationWriterLockSeams;
92
+ /**
93
+ * Bind every read and write in the request to one store. Without this a
94
+ * route test could isolate the writer but not the journal listing or the
95
+ * restore preflight (A-gate round 12).
96
+ */
97
+ store?: IntegrationStateStore;
98
+ run?: (operation: () => Promise<unknown>) => Promise<unknown>;
99
+ } | null = null;
100
+
101
+ /**
102
+ * Home and environment overrides for tests.
103
+ *
104
+ * Bun's `os.homedir()` snapshots the real home at startup and ignores a later
105
+ * `process.env.HOME` assignment, so a test that only rewrites `HOME` still
106
+ * resolves the DEVELOPER'S client configs — which is exactly how a route test
107
+ * wrote a real `~/.hermes/config.yaml` during this work package. The writer
108
+ * and the state reader both already take `env`/`home` explicitly; the route
109
+ * simply had no way to pass them. It does now, and production leaves it unset.
110
+ */
111
+ let integrationPathTestHooks: { env?: NodeJS.ProcessEnv; home?: string } | null = null;
112
+
113
+ export function setIntegrationPathTestHooks(hooks: { env?: NodeJS.ProcessEnv; home?: string } | null): void {
114
+ integrationPathTestHooks = hooks;
115
+ }
116
+
117
+ /** The `env`/`home` overrides, spread into every registry-resolving call. */
118
+ function pathOverrides(): { env?: NodeJS.ProcessEnv; home?: string } {
119
+ return {
120
+ ...(integrationPathTestHooks?.env ? { env: integrationPathTestHooks.env } : {}),
121
+ ...(integrationPathTestHooks?.home ? { home: integrationPathTestHooks.home } : {}),
122
+ };
123
+ }
124
+
125
+ function isPlainRecord(value: unknown): value is Record<string, unknown> {
126
+ return typeof value === "object" && value !== null && !Array.isArray(value);
127
+ }
128
+
129
+ function decodeClientPath(pathname: string): string | null {
130
+ if (!pathname.startsWith(INTEGRATION_ROUTE_PREFIX)) return null;
131
+ const encoded = pathname.slice(INTEGRATION_ROUTE_PREFIX.length);
132
+ if (!encoded || encoded.includes("/")) return null;
133
+ try {
134
+ return decodeURIComponent(encoded);
135
+ } catch {
136
+ return encoded;
137
+ }
138
+ }
139
+
140
+ export function setIntegrationMutationFlightTestHooks(
141
+ hooks: {
142
+ io?: IntegrationIO;
143
+ lockSeams?: IntegrationWriterLockSeams;
144
+ /** Binds the WHOLE request — reads, writes and journal — to one store. */
145
+ store?: IntegrationStateStore;
146
+ run?: (operation: () => Promise<unknown>) => Promise<unknown>;
147
+ } | null,
148
+ ): void {
149
+ integrationMutationTestHooks = hooks;
150
+ setIntegrationMutationFlightTestHook(hooks?.run ?? null);
151
+ // Path overrides are part of the same isolation contract: clearing flights
152
+ // while leaving a temp home bound would let the next suite write real files.
153
+ if (hooks === null) integrationPathTestHooks = null;
154
+ }
155
+
156
+ /**
157
+ * ONE store per request, used by every read and every write in that request.
158
+ * The route previously called module-level `listOperations`/`readSnapshot`
159
+ * while handing the writer a separate default store, so a test could not bind
160
+ * the whole operation to a temp root (A-gate round 12).
161
+ */
162
+ function integrationStore(): IntegrationStateStore {
163
+ return integrationMutationTestHooks?.store ?? createIntegrationStateStore();
164
+ }
165
+
166
+ async function buildIntegrationWriteInput(
167
+ clientId: IntegrationClientId,
168
+ ctx: ManagementContext,
169
+ store: IntegrationStateStore,
170
+ ): Promise<IntegrationWriteInput> {
171
+ return {
172
+ clientId,
173
+ models: await loadExportModels(ctx.config),
174
+ config: ctx.config,
175
+ port: Number(ctx.url.port) || ctx.config.port,
176
+ store,
177
+ io: integrationMutationTestHooks?.io,
178
+ ...pathOverrides(),
179
+ };
180
+ }
181
+
182
+ /**
183
+ * The file's current bytes, or `null` when it is missing.
184
+ *
185
+ * `null` is NOT the same as `""`: an absent file and an empty one are
186
+ * different states, and collapsing them is what made this route disagree with
187
+ * the writer about whether an absence-result operation had drifted.
188
+ * `undefined` means we could not read it at all, which is neither.
189
+ */
190
+ function currentConfigText(configPath: string): string | null | undefined {
191
+ try {
192
+ return readFileSync(configPath, "utf8");
193
+ } catch (error) {
194
+ if (isPlainRecord(error) && error.code === "ENOENT") return null;
195
+ return undefined;
196
+ }
197
+ }
198
+
199
+ function invalidClientResponse(ctx: ManagementContext): Response {
200
+ return jsonResponse({
201
+ error: "invalid integration client",
202
+ code: "invalid_integration_client",
203
+ validClients: INTEGRATION_CLIENT_IDS,
204
+ }, 400, ctx.req, ctx.config);
205
+ }
206
+
207
+ function internalErrorResponse(error: unknown, ctx: ManagementContext): Response {
208
+ return jsonResponse({
209
+ error: error instanceof Error ? error.message : String(error),
210
+ code: "integration_internal_error",
211
+ }, 500, ctx.req, ctx.config);
212
+ }
213
+
214
+ async function readJsonBody(ctx: ManagementContext): Promise<unknown | Response> {
215
+ try {
216
+ return await readManagementJsonBody(ctx.req);
217
+ } catch (error) {
218
+ rethrowManagementBodyTooLarge(error);
219
+ return jsonResponse({
220
+ error: "invalid JSON body",
221
+ code: "invalid_json_body",
222
+ }, 400, ctx.req, ctx.config);
223
+ }
224
+ }
225
+
226
+ function writerFailureResponse(
227
+ clientId: IntegrationClientId,
228
+ /*
229
+ * The writer's own refusal type, not a structural echo of it.
230
+ *
231
+ * A local shape with an optional `message` accepted a refusal that had lost
232
+ * its message on the way here, which is exactly how the drift branch shipped
233
+ * without one. `WriteRefused` requires it, so the compiler now objects.
234
+ */
235
+ result: WriteRefused,
236
+ ctx: ManagementContext,
237
+ ): Response {
238
+ /*
239
+ * Routed by `reason`, never by `state` (006 §5). A `write_failed` that
240
+ * happens to occur while the file is in a `conflict` state is still a write
241
+ * failure, and mapping on state first silently dropped its message,
242
+ * snapshotPath, and residual — the recovery information the flag exists to
243
+ * carry (A-gate round 5, blocker 3).
244
+ */
245
+ const recovery = {
246
+ message: result.message,
247
+ ...(result.snapshotPath ? { snapshotPath: result.snapshotPath } : {}),
248
+ ...(result.residual ? { residual: true } : {}),
249
+ };
250
+
251
+ if (result.reason === "unsafe") {
252
+ return jsonResponse({
253
+ error: "integration config is unsafe",
254
+ code: "integration_unsafe",
255
+ clientId, state: result.state, reason: result.reason, ...recovery,
256
+ }, 409, ctx.req, ctx.config);
257
+ }
258
+ if (result.reason === "conflict") {
259
+ return jsonResponse({
260
+ error: "integration config conflicts with ownership record",
261
+ code: "integration_conflict",
262
+ clientId, state: result.state, reason: result.reason, ...recovery,
263
+ }, 409, ctx.req, ctx.config);
264
+ }
265
+ if (result.reason === "drift_requires_confirm") {
266
+ return jsonResponse({
267
+ error: "restore requires drift confirmation",
268
+ code: "integration_drift_confirmation_required",
269
+ clientId, state: result.state, reason: result.reason, ...recovery,
270
+ }, 409, ctx.req, ctx.config);
271
+ }
272
+ if (result.reason === "snapshot_expired") {
273
+ return jsonResponse({
274
+ error: "integration snapshot expired",
275
+ code: "integration_snapshot_expired",
276
+ clientId, state: result.state, reason: result.reason, ...recovery,
277
+ }, 410, ctx.req, ctx.config);
278
+ }
279
+ // not_installed, non_loopback, write_failed — always carry recovery fields.
280
+ return jsonResponse({
281
+ error: "integration mutation failed",
282
+ code: "integration_mutation_failed",
283
+ clientId, state: result.state, reason: result.reason, ...recovery,
284
+ }, 500, ctx.req, ctx.config);
285
+ }
286
+
287
+ export async function handleIntegrationRoutes(ctx: ManagementContext): Promise<Response | null> {
288
+ const { req, url } = ctx;
289
+
290
+ if (url.pathname === "/api/client-integrations" && req.method === "GET") {
291
+ try {
292
+ const models = await loadExportModels(ctx.config);
293
+ const port = Number(url.port) || ctx.config.port;
294
+ // One store for the whole collection read: without it this route retried
295
+ // maintenance and counted snapshots in the default store even when the
296
+ // caller had bound everything else to a temp root (A-gate round 13).
297
+ const store = integrationStore();
298
+ /*
299
+ * The envelope carries `clientId`, but it is not restated here: WP2 and
300
+ * WP3 both echo `input.clientId` back in their result, and `input`
301
+ * IS this route's client. Writing it twice made the compiler pick the
302
+ * later one silently — a duplicate that could only ever hide a
303
+ * disagreement, never surface it.
304
+ */
305
+ const clients = INTEGRATION_CLIENT_IDS.map(clientId =>
306
+ readIntegrationState({ clientId, models, config: ctx.config, port, store, ...pathOverrides() }));
307
+ return jsonResponse({ clients } satisfies IntegrationStateListEnvelope, 200, req, ctx.config);
308
+ } catch (error) {
309
+ return internalErrorResponse(error, ctx);
310
+ }
311
+ }
312
+
313
+ if (url.pathname === "/api/client-integrations/journal") {
314
+ if (req.method !== "GET") return null;
315
+ const requestedClient = url.searchParams.get("client");
316
+ if (requestedClient !== null && !isIntegrationClientId(requestedClient)) {
317
+ return invalidClientResponse(ctx);
318
+ }
319
+ try {
320
+ const store = integrationStore();
321
+ const storedOperations = store.listOperations(requestedClient ?? undefined);
322
+ const newestByClient = new Map<IntegrationClientId, string>();
323
+ for (const operation of storedOperations) {
324
+ if (!newestByClient.has(operation.clientId)) {
325
+ newestByClient.set(operation.clientId, operation.opId);
326
+ }
327
+ }
328
+ const operations: IntegrationJournalRow[] = storedOperations.map(operation => {
329
+ /*
330
+ * Resolved against the DISK, not read off the row.
331
+ *
332
+ * Retention deletes snapshot files and deliberately leaves the row's
333
+ * persisted tag saying `stored`, so copying that tag advertised undo
334
+ * for bytes that no longer exist — the GUI would offer the button and
335
+ * the restore route would answer 410. `readSnapshot` is the same
336
+ * resolver that preflight uses, which is what keeps the two agreeing.
337
+ */
338
+ const snapshot = store.readSnapshot(operation).kind;
339
+ return {
340
+ opId: operation.opId,
341
+ clientId: operation.clientId,
342
+ kind: operation.kind,
343
+ at: operation.at,
344
+ configPath: operation.configPath,
345
+ snapshot,
346
+ /*
347
+ * The SAME resolution decides `undoable`. Reporting the tag honestly
348
+ * and then offering undo anyway is the identical defect one field
349
+ * over: restore would answer 410 for a row the GUI drew a button on.
350
+ * `none` stays undoable — restoring an op that created a file means
351
+ * deleting it, and that needs no snapshot bytes.
352
+ */
353
+ /*
354
+ * Eligibility goes through the SAME matcher restore uses. This route
355
+ * used to represent a missing file as `""` and call that a match,
356
+ * while restore hashed `""` into a real digest — so the row was
357
+ * offered as Undo and then refused as drift.
358
+ */
359
+ undoable: (() => {
360
+ if (snapshot === "expired") return false;
361
+ if (newestByClient.get(operation.clientId) !== operation.opId) return false;
362
+ const current = currentConfigText(operation.configPath);
363
+ return current === undefined ? false : matchesOperationResult(operation, current);
364
+ })(),
365
+ };
366
+ });
367
+ return jsonResponse({ operations } satisfies IntegrationJournalEnvelope, 200, req, ctx.config);
368
+ } catch (error) {
369
+ return internalErrorResponse(error, ctx);
370
+ }
371
+ }
372
+
373
+ if (url.pathname === "/api/client-integrations/restore") {
374
+ if (req.method !== "POST") return null;
375
+ const parsed = await readJsonBody(ctx);
376
+ if (parsed instanceof Response) return parsed;
377
+ if (!isPlainRecord(parsed) || typeof parsed.opId !== "string" || parsed.opId.trim().length === 0) {
378
+ return jsonResponse({
379
+ error: "opId must be a non-empty string",
380
+ code: "invalid_op_id",
381
+ }, 400, req, ctx.config);
382
+ }
383
+ if (parsed.confirmDrift !== undefined && typeof parsed.confirmDrift !== "boolean") {
384
+ return jsonResponse({
385
+ error: "confirmDrift must be a boolean",
386
+ code: "invalid_confirm_drift",
387
+ }, 400, req, ctx.config);
388
+ }
389
+
390
+ const opId = parsed.opId.trim();
391
+ const confirmDrift = parsed.confirmDrift ?? false;
392
+ let restoreClientId: IntegrationClientId | undefined;
393
+ try {
394
+ const store = integrationStore();
395
+ const operation = store.findOperation(opId);
396
+ if (!operation) {
397
+ return jsonResponse({
398
+ error: "integration operation not found",
399
+ code: "integration_operation_not_found",
400
+ opId,
401
+ }, 404, req, ctx.config);
402
+ }
403
+ restoreClientId = operation.clientId;
404
+ const snapshot = store.readSnapshot(operation);
405
+ if (snapshot.kind === "expired") {
406
+ return jsonResponse({
407
+ error: "integration snapshot expired",
408
+ code: "integration_snapshot_expired",
409
+ opId,
410
+ }, 410, req, ctx.config);
411
+ }
412
+
413
+ const writeInput = await buildIntegrationWriteInput(operation.clientId, ctx, store);
414
+ const restoreInput: IntegrationRestoreInput = {
415
+ ...writeInput,
416
+ opId,
417
+ confirmDrift,
418
+ };
419
+ const result = await runIntegrationMutationFlight(
420
+ operation.clientId,
421
+ `restore:${opId}:${confirmDrift}`,
422
+ writeInput.io?.now ?? Date.now,
423
+ () => restoreIntegrationCoordinated(restoreInput, {
424
+ lockSeams: integrationMutationTestHooks?.lockSeams,
425
+ }),
426
+ );
427
+ if (!result.ok) {
428
+ /*
429
+ * Drift is NOT special-cased here.
430
+ *
431
+ * It used to be, and the hand-written branch dropped the writer's
432
+ * `message` — which is the only thing that tells the user WHICH file
433
+ * drifted and where its backup went. Every refusal leaves through the
434
+ * one serializer, so a refusal cannot lose its recovery fields by
435
+ * being routed through a shorter path.
436
+ */
437
+ return writerFailureResponse(operation.clientId, result, ctx);
438
+ }
439
+ return jsonResponse(result satisfies IntegrationRestoreEnvelope, 200, req, ctx.config);
440
+ } catch (error) {
441
+ if (error instanceof IntegrationMutationBusyError || error instanceof IntegrationWriterLockBusyError) {
442
+ return jsonResponse({
443
+ error: "integration mutation busy",
444
+ code: "integration_mutation_busy",
445
+ clientId: restoreClientId ?? (error instanceof IntegrationMutationBusyError ? error.clientId : undefined),
446
+ }, 409, req, ctx.config);
447
+ }
448
+ return internalErrorResponse(error, ctx);
449
+ }
450
+ }
451
+
452
+ if (req.method !== "GET" && req.method !== "PUT") return null;
453
+ const requestedClient = decodeClientPath(url.pathname);
454
+ if (requestedClient === null) return null;
455
+ if (!isIntegrationClientId(requestedClient)) return invalidClientResponse(ctx);
456
+
457
+ if (req.method === "GET") {
458
+ try {
459
+ const input = await buildIntegrationWriteInput(requestedClient, ctx, integrationStore());
460
+ const state = readIntegrationState(input);
461
+ return jsonResponse(state satisfies IntegrationStateEnvelope, 200, req, ctx.config);
462
+ } catch (error) {
463
+ return internalErrorResponse(error, ctx);
464
+ }
465
+ }
466
+
467
+ const parsed = await readJsonBody(ctx);
468
+ if (parsed instanceof Response) return parsed;
469
+ if (!isPlainRecord(parsed) || typeof parsed.enabled !== "boolean") {
470
+ return jsonResponse({
471
+ error: "enabled must be a boolean",
472
+ code: "invalid_enabled",
473
+ }, 400, req, ctx.config);
474
+ }
475
+
476
+ try {
477
+ const input = await buildIntegrationWriteInput(requestedClient, ctx, integrationStore());
478
+ const result = await runIntegrationMutationFlight(
479
+ requestedClient,
480
+ parsed.enabled ? "apply" : "disable",
481
+ input.io?.now ?? Date.now,
482
+ () => parsed.enabled
483
+ ? applyIntegrationCoordinated(input, { lockSeams: integrationMutationTestHooks?.lockSeams })
484
+ : disableIntegrationCoordinated(input, { lockSeams: integrationMutationTestHooks?.lockSeams }),
485
+ );
486
+ if (!result.ok) return writerFailureResponse(requestedClient, result, ctx);
487
+ return jsonResponse(result satisfies IntegrationToggleEnvelope, 200, req, ctx.config);
488
+ } catch (error) {
489
+ if (error instanceof IntegrationMutationBusyError || error instanceof IntegrationWriterLockBusyError) {
490
+ return jsonResponse({
491
+ error: "integration mutation busy",
492
+ code: "integration_mutation_busy",
493
+ clientId: requestedClient,
494
+ }, 409, req, ctx.config);
495
+ }
496
+ return internalErrorResponse(error, ctx);
497
+ }
498
+ }