@yansigit/opencodex 2.31.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (826) hide show
  1. package/AGENTS_INSTALL.md +109 -0
  2. package/LICENSE +21 -0
  3. package/README.md +303 -0
  4. package/assets/architecture.png +0 -0
  5. package/assets/banner.png +0 -0
  6. package/assets/claude-code-models.gif +0 -0
  7. package/assets/codex-app-picker.png +0 -0
  8. package/bin/ocx.mjs +587 -0
  9. package/bin/package-main.mjs +9 -0
  10. package/gui/dist/assets/index-BNJ7r4Gd.js +102 -0
  11. package/gui/dist/assets/index-CGoDO3uO.css +1 -0
  12. package/gui/dist/favicon.png +0 -0
  13. package/gui/dist/icons.svg +24 -0
  14. package/gui/dist/index.html +25 -0
  15. package/gui/dist/logo.png +0 -0
  16. package/gui/dist/provider-icons/alibaba-color.svg +1 -0
  17. package/gui/dist/provider-icons/antigravity-color.svg +1 -0
  18. package/gui/dist/provider-icons/claude-color.svg +1 -0
  19. package/gui/dist/provider-icons/cline-color.svg +16 -0
  20. package/gui/dist/provider-icons/cloudflare-ai-gateway-color.svg +1 -0
  21. package/gui/dist/provider-icons/commandcode-color.svg +1 -0
  22. package/gui/dist/provider-icons/copilot-color.svg +1 -0
  23. package/gui/dist/provider-icons/cursor-color.svg +2 -0
  24. package/gui/dist/provider-icons/deepseek-color.svg +1 -0
  25. package/gui/dist/provider-icons/discord.svg +1 -0
  26. package/gui/dist/provider-icons/firepass-color.svg +1 -0
  27. package/gui/dist/provider-icons/fireworks-color.svg +1 -0
  28. package/gui/dist/provider-icons/gemini-color.svg +1 -0
  29. package/gui/dist/provider-icons/github-copilot-color.svg +1 -0
  30. package/gui/dist/provider-icons/gitlab-duo-color.svg +1 -0
  31. package/gui/dist/provider-icons/grok.svg +1 -0
  32. package/gui/dist/provider-icons/groq-color.svg +1 -0
  33. package/gui/dist/provider-icons/huggingface-color.svg +1 -0
  34. package/gui/dist/provider-icons/kimi-color.svg +1 -0
  35. package/gui/dist/provider-icons/kiro-color.svg +15 -0
  36. package/gui/dist/provider-icons/lm-studio-color.svg +1 -0
  37. package/gui/dist/provider-icons/mistral-color.svg +1 -0
  38. package/gui/dist/provider-icons/moonshot-color.svg +1 -0
  39. package/gui/dist/provider-icons/nvidia-color.svg +1 -0
  40. package/gui/dist/provider-icons/ollama-color.svg +1 -0
  41. package/gui/dist/provider-icons/openai.svg +1 -0
  42. package/gui/dist/provider-icons/opencode.svg +2 -0
  43. package/gui/dist/provider-icons/openrouter-color.svg +1 -0
  44. package/gui/dist/provider-icons/pi.svg +21 -0
  45. package/gui/dist/provider-icons/qianfan-color.svg +1 -0
  46. package/gui/dist/provider-icons/qwen-portal-color.svg +1 -0
  47. package/gui/dist/provider-icons/telegram.svg +1 -0
  48. package/gui/dist/provider-icons/vercel-ai-gateway-color.svg +1 -0
  49. package/gui/dist/provider-icons/vllm-color.svg +1 -0
  50. package/gui/dist/provider-icons/xiaomi-color.svg +1 -0
  51. package/package.json +108 -0
  52. package/src/AGENTS.md +28 -0
  53. package/src/adapters/anthropic-image-guard.ts +251 -0
  54. package/src/adapters/anthropic-image-normalize.ts +518 -0
  55. package/src/adapters/anthropic-output-schema.ts +137 -0
  56. package/src/adapters/anthropic.ts +1327 -0
  57. package/src/adapters/azure.ts +36 -0
  58. package/src/adapters/base.ts +121 -0
  59. package/src/adapters/client-fingerprint.ts +65 -0
  60. package/src/adapters/cline-pass-deepseek-v4-tool-replay.ts +69 -0
  61. package/src/adapters/command-code.ts +601 -0
  62. package/src/adapters/cursor/arg-codec.ts +38 -0
  63. package/src/adapters/cursor/arg-normalize.ts +104 -0
  64. package/src/adapters/cursor/checkpoint-store.ts +303 -0
  65. package/src/adapters/cursor/cursor-errors.ts +288 -0
  66. package/src/adapters/cursor/discovery.ts +333 -0
  67. package/src/adapters/cursor/effort-map.ts +151 -0
  68. package/src/adapters/cursor/exec-policy.ts +88 -0
  69. package/src/adapters/cursor/framing.ts +250 -0
  70. package/src/adapters/cursor/gen/agent_pb.ts +15274 -0
  71. package/src/adapters/cursor/h2-pool.ts +123 -0
  72. package/src/adapters/cursor/http1-bidi.ts +361 -0
  73. package/src/adapters/cursor/images.ts +704 -0
  74. package/src/adapters/cursor/kv-store.ts +52 -0
  75. package/src/adapters/cursor/live-models.ts +269 -0
  76. package/src/adapters/cursor/live-smoke-gate.ts +41 -0
  77. package/src/adapters/cursor/live-transport.ts +1653 -0
  78. package/src/adapters/cursor/mcp-config.ts +42 -0
  79. package/src/adapters/cursor/mcp-manager.ts +333 -0
  80. package/src/adapters/cursor/message-mapper.ts +49 -0
  81. package/src/adapters/cursor/native-exec-common.ts +76 -0
  82. package/src/adapters/cursor/native-exec-desktop.ts +184 -0
  83. package/src/adapters/cursor/native-exec-fs.ts +332 -0
  84. package/src/adapters/cursor/native-exec-mcp.ts +153 -0
  85. package/src/adapters/cursor/native-exec-network.ts +43 -0
  86. package/src/adapters/cursor/native-exec-shell.ts +547 -0
  87. package/src/adapters/cursor/native-exec-tools.ts +118 -0
  88. package/src/adapters/cursor/native-exec.ts +663 -0
  89. package/src/adapters/cursor/protobuf-events.ts +1381 -0
  90. package/src/adapters/cursor/protobuf-request.ts +1032 -0
  91. package/src/adapters/cursor/request-builder.ts +461 -0
  92. package/src/adapters/cursor/thread-continuity.ts +67 -0
  93. package/src/adapters/cursor/tool-definitions.ts +735 -0
  94. package/src/adapters/cursor/tool-result-normalize.ts +92 -0
  95. package/src/adapters/cursor/transport-retry.ts +132 -0
  96. package/src/adapters/cursor/transport.ts +79 -0
  97. package/src/adapters/cursor/types.ts +79 -0
  98. package/src/adapters/cursor.ts +322 -0
  99. package/src/adapters/google-antigravity-hosts.ts +48 -0
  100. package/src/adapters/google-antigravity-replay.ts +827 -0
  101. package/src/adapters/google-antigravity-tools.ts +105 -0
  102. package/src/adapters/google-antigravity-wire.ts +141 -0
  103. package/src/adapters/google-errors.ts +92 -0
  104. package/src/adapters/google-http.ts +460 -0
  105. package/src/adapters/google-tool-schema.ts +238 -0
  106. package/src/adapters/google-truncation.ts +24 -0
  107. package/src/adapters/google-wire-compiler.ts +232 -0
  108. package/src/adapters/google.ts +1377 -0
  109. package/src/adapters/identity.ts +77 -0
  110. package/src/adapters/image.ts +23 -0
  111. package/src/adapters/kiro-constants.ts +16 -0
  112. package/src/adapters/kiro-errors.ts +208 -0
  113. package/src/adapters/kiro-events.ts +197 -0
  114. package/src/adapters/kiro-images.ts +129 -0
  115. package/src/adapters/kiro-retry.ts +312 -0
  116. package/src/adapters/kiro-thinking.ts +112 -0
  117. package/src/adapters/kiro-tool-fallback.ts +36 -0
  118. package/src/adapters/kiro-tools.ts +224 -0
  119. package/src/adapters/kiro-truncation.ts +33 -0
  120. package/src/adapters/kiro-wire.ts +129 -0
  121. package/src/adapters/kiro.ts +1936 -0
  122. package/src/adapters/mimo-free.ts +280 -0
  123. package/src/adapters/openai-chat-url.ts +11 -0
  124. package/src/adapters/openai-chat.ts +1980 -0
  125. package/src/adapters/openai-responses-url.ts +16 -0
  126. package/src/adapters/openai-responses.ts +1911 -0
  127. package/src/adapters/registry.ts +175 -0
  128. package/src/adapters/responses-tool-schema.ts +67 -0
  129. package/src/adapters/run-turn-queue.ts +114 -0
  130. package/src/adapters/tool-call-id.ts +119 -0
  131. package/src/adapters/tool-catalog-nudge.ts +154 -0
  132. package/src/adapters/upstream-http-error.ts +48 -0
  133. package/src/adapters/xai-web-search.ts +185 -0
  134. package/src/bridge.ts +1986 -0
  135. package/src/chat/inbound.ts +319 -0
  136. package/src/chat/outbound.ts +821 -0
  137. package/src/claude/agents-inject.ts +266 -0
  138. package/src/claude/alias.ts +149 -0
  139. package/src/claude/auth-detect.ts +229 -0
  140. package/src/claude/auth-mode-migration.ts +32 -0
  141. package/src/claude/auth-mode.ts +62 -0
  142. package/src/claude/context-windows.ts +205 -0
  143. package/src/claude/desktop-3p-guard.ts +35 -0
  144. package/src/claude/desktop-3p-paths.ts +84 -0
  145. package/src/claude/desktop-3p.ts +615 -0
  146. package/src/claude/desktop-health.ts +26 -0
  147. package/src/claude/desktop-profile.ts +263 -0
  148. package/src/claude/gateway-cache.ts +107 -0
  149. package/src/claude/inbound-debug.ts +163 -0
  150. package/src/claude/inbound.ts +578 -0
  151. package/src/claude/model-info.ts +174 -0
  152. package/src/claude/outbound.ts +926 -0
  153. package/src/cli/access.ts +108 -0
  154. package/src/cli/account-api.ts +302 -0
  155. package/src/cli/account-auth.ts +250 -0
  156. package/src/cli/account-catalog-refresh.ts +14 -0
  157. package/src/cli/account-extended.ts +737 -0
  158. package/src/cli/account-main.ts +317 -0
  159. package/src/cli/account.ts +299 -0
  160. package/src/cli/agent-driven.ts +70 -0
  161. package/src/cli/agent.ts +290 -0
  162. package/src/cli/catalog-prewarm.ts +27 -0
  163. package/src/cli/claude-agent-startup-sync.ts +73 -0
  164. package/src/cli/claude-desktop.ts +213 -0
  165. package/src/cli/claude.ts +355 -0
  166. package/src/cli/codex-log-guard-doctor.ts +103 -0
  167. package/src/cli/codex-shim-autorestore.ts +47 -0
  168. package/src/cli/codex-shim-readiness.ts +76 -0
  169. package/src/cli/combo.ts +127 -0
  170. package/src/cli/config-command.ts +209 -0
  171. package/src/cli/debug.ts +228 -0
  172. package/src/cli/dispatch.ts +585 -0
  173. package/src/cli/doctor.ts +1202 -0
  174. package/src/cli/ensure-desired-integrations.ts +152 -0
  175. package/src/cli/export-command.ts +213 -0
  176. package/src/cli/help.ts +101 -0
  177. package/src/cli/index.ts +973 -0
  178. package/src/cli/init.ts +211 -0
  179. package/src/cli/integrations.ts +260 -0
  180. package/src/cli/interactive-confirm.ts +133 -0
  181. package/src/cli/lab.ts +607 -0
  182. package/src/cli/launcher-context.ts +77 -0
  183. package/src/cli/minimax.ts +497 -0
  184. package/src/cli/models-runtime.ts +245 -0
  185. package/src/cli/models.ts +422 -0
  186. package/src/cli/observe.ts +206 -0
  187. package/src/cli/opencode.ts +588 -0
  188. package/src/cli/provider-replit.ts +232 -0
  189. package/src/cli/provider-runtime.ts +179 -0
  190. package/src/cli/provider.ts +492 -0
  191. package/src/cli/ready.ts +301 -0
  192. package/src/cli/registry.ts +422 -0
  193. package/src/cli/replit-gateway-key-input.ts +138 -0
  194. package/src/cli/root.ts +86 -0
  195. package/src/cli/route-policy.ts +92 -0
  196. package/src/cli/runtime-api.ts +328 -0
  197. package/src/cli/star-prompt.ts +211 -0
  198. package/src/cli/status-oauth.ts +78 -0
  199. package/src/cli/status.ts +328 -0
  200. package/src/cli/system-command.ts +112 -0
  201. package/src/cli/system-restart-client.ts +146 -0
  202. package/src/cli/tray-proxy.ts +199 -0
  203. package/src/cli/v2.ts +268 -0
  204. package/src/cli.ts +10 -0
  205. package/src/clients/config-export.ts +1704 -0
  206. package/src/codex/account-id.ts +34 -0
  207. package/src/codex/account-label.ts +47 -0
  208. package/src/codex/account-lifecycle.ts +172 -0
  209. package/src/codex/account-namespace-match.ts +63 -0
  210. package/src/codex/account-namespaces.ts +195 -0
  211. package/src/codex/account-pause.ts +20 -0
  212. package/src/codex/account-priority.ts +83 -0
  213. package/src/codex/account-runtime-state.ts +31 -0
  214. package/src/codex/account-store.ts +544 -0
  215. package/src/codex/account-usability.ts +43 -0
  216. package/src/codex/admission.ts +256 -0
  217. package/src/codex/affinity-debug.ts +162 -0
  218. package/src/codex/agent-roles-sync.ts +225 -0
  219. package/src/codex/agent-roles.ts +238 -0
  220. package/src/codex/app-server-processes.ts +1143 -0
  221. package/src/codex/app-server-restart-service.ts +232 -0
  222. package/src/codex/auth-api.ts +2147 -0
  223. package/src/codex/auth-collision.ts +109 -0
  224. package/src/codex/auth-context.ts +665 -0
  225. package/src/codex/autostart-health.ts +156 -0
  226. package/src/codex/catalog/account-models.ts +67 -0
  227. package/src/codex/catalog/aggregation.ts +436 -0
  228. package/src/codex/catalog/bundled.ts +549 -0
  229. package/src/codex/catalog/effort.ts +446 -0
  230. package/src/codex/catalog/filesystem-evidence.ts +302 -0
  231. package/src/codex/catalog/kinds.ts +2 -0
  232. package/src/codex/catalog/metadata.ts +664 -0
  233. package/src/codex/catalog/native-models.ts +72 -0
  234. package/src/codex/catalog/parsing.ts +650 -0
  235. package/src/codex/catalog/provider-fetch.ts +2064 -0
  236. package/src/codex/catalog/sync.ts +1883 -0
  237. package/src/codex/catalog-admission.ts +199 -0
  238. package/src/codex/catalog-refresh-status.ts +105 -0
  239. package/src/codex/catalog-write-serialization.ts +242 -0
  240. package/src/codex/catalog.ts +14 -0
  241. package/src/codex/codex-write-lock.ts +384 -0
  242. package/src/codex/convergence-types.ts +614 -0
  243. package/src/codex/convergence.ts +651 -0
  244. package/src/codex/coordinator-doctor.ts +332 -0
  245. package/src/codex/custom-model-catalog-migration.ts +176 -0
  246. package/src/codex/data/upstream-models.json +830 -0
  247. package/src/codex/desired-state.ts +230 -0
  248. package/src/codex/exec-invocation.ts +22 -0
  249. package/src/codex/features.ts +1566 -0
  250. package/src/codex/generation.ts +202 -0
  251. package/src/codex/history-job.ts +407 -0
  252. package/src/codex/history-lock.ts +242 -0
  253. package/src/codex/history-migration-guardian.ts +108 -0
  254. package/src/codex/history-provider.ts +979 -0
  255. package/src/codex/history-transition.ts +105 -0
  256. package/src/codex/history-worker.ts +220 -0
  257. package/src/codex/home.ts +206 -0
  258. package/src/codex/inject-coordination.ts +290 -0
  259. package/src/codex/inject.ts +1733 -0
  260. package/src/codex/injected-marker.ts +106 -0
  261. package/src/codex/integration-record.ts +266 -0
  262. package/src/codex/internal/catalog-writer.ts +203 -0
  263. package/src/codex/internal/history-writer.ts +80 -0
  264. package/src/codex/journal.ts +225 -0
  265. package/src/codex/log-guard/inspect.ts +506 -0
  266. package/src/codex/log-guard/lock.ts +150 -0
  267. package/src/codex/log-guard/maintenance.ts +403 -0
  268. package/src/codex/log-guard/path-safety.ts +88 -0
  269. package/src/codex/log-guard/policy.ts +44 -0
  270. package/src/codex/log-guard/processes.ts +205 -0
  271. package/src/codex/log-guard/protection.ts +489 -0
  272. package/src/codex/log-guard/sqlite-errors.ts +9 -0
  273. package/src/codex/main-account-cache.ts +56 -0
  274. package/src/codex/main-account.ts +68 -0
  275. package/src/codex/management-convergence.ts +167 -0
  276. package/src/codex/model-cache.ts +273 -0
  277. package/src/codex/model-entitlements.ts +353 -0
  278. package/src/codex/native-main-admission.ts +47 -0
  279. package/src/codex/native-main-auth-temp.ts +187 -0
  280. package/src/codex/native-main-claim.ts +178 -0
  281. package/src/codex/native-main-lock-file.ts +162 -0
  282. package/src/codex/native-main-owner.ts +329 -0
  283. package/src/codex/native-profile-api.ts +247 -0
  284. package/src/codex/native-profile-manager.ts +1531 -0
  285. package/src/codex/native-profile-processes.ts +121 -0
  286. package/src/codex/native-profile-recovery.ts +99 -0
  287. package/src/codex/native-profile-stage-store.ts +387 -0
  288. package/src/codex/native-profile-startup.ts +492 -0
  289. package/src/codex/native-profile-store.ts +855 -0
  290. package/src/codex/native-profile-types.ts +120 -0
  291. package/src/codex/native-residue.ts +682 -0
  292. package/src/codex/paths.ts +144 -0
  293. package/src/codex/plan-from-token.ts +140 -0
  294. package/src/codex/plan.ts +40 -0
  295. package/src/codex/plugins-doctor.ts +242 -0
  296. package/src/codex/pool-rotation.ts +295 -0
  297. package/src/codex/project-config-warnings.ts +425 -0
  298. package/src/codex/prompt-journal.ts +352 -0
  299. package/src/codex/prompt-layers.ts +967 -0
  300. package/src/codex/prompt-lock.ts +143 -0
  301. package/src/codex/quota-rejection.ts +298 -0
  302. package/src/codex/quota.ts +573 -0
  303. package/src/codex/refresh.ts +62 -0
  304. package/src/codex/reset-credit-recovery.ts +1044 -0
  305. package/src/codex/routing.ts +1888 -0
  306. package/src/codex/runtime.ts +659 -0
  307. package/src/codex/shim.ts +2170 -0
  308. package/src/codex/subagent-defaults.ts +550 -0
  309. package/src/codex/subagent-model-fallback.ts +784 -0
  310. package/src/codex/sync.ts +319 -0
  311. package/src/codex/transition-state.ts +612 -0
  312. package/src/codex/upstream-host-health.ts +368 -0
  313. package/src/codex/user-identity.ts +557 -0
  314. package/src/codex/warmup.ts +298 -0
  315. package/src/codex/websocket-registry.ts +100 -0
  316. package/src/codex/write-coordination.ts +114 -0
  317. package/src/combos/failover.ts +160 -0
  318. package/src/combos/index.ts +45 -0
  319. package/src/combos/request.ts +94 -0
  320. package/src/combos/resolve.ts +232 -0
  321. package/src/combos/types.ts +398 -0
  322. package/src/config/provider-name.ts +24 -0
  323. package/src/config.ts +4041 -0
  324. package/src/fork/register.ts +3 -0
  325. package/src/generated/compatibility-version.json +3116 -0
  326. package/src/generated/model-metadata.ts +106 -0
  327. package/src/github/star-state.ts +203 -0
  328. package/src/grok/inject.ts +530 -0
  329. package/src/grok/inspect.ts +45 -0
  330. package/src/grok/status.ts +121 -0
  331. package/src/grok/sync.ts +66 -0
  332. package/src/images/artifacts.ts +516 -0
  333. package/src/images/fulfill-video.ts +163 -0
  334. package/src/images/fulfill.ts +149 -0
  335. package/src/images/index.ts +4 -0
  336. package/src/images/loop.ts +955 -0
  337. package/src/images/plan.ts +143 -0
  338. package/src/images/synthetic-tool.ts +133 -0
  339. package/src/images/types.ts +41 -0
  340. package/src/images/xai-client.ts +141 -0
  341. package/src/images/xai-video-client.ts +163 -0
  342. package/src/index.ts +22 -0
  343. package/src/integrations/config-io.ts +269 -0
  344. package/src/integrations/journal.ts +315 -0
  345. package/src/integrations/merge.ts +135 -0
  346. package/src/integrations/mutation-flight.ts +71 -0
  347. package/src/integrations/native/ownership-preflight.ts +202 -0
  348. package/src/integrations/omp-yaml-source.ts +358 -0
  349. package/src/integrations/owned-refresh.ts +74 -0
  350. package/src/integrations/ownership.ts +111 -0
  351. package/src/integrations/registry.ts +159 -0
  352. package/src/integrations/serialize.ts +314 -0
  353. package/src/integrations/state.ts +361 -0
  354. package/src/integrations/store.ts +103 -0
  355. package/src/integrations/writer-lock.ts +98 -0
  356. package/src/integrations/writer.ts +691 -0
  357. package/src/lab/artifacts/sanitize.ts +586 -0
  358. package/src/lab/artifacts/secure-fs.ts +475 -0
  359. package/src/lab/artifacts/store.ts +310 -0
  360. package/src/lab/automation/budgets.ts +78 -0
  361. package/src/lab/automation/config-persistence.ts +256 -0
  362. package/src/lab/automation/constants.ts +39 -0
  363. package/src/lab/automation/cooldown.ts +103 -0
  364. package/src/lab/automation/dispatch.ts +211 -0
  365. package/src/lab/automation/index.ts +13 -0
  366. package/src/lab/automation/orchestrator.ts +499 -0
  367. package/src/lab/automation/persistence.ts +512 -0
  368. package/src/lab/automation/planner.ts +371 -0
  369. package/src/lab/automation/policy.ts +136 -0
  370. package/src/lab/automation/queue.ts +191 -0
  371. package/src/lab/automation/recovery.ts +24 -0
  372. package/src/lab/automation/route-context.ts +21 -0
  373. package/src/lab/automation/run-key.ts +44 -0
  374. package/src/lab/automation/runs-query.ts +34 -0
  375. package/src/lab/automation/types.ts +160 -0
  376. package/src/lab/conformance/assertion.ts +325 -0
  377. package/src/lab/conformance/digest.ts +22 -0
  378. package/src/lab/conformance/executor.ts +741 -0
  379. package/src/lab/conformance/fixture-provider.ts +27 -0
  380. package/src/lab/conformance/fixtures/live-v1-cases.json +175 -0
  381. package/src/lab/conformance/fixtures/protocol-v1-cases.json +461 -0
  382. package/src/lab/conformance/harness-budget.ts +47 -0
  383. package/src/lab/conformance/index.ts +5 -0
  384. package/src/lab/conformance/jcs.ts +64 -0
  385. package/src/lab/conformance/json-pointer.ts +39 -0
  386. package/src/lab/conformance/manifest.ts +180 -0
  387. package/src/lab/conformance/mcp-stub.ts +179 -0
  388. package/src/lab/conformance/negative-controls.ts +164 -0
  389. package/src/lab/conformance/observation.ts +355 -0
  390. package/src/lab/conformance/runner.ts +68 -0
  391. package/src/lab/conformance/sse-normalize.ts +59 -0
  392. package/src/lab/conformance/suite-manifest.ts +78 -0
  393. package/src/lab/conformance/types.ts +214 -0
  394. package/src/lab/constants.ts +126 -0
  395. package/src/lab/digest.ts +64 -0
  396. package/src/lab/events/errors.ts +9 -0
  397. package/src/lab/events/limits.ts +117 -0
  398. package/src/lab/events/types.ts +229 -0
  399. package/src/lab/events/validate.ts +781 -0
  400. package/src/lab/fabric/constants.ts +40 -0
  401. package/src/lab/fabric/executor.ts +492 -0
  402. package/src/lab/fabric/index.ts +80 -0
  403. package/src/lab/fabric/manifest.ts +222 -0
  404. package/src/lab/fabric/observe.ts +489 -0
  405. package/src/lab/fabric/patch.ts +79 -0
  406. package/src/lab/fabric/producer-child.ts +139 -0
  407. package/src/lab/fabric/producer-isolate.ts +276 -0
  408. package/src/lab/fabric/producer-protocol.ts +61 -0
  409. package/src/lab/fabric/scratch.ts +439 -0
  410. package/src/lab/fabric/subject.ts +106 -0
  411. package/src/lab/fabric/types.ts +134 -0
  412. package/src/lab/fabric/verifier.ts +98 -0
  413. package/src/lab/index.ts +54 -0
  414. package/src/lab/ledger/artifact-refs.ts +127 -0
  415. package/src/lab/ledger/invalidation.ts +136 -0
  416. package/src/lab/ledger/purge.ts +310 -0
  417. package/src/lab/ledger/store.ts +532 -0
  418. package/src/lab/live/credential-lease.ts +53 -0
  419. package/src/lab/live/destination.ts +155 -0
  420. package/src/lab/live/executor.ts +336 -0
  421. package/src/lab/live/inert-tools.ts +56 -0
  422. package/src/lab/live/manifest.ts +85 -0
  423. package/src/lab/live/mcp-loopback.ts +57 -0
  424. package/src/lab/live/runner.ts +19 -0
  425. package/src/lab/live/sandbox.ts +61 -0
  426. package/src/lab/live/suite-manifest.ts +41 -0
  427. package/src/lab/live/transport.ts +118 -0
  428. package/src/lab/live/types.ts +197 -0
  429. package/src/lab/observe/from-conformance.ts +301 -0
  430. package/src/lab/observe/from-live.ts +117 -0
  431. package/src/lab/paths.ts +153 -0
  432. package/src/lab/projection/rebuild.ts +495 -0
  433. package/src/lab/projection/schema.ts +135 -0
  434. package/src/lab/projection/verdicts.ts +474 -0
  435. package/src/lab/projection/verification.ts +412 -0
  436. package/src/lab/public/bundle.ts +217 -0
  437. package/src/lab/public/community-authority.ts +175 -0
  438. package/src/lab/public/community-files.ts +29 -0
  439. package/src/lab/public/community.ts +479 -0
  440. package/src/lab/public/file-safety.ts +155 -0
  441. package/src/lab/public/ids.ts +26 -0
  442. package/src/lab/public/index.ts +16 -0
  443. package/src/lab/public/mutation-lock.ts +424 -0
  444. package/src/lab/public/operator.ts +353 -0
  445. package/src/lab/public/origin-purge.ts +79 -0
  446. package/src/lab/public/origin.ts +203 -0
  447. package/src/lab/public/privacy.ts +143 -0
  448. package/src/lab/public/private-file.ts +261 -0
  449. package/src/lab/public/project.ts +124 -0
  450. package/src/lab/public/purge-test-fault.ts +21 -0
  451. package/src/lab/public/purge.ts +223 -0
  452. package/src/lab/public/registry.ts +44 -0
  453. package/src/lab/public/revocation.ts +252 -0
  454. package/src/lab/public/signature.ts +243 -0
  455. package/src/lab/public/storage.ts +105 -0
  456. package/src/lab/public/strict-json.ts +206 -0
  457. package/src/lab/public/time.ts +26 -0
  458. package/src/lab/public/types.ts +172 -0
  459. package/src/lab/public/validate.ts +391 -0
  460. package/src/lab/query/catalog.ts +101 -0
  461. package/src/lab/query/connection.ts +107 -0
  462. package/src/lab/query/constants.ts +4 -0
  463. package/src/lab/query/cursor.ts +132 -0
  464. package/src/lab/query/dto-map.ts +277 -0
  465. package/src/lab/query/errors.ts +22 -0
  466. package/src/lab/query/freshness.ts +53 -0
  467. package/src/lab/query/index.ts +45 -0
  468. package/src/lab/query/latest-observation.ts +59 -0
  469. package/src/lab/query/passive-production.ts +159 -0
  470. package/src/lab/query/queries.ts +444 -0
  471. package/src/lab/query/types.ts +266 -0
  472. package/src/lab/subject/behavior-fingerprint.ts +77 -0
  473. package/src/lab/subject/installation-salt.ts +112 -0
  474. package/src/lab/subject/protocol-subject.ts +80 -0
  475. package/src/lab/subject/route-subject.ts +74 -0
  476. package/src/lib/abort.ts +146 -0
  477. package/src/lib/admin-secrets.ts +25 -0
  478. package/src/lib/admission.ts +83 -0
  479. package/src/lib/app-owned-memory-stores.ts +195 -0
  480. package/src/lib/app-owned-memory.ts +265 -0
  481. package/src/lib/bounded-body.ts +346 -0
  482. package/src/lib/bun-binary-validator.d.mts +3 -0
  483. package/src/lib/bun-binary-validator.mjs +18 -0
  484. package/src/lib/bun-runtime.ts +184 -0
  485. package/src/lib/bun-stream-caps.ts +130 -0
  486. package/src/lib/codex-restart-contract.ts +120 -0
  487. package/src/lib/config-ownership.ts +364 -0
  488. package/src/lib/crash-guard.ts +344 -0
  489. package/src/lib/debug-log-buffer.ts +83 -0
  490. package/src/lib/debug-settings.ts +108 -0
  491. package/src/lib/debug.ts +31 -0
  492. package/src/lib/destination-policy.ts +380 -0
  493. package/src/lib/errors.ts +406 -0
  494. package/src/lib/eventstream-decoder.ts +253 -0
  495. package/src/lib/fabric-task-execution-authority.ts +7 -0
  496. package/src/lib/fabric-task-host.ts +29 -0
  497. package/src/lib/gcp-adc.ts +341 -0
  498. package/src/lib/injection-debug-log.ts +58 -0
  499. package/src/lib/lab-activation.ts +223 -0
  500. package/src/lib/lab-live-execution-authority.ts +13 -0
  501. package/src/lib/lab-live-host.ts +30 -0
  502. package/src/lib/lab-live-pinned-sender.ts +56 -0
  503. package/src/lib/lab-live-route-production.ts +130 -0
  504. package/src/lib/lab-passive-linker-registration.ts +26 -0
  505. package/src/lib/local-management-attestation.ts +51 -0
  506. package/src/lib/local-management-capability.ts +100 -0
  507. package/src/lib/local-provider-reload-contract.ts +100 -0
  508. package/src/lib/open-url.ts +25 -0
  509. package/src/lib/optional-shutdown-hooks.ts +57 -0
  510. package/src/lib/pinned-http.ts +270 -0
  511. package/src/lib/privacy.ts +20 -0
  512. package/src/lib/process-control.ts +168 -0
  513. package/src/lib/provider-outbound.ts +210 -0
  514. package/src/lib/provider-url.ts +14 -0
  515. package/src/lib/proxy-env.ts +18 -0
  516. package/src/lib/redact.ts +521 -0
  517. package/src/lib/retry-after.ts +55 -0
  518. package/src/lib/self-launch-argv.ts +15 -0
  519. package/src/lib/server-resource-ownership.ts +71 -0
  520. package/src/lib/service-secrets.ts +25 -0
  521. package/src/lib/shadow-call.ts +61 -0
  522. package/src/lib/sidecar-tracker.ts +52 -0
  523. package/src/lib/sse-decoder.ts +364 -0
  524. package/src/lib/state-store-registrations.ts +119 -0
  525. package/src/lib/state-store-sweeper.ts +184 -0
  526. package/src/lib/system-restart-contract.ts +73 -0
  527. package/src/lib/test-home-guard.ts +90 -0
  528. package/src/lib/token-estimate.ts +86 -0
  529. package/src/lib/tool-argument-integers.ts +202 -0
  530. package/src/lib/translator-budget.ts +400 -0
  531. package/src/lib/upstream-http-version.ts +57 -0
  532. package/src/lib/upstream-reachability.ts +95 -0
  533. package/src/lib/upstream-retry.ts +392 -0
  534. package/src/lib/win-exec.ts +115 -0
  535. package/src/lib/win-paths.ts +68 -0
  536. package/src/lib/windows-atomic-replace.ts +156 -0
  537. package/src/lib/windows-elevation.ts +773 -0
  538. package/src/lib/windows-secret-acl.ts +854 -0
  539. package/src/lib/windows-service-wrappers.ts +72 -0
  540. package/src/lib/windows-text.ts +106 -0
  541. package/src/lib/windows-user-principal.ts +341 -0
  542. package/src/lib/winsw.ts +403 -0
  543. package/src/oauth/account-import/google-antigravity-adapter.ts +74 -0
  544. package/src/oauth/account-import/index.ts +15 -0
  545. package/src/oauth/account-import/parser.ts +83 -0
  546. package/src/oauth/account-import/registry.ts +18 -0
  547. package/src/oauth/account-import/service.ts +75 -0
  548. package/src/oauth/account-import/types.ts +91 -0
  549. package/src/oauth/anthropic-routing.ts +594 -0
  550. package/src/oauth/anthropic.ts +188 -0
  551. package/src/oauth/antigravity-routing.ts +151 -0
  552. package/src/oauth/callback-server.ts +300 -0
  553. package/src/oauth/chatgpt.ts +161 -0
  554. package/src/oauth/command-code.ts +239 -0
  555. package/src/oauth/cursor.ts +252 -0
  556. package/src/oauth/github-copilot.ts +428 -0
  557. package/src/oauth/google-antigravity.ts +262 -0
  558. package/src/oauth/health.ts +407 -0
  559. package/src/oauth/index.ts +1504 -0
  560. package/src/oauth/key-providers.ts +124 -0
  561. package/src/oauth/kimi.ts +227 -0
  562. package/src/oauth/kiro-credentials.ts +726 -0
  563. package/src/oauth/kiro.ts +621 -0
  564. package/src/oauth/local-token-detect.ts +130 -0
  565. package/src/oauth/log.ts +50 -0
  566. package/src/oauth/login-cli.ts +223 -0
  567. package/src/oauth/nous.ts +798 -0
  568. package/src/oauth/pkce.ts +15 -0
  569. package/src/oauth/store.ts +728 -0
  570. package/src/oauth/token-guardian.ts +309 -0
  571. package/src/oauth/types.ts +62 -0
  572. package/src/oauth/xai.ts +241 -0
  573. package/src/providers/alibaba-region-backup.ts +75 -0
  574. package/src/providers/alibaba-region-migration.ts +156 -0
  575. package/src/providers/alibaba-region-startup.ts +36 -0
  576. package/src/providers/antigravity-models.ts +695 -0
  577. package/src/providers/antigravity-quota.ts +216 -0
  578. package/src/providers/api-keys.ts +140 -0
  579. package/src/providers/base-url-choices.ts +74 -0
  580. package/src/providers/codex-capacity.ts +292 -0
  581. package/src/providers/command-code-efforts.ts +144 -0
  582. package/src/providers/context-cap.ts +82 -0
  583. package/src/providers/cursor-pool.ts +72 -0
  584. package/src/providers/derive.ts +586 -0
  585. package/src/providers/fastwire.ts +501 -0
  586. package/src/providers/free-directory.ts +187 -0
  587. package/src/providers/github-copilot-transport.ts +56 -0
  588. package/src/providers/google-vertex-location.ts +14 -0
  589. package/src/providers/key-failover.ts +271 -0
  590. package/src/providers/kiro-models.ts +67 -0
  591. package/src/providers/label.ts +19 -0
  592. package/src/providers/model-discovery-limits.ts +16 -0
  593. package/src/providers/model-discovery.ts +449 -0
  594. package/src/providers/model-rename-migration.ts +255 -0
  595. package/src/providers/model-rename-startup.ts +28 -0
  596. package/src/providers/openai-sidecar.ts +243 -0
  597. package/src/providers/openai-tier-startup.ts +56 -0
  598. package/src/providers/openai-tiers.ts +423 -0
  599. package/src/providers/openai-virtual-models.ts +83 -0
  600. package/src/providers/opencode-zen-rate-limit.ts +102 -0
  601. package/src/providers/openrouter-routing.ts +102 -0
  602. package/src/providers/provider-id-rewrite.ts +185 -0
  603. package/src/providers/quota.ts +2345 -0
  604. package/src/providers/registry.ts +2918 -0
  605. package/src/providers/replit/constants.ts +27 -0
  606. package/src/providers/replit/derive.ts +85 -0
  607. package/src/providers/replit/headers.ts +28 -0
  608. package/src/providers/replit/origin.ts +55 -0
  609. package/src/providers/replit/pair-install-response.ts +72 -0
  610. package/src/providers/replit/probe.ts +199 -0
  611. package/src/providers/replit/setup.ts +350 -0
  612. package/src/providers/request-pacing.ts +310 -0
  613. package/src/providers/service-tier.ts +277 -0
  614. package/src/providers/slug-codec.ts +103 -0
  615. package/src/providers/static-model-discovery.ts +86 -0
  616. package/src/providers/xai-responses-opt-in.ts +15 -0
  617. package/src/providers/xai-transport.ts +148 -0
  618. package/src/reasoning-effort.ts +183 -0
  619. package/src/responses/compaction.ts +142 -0
  620. package/src/responses/custom-tool-compat.ts +266 -0
  621. package/src/responses/hosted-tool-policy.ts +9 -0
  622. package/src/responses/namespace-tool-compat.ts +355 -0
  623. package/src/responses/parser.ts +838 -0
  624. package/src/responses/provider-continuation.ts +98 -0
  625. package/src/responses/provider-opaque-metadata.ts +73 -0
  626. package/src/responses/reasoning-envelope.ts +60 -0
  627. package/src/responses/reasoning-replay-cache.ts +426 -0
  628. package/src/responses/schema.ts +165 -0
  629. package/src/responses/spill-store.ts +459 -0
  630. package/src/responses/state.ts +1433 -0
  631. package/src/responses/thought-signature-replay.ts +347 -0
  632. package/src/responses/tool-groups.ts +19 -0
  633. package/src/responses/tool-search-compat.ts +301 -0
  634. package/src/responses/truncated-stop-reason.ts +60 -0
  635. package/src/router.ts +761 -0
  636. package/src/routing/analytics.ts +378 -0
  637. package/src/routing/capability.ts +244 -0
  638. package/src/routing/compatibility/assemble.ts +73 -0
  639. package/src/routing/compatibility/behavior.ts +278 -0
  640. package/src/routing/compatibility/catalog.ts +99 -0
  641. package/src/routing/compatibility/endpoint.ts +52 -0
  642. package/src/routing/compatibility/lab-evidence-provider.ts +130 -0
  643. package/src/routing/compatibility/policy.ts +181 -0
  644. package/src/routing/compatibility/provider-slot.ts +56 -0
  645. package/src/routing/compatibility/reader.ts +110 -0
  646. package/src/routing/compatibility/subject.ts +191 -0
  647. package/src/routing/compatibility/types.ts +64 -0
  648. package/src/routing/compatibility/version.ts +104 -0
  649. package/src/routing/cost.ts +77 -0
  650. package/src/routing/evaluator.ts +495 -0
  651. package/src/routing/health.ts +412 -0
  652. package/src/routing/history/cursor.ts +43 -0
  653. package/src/routing/history/indexer.ts +605 -0
  654. package/src/routing/history/schema.ts +72 -0
  655. package/src/routing/profile-namespace.ts +15 -0
  656. package/src/routing/profile.ts +547 -0
  657. package/src/routing/quota.ts +145 -0
  658. package/src/routing/request-evidence.ts +45 -0
  659. package/src/routing/trace.ts +776 -0
  660. package/src/server/adapter-resolve.ts +53 -0
  661. package/src/server/auth-cors.ts +751 -0
  662. package/src/server/background-lifecycle.ts +182 -0
  663. package/src/server/chat-completions.ts +442 -0
  664. package/src/server/chat-native-sse.ts +331 -0
  665. package/src/server/chat-native.ts +426 -0
  666. package/src/server/claude-messages.ts +1030 -0
  667. package/src/server/direct-local-http.ts +347 -0
  668. package/src/server/effort-policy.ts +190 -0
  669. package/src/server/github-copilot-responses-repair.ts +338 -0
  670. package/src/server/gui-static.ts +152 -0
  671. package/src/server/image-retry.ts +42 -0
  672. package/src/server/images.ts +568 -0
  673. package/src/server/index.ts +1813 -0
  674. package/src/server/lifecycle.ts +498 -0
  675. package/src/server/live.ts +717 -0
  676. package/src/server/local-management-read-client.ts +90 -0
  677. package/src/server/local-provider-reload-client.ts +137 -0
  678. package/src/server/management/agent-settings-routes.ts +1433 -0
  679. package/src/server/management/api-access.ts +141 -0
  680. package/src/server/management/api-key-usage.ts +193 -0
  681. package/src/server/management/body.ts +41 -0
  682. package/src/server/management/combo-routes.ts +263 -0
  683. package/src/server/management/config-routes.ts +835 -0
  684. package/src/server/management/context.ts +113 -0
  685. package/src/server/management/integration-routes.ts +498 -0
  686. package/src/server/management/lab-automation-routes.ts +206 -0
  687. package/src/server/management/lab-routes.ts +563 -0
  688. package/src/server/management/logs-usage-routes.ts +586 -0
  689. package/src/server/management/model-routes.ts +560 -0
  690. package/src/server/management/model-rows.ts +163 -0
  691. package/src/server/management/native-integration-routes.ts +769 -0
  692. package/src/server/management/oauth-account-routes.ts +637 -0
  693. package/src/server/management/provider-capability-config.ts +48 -0
  694. package/src/server/management/provider-routes.ts +1033 -0
  695. package/src/server/management/replit-provider-routes.ts +86 -0
  696. package/src/server/management/request-history-routes.ts +191 -0
  697. package/src/server/management/routing-analytics-routes.ts +74 -0
  698. package/src/server/management/routing-profile-routes.ts +385 -0
  699. package/src/server/management/shared.ts +286 -0
  700. package/src/server/management/sidebar-routes.ts +106 -0
  701. package/src/server/management/storage-log-guard-routes.ts +186 -0
  702. package/src/server/management/sync-response.ts +69 -0
  703. package/src/server/management/system-restart.ts +435 -0
  704. package/src/server/management/system-routes.ts +194 -0
  705. package/src/server/management/usage-summary-cache.ts +94 -0
  706. package/src/server/management/vision-sidecar-options.ts +167 -0
  707. package/src/server/management/web-search-sidecar-options.ts +120 -0
  708. package/src/server/management-api.ts +314 -0
  709. package/src/server/management-auth.ts +482 -0
  710. package/src/server/memory-watchdog.ts +156 -0
  711. package/src/server/passive-route-linker.ts +66 -0
  712. package/src/server/port-reclaim.ts +307 -0
  713. package/src/server/ports.ts +156 -0
  714. package/src/server/proxy-liveness.ts +328 -0
  715. package/src/server/readiness.ts +99 -0
  716. package/src/server/relay-eager.ts +353 -0
  717. package/src/server/relay.ts +1209 -0
  718. package/src/server/request-decompress.ts +239 -0
  719. package/src/server/request-log-conversation.ts +168 -0
  720. package/src/server/request-log.ts +1259 -0
  721. package/src/server/responses/agent-task-recovery-cache.ts +143 -0
  722. package/src/server/responses/agent-task-recovery.ts +465 -0
  723. package/src/server/responses/collaboration.ts +551 -0
  724. package/src/server/responses/compact.ts +771 -0
  725. package/src/server/responses/core.ts +5389 -0
  726. package/src/server/responses/empty-completion-guard.ts +276 -0
  727. package/src/server/responses/encrypted-payload.ts +331 -0
  728. package/src/server/responses/fetch-helpers.ts +232 -0
  729. package/src/server/responses/input-admission.ts +185 -0
  730. package/src/server/responses/pacing-overload.ts +13 -0
  731. package/src/server/responses/passthrough-error.ts +78 -0
  732. package/src/server/responses/policy-fallback.ts +178 -0
  733. package/src/server/responses/responses-field-backfill.ts +251 -0
  734. package/src/server/responses/terminal-guard.ts +251 -0
  735. package/src/server/responses/upstream-error.ts +53 -0
  736. package/src/server/responses/ws-upstream.ts +308 -0
  737. package/src/server/responses-custom-tool-repair.ts +282 -0
  738. package/src/server/responses-image-gen-repair.ts +132 -0
  739. package/src/server/responses-item-id-repair.ts +272 -0
  740. package/src/server/responses-json-events.ts +90 -0
  741. package/src/server/responses-model-rewrite.ts +29 -0
  742. package/src/server/responses-reasoning-summary-rewrite.ts +178 -0
  743. package/src/server/responses-snapshot-repair.ts +621 -0
  744. package/src/server/responses-terminal-repair.ts +342 -0
  745. package/src/server/responses-tool-search-repair.ts +267 -0
  746. package/src/server/responses-undeclared-tool-guard.ts +153 -0
  747. package/src/server/responses.ts +25 -0
  748. package/src/server/search.ts +201 -0
  749. package/src/server/sse-frame-buffer.ts +292 -0
  750. package/src/server/sse-payload-rewrite.ts +263 -0
  751. package/src/server/startup-action-control.ts +315 -0
  752. package/src/server/startup-health-cache.ts +131 -0
  753. package/src/server/system-env.ts +484 -0
  754. package/src/server/windows-tcp-drop.ts +184 -0
  755. package/src/server/windows-tray-control.ts +41 -0
  756. package/src/server/ws-bridge.ts +472 -0
  757. package/src/service-manager-probe.ts +892 -0
  758. package/src/service.ts +3575 -0
  759. package/src/sidecar/auth.ts +92 -0
  760. package/src/sidecar/candidates.ts +83 -0
  761. package/src/stall-timeout.ts +20 -0
  762. package/src/storage/cleanup-job.ts +57 -0
  763. package/src/storage/cleanup.ts +3085 -0
  764. package/src/storage/policy-job.ts +457 -0
  765. package/src/storage/policy-scheduler.ts +40 -0
  766. package/src/storage/policy-worker.ts +59 -0
  767. package/src/storage/policy.ts +527 -0
  768. package/src/storage/restore-job.ts +299 -0
  769. package/src/storage/restore-worker.ts +58 -0
  770. package/src/storage/scanner.ts +238 -0
  771. package/src/storage/storage-mutation-coordinator.ts +139 -0
  772. package/src/storage/worker-lifecycle.ts +215 -0
  773. package/src/tray/assets/opencodex-tray-offline.ico +0 -0
  774. package/src/tray/assets/opencodex-tray-online.ico +0 -0
  775. package/src/tray/assets/opencodex-tray-warning.ico +0 -0
  776. package/src/tray/assets/opencodex-tray.png +0 -0
  777. package/src/tray/windows-tray.ps1 +364 -0
  778. package/src/tray/windows.ts +757 -0
  779. package/src/types/accounts.ts +37 -0
  780. package/src/types/config.ts +876 -0
  781. package/src/types/provider.ts +545 -0
  782. package/src/types/request.ts +384 -0
  783. package/src/types/tools.ts +131 -0
  784. package/src/types/wire.ts +80 -0
  785. package/src/types.ts +106 -0
  786. package/src/update/badge.ts +72 -0
  787. package/src/update/index.ts +415 -0
  788. package/src/update/job.ts +1887 -0
  789. package/src/update/notify.ts +263 -0
  790. package/src/update/npm-cache-preflight.d.mts +47 -0
  791. package/src/update/npm-cache-preflight.mjs +201 -0
  792. package/src/update/npm-invocation.d.mts +23 -0
  793. package/src/update/npm-invocation.mjs +94 -0
  794. package/src/update/transactional-install.d.mts +22 -0
  795. package/src/update/transactional-install.mjs +259 -0
  796. package/src/update/tray-update-plan.d.mts +18 -0
  797. package/src/update/tray-update-plan.mjs +38 -0
  798. package/src/usage/cost.ts +625 -0
  799. package/src/usage/debug.ts +97 -0
  800. package/src/usage/expected-prices.ts +416 -0
  801. package/src/usage/log.ts +1223 -0
  802. package/src/usage/summary.ts +753 -0
  803. package/src/usage/totals.ts +14 -0
  804. package/src/usage/user-cost-overlay-reconciler.ts +313 -0
  805. package/src/usage/user-cost-overlays.ts +314 -0
  806. package/src/vision/anthropic-describe.ts +189 -0
  807. package/src/vision/backends.ts +97 -0
  808. package/src/vision/describe.ts +131 -0
  809. package/src/vision/eligibility.ts +250 -0
  810. package/src/vision/index.ts +681 -0
  811. package/src/vision/reasoning.ts +55 -0
  812. package/src/vision/routed-describe.ts +175 -0
  813. package/src/vision/timeout-bounds.ts +9 -0
  814. package/src/web-search/anthropic-executor.ts +195 -0
  815. package/src/web-search/backends.ts +108 -0
  816. package/src/web-search/exa-executor.ts +88 -0
  817. package/src/web-search/executor.ts +113 -0
  818. package/src/web-search/format-result.ts +89 -0
  819. package/src/web-search/gemini-executor.ts +141 -0
  820. package/src/web-search/index.ts +331 -0
  821. package/src/web-search/loop.ts +896 -0
  822. package/src/web-search/parse.ts +315 -0
  823. package/src/web-search/progress-stream.ts +342 -0
  824. package/src/web-search/sources.ts +60 -0
  825. package/src/web-search/synthetic-tool.ts +47 -0
  826. package/src/web-search/xai-executor.ts +219 -0
