@bitkyc08/opencodex 2.76.0 → 2.78.0-preview.20261005

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 (353) hide show
  1. package/bin/ocx.mjs +11 -10
  2. package/gui/dist/assets/App-CppMz-6w.js +54 -0
  3. package/gui/dist/assets/App-lCIslZ1L.css +1 -0
  4. package/gui/dist/assets/{Tray-DjNwwrWS.js → Tray-CJWQqtVv.js} +1 -1
  5. package/gui/dist/assets/index-DQt9srNi.js +94 -0
  6. package/gui/dist/assets/index-DmQB8D_R.css +1 -0
  7. package/gui/dist/assets/quota-summary-BMsyoZH2.js +1 -0
  8. package/gui/dist/index.html +4 -3
  9. package/package.json +1 -1
  10. package/src/adapters/anthropic/beta-allowlist.ts +19 -2
  11. package/src/adapters/anthropic/client-identity.ts +13 -4
  12. package/src/adapters/anthropic/native-client-preamble.ts +31 -0
  13. package/src/adapters/anthropic/passthrough.ts +103 -25
  14. package/src/adapters/antigravity-refusal.ts +28 -0
  15. package/src/adapters/cursor/protobuf-request.ts +6 -0
  16. package/src/adapters/cursor/request-builder.ts +3 -0
  17. package/src/adapters/cursor/structured-output.ts +13 -0
  18. package/src/adapters/cursor/types.ts +2 -0
  19. package/src/adapters/devin/cloud-direct/chat.ts +7 -2
  20. package/src/adapters/devin/trajectory.ts +49 -0
  21. package/src/adapters/devin.ts +13 -0
  22. package/src/adapters/ollama-native.ts +62 -19
  23. package/src/adapters/openai-responses/passthrough.ts +133 -103
  24. package/src/adapters/openai-responses/request-strips.ts +10 -4
  25. package/src/adapters/zed.ts +26 -4
  26. package/src/bridge/response-json.ts +14 -14
  27. package/src/bridge/sse.ts +15 -5
  28. package/src/chatgpt/app-server-shim/bundle-trust.ts +40 -10
  29. package/src/chatgpt/app-server-shim/gate-rewrite.ts +3 -0
  30. package/src/claude/agents-inject.ts +4 -43
  31. package/src/claude/gateway-cache.ts +16 -13
  32. package/src/claude/inbound-model-options.ts +9 -2
  33. package/src/claude/intercept/cli-catalog.ts +27 -16
  34. package/src/claude/intercept/client-hello.ts +103 -0
  35. package/src/claude/intercept/model-bindings.ts +3 -2
  36. package/src/claude/intercept/picker-bootstrap.ts +37 -16
  37. package/src/claude/intercept/picker-budget.ts +41 -0
  38. package/src/claude/intercept/picker-listener.ts +279 -66
  39. package/src/claude/outbound.ts +2 -0
  40. package/src/claude/subagent-force-status.ts +53 -0
  41. package/src/claude/subagent-model.ts +93 -0
  42. package/src/cli/access-audio-input.ts +84 -0
  43. package/src/cli/access-audio-live.ts +99 -0
  44. package/src/cli/access-audio.ts +123 -0
  45. package/src/cli/access-data-client.ts +127 -0
  46. package/src/cli/access-data-plane.ts +104 -0
  47. package/src/cli/access-data-response.ts +76 -0
  48. package/src/cli/access.ts +65 -2
  49. package/src/cli/account-api.ts +33 -6
  50. package/src/cli/account-auth.ts +111 -42
  51. package/src/cli/account-key-quota.ts +118 -0
  52. package/src/cli/account-main.ts +11 -4
  53. package/src/cli/account-next-actions.ts +63 -0
  54. package/src/cli/account-policy-dto.ts +68 -0
  55. package/src/cli/account-policy.ts +167 -0
  56. package/src/cli/account-target.ts +8 -0
  57. package/src/cli/account.ts +37 -9
  58. package/src/cli/agent-runtime-settings.ts +130 -0
  59. package/src/cli/agent-settings.ts +101 -0
  60. package/src/cli/agent.ts +29 -2
  61. package/src/cli/alias.ts +7 -2
  62. package/src/cli/aside-profiles.ts +2 -2
  63. package/src/cli/capabilities-access-remote.ts +147 -0
  64. package/src/cli/capabilities-accounts.ts +195 -0
  65. package/src/cli/capabilities-agents-routing.ts +414 -0
  66. package/src/cli/capabilities-base.ts +783 -0
  67. package/src/cli/capabilities-command.ts +1 -0
  68. package/src/cli/capabilities-integrations.ts +264 -0
  69. package/src/cli/capabilities-lab.ts +214 -0
  70. package/src/cli/capabilities-observe-system.ts +662 -0
  71. package/src/cli/capabilities-provider-models.ts +302 -0
  72. package/src/cli/capabilities.ts +30 -1190
  73. package/src/cli/capability-types.ts +54 -0
  74. package/src/cli/catalog-command-result.ts +57 -0
  75. package/src/cli/chatgpt-command.ts +35 -9
  76. package/src/cli/claude-agent-startup-sync.ts +17 -0
  77. package/src/cli/claude-desktop-profile.ts +100 -0
  78. package/src/cli/claude-desktop.ts +39 -6
  79. package/src/cli/claude.ts +22 -6
  80. package/src/cli/codex-shim-autorestore.ts +2 -1
  81. package/src/cli/codex-shim-readiness.ts +109 -0
  82. package/src/cli/combo-input.ts +88 -0
  83. package/src/cli/combo-result.ts +52 -0
  84. package/src/cli/combo-stats.ts +123 -0
  85. package/src/cli/combo.ts +37 -14
  86. package/src/cli/companion-timeline.ts +142 -0
  87. package/src/cli/companion-usage.ts +146 -0
  88. package/src/cli/companion.ts +12 -3
  89. package/src/cli/config-command.ts +24 -8
  90. package/src/cli/connect.ts +19 -0
  91. package/src/cli/dispatch.ts +55 -82
  92. package/src/cli/doctor.ts +22 -4
  93. package/src/cli/export-command.ts +20 -9
  94. package/src/cli/gui.ts +8 -3
  95. package/src/cli/help-catalog.ts +101 -0
  96. package/src/cli/help-models-context.ts +17 -0
  97. package/src/cli/help-navigation.ts +50 -0
  98. package/src/cli/help-recovery.ts +66 -0
  99. package/src/cli/help.ts +69 -11
  100. package/src/cli/index.ts +38 -27
  101. package/src/cli/injection-follow.ts +35 -0
  102. package/src/cli/inspect.ts +5 -0
  103. package/src/cli/integration-aside-sync.ts +69 -0
  104. package/src/cli/integration-cursor.ts +106 -0
  105. package/src/cli/integration-input.ts +60 -0
  106. package/src/cli/integration-journal.ts +49 -0
  107. package/src/cli/integration-plan-dto.ts +156 -0
  108. package/src/cli/integration-preview.ts +215 -0
  109. package/src/cli/integrations.ts +24 -18
  110. package/src/cli/json-input.ts +134 -0
  111. package/src/cli/link.ts +32 -4
  112. package/src/cli/local-sync-result.ts +41 -0
  113. package/src/cli/log-follow.ts +84 -0
  114. package/src/cli/log-view-filter.ts +146 -0
  115. package/src/cli/logout-command.ts +44 -0
  116. package/src/cli/model-picker-ordering.ts +137 -0
  117. package/src/cli/models-custom-input.ts +107 -0
  118. package/src/cli/models-custom-runtime.ts +112 -0
  119. package/src/cli/models-order.ts +194 -0
  120. package/src/cli/models-runtime-subcommands.ts +2 -0
  121. package/src/cli/models-runtime.ts +9 -1
  122. package/src/cli/models.ts +66 -81
  123. package/src/cli/observe-stream.ts +142 -0
  124. package/src/cli/observe.ts +75 -34
  125. package/src/cli/opencode.ts +54 -10
  126. package/src/cli/provider-batch.ts +77 -0
  127. package/src/cli/provider-lifecycle-runtime.ts +170 -0
  128. package/src/cli/provider-result.ts +124 -0
  129. package/src/cli/provider-runtime.ts +15 -12
  130. package/src/cli/provider-settings.ts +143 -0
  131. package/src/cli/provider.ts +116 -64
  132. package/src/cli/registry.ts +90 -24
  133. package/src/cli/remote-workspace-hub.ts +83 -0
  134. package/src/cli/remote-workspace.ts +6 -1
  135. package/src/cli/restart-failure.ts +27 -0
  136. package/src/cli/root.ts +42 -9
  137. package/src/cli/route-policy-write.ts +137 -0
  138. package/src/cli/route-policy.ts +8 -0
  139. package/src/cli/runtime-api.ts +57 -80
  140. package/src/cli/secret-args.ts +149 -0
  141. package/src/cli/settings-result.ts +30 -0
  142. package/src/cli/storage.ts +77 -7
  143. package/src/cli/system-command.ts +60 -2
  144. package/src/cli/system-restart-client.ts +20 -3
  145. package/src/cli/system-settings-parity.ts +83 -0
  146. package/src/cli/tray-proxy.ts +3 -2
  147. package/src/cli/update-restart-candidate.ts +21 -0
  148. package/src/cli/update-restart-child.ts +81 -0
  149. package/src/cli/update-restart-home.ts +38 -0
  150. package/src/cli/update-restart-transport.ts +193 -0
  151. package/src/cli/update-restart.ts +260 -0
  152. package/src/cli/usage-model-search.ts +58 -0
  153. package/src/cli/usage-report.ts +13 -5
  154. package/src/cli/v2-input.ts +66 -0
  155. package/src/cli/v2-local-output.ts +37 -0
  156. package/src/cli/v2-runtime.ts +90 -0
  157. package/src/cli/v2.ts +102 -144
  158. package/src/clients/config-export/contracts.ts +100 -0
  159. package/src/clients/config-export/droid.ts +54 -2
  160. package/src/clients/config-export/dsh.ts +21 -0
  161. package/src/clients/config-export/kilo.ts +12 -2
  162. package/src/clients/config-export/model-metadata.ts +10 -4
  163. package/src/clients/config-export/reasoning-metadata.ts +47 -0
  164. package/src/clients/config-export.ts +53 -67
  165. package/src/clients/omo-role-models.ts +17 -3
  166. package/src/codex/account-credit-use.ts +4 -2
  167. package/src/codex/account-runtime-state.ts +21 -0
  168. package/src/codex/account-store.ts +11 -47
  169. package/src/codex/account-usability.ts +11 -8
  170. package/src/codex/auth-api/account-list.ts +73 -63
  171. package/src/codex/auth-api/main-account-probe.ts +25 -12
  172. package/src/codex/auth-api/pool-mode-gate.ts +6 -9
  173. package/src/codex/auth-api/pool-quota-probe.ts +2 -4
  174. package/src/codex/auth-api/reset-credit-service.ts +3 -2
  175. package/src/codex/auth-context.ts +30 -11
  176. package/src/codex/catalog/aggregation.ts +3 -0
  177. package/src/codex/catalog/build-entries.ts +1 -1
  178. package/src/codex/catalog/bundled.ts +9 -2
  179. package/src/codex/catalog/heal-observation.ts +66 -0
  180. package/src/codex/catalog/model-hints.ts +2 -1
  181. package/src/codex/catalog/model-visibility.ts +6 -3
  182. package/src/codex/catalog/parsing.ts +2 -0
  183. package/src/codex/catalog/provider-models.ts +13 -4
  184. package/src/codex/catalog/publication-observer.ts +19 -0
  185. package/src/codex/catalog/remote.ts +13 -15
  186. package/src/codex/catalog/restore.ts +19 -6
  187. package/src/codex/catalog/retained-sync.ts +60 -11
  188. package/src/codex/catalog/routed-removal.ts +116 -0
  189. package/src/codex/catalog/write-audit-contract.ts +21 -0
  190. package/src/codex/catalog/write-audit.ts +171 -0
  191. package/src/codex/catalog-self-heal.ts +284 -0
  192. package/src/codex/catalog-write-serialization.ts +71 -7
  193. package/src/codex/chatgpt-refresh-failure.ts +56 -0
  194. package/src/codex/codex-home-owner.ts +124 -0
  195. package/src/codex/convergence.ts +57 -16
  196. package/src/codex/features.ts +8 -1
  197. package/src/codex/inject/restore.ts +46 -4
  198. package/src/codex/inject.ts +11 -1
  199. package/src/codex/internal/catalog-writer.ts +120 -13
  200. package/src/codex/journal.ts +49 -13
  201. package/src/codex/main-account.ts +144 -11
  202. package/src/codex/management-convergence.ts +3 -0
  203. package/src/codex/quota-refresh-outcome.ts +17 -2
  204. package/src/codex/quota-types.ts +36 -1
  205. package/src/codex/quota.ts +67 -16
  206. package/src/codex/refresh.ts +20 -9
  207. package/src/codex/routing/cooldown-math.ts +10 -4
  208. package/src/codex/routing/selection.ts +11 -4
  209. package/src/codex/routing.ts +9 -9
  210. package/src/codex/runtime.ts +7 -1
  211. package/src/codex/shim-diagnostics.ts +80 -0
  212. package/src/codex/shim-fingerprint.ts +7 -2
  213. package/src/codex/shim-migration.ts +153 -0
  214. package/src/codex/shim-overlay.ts +509 -0
  215. package/src/codex/shim-path-resolution.ts +145 -0
  216. package/src/codex/shim-probe.ts +4 -3
  217. package/src/codex/shim-state-file.ts +93 -7
  218. package/src/codex/shim.ts +54 -107
  219. package/src/codex/subagent-model-fallback.ts +2 -1
  220. package/src/codex/sync.ts +24 -4
  221. package/src/combos/failover.ts +101 -1
  222. package/src/combos/index.ts +1 -0
  223. package/src/combos/jev.ts +13 -3
  224. package/src/combos/resolve.ts +12 -0
  225. package/src/config/atomic-write.ts +13 -8
  226. package/src/config/diagnostics.ts +23 -1
  227. package/src/config/load-degrade.ts +7 -0
  228. package/src/config/provider-validation.ts +3 -0
  229. package/src/config/schema/chatgpt-desktop.ts +22 -0
  230. package/src/config/schema/compaction-triggers.ts +8 -0
  231. package/src/config/schema/config-schema.ts +43 -14
  232. package/src/config/schema/leaf-validators.ts +8 -3
  233. package/src/config/subagent-models.ts +12 -0
  234. package/src/generated/compatibility-version.json +645 -237
  235. package/src/grok/session-identity.ts +33 -0
  236. package/src/integrations/catalog-refresh.ts +1 -1
  237. package/src/integrations/merge.ts +13 -5
  238. package/src/integrations/mutation-plan.ts +50 -5
  239. package/src/integrations/omp-yaml-source.ts +181 -1
  240. package/src/integrations/ownership-policy.ts +66 -0
  241. package/src/integrations/registry.ts +50 -1
  242. package/src/integrations/state.ts +106 -19
  243. package/src/integrations/target.ts +25 -2
  244. package/src/integrations/writer.ts +107 -35
  245. package/src/lib/gui-pair-capability.ts +17 -0
  246. package/src/lib/package-tree-integrity.ts +42 -1
  247. package/src/lib/provider-client-headers.ts +62 -0
  248. package/src/lib/proxy-env.ts +3 -0
  249. package/src/lib/test-home-guard.ts +2 -1
  250. package/src/oauth/anthropic-account-refusal.ts +19 -8
  251. package/src/oauth/anthropic-continuity.ts +65 -0
  252. package/src/oauth/anthropic-identity.ts +75 -0
  253. package/src/oauth/anthropic-routing.ts +20 -15
  254. package/src/oauth/anthropic.ts +34 -3
  255. package/src/oauth/generic-account-failover.ts +21 -0
  256. package/src/oauth/health.ts +32 -5
  257. package/src/oauth/index.ts +42 -35
  258. package/src/oauth/local-token-detect.ts +7 -0
  259. package/src/oauth/pool-settings-capability.ts +9 -2
  260. package/src/oauth/refresh-policy.ts +2 -0
  261. package/src/oauth/store.ts +55 -6
  262. package/src/oauth/types.ts +9 -0
  263. package/src/protocols/encoders/messages.ts +4 -3
  264. package/src/protocols/plan-snapshot.ts +1 -1
  265. package/src/protocols/settings.ts +28 -4
  266. package/src/providers/antigravity-effort-families.ts +75 -0
  267. package/src/providers/antigravity-models.ts +54 -16
  268. package/src/providers/antigravity-wire-snapshot.ts +66 -0
  269. package/src/providers/derive.ts +2 -0
  270. package/src/providers/model-rename-fields.ts +3 -0
  271. package/src/providers/new-model-policy.ts +48 -10
  272. package/src/providers/registry/entries-extended.ts +3 -0
  273. package/src/providers/registry/model-ids.ts +2 -0
  274. package/src/providers/registry/model-seeds.ts +5 -0
  275. package/src/providers/registry/types.ts +4 -0
  276. package/src/responses/compaction.ts +19 -0
  277. package/src/router.ts +6 -0
  278. package/src/server/auth-cors.ts +9 -0
  279. package/src/server/caller-session-identity.ts +32 -0
  280. package/src/server/chat-completions.ts +10 -0
  281. package/src/server/claude-messages.ts +29 -15
  282. package/src/server/droid-reasoning-default.ts +50 -0
  283. package/src/server/github-copilot-responses-repair.ts +3 -6
  284. package/src/server/grok-responses-control-frame.ts +2 -2
  285. package/src/server/grok-responses-snapshot-repair.ts +4 -5
  286. package/src/server/gui-session.ts +33 -11
  287. package/src/server/index/claude-intercept-lifecycle.ts +4 -0
  288. package/src/server/index/serve-options.ts +13 -7
  289. package/src/server/index.ts +1 -1
  290. package/src/server/management/agent-settings-routes.ts +12 -134
  291. package/src/server/management/config-routes.ts +1 -1
  292. package/src/server/management/context.ts +8 -1
  293. package/src/server/management/cursor-integration-routes.ts +3 -3
  294. package/src/server/management/integration-routes.ts +69 -11
  295. package/src/server/management/link-routes.ts +20 -13
  296. package/src/server/management/model-routes.ts +3 -3
  297. package/src/server/management/model-row-export-metadata.ts +150 -0
  298. package/src/server/management/model-rows.ts +148 -9
  299. package/src/server/management/native-integration-routes.ts +2 -2
  300. package/src/server/management/oauth-account-routes.ts +96 -30
  301. package/src/server/management/route-registry.ts +29 -27
  302. package/src/server/management/shared.ts +19 -5
  303. package/src/server/management/subagent-model-routes.ts +214 -0
  304. package/src/server/messages-native-eligibility.ts +3 -6
  305. package/src/server/messages-native-oauth.ts +82 -35
  306. package/src/server/messages-native.ts +78 -16
  307. package/src/server/relay.ts +14 -44
  308. package/src/server/request-log-generation-window.ts +38 -0
  309. package/src/server/request-log.ts +13 -0
  310. package/src/server/responses/adapter-dispatch.ts +152 -28
  311. package/src/server/responses/codex-auth-error.ts +10 -2
  312. package/src/server/responses/combo-stream-preflight.ts +29 -3
  313. package/src/server/responses/compaction-routing.ts +10 -1
  314. package/src/server/responses/core-auth.ts +67 -30
  315. package/src/server/responses/core-codex-account.ts +6 -3
  316. package/src/server/responses/core-combo-failure.ts +5 -1
  317. package/src/server/responses/core-combo-native.ts +7 -1
  318. package/src/server/responses/core-combo.ts +64 -7
  319. package/src/server/responses/core-normalize.ts +7 -0
  320. package/src/server/responses/core-options.ts +5 -0
  321. package/src/server/responses/fetch-helpers.ts +9 -0
  322. package/src/server/responses/passthrough-delivery.ts +1 -1
  323. package/src/server/responses/policy-fallback.ts +1 -1
  324. package/src/server/responses/request-prepare.ts +5 -0
  325. package/src/server/responses/request-spend.ts +30 -30
  326. package/src/server/responses-custom-tool-repair.ts +2 -2
  327. package/src/server/responses-hosted-image-display.ts +70 -9
  328. package/src/server/responses-terminal-repair.ts +15 -2
  329. package/src/server/sse-frame-buffer.ts +38 -36
  330. package/src/server/sse-payload-rewrite.ts +78 -49
  331. package/src/server/ws-bridge.ts +1 -11
  332. package/src/service/cli.ts +6 -1
  333. package/src/service/ownership-mutation-lease.d.mts +26 -0
  334. package/src/service/ownership-mutation-lease.mjs +76 -1
  335. package/src/service/windows-taskxml.ts +1 -2
  336. package/src/service-manager-probe.ts +36 -2
  337. package/src/types/config.ts +6 -0
  338. package/src/types/provider.ts +28 -10
  339. package/src/update/index.ts +2 -1
  340. package/src/update/npm-invocation.mjs +35 -3
  341. package/src/update/proxy-liveness-probe.mjs +38 -8
  342. package/src/update/update-failure-guidance.d.mts +6 -0
  343. package/src/update/update-failure-guidance.mjs +30 -5
  344. package/src/usage/expected-prices.ts +9 -0
  345. package/src/usage/log.ts +7 -0
  346. package/src/usage/summary.ts +82 -1
  347. package/src/web-search/loop.ts +11 -8
  348. package/src/web-search/run-turn-loop.ts +10 -7
  349. package/gui/dist/assets/App-CddorHdA.js +0 -51
  350. package/gui/dist/assets/App-DMudtISW.css +0 -1
  351. package/gui/dist/assets/index-Btze1I3T.css +0 -1
  352. package/gui/dist/assets/index-CvnY7E6i.js +0 -86
  353. package/gui/dist/assets/quota-summary-B_AWpHfP.js +0 -1
