@bitkyc08/opencodex 2.77.0 → 2.78.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 (222) hide show
  1. package/bin/ocx.mjs +11 -10
  2. package/gui/dist/assets/App-BtfG5id-.js +54 -0
  3. package/gui/dist/assets/App-lCIslZ1L.css +1 -0
  4. package/gui/dist/assets/{Tray-gloIYNaW.js → Tray-DiJpSub0.js} +1 -1
  5. package/gui/dist/assets/index-Btc3Ogw4.js +94 -0
  6. package/gui/dist/assets/index-DmQB8D_R.css +1 -0
  7. package/gui/dist/assets/quota-summary-B_a96nXj.js +1 -0
  8. package/gui/dist/index.html +2 -2
  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/devin/cloud-direct/chat.ts +7 -2
  15. package/src/adapters/devin/trajectory.ts +49 -0
  16. package/src/adapters/devin.ts +13 -0
  17. package/src/adapters/ollama-native.ts +35 -19
  18. package/src/claude/intercept/client-hello.ts +103 -0
  19. package/src/claude/intercept/model-bindings.ts +3 -2
  20. package/src/claude/intercept/picker-listener.ts +279 -66
  21. package/src/cli/access-audio-input.ts +84 -0
  22. package/src/cli/access-audio-live.ts +99 -0
  23. package/src/cli/access-audio.ts +123 -0
  24. package/src/cli/access-data-client.ts +127 -0
  25. package/src/cli/access-data-plane.ts +104 -0
  26. package/src/cli/access-data-response.ts +76 -0
  27. package/src/cli/access.ts +65 -2
  28. package/src/cli/account-api.ts +30 -6
  29. package/src/cli/account-auth.ts +111 -42
  30. package/src/cli/account-key-quota.ts +118 -0
  31. package/src/cli/account-main.ts +11 -4
  32. package/src/cli/account-next-actions.ts +63 -0
  33. package/src/cli/account-policy-dto.ts +68 -0
  34. package/src/cli/account-policy.ts +167 -0
  35. package/src/cli/account-target.ts +8 -0
  36. package/src/cli/account.ts +34 -8
  37. package/src/cli/agent-runtime-settings.ts +130 -0
  38. package/src/cli/agent-settings.ts +101 -0
  39. package/src/cli/agent.ts +19 -2
  40. package/src/cli/alias.ts +7 -2
  41. package/src/cli/aside-profiles.ts +2 -2
  42. package/src/cli/capabilities-access-remote.ts +147 -0
  43. package/src/cli/capabilities-accounts.ts +195 -0
  44. package/src/cli/capabilities-agents-routing.ts +414 -0
  45. package/src/cli/capabilities-base.ts +783 -0
  46. package/src/cli/capabilities-command.ts +1 -0
  47. package/src/cli/capabilities-integrations.ts +264 -0
  48. package/src/cli/capabilities-lab.ts +214 -0
  49. package/src/cli/capabilities-observe-system.ts +662 -0
  50. package/src/cli/capabilities-provider-models.ts +302 -0
  51. package/src/cli/capabilities.ts +30 -1199
  52. package/src/cli/capability-types.ts +54 -0
  53. package/src/cli/catalog-command-result.ts +57 -0
  54. package/src/cli/chatgpt-command.ts +25 -2
  55. package/src/cli/claude-agent-startup-sync.ts +17 -0
  56. package/src/cli/claude-desktop-profile.ts +100 -0
  57. package/src/cli/claude-desktop.ts +39 -6
  58. package/src/cli/codex-shim-autorestore.ts +2 -1
  59. package/src/cli/codex-shim-readiness.ts +23 -3
  60. package/src/cli/combo-input.ts +88 -0
  61. package/src/cli/combo-result.ts +52 -0
  62. package/src/cli/combo-stats.ts +123 -0
  63. package/src/cli/combo.ts +37 -14
  64. package/src/cli/companion-timeline.ts +142 -0
  65. package/src/cli/companion-usage.ts +146 -0
  66. package/src/cli/companion.ts +12 -3
  67. package/src/cli/config-command.ts +24 -8
  68. package/src/cli/dispatch.ts +52 -79
  69. package/src/cli/doctor.ts +22 -4
  70. package/src/cli/help-catalog.ts +31 -14
  71. package/src/cli/help-recovery.ts +2 -2
  72. package/src/cli/help.ts +25 -11
  73. package/src/cli/index.ts +38 -27
  74. package/src/cli/injection-follow.ts +35 -0
  75. package/src/cli/inspect.ts +5 -0
  76. package/src/cli/integration-aside-sync.ts +69 -0
  77. package/src/cli/integration-cursor.ts +106 -0
  78. package/src/cli/integration-input.ts +60 -0
  79. package/src/cli/integration-journal.ts +49 -0
  80. package/src/cli/integration-plan-dto.ts +156 -0
  81. package/src/cli/integration-preview.ts +215 -0
  82. package/src/cli/integrations.ts +24 -18
  83. package/src/cli/json-input.ts +134 -0
  84. package/src/cli/link.ts +32 -4
  85. package/src/cli/local-sync-result.ts +41 -0
  86. package/src/cli/log-follow.ts +84 -0
  87. package/src/cli/log-view-filter.ts +146 -0
  88. package/src/cli/logout-command.ts +44 -0
  89. package/src/cli/model-picker-ordering.ts +137 -0
  90. package/src/cli/models-custom-input.ts +107 -0
  91. package/src/cli/models-custom-runtime.ts +112 -0
  92. package/src/cli/models-order.ts +194 -0
  93. package/src/cli/models-runtime-subcommands.ts +2 -0
  94. package/src/cli/models-runtime.ts +7 -0
  95. package/src/cli/models.ts +66 -81
  96. package/src/cli/observe-stream.ts +142 -0
  97. package/src/cli/observe.ts +75 -34
  98. package/src/cli/provider-batch.ts +77 -0
  99. package/src/cli/provider-lifecycle-runtime.ts +170 -0
  100. package/src/cli/provider-result.ts +124 -0
  101. package/src/cli/provider-runtime.ts +15 -12
  102. package/src/cli/provider-settings.ts +143 -0
  103. package/src/cli/provider.ts +112 -34
  104. package/src/cli/registry.ts +62 -20
  105. package/src/cli/remote-workspace-hub.ts +83 -0
  106. package/src/cli/remote-workspace.ts +6 -1
  107. package/src/cli/restart-failure.ts +27 -0
  108. package/src/cli/root.ts +12 -0
  109. package/src/cli/route-policy-write.ts +137 -0
  110. package/src/cli/route-policy.ts +8 -0
  111. package/src/cli/runtime-api.ts +56 -79
  112. package/src/cli/secret-args.ts +149 -0
  113. package/src/cli/settings-result.ts +30 -0
  114. package/src/cli/storage.ts +77 -7
  115. package/src/cli/system-command.ts +60 -2
  116. package/src/cli/system-restart-client.ts +20 -3
  117. package/src/cli/system-settings-parity.ts +83 -0
  118. package/src/cli/update-restart-candidate.ts +21 -0
  119. package/src/cli/update-restart-child.ts +81 -0
  120. package/src/cli/update-restart-home.ts +38 -0
  121. package/src/cli/update-restart-transport.ts +193 -0
  122. package/src/cli/update-restart.ts +260 -0
  123. package/src/cli/usage-model-search.ts +58 -0
  124. package/src/cli/usage-report.ts +13 -5
  125. package/src/cli/v2-input.ts +66 -0
  126. package/src/cli/v2-local-output.ts +37 -0
  127. package/src/cli/v2-runtime.ts +90 -0
  128. package/src/cli/v2.ts +102 -144
  129. package/src/clients/config-export/dsh.ts +21 -0
  130. package/src/clients/config-export.ts +7 -1
  131. package/src/codex/catalog/build-entries.ts +1 -1
  132. package/src/codex/catalog/bundled.ts +9 -2
  133. package/src/codex/catalog/heal-observation.ts +66 -0
  134. package/src/codex/catalog/publication-observer.ts +19 -0
  135. package/src/codex/catalog/remote.ts +13 -15
  136. package/src/codex/catalog/restore.ts +19 -6
  137. package/src/codex/catalog/retained-sync.ts +58 -10
  138. package/src/codex/catalog/routed-removal.ts +116 -0
  139. package/src/codex/catalog/write-audit-contract.ts +21 -0
  140. package/src/codex/catalog/write-audit.ts +171 -0
  141. package/src/codex/catalog-self-heal.ts +284 -0
  142. package/src/codex/catalog-write-serialization.ts +71 -7
  143. package/src/codex/codex-home-owner.ts +124 -0
  144. package/src/codex/convergence.ts +55 -15
  145. package/src/codex/features.ts +8 -1
  146. package/src/codex/inject/restore.ts +46 -4
  147. package/src/codex/inject.ts +11 -1
  148. package/src/codex/internal/catalog-writer.ts +120 -13
  149. package/src/codex/journal.ts +49 -13
  150. package/src/codex/management-convergence.ts +3 -0
  151. package/src/codex/quota-types.ts +3 -0
  152. package/src/codex/quota.ts +13 -3
  153. package/src/codex/refresh.ts +20 -9
  154. package/src/codex/runtime.ts +7 -1
  155. package/src/codex/shim-diagnostics.ts +80 -0
  156. package/src/codex/shim-fingerprint.ts +7 -2
  157. package/src/codex/shim-migration.ts +153 -0
  158. package/src/codex/shim-overlay.ts +509 -0
  159. package/src/codex/shim-path-resolution.ts +14 -2
  160. package/src/codex/shim-probe.ts +4 -3
  161. package/src/codex/shim-state-file.ts +93 -7
  162. package/src/codex/shim.ts +15 -68
  163. package/src/codex/sync.ts +24 -4
  164. package/src/combos/failover.ts +19 -0
  165. package/src/combos/index.ts +1 -0
  166. package/src/combos/resolve.ts +12 -0
  167. package/src/config/atomic-write.ts +13 -8
  168. package/src/config/diagnostics.ts +19 -1
  169. package/src/config/load-degrade.ts +3 -0
  170. package/src/config/schema/chatgpt-desktop.ts +22 -0
  171. package/src/config/schema/config-schema.ts +32 -14
  172. package/src/config/schema/leaf-validators.ts +3 -2
  173. package/src/generated/compatibility-version.json +445 -129
  174. package/src/integrations/merge.ts +13 -5
  175. package/src/integrations/mutation-plan.ts +46 -3
  176. package/src/integrations/omp-yaml-source.ts +181 -1
  177. package/src/integrations/ownership-policy.ts +66 -0
  178. package/src/integrations/registry.ts +50 -1
  179. package/src/integrations/state.ts +46 -21
  180. package/src/integrations/target.ts +25 -2
  181. package/src/integrations/writer.ts +89 -31
  182. package/src/lib/package-tree-integrity.ts +42 -1
  183. package/src/lib/proxy-env.ts +3 -0
  184. package/src/lib/test-home-guard.ts +2 -1
  185. package/src/oauth/anthropic-account-refusal.ts +19 -8
  186. package/src/oauth/anthropic-routing.ts +17 -12
  187. package/src/oauth/anthropic.ts +27 -2
  188. package/src/oauth/index.ts +6 -8
  189. package/src/oauth/pool-settings-capability.ts +9 -2
  190. package/src/protocols/plan-snapshot.ts +1 -1
  191. package/src/protocols/settings.ts +28 -4
  192. package/src/server/caller-session-identity.ts +32 -0
  193. package/src/server/claude-messages.ts +11 -4
  194. package/src/server/index/serve-options.ts +12 -7
  195. package/src/server/index.ts +1 -1
  196. package/src/server/management/agent-settings-routes.ts +6 -5
  197. package/src/server/management/context.ts +8 -1
  198. package/src/server/management/cursor-integration-routes.ts +3 -3
  199. package/src/server/management/integration-routes.ts +5 -5
  200. package/src/server/management/model-routes.ts +3 -3
  201. package/src/server/management/native-integration-routes.ts +2 -2
  202. package/src/server/management/oauth-account-routes.ts +96 -30
  203. package/src/server/management/route-registry.ts +25 -24
  204. package/src/server/messages-native-eligibility.ts +3 -6
  205. package/src/server/messages-native-oauth.ts +82 -35
  206. package/src/server/messages-native.ts +78 -16
  207. package/src/server/responses/adapter-dispatch.ts +53 -28
  208. package/src/server/responses/core-auth.ts +10 -4
  209. package/src/server/responses/core-combo.ts +46 -6
  210. package/src/service/cli.ts +6 -1
  211. package/src/service/ownership-mutation-lease.d.mts +26 -0
  212. package/src/service/ownership-mutation-lease.mjs +76 -1
  213. package/src/types/config.ts +2 -0
  214. package/src/types/provider.ts +10 -10
  215. package/src/update/index.ts +2 -1
  216. package/src/update/update-failure-guidance.d.mts +6 -0
  217. package/src/update/update-failure-guidance.mjs +30 -5
  218. package/gui/dist/assets/App-COdEeqSj.css +0 -1
  219. package/gui/dist/assets/App-DEpCJEP_.js +0 -54
  220. package/gui/dist/assets/index-Cd7ittMv.css +0 -1
  221. package/gui/dist/assets/index-DwJKFJm5.js +0 -94
  222. package/gui/dist/assets/quota-summary-DGcEJU3h.js +0 -1