@@ -0,0 +1,530 @@
1
+ import { constants, copyFileSync, existsSync, readFileSync, statSync } from "node:fs";
2
+ import { homedir } from "node:os";
3
+ import { join } from "node:path";
4
+ import { atomicWriteFile } from "../config";
5
+ import { applyEol, dominantEol, isLoopbackHostname, providerBaseHost } from "../codex/inject";
6
+
7
+ export interface GrokInjectModel {
8
+ id: string;
9
+ name?: string;
10
+ contextWindow?: number;
11
+ }
12
+
13
+ export interface GrokInjectResult {
14
+ ok: boolean;
15
+ changed: boolean;
16
+ message: string;
17
+ skippedReason?: "no-grok-home" | "orphaned-marker" | "non-loopback";
18
+ }
19
+
20
+ const BEGIN_MARKER = "# >>> opencodex managed block — do not edit (removed by `ocx stop`) >>>";
21
+ const END_MARKER = "# <<< opencodex managed block <<<";
22
+ // grok 0.2.101 verified live (2026-07-23): [model_providers.<id>] inheritance parses but the
23
+ // inherited base_url is NOT applied to inference routing — the turn falls through to the default
24
+ // cli-chat-proxy and 401s. Per-model direct fields DO route. So every [model.*] block carries its
25
+ // own base_url/api_backend/api_key and no [model_providers] table is emitted at all.
26
+
27
+ /**
28
+ * INTERNAL API shared with `./inspect` (WP2, devlog 260803_integrations_toggle_all/012).
29
+ * The inspector and the writer are its only callers — one parser for one fence, so a
30
+ * read and a strip can never disagree about where our block starts and stops.
31
+ */
32
+ export interface ManagedRegion {
33
+ start: number;
34
+ end: number;
35
+ orphaned: boolean;
36
+ }
37
+
38
+ function tomlString(value: string): string {
39
+ return JSON.stringify(value);
40
+ }
41
+
42
+ /**
43
+ * INTERNAL API shared with `./inspect`, so the reader and the writer resolve the
44
+ * authoritative home identically (GROK_HOME, then ~/.grok). Not a public surface.
45
+ */
46
+ export function resolveGrokHome(grokHome?: string): string {
47
+ return grokHome ?? (process.env.GROK_HOME || join(homedir(), ".grok"));
48
+ }
49
+
50
+ /** INTERNAL API shared with `./inspect` — a missing home is a STATE, not an error. */
51
+ export function isDirectory(path: string): boolean {
52
+ try {
53
+ return statSync(path).isDirectory();
54
+ } catch {
55
+ return false;
56
+ }
57
+ }
58
+
59
+ /** INTERNAL API — see `ManagedRegion` above. Not a public fence-parsing surface. */
60
+ export function findManagedRegion(content: string): ManagedRegion | null {
61
+ const start = content.indexOf(BEGIN_MARKER);
62
+ if (start === -1) return null;
63
+ const endMarkerStart = content.indexOf(END_MARKER, start + BEGIN_MARKER.length);
64
+ if (endMarkerStart === -1) return { start, end: content.length, orphaned: true };
65
+ return { start, end: endMarkerStart + END_MARKER.length, orphaned: false };
66
+ }
67
+
68
+ /**
69
+ * A TOML key segment as it may be spelled in a table header: bare, basic string, or literal
70
+ * string. All three spellings of the same key address the SAME table, so both segments of a
71
+ * `[model.<alias>]` header must be canonicalized before comparison.
72
+ */
73
+ const KEY_SEGMENT = String.raw`(?:[A-Za-z0-9_-]+|"(?:[^"\\]|\\.)*"|'[^']*')`;
74
+ /**
75
+ * User-owned model table headers. Also matches array-of-table (`[[model.x]]`) and sub-table
76
+ * (`[model.x.sub]`) spellings. `[[model.x]]` genuinely collides with a generated `[model.x]`,
77
+ * and one collision makes grok reject the ENTIRE config layer ("duplicate key"), taking every
78
+ * unrelated user setting with it; `[model.x.sub]` does not strictly collide, but reserving it
79
+ * costs only a suffixed alias and keeps us clear of the user's namespace.
80
+ *
81
+ * Every character class here is newline-free ON PURPOSE. With `[^\]]*` the optional sub-table
82
+ * tail runs past the end of its own line, so an unclosed `[model.…` inside a multiline string
83
+ * swallows the following lines — including a real `[model.<alias>]` header, which then goes
84
+ * unreserved and produces the very duplicate-key config this scan exists to prevent.
85
+ */
86
+ const MODEL_TABLE_HEADER = new RegExp(
87
+ String.raw`^[ \t]*\[\[?[ \t]*(${KEY_SEGMENT})[ \t]*\.[ \t]*(${KEY_SEGMENT})[ \t]*(?:\.[^\]\r\n]*)?\]\]?[ \t]*(?:#.*)?$`,
88
+ "gm",
89
+ );
90
+
91
+ /**
92
+ * ANY table header, capturing its full dotted key. Used to compute table SPANS: a table
93
+ * body runs from its own header to the next header of any kind, so the orphan sweep can
94
+ * remove a whole table instead of a guessed line range (a partial removal would re-parent
95
+ * the leftover keys onto the preceding table).
96
+ */
97
+ const ANY_TABLE_HEADER = /^[ \t]*\[\[?[ \t]*([^\]\r\n]*?)[ \t]*\]\]?[ \t]*(?:#.*)?$/gm;
98
+
99
+ /** Resolve a header key segment (bare / basic / literal) to the key it actually addresses. */
100
+ function canonicalKeySegment(raw: string): string {
101
+ if (raw.startsWith('"')) return decodeTomlBasicString(raw.slice(1, -1));
102
+ if (raw.startsWith("'")) return raw.slice(1, -1); // literal strings have no escapes
103
+ return raw;
104
+ }
105
+
106
+ /**
107
+ * `[model.<alias>]` table headers the USER owns (outside our fence) — reserved for collisions.
108
+ * TOML admits equivalent header spellings for BOTH segments (`["model"."ocx-mine"]`,
109
+ * `['model'.ocx-mine]`, `[ model . ocx-mine ]`); all of them redefine the same table, so each
110
+ * form is canonicalized before it is reserved.
111
+ */
112
+ function userModelAliases(content: string, region: ManagedRegion | null): Set<string> {
113
+ const outsideManagedRegion = region
114
+ ? content.slice(0, region.start) + content.slice(region.end)
115
+ : content;
116
+ const aliases = new Set<string>();
117
+ for (const match of outsideManagedRegion.matchAll(MODEL_TABLE_HEADER)) {
118
+ if (canonicalKeySegment(match[1]!) !== "model") continue;
119
+ aliases.add(canonicalKeySegment(match[2]!));
120
+ }
121
+ return aliases;
122
+ }
123
+
124
+ /**
125
+ * The api_key literal every generated entry carries. It is the STRONG ownership signal:
126
+ * a value we mint, that a human has no reason to type by hand.
127
+ */
128
+ const OPENCODEX_API_KEY = "opencodex-loopback";
129
+
130
+ /** A plain `[model.<alias>]` table outside the fence that opencodex itself wrote. */
131
+ interface OrphanTable {
132
+ alias: string;
133
+ /** The model id this entry routes to — used to find its replacement alias. */
134
+ modelId: string | undefined;
135
+ /** Offsets into the NORMALIZED content: header start .. next header start (or EOF). */
136
+ start: number;
137
+ end: number;
138
+ }
139
+
140
+ /** `key = "value"` / `key = value` pairs at the top level of one table body. */
141
+ function tableBodyKeys(body: string): Map<string, string> {
142
+ const keys = new Map<string, string>();
143
+ for (const line of body.split("\n")) {
144
+ const match = /^[ \t]*([A-Za-z0-9_-]+)[ \t]*=[ \t]*(.*?)[ \t]*$/.exec(line);
145
+ if (!match) continue;
146
+ const raw = match[2]!;
147
+ const value = raw.startsWith('"') && raw.endsWith('"') && raw.length >= 2
148
+ ? decodeTomlBasicString(raw.slice(1, -1))
149
+ : raw;
150
+ if (!keys.has(match[1]!)) keys.set(match[1]!, value);
151
+ }
152
+ return keys;
153
+ }
154
+
155
+ /** Is this base_url pointed at the local machine? */
156
+ function isLoopbackBaseUrl(value: string | undefined): boolean {
157
+ if (!value) return false;
158
+ try {
159
+ return isLoopbackHostname(new URL(value).hostname);
160
+ } catch {
161
+ return false;
162
+ }
163
+ }
164
+
165
+ /**
166
+ * Model tables OUTSIDE the fence that opencodex itself wrote (#511).
167
+ *
168
+ * These are entries from a version that predates the markers (or predates
169
+ * `context_window`). Because they sit outside the fence, `userModelAliases` reserves
170
+ * their aliases as user-owned and the writer routes around them with a `-2` suffix — so
171
+ * every sync adds a CORRECT duplicate and never removes the stale original. Grok then
172
+ * resolves the original, finds no `context_window`, and falls back to its own 200k.
173
+ *
174
+ * Ownership is CONJUNCTIVE and deliberately strict, because a false positive deletes a
175
+ * hand-written user model:
176
+ * - a plain `[model.x]` header (never `[[model.x]]` / `[model.x.sub]` — those spellings
177
+ * mark human authorship and stay reserved);
178
+ * - `api_key` equal to our own literal;
179
+ * - a loopback `base_url`, so an entry that merely copied our key while pointing at a
180
+ * remote host is left alone.
181
+ * A loopback base_url ALONE is not enough: aiming your own model at the local proxy is a
182
+ * legitimate thing to do.
183
+ */
184
+ function findOpencodexOrphans(content: string, region: ManagedRegion | null): OrphanTable[] {
185
+ const orphans: OrphanTable[] = [];
186
+ // A pre-fence orphan's body must stop AT the fence. The managed block opens with a
187
+ // COMMENT, not a table header, so a span that runs to "the next table header" swallows
188
+ // the BEGIN marker whenever no other table separates them — and removing the orphan then
189
+ // deletes the fence opener itself, which strands the END marker and makes every later
190
+ // sync re-append a block (the #511 duplicate loop, one layer down).
191
+ // `region` is null ONLY when BEGIN_MARKER is absent (see findManagedRegion), so -1
192
+ // disables the clamp for marker-less files without a redundant scan.
193
+ const fenceStart = region ? region.start : -1;
194
+ const clampEnd = (start: number, end: number): number =>
195
+ fenceStart >= 0 && start < fenceStart ? Math.min(end, fenceStart) : end;
196
+ // Collect every table header first: a table body runs to the NEXT header, whatever it is.
197
+ const headers: Array<{ index: number; length: number; segments: string[]; array: boolean }> = [];
198
+ for (const match of content.matchAll(ANY_TABLE_HEADER)) {
199
+ headers.push({
200
+ index: match.index!,
201
+ length: match[0].length,
202
+ segments: match[1]!.split(".").map(part => canonicalKeySegment(part.trim())),
203
+ array: match[0].trimStart().startsWith("[["),
204
+ });
205
+ }
206
+ for (const [position, header] of headers.entries()) {
207
+ if (header.array || header.segments.length !== 2 || header.segments[0] !== "model") continue;
208
+ // Inside the fence the regular splice already owns it.
209
+ if (region && header.index >= region.start && header.index < region.end) continue;
210
+ const bodyEnd = clampEnd(header.index, headers[position + 1]?.index ?? content.length);
211
+ const keys = tableBodyKeys(content.slice(header.index + header.length, bodyEnd));
212
+ if (keys.get("api_key") !== OPENCODEX_API_KEY) continue;
213
+ if (!isLoopbackBaseUrl(keys.get("base_url"))) continue;
214
+ // Swallow the entry's OWN sub-tables (`[model.<alias>.extra_headers]`). Grok writes
215
+ // them when it re-serializes the file, and leaving one behind keeps the alias
216
+ // reserved by `userModelAliases` — so the sweep would remove the parent and STILL
217
+ // allocate a suffixed duplicate, which is the exact #511 loop we came to close.
218
+ let end = bodyEnd;
219
+ for (let next = position + 1; next < headers.length; next += 1) {
220
+ const child = headers[next]!;
221
+ // Only a PRE-fence parent may be cut short by the fence. Without the parent test a
222
+ // below-fence orphan would break on its first child (every index is past the fence),
223
+ // leaving the sub-table behind to keep the alias reserved — the -2 loop again.
224
+ if (fenceStart >= 0 && header.index < fenceStart && child.index >= fenceStart) break;
225
+ if (child.segments.length <= 2) break;
226
+ if (child.segments[0] !== "model" || child.segments[1] !== header.segments[1]) break;
227
+ end = clampEnd(header.index, headers[next + 1]?.index ?? content.length);
228
+ }
229
+ orphans.push({ alias: header.segments[1]!, modelId: keys.get("model"), start: header.index, end });
230
+ }
231
+ return orphans;
232
+ }
233
+
234
+ /** Remove whole tables, back to front so earlier offsets stay valid. */
235
+ function removeOrphanTables(content: string, orphans: OrphanTable[]): string {
236
+ let next = content;
237
+ for (const orphan of [...orphans].sort((a, b) => b.start - a.start)) {
238
+ next = next.slice(0, orphan.start) + next.slice(orphan.end);
239
+ }
240
+ return next;
241
+ }
242
+
243
+ /**
244
+ * Repoint `default` / `fork_secondary_model` at the alias that survived.
245
+ *
246
+ * Removing an adopted orphan that `[models] default` names would leave Grok pointing at
247
+ * a model that no longer exists — and on a real machine `default` DOES name one, so this
248
+ * is the common path rather than an edge case.
249
+ */
250
+ function rewriteAliasReferences(content: string, renames: Map<string, string>): string {
251
+ if (renames.size === 0) return content;
252
+ return content.replace(
253
+ /^([ \t]*(?:default|fork_secondary_model)[ \t]*=[ \t]*")([^"]*)(")/gm,
254
+ (whole, prefix: string, value: string, suffix: string) => {
255
+ const replacement = renames.get(value);
256
+ return replacement ? `${prefix}${replacement}${suffix}` : whole;
257
+ },
258
+ );
259
+ }
260
+
261
+ function orphanedMarkerResult(action: string): GrokInjectResult {
262
+ return {
263
+ ok: false,
264
+ changed: false,
265
+ message: `Grok config ${action} refused: found the opencodex begin marker without its end marker. `
266
+ + "The managed region boundary is ambiguous, so nothing was modified. "
267
+ + "Repair ~/.grok/config.toml manually (see config.toml.bak-opencodex) and re-run.",
268
+ skippedReason: "orphaned-marker",
269
+ };
270
+ }
271
+
272
+ function copyBackupOnce(configPath: string, backupPath: string): void {
273
+ if (existsSync(backupPath)) return;
274
+ try {
275
+ copyFileSync(configPath, backupPath, constants.COPYFILE_EXCL);
276
+ } catch (error) {
277
+ if (!(error instanceof Error && "code" in error && error.code === "EEXIST")) throw error;
278
+ }
279
+ }
280
+
281
+ function errorResult(action: string, error: unknown): GrokInjectResult {
282
+ const detail = error instanceof Error ? error.message : String(error);
283
+ return { ok: false, changed: false, message: `Could not ${action} Grok config: ${detail}` };
284
+ }
285
+
286
+ export function buildGrokManagedBlock(
287
+ port: number,
288
+ models: GrokInjectModel[],
289
+ hostname?: string,
290
+ reservedAliases?: ReadonlySet<string>,
291
+ /**
292
+ * Ids to allocate an alias for but NOT emit. Alias numbering must not depend on which
293
+ * models the user switched off, or excluding one colliding model would rename another
294
+ * model's alias out from under a grok config that already uses it.
295
+ */
296
+ excluded?: ReadonlySet<string>,
297
+ ): string {
298
+ const host = providerBaseHost(hostname);
299
+ const baseUrl = `http://${host}:${port}/v1`;
300
+ const lines = [
301
+ BEGIN_MARKER,
302
+ ];
303
+ const aliasCounts = new Map<string, number>();
304
+ const taken = new Set(reservedAliases ?? []);
305
+
306
+ for (const model of models) {
307
+ const baseAlias = `ocx-${model.id.replace(/[^A-Za-z0-9_-]/g, "-")}`;
308
+ let count = (aliasCounts.get(baseAlias) ?? 0) + 1;
309
+ let alias = count === 1 ? baseAlias : `${baseAlias}-${count}`;
310
+ // User-owned [model.<alias>] tables outside the fence are reserved: emitting a
311
+ // duplicate table header would make the whole TOML invalid for grok.
312
+ while (taken.has(alias)) {
313
+ count += 1;
314
+ alias = `${baseAlias}-${count}`;
315
+ }
316
+ aliasCounts.set(baseAlias, count);
317
+ taken.add(alias);
318
+ // Slot consumed, table not written: this is what keeps every other alias stable
319
+ // across selection changes.
320
+ if (excluded?.has(model.id)) continue;
321
+ const isFirst = lines.length === 1;
322
+ lines.push(
323
+ ...(isFirst ? [] : [""]),
324
+ `[model.${alias}]`,
325
+ `model = ${tomlString(model.id)}`,
326
+ `base_url = ${tomlString(baseUrl)}`,
327
+ 'api_backend = "responses"',
328
+ 'api_key = "opencodex-loopback"',
329
+ `name = ${tomlString(model.name ?? `OCX ${model.id}`)}`,
330
+ // Best-effort attribution tag for the usage dashboard. Upstream Grok sends
331
+ // extra_headers verbatim on inference calls (11-custom-models.md). This is NOT a
332
+ // security boundary — any loopback client could send the same header.
333
+ 'extra_headers = { "x-opencodex-grok" = "1" }',
334
+ );
335
+ if (Number.isFinite(model.contextWindow) && (model.contextWindow ?? 0) > 0) {
336
+ lines.push(`context_window = ${model.contextWindow}`);
337
+ }
338
+ }
339
+
340
+ lines.push(END_MARKER);
341
+ return lines.join("\n");
342
+ }
343
+
344
+ export function injectGrokConfig(
345
+ port: number,
346
+ models: GrokInjectModel[],
347
+ opts: { grokHome?: string; hostname?: string; excluded?: ReadonlySet<string> } = {},
348
+ ): GrokInjectResult {
349
+ const grokHome = resolveGrokHome(opts.grokHome);
350
+ if (!isDirectory(grokHome)) {
351
+ return {
352
+ ok: true,
353
+ changed: false,
354
+ message: `Grok home not found at ${grokHome}; config injection skipped.`,
355
+ skippedReason: "no-grok-home",
356
+ };
357
+ }
358
+
359
+ // Non-loopback binds require the real admission token (src/server/auth-cors.ts), and there is
360
+ // no safe way for a REGENERATED block to carry it: a literal token would write the user's
361
+ // secret into their own file and overwrite it on every start/ensure/restart, while omitting
362
+ // api_key in favour of env_key opens grok's credential fallthrough — with no `model_provider`
363
+ // to fail closed, an unresolved env_key makes grok send its xAI session bearer to our
364
+ // plaintext LAN endpoint (upstream config.rs resolve_credentials). So we do not auto-register
365
+ // at all here; the user configures models manually, outside our fence, where nothing we do
366
+ // can clobber their credential.
367
+ if (!isLoopbackHostname(opts.hostname)) {
368
+ const removed = stripGrokConfig({ ...(opts.grokHome !== undefined ? { grokHome: opts.grokHome } : {}) });
369
+ const cleanup = removed.changed
370
+ ? " Removed the previously generated block, which pointed at a loopback address."
371
+ : "";
372
+ return {
373
+ ok: true, // a deliberate policy skip, not a failure — it must never block startup
374
+ changed: removed.changed,
375
+ skippedReason: "non-loopback",
376
+ message: `Grok auto-registration skipped: opencodex is bound to the non-loopback host `
377
+ + `"${opts.hostname}", where requests need your admission token. A managed block would `
378
+ + `either store that secret in ~/.grok/config.toml or overwrite it on the next start, so `
379
+ + `add the models yourself OUTSIDE the opencodex markers (see the Grok Build guide).${cleanup}`,
380
+ };
381
+ }
382
+
383
+ const configPath = join(grokHome, "config.toml");
384
+ const backupPath = join(grokHome, "config.toml.bak-opencodex");
385
+ try {
386
+ const configExisted = existsSync(configPath);
387
+ const rawContent = configExisted ? readFileSync(configPath, "utf8") : "";
388
+ const eol = dominantEol(rawContent);
389
+ const originalContent = applyEol(rawContent, "\n");
390
+ const originalRegion = findManagedRegion(originalContent);
391
+ // Ambiguous fence: refuse before the sweep, or "outside the region" could mean the
392
+ // entire file.
393
+ if (originalRegion?.orphaned) return orphanedMarkerResult("injection");
394
+
395
+ // Adopt our own pre-fence entries (#511) BEFORE reserving user aliases, so the stale
396
+ // duplicate is replaced instead of routed around forever. Runs inside the normalized
397
+ // window so the user's dominant EOL is still restored below.
398
+ const orphans = findOpencodexOrphans(originalContent, originalRegion);
399
+ const content = removeOrphanTables(originalContent, orphans);
400
+ // Removing bytes above the fence MOVES it: recompute rather than adjust arithmetic,
401
+ // so the splice below cannot cut the file in the wrong place.
402
+ const region = orphans.length > 0 ? findManagedRegion(content) : originalRegion;
403
+
404
+ const block = buildGrokManagedBlock(port, models, opts.hostname, userModelAliases(content, region), opts.excluded);
405
+ let nextContent: string;
406
+ if (region) {
407
+ nextContent = content.slice(0, region.start) + block + content.slice(region.end);
408
+ } else if (content.length === 0) {
409
+ nextContent = `${block}\n`;
410
+ } else {
411
+ // Exactly ONE separator newline, always. The old rule ("\n\n" when the file lacked a
412
+ // trailing newline) made two different originals — "X" and "X\n" — produce byte-identical
413
+ // files, so strip could not restore both. One newline keeps injection injective: the
414
+ // user's own terminator is preserved verbatim and strip can undo exactly what we added.
415
+ nextContent = `${content}\n${block}\n`;
416
+ }
417
+
418
+ // Repoint `default` / `fork_secondary_model` at whichever alias survived. A removed
419
+ // model with no replacement keeps its reference untouched — a stale name in a working
420
+ // file beats a dangling one.
421
+ if (orphans.length > 0) {
422
+ const survivors = new Map<string, string>();
423
+ for (const match of nextContent.matchAll(MODEL_TABLE_HEADER)) {
424
+ if (canonicalKeySegment(match[1]!) !== "model") continue;
425
+ const alias = canonicalKeySegment(match[2]!);
426
+ const body = nextContent.slice(match.index! + match[0].length);
427
+ const modelId = tableBodyKeys(body.slice(0, body.search(/^[ \t]*\[/m) + 1 || body.length)).get("model");
428
+ if (modelId !== undefined && !survivors.has(modelId)) survivors.set(modelId, alias);
429
+ }
430
+ const renames = new Map<string, string>();
431
+ for (const orphan of orphans) {
432
+ const replacement = orphan.modelId === undefined ? undefined : survivors.get(orphan.modelId);
433
+ if (replacement && replacement !== orphan.alias) renames.set(orphan.alias, replacement);
434
+ }
435
+ nextContent = rewriteAliasReferences(nextContent, renames);
436
+ }
437
+
438
+ const output = applyEol(nextContent, eol);
439
+ if (output === rawContent) {
440
+ return { ok: true, changed: false, message: "Grok config already contains the current opencodex managed block." };
441
+ }
442
+ // Back up before a first-time fence write AND before any sweep, since adopting an orphan
443
+ // deletes a table the user has in their file. Previously the adjacent-orphan layout got a
444
+ // backup only as a side effect of the fence being destroyed (which made `region` falsy);
445
+ // preserving the fence must not silently drop that safety net.
446
+ if (configExisted && (!region || orphans.length > 0)) copyBackupOnce(configPath, backupPath);
447
+ atomicWriteFile(configPath, output);
448
+ return {
449
+ ok: true,
450
+ changed: true,
451
+ message: region
452
+ ? "Updated the opencodex managed block in Grok config."
453
+ : "Added the opencodex managed block to Grok config.",
454
+ };
455
+ } catch (error) {
456
+ return errorResult("inject", error);
457
+ }
458
+ }
459
+
460
+ export function stripGrokConfig(opts: { grokHome?: string } = {}): GrokInjectResult {
461
+ const grokHome = resolveGrokHome(opts.grokHome);
462
+ if (!isDirectory(grokHome)) {
463
+ return {
464
+ ok: true,
465
+ changed: false,
466
+ message: `Grok home not found at ${grokHome}; no managed config to remove.`,
467
+ skippedReason: "no-grok-home",
468
+ };
469
+ }
470
+
471
+ const configPath = join(grokHome, "config.toml");
472
+ if (!existsSync(configPath)) {
473
+ return { ok: true, changed: false, message: "Grok config not found; no managed block to remove." };
474
+ }
475
+
476
+ try {
477
+ const rawContent = readFileSync(configPath, "utf8");
478
+ const eol = dominantEol(rawContent);
479
+ const content = applyEol(rawContent, "\n");
480
+ const region = findManagedRegion(content);
481
+ if (!region) {
482
+ return { ok: true, changed: false, message: "No opencodex managed block found in Grok config." };
483
+ }
484
+ if (region.orphaned) return orphanedMarkerResult("cleanup");
485
+
486
+ let removalEnd = region.end;
487
+ if (content.startsWith("\n", removalEnd)) removalEnd += 1;
488
+ let prefix = content.slice(0, region.start);
489
+ const restOfFile = content.slice(removalEnd);
490
+ // Undo the single separator newline injection added. Two cases, mirroring inject:
491
+ // "X\n" -> "X\n" + "\n" + block => prefix ends "\n\n", drop one.
492
+ // "X" -> "X" + "\n" + block => prefix ends "\n" at EOF, drop it.
493
+ // A block the user has appended content after is left alone: we never shrink their bytes.
494
+ if (prefix.endsWith("\n\n")) prefix = prefix.slice(0, -1);
495
+ else if (restOfFile.length === 0 && prefix.endsWith("\n")) prefix = prefix.slice(0, -1);
496
+ const stripped = prefix + restOfFile;
497
+ atomicWriteFile(configPath, applyEol(stripped, eol));
498
+
499
+ return {
500
+ ok: true,
501
+ changed: true,
502
+ message: "Removed the opencodex managed block from Grok config.",
503
+ };
504
+ } catch (error) {
505
+ return errorResult("strip", error);
506
+ }
507
+ }
508
+ /** Decode a TOML basic-string body: JSON-compatible escapes plus TOML's \uXXXX / \UXXXXXXXX. */
509
+ function decodeTomlBasicString(body: string): string {
510
+ return body.replace(
511
+ /\\(u[0-9A-Fa-f]{4}|U[0-9A-Fa-f]{8}|.)/g,
512
+ (whole, esc: string) => {
513
+ if (esc[0] === "u") return String.fromCharCode(parseInt(esc.slice(1), 16));
514
+ if (esc[0] === "U") {
515
+ const code = parseInt(esc.slice(1), 16);
516
+ return code <= 0x10ffff ? String.fromCodePoint(code) : whole;
517
+ }
518
+ switch (esc) {
519
+ case "b": return "\b";
520
+ case "t": return "\t";
521
+ case "n": return "\n";
522
+ case "f": return "\f";
523
+ case "r": return "\r";
524
+ case '"': return '"';
525
+ case "\\": return "\\";
526
+ default: return whole; // invalid escape — keep raw, reservation stays conservative
527
+ }
528
+ },
529
+ );
530
+ }
@@ -0,0 +1,45 @@
1
+ /**
2
+ * The non-mutating Grok inspector (WP2, devlog 260803_integrations_toggle_all/012).
3
+ *
4
+ * Exists because GET /api/native-integrations must not write, and the only code
5
+ * that could answer "would a disable be refused?" used to be `stripGrokConfig`,
6
+ * which writes. This reads, never writes, and shares `findManagedRegion` with
7
+ * the writer so the two can never disagree about where our block starts and
8
+ * stops — two parsers for one fence is how a strip eventually removes the
9
+ * wrong bytes.
10
+ *
11
+ * It deliberately does NOT parse the block's contents (that is `status.ts`,
12
+ * for the dashboard's model list). This answers exactly one question: what
13
+ * state is the fence in?
14
+ */
15
+ import { existsSync, readFileSync } from "node:fs";
16
+ import { join } from "node:path";
17
+ import { findManagedRegion, isDirectory, resolveGrokHome } from "./inject";
18
+
19
+ export type GrokInspection =
20
+ /** No fence, or no config file. */
21
+ | { kind: "absent" }
22
+ /** A well-formed fence we own. */
23
+ | { kind: "present" }
24
+ /** No GROK_HOME at all. */
25
+ | { kind: "not_installed" }
26
+ /** Begin marker without an end marker — a disable would refuse. */
27
+ | { kind: "orphaned_marker" };
28
+
29
+ export function inspectGrokConfig(opts: { grokHome?: string } = {}): GrokInspection {
30
+ const grokHome = resolveGrokHome(opts.grokHome);
31
+ if (!isDirectory(grokHome)) return { kind: "not_installed" };
32
+ const configPath = join(grokHome, "config.toml");
33
+ if (!existsSync(configPath)) return { kind: "absent" };
34
+ let content: string;
35
+ try {
36
+ content = readFileSync(configPath, "utf8");
37
+ } catch {
38
+ // Unreadable is indistinguishable from absent for a READ-ONLY answer; the
39
+ // writer's own error path reports a genuine IO failure when it matters.
40
+ return { kind: "absent" };
41
+ }
42
+ const region = findManagedRegion(content);
43
+ if (!region) return { kind: "absent" };
44
+ return region.orphaned ? { kind: "orphaned_marker" } : { kind: "present" };
45
+ }