@@ -0,0 +1,130 @@
1
+ import { isValidVisionTimeoutMs } from "../vision/plan";
2
+ import { isDeclaredReasoningEffort } from "../reasoning-effort";
3
+ import { runCatalogAction } from "./catalog-command-result";
4
+ import { serializeManagementJson } from "./json-input";
5
+ import { projectSettingsApply } from "./settings-result";
6
+ import { CliUsageError, desktopSwitchApplyReason, printData, runtimeBaseUrl, runtimeRequest,
7
+ takeFlag, takeOptionWithSyntax, type RuntimeApiDeps } from "./runtime-api";
8
+
9
+ function record(value: unknown): value is Record<string, unknown> {
10
+ return value !== null && typeof value === "object" && !Array.isArray(value);
11
+ }
12
+ function boolean(args: string[], flag: string): boolean | undefined {
13
+ const value = takeOptionWithSyntax(args, flag)?.value;
14
+ if (value === undefined) return undefined;
15
+ if (["on", "true", "yes", "1", "enabled"].includes(value.toLowerCase())) return true;
16
+ if (["off", "false", "no", "0", "disabled"].includes(value.toLowerCase())) return false;
17
+ throw new CliUsageError(`${flag} must be on or off`);
18
+ }
19
+ function invalid(): never { throw new Error("Invalid agent settings receipt"); }
20
+
21
+ /** Additive default-sync option; normalized server state, not a native-write claim. */
22
+ export async function handleInjectionDefaults(argsInput: string[], deps: RuntimeApiDeps = {}): Promise<number> {
23
+ return runCatalogAction(async () => {
24
+ const args = [...argsInput];
25
+ if (args.shift() !== "set") throw new CliUsageError("--sync-codex-defaults requires agent injection set");
26
+ const wantsJson = takeFlag(args, "--json");
27
+ const sync = boolean(args, "--sync-codex-defaults");
28
+ const guidance = boolean(args, "--guidance");
29
+ const body: Record<string, unknown> = {};
30
+ for (const [flag, key] of [["--model", "model"], ["--effort", "effort"], ["--prompt", "prompt"]] as const) {
31
+ const value = takeOptionWithSyntax(args, flag)?.value;
32
+ if (value !== undefined) body[key] = value === "-" ? null : value;
33
+ }
34
+ if (sync === undefined || args.length) throw new CliUsageError("Provide --sync-codex-defaults on or off and supported injection options");
35
+ body.syncCodexSubagentDefaults = sync;
36
+ if (guidance !== undefined) body.multiAgentGuidanceEnabled = guidance;
37
+ const pinned = { ...deps, baseUrl: await runtimeBaseUrl(deps) };
38
+ const value = await runtimeRequest("/api/injection-model", { method: "PUT", redirect: "error", body: serializeManagementJson(body) }, pinned);
39
+ if (!record(value) || value.ok !== true || typeof value.multiAgentGuidanceEnabled !== "boolean"
40
+ || typeof value.syncCodexSubagentDefaults !== "boolean"
41
+ || ["model", "effort", "prompt"].some(key => value[key] !== null && typeof value[key] !== "string")) invalid();
42
+ const data = { ok: true, multiAgentGuidanceEnabled: value.multiAgentGuidanceEnabled,
43
+ syncCodexSubagentDefaults: value.syncCodexSubagentDefaults, model: value.model, effort: value.effort, prompt: value.prompt };
44
+ printData(data, wantsJson, ["Injection settings saved.", `Guidance: ${data.multiAgentGuidanceEnabled}`,
45
+ `Effective default-sync setting: ${data.syncCodexSubagentDefaults}`]);
46
+ return 0;
47
+ });
48
+ }
49
+
50
+ /** New sidecar fields share the existing candidate normalization and partial PUT contract. */
51
+ export async function handleSidecarRuntimeSettings(argsInput: string[], deps: RuntimeApiDeps = {}): Promise<number> {
52
+ return runCatalogAction(async () => {
53
+ const args = [...argsInput], section = args.shift();
54
+ if (section !== "web" && section !== "vision") throw new CliUsageError("Sidecar settings require web or vision");
55
+ const wantsJson = takeFlag(args, "--json");
56
+ const model = takeOptionWithSyntax(args, "--model")?.value;
57
+ const backend = takeOptionWithSyntax(args, "--backend")?.value;
58
+ const reasoning = takeOptionWithSyntax(args, "--reasoning")?.value;
59
+ const max = takeOptionWithSyntax(args, "--max-descriptions")?.value;
60
+ const timeout = takeOptionWithSyntax(args, "--timeout-ms")?.value;
61
+ const enabled = boolean(args, "--enabled");
62
+ const stream = boolean(args, "--stream-routed-output");
63
+ if (args.length || (section === "web" && (max !== undefined || timeout !== undefined))
64
+ || (section === "vision" && stream !== undefined)) throw new CliUsageError("Unsupported option for this sidecar section");
65
+ const settings: Record<string, unknown> = {};
66
+ if (model !== undefined) settings.model = model === "-" ? "" : model;
67
+ if (backend !== undefined) settings.backend = backend === "-" ? null : backend;
68
+ if (reasoning !== undefined) settings.reasoning = reasoning;
69
+ if (enabled !== undefined) settings.enabled = enabled;
70
+ if (stream !== undefined) settings.streamRoutedModelOutput = stream;
71
+ if (max !== undefined) {
72
+ const value = Number(max);
73
+ if (!max.trim() || !Number.isSafeInteger(value) || value < 1) throw new CliUsageError("--max-descriptions requires a positive integer");
74
+ settings.maxDescriptionsPerTurn = value;
75
+ }
76
+ if (timeout !== undefined) {
77
+ const value = Number(timeout);
78
+ if (!timeout.trim() || !isValidVisionTimeoutMs(value)) throw new CliUsageError("--timeout-ms requires an integer from 1 to 2147483647");
79
+ settings.timeoutMs = value;
80
+ }
81
+ if (!Object.keys(settings).length) throw new CliUsageError("Provide at least one sidecar setting");
82
+ const pinned = { ...deps, baseUrl: await runtimeBaseUrl(deps) };
83
+ if (section === "web" && model !== undefined && model !== "-") {
84
+ const offered = await runtimeRequest("/api/sidecar-settings", { redirect: "error" }, pinned);
85
+ if (!record(offered) || !Array.isArray(offered.webSearchModels)) invalid();
86
+ const requestedBackend = backend === "-" ? "openai" : backend;
87
+ const option = offered.webSearchModels.find(row => record(row)
88
+ && (row.value === model || row.model === model)
89
+ && (requestedBackend === undefined || row.backend === requestedBackend));
90
+ if (option !== undefined) {
91
+ if (!record(option) || typeof option.model !== "string" || typeof option.backend !== "string"
92
+ || !["openai", "anthropic", "xai", "gemini", "exa"].includes(option.backend)) invalid();
93
+ settings.model = option.model;
94
+ if (backend !== "-") settings.backend = option.backend;
95
+ }
96
+ }
97
+ const value = await runtimeRequest("/api/sidecar-settings", { method: "PUT", redirect: "error",
98
+ body: serializeManagementJson(section === "web" ? { webSearch: settings } : { vision: settings }) }, pinned);
99
+ if (!record(value) || value.ok !== true) invalid();
100
+ const raw = section === "web" ? value.webSearch : value.vision;
101
+ const backends = section === "web" ? ["openai", "anthropic", "xai", "gemini", "exa"] : ["openai", "anthropic", "routed"];
102
+ if (!record(raw) || typeof raw.enabled !== "boolean" || typeof raw.model !== "string" || !raw.model.trim()
103
+ || (raw.backend !== undefined && (typeof raw.backend !== "string" || !backends.includes(raw.backend)))) invalid();
104
+ const selected: Record<string, unknown> = { enabled: raw.enabled, model: raw.model,
105
+ ...(raw.backend !== undefined ? { backend: raw.backend } : {}) };
106
+ let verified = true;
107
+ if (section === "web") {
108
+ if (typeof raw.streamRoutedModelOutput !== "boolean") invalid();
109
+ selected.streamRoutedModelOutput = raw.streamRoutedModelOutput;
110
+ if (stream !== undefined && raw.streamRoutedModelOutput !== stream) verified = false;
111
+ } else {
112
+ if (!isValidVisionTimeoutMs(raw.timeoutMs) || typeof raw.maxDescriptionsPerTurn !== "number"
113
+ || !Number.isSafeInteger(raw.maxDescriptionsPerTurn) || raw.maxDescriptionsPerTurn < 1
114
+ || (raw.reasoning !== undefined && (typeof raw.reasoning !== "string" || !isDeclaredReasoningEffort(raw.reasoning)))) invalid();
115
+ selected.timeoutMs = raw.timeoutMs;
116
+ selected.maxDescriptionsPerTurn = raw.maxDescriptionsPerTurn;
117
+ if (raw.reasoning !== undefined) selected.reasoning = raw.reasoning;
118
+ if (timeout !== undefined && raw.timeoutMs !== Number(timeout)) verified = false;
119
+ }
120
+ const apply = projectSettingsApply(value.codexWebSearch);
121
+ if (!apply) invalid();
122
+ const data = { ok: true, [section === "web" ? "webSearch" : "vision"]: selected, codexWebSearch: apply,
123
+ ...(!verified ? { verification: "unverified" } : {}) };
124
+ const lines = [`${section} sidecar settings saved.`];
125
+ if (!apply.applied) lines.push(`Native apply: ${desktopSwitchApplyReason(apply.reason)}.`);
126
+ if (!verified) lines.push("The target did not confirm the requested new setting. Read back before retrying.");
127
+ printData(data, wantsJson, lines);
128
+ return !verified || (!apply.applied && apply.reason !== "not_requested") ? 1 : 0;
129
+ });
130
+ }
@@ -0,0 +1,101 @@
1
+ import { compactionRoutingSchema, memoryModelsSchema } from "../config/schema/leaf-validators";
2
+ import { runCatalogAction } from "./catalog-command-result";
3
+ import { readJsonInput, serializeManagementJson } from "./json-input";
4
+ import { printSettingsResult } from "./settings-result";
5
+ import {
6
+ CliUsageError, printData, runtimeBaseUrl, runtimeRequest, takeFlag,
7
+ takeOptionWithSyntax, type RuntimeApiDeps,
8
+ } from "./runtime-api";
9
+
10
+ type SettingCommand = "memory-models" | "compaction-routing";
11
+
12
+ function usage(sub: SettingCommand): string {
13
+ const fields = sub === "memory-models"
14
+ ? "[--extract-model <model> [--extract-effort <effort>]] [--consolidation-model <model> [--consolidation-effort <effort>]]"
15
+ : "--model <model> [--effort <effort>] [--triggers <manual,auto>] [--sources <selector,...>]";
16
+ return `Usage: ocx agent ${sub} show|clear [--json]\n ocx agent ${sub} set (--file <FILE|-> | ${fields}) [--json]`;
17
+ }
18
+
19
+ function scalarBlock(sub: SettingCommand, values: Record<string, string>): Record<string, unknown> {
20
+ if (sub === "memory-models") {
21
+ const block: Record<string, unknown> = {};
22
+ for (const phase of ["extract", "consolidation"]) {
23
+ const model = values[`--${phase}-model`], effort = values[`--${phase}-effort`];
24
+ if (effort !== undefined && model === undefined) {
25
+ throw new CliUsageError("A memory phase effort requires its model", usage(sub));
26
+ }
27
+ if (model !== undefined) block[phase] = { model, ...(effort === undefined ? {} : { reasoningEffort: effort }) };
28
+ }
29
+ if (!Object.keys(block).length) throw new CliUsageError("Set requires at least one memory phase model or an explicit file", usage(sub));
30
+ return block;
31
+ }
32
+ return {
33
+ ...(values["--model"] === undefined ? {} : { model: values["--model"] }),
34
+ ...(values["--effort"] === undefined ? {} : { reasoningEffort: values["--effort"] }),
35
+ // Deliberately preserve every CSV token: schema validation rejects blanks,
36
+ // duplicates and whitespace instead of changing the requested scope.
37
+ ...(values["--triggers"] === undefined ? {} : { triggers: values["--triggers"].split(",") }),
38
+ ...(values["--sources"] === undefined ? {} : { sourceModels: values["--sources"].split(",") }),
39
+ };
40
+ }
41
+
42
+ function normalizedBlock(sub: SettingCommand, value: unknown, input: boolean): Record<string, unknown> | null {
43
+ if (!input && value === null) return null;
44
+ const parsed = sub === "memory-models" ? memoryModelsSchema.safeParse(value) : compactionRoutingSchema.safeParse(value);
45
+ if (!parsed.success) {
46
+ if (input) throw new CliUsageError("Invalid model override block; check the supported fields and model/effort values", usage(sub));
47
+ throw new Error("Invalid settings response");
48
+ }
49
+ return parsed.data;
50
+ }
51
+
52
+ /** Task-only settings replacement; no local fallback, model probe or pipeline toggle. */
53
+ export async function handleAgentSettingsCommand(
54
+ sub: SettingCommand, argv: string[], deps: RuntimeApiDeps = {},
55
+ ): Promise<number> {
56
+ return runCatalogAction(async () => {
57
+ const args = [...argv];
58
+ const action = args.shift();
59
+ if (action !== "show" && action !== "set" && action !== "clear") {
60
+ throw new CliUsageError("Expected show, set or clear", usage(sub));
61
+ }
62
+ const wantsJson = takeFlag(args, "--json");
63
+ const file = takeOptionWithSyntax(args, "--file")?.value;
64
+ const flags = sub === "memory-models"
65
+ ? ["--extract-model", "--extract-effort", "--consolidation-model", "--consolidation-effort"]
66
+ : ["--model", "--effort", "--triggers", "--sources"];
67
+ const values: Record<string, string> = {};
68
+ for (const flag of flags) {
69
+ const value = takeOptionWithSyntax(args, flag)?.value;
70
+ if (value !== undefined) values[flag] = value;
71
+ }
72
+ if (args.length) throw new CliUsageError("Unexpected or repeated settings argument", usage(sub));
73
+ const hasFields = Object.keys(values).length > 0;
74
+ if (action !== "set" && (file !== undefined || hasFields)) {
75
+ throw new CliUsageError("Only set accepts a file or model options", usage(sub));
76
+ }
77
+ if (file !== undefined && hasFields) throw new CliUsageError("--file cannot be combined with model options", usage(sub));
78
+ const key = sub === "memory-models" ? "memoryModels" : "compactionRouting";
79
+ const block = action === "set"
80
+ ? normalizedBlock(sub, file === undefined ? scalarBlock(sub, values) : await readJsonInput(file, deps), true)
81
+ : null;
82
+ const body = action === "show" ? undefined : serializeManagementJson({ [key]: block });
83
+ const pinned = { ...deps, baseUrl: await runtimeBaseUrl(deps) };
84
+ const response = await runtimeRequest("/api/settings", {
85
+ method: action === "show" ? "GET" : "PUT", redirect: "error", ...(body === undefined ? {} : { body }),
86
+ }, pinned);
87
+ if (!response || typeof response !== "object" || Array.isArray(response)) throw new Error("Invalid settings response");
88
+ const record = response as Record<string, unknown>;
89
+ if (action !== "show" && record.ok !== true) throw new Error("Settings acceptance was not reported");
90
+ const observed = normalizedBlock(sub, record[key], false);
91
+ const data = { [key]: observed };
92
+ const lines = [observed === null || Object.keys(observed).length === 0
93
+ ? `${sub}: no custom overrides; existing routing remains in use.`
94
+ : `${sub}: ${JSON.stringify(observed)}`];
95
+ if (action === "show") {
96
+ printData(data, wantsJson, lines);
97
+ return 0;
98
+ }
99
+ return printSettingsResult(data, record.catalogRefreshPending, wantsJson, lines);
100
+ });
101
+ }
package/src/cli/agent.ts CHANGED
@@ -24,15 +24,19 @@ interface WebSearchModelOption {
24
24
  const USAGE = `Usage:
25
25
  ocx agent [status] [--json]
26
26
  ocx agent injection <status|set> [--model <id|->] [--effort <level|->]
27
- [--prompt <text|->] [--guidance <on|off>] [--json]
27
+ [--prompt <text|->] [--guidance <on|off>] [--sync-codex-defaults <on|off>] [--json]
28
28
  ocx agent injection suggest <work description> [--model <id>] [--apply] [--json]
29
29
  ocx agent effort <status|set> [--main <level|->] [--subagent <level|->] [--json]
30
30
  ocx agent subagents <status|set|clear> [model,model...] [--json]
31
+ ocx agent subagents force <model|-> [--json]
31
32
  ocx agent fallback <status|set|clear> [model,model...] [--poll-ms <5000-600000>] [--json]
32
33
  ocx agent roles [status|set <role> <model>|suggest [--model <id>] [--apply]] [--json]
33
34
  ocx agent sidecar <status|web|vision> [--list] [--model <id|->]
34
35
  [--backend web:<openai|anthropic|xai|gemini|exa|-> vision:<openai|anthropic|routed|->]
35
- [--reasoning <level>] [--max-descriptions <n>] [--enabled <on|off>] [--json]
36
+ [--reasoning <level>] [--max-descriptions <n> (vision)] [--enabled <on|off>]
37
+ [--stream-routed-output <on|off> (web)] [--timeout-ms <1-2147483647> (vision)] [--json]
38
+ ocx agent memory-models <show|set|clear> [options] [--json]
39
+ ocx agent compaction-routing <show|set|clear> [options] [--json]
36
40
  ocx agent request-user-input [on|off] [--json]`;
37
41
 
38
42
  function clearable(value: string | undefined): string | null | undefined {
@@ -169,6 +173,15 @@ async function subagents(argv: string[], deps: RuntimeApiDeps): Promise<void> {
169
173
  printData(result, wantsJson, summaryLines(result));
170
174
  return;
171
175
  }
176
+ if (action === "force") {
177
+ const model = args.shift();
178
+ if (!model?.trim()) throw new CliUsageError("a force model or - is required", USAGE);
179
+ rejectArgs(args, USAGE);
180
+ const force = clearable(model);
181
+ const result = await runtimeRequest("/api/subagent-models", { method: "PUT", body: JSON.stringify({ force }) }, deps);
182
+ printData(result, wantsJson, [force ? `Claude subagent force: ${force}. Applies on the next routed ocx claude launch.` : "Claude subagent force cleared."]);
183
+ return;
184
+ }
172
185
  let models: string[];
173
186
  if (action === "clear") models = [];
174
187
  else if (action === "set") {
@@ -247,6 +260,7 @@ async function sidecar(argv: string[], deps: RuntimeApiDeps): Promise<void> {
247
260
  const backend = takeOption(args, "--backend");
248
261
  const reasoning = takeOption(args, "--reasoning");
249
262
  const maxDescriptionsPerTurn = takeIntegerOption(args, "--max-descriptions", { min: 1 });
263
+ if (section === "web" && maxDescriptionsPerTurn !== undefined) throw new CliUsageError("--max-descriptions applies only to the vision sidecar", USAGE);
250
264
  const enabled = takeBooleanOption(args, "--enabled");
251
265
  rejectArgs(args, USAGE);
252
266
  const settings: Record<string, unknown> = {};
@@ -408,6 +422,19 @@ async function roles(argv: string[], deps: RuntimeApiDeps): Promise<void> {
408
422
  }
409
423
 
410
424
  export async function handleAgentCommand(argv: string[], deps: RuntimeApiDeps = {}): Promise<number> {
425
+ const has = (flag: string) => argv.some(arg => arg === flag || arg.startsWith(`${flag}=`));
426
+ if ((argv[0] === "injection" || argv[0] === "guidance") && has("--sync-codex-defaults")) {
427
+ const { handleInjectionDefaults } = await import("./agent-runtime-settings");
428
+ return handleInjectionDefaults(argv.slice(1), deps);
429
+ }
430
+ if (argv[0] === "sidecar" && (has("--stream-routed-output") || has("--timeout-ms"))) {
431
+ const { handleSidecarRuntimeSettings } = await import("./agent-runtime-settings");
432
+ return handleSidecarRuntimeSettings(argv.slice(1), deps);
433
+ }
434
+ if (argv[0] === "memory-models" || argv[0] === "compaction-routing") {
435
+ const { handleAgentSettingsCommand } = await import("./agent-settings");
436
+ return handleAgentSettingsCommand(argv[0], argv.slice(1), deps);
437
+ }
411
438
  return runCliAction(async () => {
412
439
  const [sub = "status", ...rest] = argv;
413
440
  if (sub === "status") await status(rest, deps);
package/src/cli/alias.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { CliUsageError, printData, rejectArgs, runtimeRequest, takeFlag, takeOption, type RuntimeApiDeps } from "./runtime-api";
1
+ import { CliUsageError, printData, rejectArgs, runCliAction, runtimeRequest, takeFlag, takeOption, type RuntimeApiDeps } from "./runtime-api";
2
2
 
3
3
  const USAGE = `Usage:
4
4
  ocx alias list [--json]
@@ -14,6 +14,10 @@ function selector(value: string): { provider: string; model?: string } {
14
14
 
15
15
  /** Manage model aliases, consuming JSON output selection before the default list action. */
16
16
  export async function handleAliasCommand(argv: string[], deps: RuntimeApiDeps = {}): Promise<number> {
17
+ return runCliAction(async () => { await runAliasAction(argv, deps); });
18
+ }
19
+
20
+ async function runAliasAction(argv: string[], deps: RuntimeApiDeps): Promise<number> {
17
21
  const args = [...argv];
18
22
  const wantsJson = takeFlag(args, "--json");
19
23
  const action = (args.shift() ?? "list").toLowerCase();
@@ -37,6 +41,7 @@ export async function handleAliasCommand(argv: string[], deps: RuntimeApiDeps =
37
41
  printData(result, wantsJson, [`Default aliases ${state}${provider ? ` for ${provider}` : " globally"}.`]);
38
42
  return 0;
39
43
  }
44
+ if (action !== "set" && action !== "rm") throw new CliUsageError(`Unknown alias action: ${action}. See: ocx help alias`, USAGE);
40
45
  const target = args.shift()?.trim();
41
46
  if (!target) throw new CliUsageError("alias target is required", USAGE);
42
47
  const parsed = selector(target);
@@ -63,5 +68,5 @@ export async function handleAliasCommand(argv: string[], deps: RuntimeApiDeps =
63
68
  printData(result, wantsJson, [`Removed alias for ${target}.`]);
64
69
  return 0;
65
70
  }
66
- throw new CliUsageError(`unknown alias action '${action}'`, USAGE);
71
+ return 0;
67
72
  }
@@ -4,7 +4,7 @@ import { createLocalAttestationChallenge, LOCAL_ATTESTATION_CHALLENGE_HEADER, LO
4
4
  import { createLocalAsideSyncCapability, LOCAL_ASIDE_SYNC_CAPABILITY_HEADER, LOCAL_ASIDE_SYNC_CAPABILITY_TTL_MS, LOCAL_ASIDE_SYNC_CAPABILITY_VERSION, LOCAL_ASIDE_SYNC_EXPECTED_PID_HEADER, LOCAL_ASIDE_SYNC_EXPIRES_AT_HEADER, LOCAL_ASIDE_SYNC_METHOD, LOCAL_ASIDE_SYNC_NONCE_HEADER, LOCAL_ASIDE_SYNC_PATH } from "../lib/local-aside-sync-contract";
5
5
  import { directLocalHttpFetch } from "../server/direct-local-http";
6
6
  import { findLiveProxy, isOpencodexHealthz, probeHostname } from "../server/proxy-liveness";
7
- import { runtimeRequest, RuntimeApiError, type RuntimeApiDeps } from "./runtime-api";
7
+ import { runtimeRequest, RuntimeApiError, PROXY_NOT_RUNNING_MESSAGE, type RuntimeApiDeps } from "./runtime-api";
8
8
 
9
9
  /** Aside policy and file writes share the running server's mutation owner. Never fall back locally. */
10
10
  export async function refreshAsideProfilesThroughServer(
@@ -27,7 +27,7 @@ export async function refreshAsideProfilesThroughServer(
27
27
  const deadline = controller.signal;
28
28
  try {
29
29
  const live = await (deps.findLiveProxy ?? findLiveProxy)();
30
- if (!live) throw new RuntimeApiError("Proxy is not running. Start it with: ocx start", 503, null);
30
+ if (!live) throw new RuntimeApiError(PROXY_NOT_RUNNING_MESSAGE, 503, null, "proxy_not_running");
31
31
  if (live.source !== "runtime" || live.pid === null) {
32
32
  throw new RuntimeApiError("Aside profile synchronization requires an attested running proxy", 503, null);
33
33
  }
@@ -0,0 +1,147 @@
1
+ import type { Capability } from "./capability-types";
2
+
3
+ /** Verified existing handlers only; local operations never claim management routes. */
4
+ export const ACCESS_REMOTE_CAPABILITIES: readonly Capability[] = [
5
+ {
6
+ command: ["access", "key"], summary: "Manage API access keys and inspect masked metadata.",
7
+ usage: "ocx access key list [--json]",
8
+ routes: [{"method": "GET", "path": "/api/keys"}, {"method": "POST", "path": "/api/keys"}, {"method": "PATCH", "path": "/api/keys"}, {"method": "DELETE", "path": "/api/keys"}, {"method": "POST", "path": "/api/keys/rotate"}, {"method": "POST", "path": "/api/keys/rotate/commit"}, {"method": "DELETE", "path": "/api/keys/rotate"}],
9
+ flags: [{"name": "--json", "value": "boolean", "summary": "Emit the result as JSON."}],
10
+ mutates: true, json: "payload",
11
+ details: ["Mixed family: list/get read masked metadata; scope edits, revocation and rotation change authorization.", "Creation and rotation initiation return plaintext secrets once and are human-only handoffs. Ask the operator to perform them in their terminal or dashboard; never capture the returned credential.", "Use the separately documented safe follow-up leaves. keys and top-level api-key are aliases."],
12
+ },
13
+ {
14
+ command: ["access", "key", "list"], summary: "List masked access keys, usage, endpoints and pending rotations.",
15
+ usage: "ocx access key list [--json]",
16
+ routes: [{"method": "GET", "path": "/api/keys"}],
17
+ flags: [{"name": "--json", "value": "boolean", "summary": "Emit the result as JSON."}],
18
+ mutates: false, json: "payload",
19
+ details: ["No plaintext secret is returned by the list route."],
20
+ },
21
+ {
22
+ command: ["access", "key", "get"], summary: "Read one masked key and its access scope.",
23
+ usage: "ocx access key get <id-or-name> [--json]",
24
+ routes: [{"method": "GET", "path": "/api/keys"}],
25
+ flags: [{"name": "--json", "value": "boolean", "summary": "Emit the result as JSON."}],
26
+ mutates: false, json: "payload",
27
+ details: ["Case-insensitive ID takes precedence over name; ambiguous names are refused."],
28
+ },
29
+ {
30
+ command: ["access", "key", "set"], summary: "Replace selected provider/model scope dimensions.",
31
+ usage: "ocx access key set <id-or-name> [--allow-provider <name>]... [--allow-model <id>]... [--clear] [--json]",
32
+ routes: [{"method": "GET", "path": "/api/keys"}, {"method": "PATCH", "path": "/api/keys"}],
33
+ flags: [{"name": "--allow-provider", "value": "string", "summary": "Provider scope; repeatable, replaces that dimension."}, {"name": "--allow-model", "value": "string", "summary": "Model scope; repeatable, replaces that dimension."}, {"name": "--clear", "value": "boolean", "summary": "Clear both dimensions; submitted allow options then override their dimension."}, {"name": "--json", "value": "boolean", "summary": "Emit the result as JSON."}],
34
+ mutates: true, json: "payload",
35
+ details: ["At least one scope option is required. Unspecified dimensions are preserved; this command does not rename keys."],
36
+ },
37
+ {
38
+ command: ["access", "key", "rotate", "commit"], summary: "Commit a pending key rotation.",
39
+ usage: "ocx access key rotate commit <id> <rotation-id> [--json]",
40
+ routes: [{"method": "POST", "path": "/api/keys/rotate/commit"}],
41
+ flags: [{"name": "--json", "value": "boolean", "summary": "Emit the result as JSON."}],
42
+ mutates: true, json: "payload",
43
+ details: ["Use IDs from the human-authorized rotation. Commit only after the client accepts the replacement; the old credential is retired."],
44
+ },
45
+ {
46
+ command: ["access", "key", "rotate", "abort"], summary: "Abort a pending key rotation.",
47
+ usage: "ocx access key rotate abort <id> <rotation-id> [--json]",
48
+ routes: [{"method": "DELETE", "path": "/api/keys/rotate"}],
49
+ flags: [{"name": "--json", "value": "boolean", "summary": "Emit the result as JSON."}],
50
+ mutates: true, json: "payload",
51
+ details: ["Use IDs from the human-authorized rotation. Abort discards the pending replacement credential."],
52
+ },
53
+ {
54
+ command: ["access", "key", "remove"], summary: "Revoke one API access key.",
55
+ usage: "ocx access key remove <id> --yes [--json]",
56
+ routes: [{"method": "DELETE", "path": "/api/keys"}],
57
+ flags: [{"name": "--yes", "value": "boolean", "summary": "Required confirmation before revoking the key.", "required": true}, {"name": "--json", "value": "boolean", "summary": "Emit the result as JSON."}],
58
+ mutates: true, json: "payload",
59
+ details: ["Uses the exact ID, not name resolution; delete is an alias."],
60
+ },
61
+ {
62
+ command: ["access", "endpoints"], summary: "Read endpoint URLs from the access-key metadata.",
63
+ usage: "ocx access endpoints [--json]",
64
+ routes: [{"method": "GET", "path": "/api/keys"}],
65
+ flags: [{"name": "--json", "value": "boolean", "summary": "Emit the result as JSON."}],
66
+ mutates: false, json: "envelope",
67
+ details: ["Projects only baseUrl, endpoint and fields ending in Endpoint; use key list for the full metadata payload."],
68
+ },
69
+ {
70
+ command: ["access", "models"], summary: "Read the public external-model catalog.",
71
+ usage: "ocx access models [--json]",
72
+ routes: [],
73
+ flags: [{"name": "--json", "value": "boolean", "summary": "Emit the result as JSON."}],
74
+ mutates: false, json: "payload",
75
+ details: ["Data-plane GET /v1/models via the runtime client; differs from management models live. The routes field indexes management API routes only."],
76
+ },
77
+ {
78
+ command: ["access","test"],
79
+ summary: "Send a small inference request through the selected protocol.",
80
+ usage: "ocx access test <model> [--protocol <chat|responses|messages>] [--api-key-stdin] [--json]",
81
+ routes: [],
82
+ flags: [{"name":"--protocol","value":"string","summary":"chat | responses | messages; default chat."},{"name":"--json","value":"boolean","summary":"Emit the result as JSON."},{"name":"--api-key-stdin","value":"boolean","summary":"Read one explicit data key from bounded piped stdin; no secret argv/env or management/enrolled-key fallback."}],
83
+ mutates: true,
84
+ json: "envelope",
85
+ details: ["Data-plane model POSTs are not management routes. The request may spend provider quota; run only for an explicitly authorized model probe. Legacy unkeyed behavior/JSON remains unchanged.","Explicit-key mode first sends a credentialless malformed-body control to the same protocol endpoint. Only the native key-required401 permits one16-token keyed request. Authless/unrecognized targets refuse before inference.","Version1 selected-key JSON reports control/request observations and a safe text/completion/usage projection. Limited output stays limited; neither control nor response certifies billing identity, key scopes or atomic policy stability.","Keys use explicit bounded stdin and printableASCII input compatible with issued keys. Same-target identity checks, deadlines, redirect refusal, exact-key redaction and cancellation apply; no retries or fallback credential."],
86
+ },
87
+ {
88
+ command: ["remote-workspace","hub","status"],
89
+ usage: "ocx remote-workspace hub status [--json]",
90
+ summary: "Read Hub devices, runtime availability and sessions.",
91
+ routes: [{"method":"GET","path":"/api/remote-workspace"}],
92
+ flags: [{"name":"--json","value":"boolean","summary":"Emit one validated task result as JSON."}],
93
+ mutates: false,
94
+ json: "payload",
95
+ details: ["Existing remote-workspace status remains executor-local. These fixed reads use the selected management Hub; they do not create pairing grants, sessions or remote commands.","Available empty lists succeed. Disabled Hub observations return explicit available:false and exit1; malformed or refused responses are not presented as empty success. Runtime reads can perform availability probes."],
96
+ },
97
+ {
98
+ command: ["remote-workspace","hub","runtimes"],
99
+ usage: "ocx remote-workspace hub runtimes [--json]",
100
+ summary: "Read Codex, Claude and Pi availability on the Hub.",
101
+ routes: [{"method":"GET","path":"/api/remote-workspace/runtimes"}],
102
+ flags: [{"name":"--json","value":"boolean","summary":"Emit one validated task result as JSON."}],
103
+ mutates: false,
104
+ json: "payload",
105
+ details: ["Existing remote-workspace status remains executor-local. These fixed reads use the selected management Hub; they do not create pairing grants, sessions or remote commands.","Available empty lists succeed. Disabled Hub observations return explicit available:false and exit1; malformed or refused responses are not presented as empty success. Runtime reads can perform availability probes."],
106
+ },
107
+ {
108
+ command: ["remote-workspace","hub","sessions"],
109
+ usage: "ocx remote-workspace hub sessions [--json]",
110
+ summary: "Read Hub sessions and their public recent events.",
111
+ routes: [{"method":"GET","path":"/api/remote-workspace/sessions"}],
112
+ flags: [{"name":"--json","value":"boolean","summary":"Emit one validated task result as JSON."}],
113
+ mutates: false,
114
+ json: "payload",
115
+ details: ["Existing remote-workspace status remains executor-local. These fixed reads use the selected management Hub; they do not create pairing grants, sessions or remote commands.","Available empty lists succeed. Disabled Hub observations return explicit available:false and exit1; malformed or refused responses are not presented as empty success. Runtime reads can perform availability probes."],
116
+ },
117
+ {
118
+ command: ["access","key","rename"],
119
+ usage: "ocx access key rename <id-or-name> <name> [--json]",
120
+ summary: "Rename an unambiguously selected API key while preserving its scopes.",
121
+ routes: [{"method":"GET","path":"/api/keys"},{"method":"PATCH","path":"/api/keys"}],
122
+ flags: [{"name":"--json","value":"boolean","summary":"Emit the command result as JSON."}],
123
+ mutates: true,
124
+ json: "payload",
125
+ details: ["Resolves a unique ID/name from the pinned management roster and sends only id/name. Duplicate-ID ambiguity is refused; no plaintext, scope clear, rotation or deletion is involved.","Name follows existing trimmed nonempty64-unit/control-character rules. Resolution is not revision CAS; API-key root alias shares the operation."],
126
+ },
127
+ {
128
+ command: ["access","audio","transcribe"],
129
+ usage: "ocx access audio transcribe <file> --model <gpt-4o-transcribe|gpt-4o-mini-transcribe|whisper-1> --api-key-stdin [--json]",
130
+ summary: "Transcribe an explicitly chosen bounded audio file with a supplied data key.",
131
+ routes: [],
132
+ flags: [{"name":"--model","value":"string","summary":"Required supported transcription model; no silent model fallback.","required":true},{"name":"--api-key-stdin","value":"boolean","summary":"Required bounded explicit data key on piped stdin; no management/enrolled-key substitution.","required":true},{"name":"--json","value":"boolean","summary":"Emit the command result as JSON."}],
133
+ mutates: true,
134
+ json: "payload",
135
+ details: ["Fixed data-plane POST /v1/audio/transcriptions with file/model/response_format=json. May use provider quota; requires explicit upload/inference authority.","File must be nonempty regular input≤25,000,000bytes; multipart≤32MiB, response≤2MiB, request130s. Only the requested text result is returned, with exact supplied-key redaction.","Audio uses its own explicit-key admission, including on an otherwise authless model listener. No generic model control, retries, secret argv/env or redirect following."],
136
+ },
137
+ {
138
+ command: ["access","audio","live-check"],
139
+ usage: "ocx access audio live-check --model <id> --api-key-stdin [--json]",
140
+ summary: "Check actual live-session readiness, then close the connection.",
141
+ routes: [],
142
+ flags: [{"name":"--model","value":"string","summary":"Required live model; sent to the existing live route.","required":true},{"name":"--api-key-stdin","value":"boolean","summary":"Required bounded printableASCII key, encoded only in the established audio subprotocol.","required":true},{"name":"--json","value":"boolean","summary":"Emit the command result as JSON."}],
143
+ mutates: true,
144
+ json: "envelope",
145
+ details: ["Fixed data-plane WebSocket /v1/live with the existing audio key carrier and session.update, then session.close. It contacts upstream and may incur provider usage; no microphone, audio upload, tool execution or voice-roundtrip claim.","Version1 report distinguishes readiness from confirmed normal close. Socket-open alone is not ready.15s readiness,2s close deadline; stuck/abnormal closure remains unverified/nonzero, with local socket termination.","No raw frames/session IDs/encoded credentials are printed. NativeWebSocket redirect refusal is verified separately from HTTP upload behavior."],
146
+ },
147
+ ];