@@ -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,7 +24,7 @@ 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]
@@ -33,7 +33,10 @@ const USAGE = `Usage:
33
33
  ocx agent roles [status|set <role> <model>|suggest [--model <id>] [--apply]] [--json]
34
34
  ocx agent sidecar <status|web|vision> [--list] [--model <id|->]
35
35
  [--backend web:<openai|anthropic|xai|gemini|exa|-> vision:<openai|anthropic|routed|->]
36
- [--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]
37
40
  ocx agent request-user-input [on|off] [--json]`;
38
41
 
39
42
  function clearable(value: string | undefined): string | null | undefined {
@@ -257,6 +260,7 @@ async function sidecar(argv: string[], deps: RuntimeApiDeps): Promise<void> {
257
260
  const backend = takeOption(args, "--backend");
258
261
  const reasoning = takeOption(args, "--reasoning");
259
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);
260
264
  const enabled = takeBooleanOption(args, "--enabled");
261
265
  rejectArgs(args, USAGE);
262
266
  const settings: Record<string, unknown> = {};
@@ -418,6 +422,19 @@ async function roles(argv: string[], deps: RuntimeApiDeps): Promise<void> {
418
422
  }
419
423
 
420
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
+ }
421
438
  return runCliAction(async () => {
422
439
  const [sub = "status", ...rest] = argv;
423
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
+ ];
@@ -0,0 +1,195 @@
1
+ import type { Capability } from "./capability-types";
2
+
3
+ /** Account pool operations and physical native-login profiles have separate owners. */
4
+ export const ACCOUNT_CAPABILITIES: readonly Capability[] = [
5
+ {
6
+ command: ["logout"],
7
+ summary: "Remove the active stored OAuth credential for a provider locally.",
8
+ usage: "ocx logout <provider> [--live] [--json]",
9
+ routes: [{"method":"POST","path":"/api/oauth/logout"}],
10
+ flags: [{"name":"--live","value":"boolean","summary":"Use the selected public-OAuth runtime logout; no local credential fallback."},{"name":"--json","value":"boolean","summary":"Emit the validated task result as one JSON document."}],
11
+ mutates: true,
12
+ json: "envelope",
13
+ details: ["No-live retains atomic local removed/not-found results and exits0/4. Live sends one provider-level OAuth logout and reports only its success receipt, not removed:true or global sign-out.","Live does not sign out Codex/native-main. Target/argument failure never causes local credential removal."],
14
+ },
15
+ {
16
+ command: ["account", "current"], summary: "Read the active account or API key for a provider.",
17
+ usage: "ocx account current <provider> [--json]",
18
+ routes: [{ method: "GET", path: "/api/codex-auth/accounts" }, { method: "GET", path: "/api/codex-auth/active" }, { method: "GET", path: "/api/oauth/accounts" }, { method: "GET", path: "/api/providers/keys" }],
19
+ flags: [{ name: "--json", value: "boolean", summary: "Emit provider, type, activeId and the projected account." }], mutates: false, json: "envelope",
20
+ details: ["Uses the live route for the configured account family; this does not report the physical native-main profile."],
21
+ },
22
+ {
23
+ command: ["account", "use"], summary: "Select a provider's pool account or API key.",
24
+ usage: "ocx account use <provider> <account-or-key-id|alias|main|auto> [--json]",
25
+ routes: [{ method: "GET", path: "/api/codex-auth/accounts" }, { method: "GET", path: "/api/codex-auth/active" }, { method: "PUT", path: "/api/codex-auth/active" }, { method: "PUT", path: "/api/oauth/accounts/active" }, { method: "PUT", path: "/api/providers/keys/active" }],
26
+ flags: [{ name: "--json", value: "boolean", summary: "Emit the selection receipt, including pin-drain information when present." }], mutates: true, json: "envelope",
27
+ details: ["Codex resolves IDs and aliases before reserved words; an account actually named auto wins. account clear openai always clears. OAuth and API-key selection pass the ID directly. This does not switch the physical Codex App login."],
28
+ },
29
+ {
30
+ command: ["account", "clear"], summary: "Clear a Codex pool's manual account selection pin.",
31
+ usage: "ocx account clear <provider> [--json]",
32
+ routes: [{ method: "PUT", path: "/api/codex-auth/active" }],
33
+ flags: [{ name: "--json", value: "boolean", summary: "Emit the clear receipt." }], mutates: true, json: "envelope",
34
+ details: ["Only Codex account pools are supported; other families are refused. Sends accountId:null without interpreting auto as an account ID."],
35
+ },
36
+ {
37
+ command: ["account", "alias"], summary: "Set or clear an account's display alias.",
38
+ usage: "ocx account alias <provider> <account-or-key-id|alias> <display-name|-> [--json]",
39
+ routes: [{ method: "GET", path: "/api/codex-auth/accounts" }, { method: "PUT", path: "/api/codex-auth/accounts/alias" }, { method: "PUT", path: "/api/oauth/accounts/alias" }, { method: "PUT", path: "/api/providers/keys/alias" }],
40
+ flags: [{ name: "--json", value: "boolean", summary: "Emit the applied alias, or null after clearing." }], mutates: true, json: "envelope",
41
+ details: ["- clears with an empty string. Codex resolves existing aliases; other families take an ID. Native main cannot be renamed; aliases are at most 80 printable characters. rename is an existing command alias."],
42
+ },
43
+ {
44
+ command: ["account", "priority"], summary: "Read or change Codex account selection order.",
45
+ usage: "ocx account priority <provider> <account-id|alias|main> [<-100..100|first|earlier|normal|later|last|reset>] [--json]",
46
+ routes: [{ method: "GET", path: "/api/codex-auth/accounts" }, { method: "GET", path: "/api/codex-auth/active" }, { method: "PUT", path: "/api/codex-auth/accounts/priority" }],
47
+ flags: [{ name: "--json", value: "boolean", summary: "Emit the normalized priority and named preset." }], mutates: true, json: "envelope",
48
+ details: ["Only Codex pools support selection order. Omitting the value reads; reset sends null. Every write releases any manual pin, even if the value is unchanged; running threads retain their account until drained."],
49
+ },
50
+ {
51
+ command: ["account", "clear-cooldown"], summary: "Lift an operator-clearable Codex or Anthropic account cooldown.",
52
+ usage: "ocx account clear-cooldown <provider> <account-id|alias|main> [--json]",
53
+ routes: [{ method: "GET", path: "/api/codex-auth/accounts" }, { method: "GET", path: "/api/oauth/accounts" }, { method: "POST", path: "/api/codex-auth/accounts/clear-cooldown" }, { method: "POST", path: "/api/oauth/accounts/clear-cooldown" }],
54
+ flags: [{ name: "--json", value: "boolean", summary: "Emit whether a cooldown was actually cleared." }], mutates: true, json: "envelope",
55
+ details: ["Other provider families are refused. Resolves Codex or Anthropic account aliases before writing."],
56
+ },
57
+ {
58
+ command: ["account", "remove"], summary: "Remove a pool account or provider API key with explicit confirmation.",
59
+ usage: "ocx account remove <provider> <account-or-key-id|alias> --yes [--json]",
60
+ routes: [{ method: "GET", path: "/api/codex-auth/accounts" }, { method: "GET", path: "/api/codex-auth/active" }, { method: "GET", path: "/api/oauth/accounts" }, { method: "GET", path: "/api/providers/keys" }, { method: "DELETE", path: "/api/codex-auth/accounts" }, { method: "DELETE", path: "/api/oauth/accounts" }, { method: "DELETE", path: "/api/providers/keys" }],
61
+ flags: [{ name: "--yes", value: "boolean", required: true, summary: "Confirm account/key deletion." }, { name: "--json", value: "boolean", summary: "Emit removal and promoted-account information." }], mutates: true, json: "envelope",
62
+ details: ["Native main removal is refused. Reads the account family before and after deletion; a failed post-delete read means deletion may have succeeded. Only Codex resolves aliases here."],
63
+ },
64
+ {
65
+ command: ["account", "add-key"], summary: "Import an existing provider API key from a human-controlled stdin source.",
66
+ usage: "ocx account add-key <provider> [--label <label>] [--json]",
67
+ routes: [{ method: "POST", path: "/api/providers/keys" }],
68
+ flags: [{ name: "--label", value: "string", summary: "Optional label for the imported key." }, { name: "--json", value: "boolean", summary: "Emit a redacted receipt containing the key ID, never the key." }], mutates: true, json: "envelope",
69
+ details: ["API-key providers only. Requires non-TTY stdin and reads one secret line; never put plaintext keys in command arguments or agent transcripts. This imports an upstream credential, not an OpenCodex access-key creation workflow."],
70
+ },
71
+ {
72
+ command: ["account", "import"], summary: "Import Google Antigravity accounts from a bounded Cockpit Tools document.",
73
+ usage: "ocx account import google-antigravity --format cockpit-tools (--file <path>|--stdin) [--json]",
74
+ routes: [{ method: "POST", path: "/api/oauth/accounts/import" }],
75
+ flags: [{ name: "--format", value: "string", required: true, summary: "Only cockpit-tools is supported." }, { name: "--file", value: "string", summary: "Bounded source document; exclusive with --stdin." }, { name: "--stdin", value: "boolean", summary: "Read the document from non-TTY stdin." }, { name: "--json", value: "boolean", summary: "Emit sanitized per-record import outcomes." }], mutates: true, json: "envelope",
76
+ details: ["Human-controlled credential handoff: choose exactly one source. Unsupported providers/formats are refused before source I/O. Partial failures or unsupported records return nonzero; do not echo the document."],
77
+ },
78
+ {
79
+ command: ["account","reauth"],
80
+ summary: "Reauthenticate a provider account through the existing login flow.",
81
+ usage: "ocx account reauth <provider> [--id <account-id>] [--device] [--code -] [--no-wait] [--open-browser <on|off>] [--json]",
82
+ routes: [{"method":"POST","path":"/api/codex-auth/login"},{"method":"GET","path":"/api/codex-auth/login-status"},{"method":"POST","path":"/api/codex-auth/login/code"},{"method":"POST","path":"/api/oauth/login"},{"method":"GET","path":"/api/oauth/status"},{"method":"POST","path":"/api/oauth/login/code"}],
83
+ flags: [{"name":"--id","value":"string","summary":"Account identity to reauthenticate."},{"name":"--device","value":"boolean","summary":"Codex device login; accepted for already-device-native kimi, nous and github-copilot."},{"name":"--code","value":"string","summary":"Use - to read the short-lived authorization code from stdin."},{"name":"--no-wait","value":"boolean","summary":"Return after starting the flow."},{"name":"--json","value":"boolean","summary":"Emit login instructions or completion state."},{"name":"--open-browser","value":"string","summary":"on or off for browser-capable login; rejected for explicit/native device flows."}],
84
+ mutates: true,
85
+ json: "payload",
86
+ details: ["Alias of account login with --reauth. openai, codex and chatgpt address the pool; native main uses account main reauth. Human completes authorization; keep returned login material out of transcripts. Kiro --method cannot be combined with reauth.","Explicit add-account is incompatible with reauth. Browser preference is accepted only by browser-capable flows; device verification remains manual."],
87
+ },
88
+ {
89
+ command: ["account", "code"], summary: "Submit a login redirect or authorization code from stdin.",
90
+ usage: "ocx account code <provider> [--flow <flow-id>] [--code -] [--json]",
91
+ routes: [{ method: "POST", path: "/api/codex-auth/login/code" }, { method: "POST", path: "/api/oauth/login/code" }],
92
+ flags: [{ name: "--flow", value: "string", summary: "Required for openai, codex or chatgpt pool flows." }, { name: "--code", value: "string", summary: "Use - for stdin; omission also reads stdin." }, { name: "--json", value: "boolean", summary: "Emit submission receipt." }], mutates: true, json: "payload",
93
+ details: ["A short-lived credential is a human handoff. Legacy positional/argv code input exists but warns about exposure; use stdin and never echo it."],
94
+ },
95
+ {
96
+ command: ["account", "cancel"], summary: "Cancel a pending account login flow.",
97
+ usage: "ocx account cancel <provider> [--flow <flow-id>] [--json]",
98
+ routes: [{ method: "POST", path: "/api/codex-auth/login/cancel" }, { method: "POST", path: "/api/oauth/login/cancel" }],
99
+ flags: [{ name: "--flow", value: "string", summary: "Required for Codex; selects a native Kiro flow when supplied." }, { name: "--json", value: "boolean", summary: "Emit cancellation receipt." }], mutates: true, json: "payload",
100
+ details: ["Codex cancellation sends flowId. Other providers send provider; Kiro additionally forwards a supplied flowId."],
101
+ },
102
+ {
103
+ command: ["account", "reset-credits"], summary: "Read Codex reset-credit state, or explicitly consume one with operator authorization.",
104
+ usage: "ocx account reset-credits <account-id|main> [--consume --yes [--operation-id <uuid>]] [--json]",
105
+ routes: [{ method: "GET", path: "/api/codex-auth/reset-credits" }, { method: "POST", path: "/api/codex-auth/reset-credits/consume" }],
106
+ flags: [{ name: "--consume", value: "boolean", summary: "Spend a reset credit; requires operator intent and --yes." }, { name: "--yes", value: "boolean", summary: "Confirm consumption." }, { name: "--operation-id", value: "string", summary: "UUIDv4 retry identity; only valid with --consume." }, { name: "--json", value: "boolean", summary: "Emit reset-credit state or receipt." }], mutates: true, json: "payload",
107
+ details: ["A bare invocation reads only. main maps to __main__; reads never consume a credit. This does not control credits-after-limit settings."],
108
+ },
109
+ {
110
+ command: ["account", "main", "doctor"], summary: "Diagnose native Codex login profile storage and recovery state.",
111
+ usage: "ocx account main doctor [--json]", routes: [{ method: "GET", path: "/api/native-main-profiles/doctor" }],
112
+ flags: [{ name: "--json", value: "boolean", summary: "Emit diagnosis; this command also prints JSON by default." }], mutates: false, json: "payload",
113
+ details: ["Reports the physical login in the server's effective CODEX_HOME, independently of pool account selection."],
114
+ },
115
+ {
116
+ command: ["account", "main", "list"], summary: "List encrypted native Codex login profiles.",
117
+ usage: "ocx account main list [--json]", routes: [{ method: "GET", path: "/api/native-main-profiles" }],
118
+ flags: [{ name: "--json", value: "boolean", summary: "Emit public profile metadata, not stored credentials." }], mutates: false, json: "payload",
119
+ },
120
+ {
121
+ command: ["account", "main", "register"], summary: "Register the current physical Codex login as an encrypted profile.",
122
+ usage: "ocx account main register <label> [--json]", routes: [{ method: "POST", path: "/api/native-main-profiles/register" }],
123
+ flags: [{ name: "--json", value: "boolean", summary: "Emit the registration receipt." }], mutates: true, json: "payload",
124
+ details: ["Captures the current login in the effective CODEX_HOME; it does not start a new login or select a pool account."],
125
+ },
126
+ {
127
+ command: ["account", "main", "add"], summary: "Add a native login profile through a human-operated official Codex login.",
128
+ usage: "ocx account main add <label>",
129
+ routes: [{ method: "POST", path: "/api/native-main-profiles/stage" }, { method: "POST", path: "/api/native-main-profiles/stage/heartbeat" }, { method: "POST", path: "/api/native-main-profiles/stage/finish" }, { method: "POST", path: "/api/native-main-profiles/stage/cancel" }],
130
+ flags: [], mutates: true, json: "none",
131
+ details: ["Human handoff: runs official Codex login locally in the server-provided restricted staging home, maintains a writer lease and encrypts the result. No --json, --yes or --rollback mode. Cleanup failure requires account main doctor; never expose writer tokens or credential files."],
132
+ },
133
+ {
134
+ command: ["account", "main", "reauth", "status"], summary: "Read an existing same-identity native-main reauthentication flow.",
135
+ usage: "ocx account main reauth status --flow <id> [--json]", routes: [{ method: "GET", path: "/api/codex-auth/main/reauth-device" }],
136
+ flags: [{ name: "--flow", value: "string", required: true, summary: "Flow ID returned by the human-started reauthentication." }, { name: "--json", value: "boolean", summary: "Emit flow state; pending state may include human login material." }], mutates: false, json: "payload",
137
+ },
138
+ {
139
+ command: ["account", "main", "reauth", "cancel"], summary: "Cancel a native-main reauthentication flow.",
140
+ usage: "ocx account main reauth cancel --flow <id> [--json]", routes: [{ method: "DELETE", path: "/api/codex-auth/main/reauth-device" }],
141
+ flags: [{ name: "--flow", value: "string", required: true, summary: "Flow ID to cancel." }, { name: "--json", value: "boolean", summary: "Emit cancellation state." }], mutates: true, json: "payload",
142
+ },
143
+ {
144
+ command: ["account", "main", "switch"], summary: "Switch the physical Codex App/CLI login to a registered profile.",
145
+ usage: "ocx account main switch <profile-id-or-label> --yes [--json]", routes: [{ method: "POST", path: "/api/native-main-profiles/switch" }],
146
+ flags: [{ name: "--yes", value: "boolean", required: true, summary: "Confirm the operator has closed Codex App/CLI." }, { name: "--json", value: "boolean", summary: "Emit the native-login switch receipt." }], mutates: true, json: "payload",
147
+ details: ["Changes the effective CODEX_HOME login, independently of account use openai. The operator must stop Codex first and restart it afterwards; no automatic restart is performed."],
148
+ },
149
+ {
150
+ command: ["account", "main", "recover"], summary: "Recover an interrupted native-login profile transaction.",
151
+ usage: "ocx account main recover [--rollback --yes] [--json]", routes: [{ method: "POST", path: "/api/native-main-profiles/recover" }],
152
+ flags: [{ name: "--rollback", value: "boolean", summary: "Restore the previous login; requires --yes." }, { name: "--yes", value: "boolean", summary: "Confirm Codex App/CLI is stopped for rollback." }, { name: "--json", value: "boolean", summary: "Emit recovery outcome." }], mutates: true, json: "payload",
153
+ details: ["Even without --rollback this calls recovery with rollback:false; it is not the doctor read. Rollback writes the native login only after explicit confirmation."],
154
+ },
155
+ {
156
+ command: ["account","pool"],
157
+ usage: "ocx account pool <provider> [--enabled <on|off>] [--threshold <0-100>] [--strategy <name>] [--sticky <1-100>] [--quota-window <five-hour|weekly|max-utilization>] [--json]",
158
+ summary: "Read or edit the selected runtime's supported pool policy fields.",
159
+ routes: [{"method":"GET","path":"/api/pool/settings"},{"method":"PUT","path":"/api/pool/settings"}],
160
+ flags: [{"name":"--enabled","value":"string","summary":"Stored pool preference; unsupported for Codex. Not equivalent to threshold0."},{"name":"--threshold","value":"number","summary":"Auto-switch threshold0–100."},{"name":"--strategy","value":"string","summary":"Use a strategy supported by this provider kind; reset-first is Codex, least-loaded is Kiro."},{"name":"--sticky","value":"number","summary":"Sticky limit1–100."},{"name":"--quota-window","value":"string","summary":"Anthropic only: five-hour, weekly or max-utilization."},{"name":"--json","value":"boolean","summary":"Emit the validated task result as one JSON document."}],
161
+ mutates: true,
162
+ json: "envelope",
163
+ details: ["Reads the target supported-field list before a narrow PUT. Null/unsupported, stored/effective and generic inert policy stay distinct; disabling does not promise that reactive429 rotation stops.","No local classification/defaults are round-tripped into the live target; supported-field reads are not CAS."],
164
+ },
165
+ {
166
+ command: ["account","credits"],
167
+ usage: "ocx account credits openai <id|alias|main> <on|off> [--json]; ocx account credits openai --all <on|off> [--json]",
168
+ summary: "Explicitly opt one or all current Codex accounts into paid credits after quota limits.",
169
+ routes: [{"method":"GET","path":"/api/codex-auth/accounts"},{"method":"PUT","path":"/api/codex-auth/accounts/credits"}],
170
+ flags: [{"name":"--all","value":"boolean","summary":"Exclusive with one account selector. On covers current selectable accounts plus main; off clears the opt-in set."},{"name":"--json","value":"boolean","summary":"Emit the validated task result as one JSON document."}],
171
+ mutates: true,
172
+ json: "envelope",
173
+ details: ["Requires explicit operator on/off intent. Showing credit balances does not grant paid-use permission; no login/quota failure auto-enables it.","One/all shapes are exclusive. Strict selected-runtime account resolution refuses ambiguity/unavailable roster; the response owns the applied set. It never consumes a reset grant."],
174
+ },
175
+ {
176
+ command: ["account","quota-activation"],
177
+ usage: "ocx account quota-activation openai <id|alias|main> --window <fiveHour|weekly> <on|off> [--json]",
178
+ summary: "Enable or disable a Codex account window's automatic quota refresh policy.",
179
+ routes: [{"method":"GET","path":"/api/codex-auth/accounts"},{"method":"PUT","path":"/api/settings"}],
180
+ flags: [{"name":"--window","value":"string","summary":"fiveHour or weekly; these spellings differ from pool quota-window.","required":true},{"name":"--json","value":"boolean","summary":"Emit the validated task result as one JSON document."}],
181
+ mutates: true,
182
+ json: "envelope",
183
+ details: ["Writes only the selected account/window mutation, preserving siblings. Enabling an unavailable window returns conflict; disabling remains allowed.","The server may schedule a quota refresh. This does not redeem a reset grant or opt into paid credits."],
184
+ },
185
+ {
186
+ command: ["account","anthropic-reset-grants"],
187
+ usage: "ocx account anthropic-reset-grants [account-id] [--json]",
188
+ summary: "Read Anthropic reset-grant eligibility and pending status without consuming a grant.",
189
+ routes: [{"method":"GET","path":"/api/anthropic/reset-grants"}],
190
+ flags: [{"name":"--json","value":"boolean","summary":"Emit the validated task result as one JSON document."}],
191
+ mutates: false,
192
+ json: "envelope",
193
+ details: ["Optional identity is the exact Anthropic account ID. Omission delegates active/fallback account choice to the server, not the Codex alias resolver.","This GET can refresh access/status information upstream. Empty grants, unavailable status, pending operation and unavailable journal remain distinct. Consume remains a GUI-session-only human handoff; no session acquisition or retry is performed."],
194
+ },
195
+ ];