@bitkyc08/opencodex 2.80.0 → 2.81.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 (227) hide show
  1. package/README.md +3 -3
  2. package/gui/dist/assets/App-7yhoys8a.js +54 -0
  3. package/gui/dist/assets/Tray-EwAOsP0S.js +1 -0
  4. package/gui/dist/assets/index-RsoaAxXY.js +94 -0
  5. package/gui/dist/assets/quota-summary-D2lN8tDm.js +1 -0
  6. package/gui/dist/index.html +1 -1
  7. package/gui/dist/provider-icons/claude-green.svg +1 -0
  8. package/package.json +3 -2
  9. package/src/adapters/anthropic-model-contract.ts +8 -2
  10. package/src/adapters/anthropic.ts +7 -2
  11. package/src/adapters/codebuddy/mcp-server.ts +2 -25
  12. package/src/adapters/codebuddy/tool-bridge.ts +1 -7
  13. package/src/adapters/coding-agent/mcp-server.ts +33 -0
  14. package/src/adapters/coding-agent/protocol.ts +122 -17
  15. package/src/adapters/coding-agent/tool-catalog.ts +75 -0
  16. package/src/adapters/coding-agent/turn.ts +101 -44
  17. package/src/adapters/cursor/catalog.ts +8 -0
  18. package/src/adapters/cursor/effort-map.ts +2 -0
  19. package/src/adapters/devin/live-models.ts +2 -0
  20. package/src/adapters/kiro-retry.ts +9 -4
  21. package/src/adapters/openai-chat/messages.ts +7 -6
  22. package/src/adapters/physical-send.ts +8 -5
  23. package/src/adapters/qoder/adapter.ts +41 -6
  24. package/src/adapters/qoder/scaffold-guard.ts +2 -3
  25. package/src/adapters/zed.ts +16 -1
  26. package/src/claude/inbound-cache-stabilize.ts +4 -9
  27. package/src/claude/inbound.ts +1 -0
  28. package/src/claude/intercept/model-bindings.ts +1 -0
  29. package/src/claude/intercept/picker-listener.ts +71 -4
  30. package/src/cli/account-anthropic-threshold.ts +14 -5
  31. package/src/cli/account-api.ts +3 -1
  32. package/src/cli/account-extended.ts +13 -9
  33. package/src/cli/account-policy-dto.ts +1 -1
  34. package/src/cli/account-policy.ts +13 -4
  35. package/src/cli/account.ts +3 -3
  36. package/src/cli/capabilities-accounts.ts +2 -2
  37. package/src/cli/capabilities-agents-routing.ts +24 -0
  38. package/src/cli/capabilities-integrations.ts +16 -0
  39. package/src/cli/codex-shim-autorestore.ts +3 -0
  40. package/src/cli/dispatch.ts +10 -1
  41. package/src/cli/help.ts +4 -1
  42. package/src/cli/index.ts +11 -5
  43. package/src/cli/integration-plan-dto.ts +1 -0
  44. package/src/cli/integration-preview.ts +8 -1
  45. package/src/cli/integrations.ts +32 -3
  46. package/src/cli/message-args.ts +34 -0
  47. package/src/cli/message-command.ts +43 -0
  48. package/src/cli/message-runtime.ts +6 -0
  49. package/src/cli/observe.ts +3 -1
  50. package/src/cli/provider.ts +29 -6
  51. package/src/cli/registry.ts +24 -2
  52. package/src/clients/config-export/commandcode.ts +131 -0
  53. package/src/clients/config-export/contracts.ts +12 -0
  54. package/src/clients/config-export.ts +64 -1
  55. package/src/codex/auth-api/account-list.ts +11 -3
  56. package/src/codex/auth-api/main-account-probe.ts +25 -8
  57. package/src/codex/auth-api/pool-mode-gate.ts +33 -9
  58. package/src/codex/auth-api/pool-quota-probe.ts +15 -1
  59. package/src/codex/auth-api/routes.ts +1 -0
  60. package/src/codex/catalog/auto-review.ts +13 -6
  61. package/src/codex/catalog/build-entries.ts +15 -7
  62. package/src/codex/catalog/control-plane.ts +45 -0
  63. package/src/codex/catalog/effort.ts +11 -1
  64. package/src/codex/catalog/gather-capture.ts +5 -3
  65. package/src/codex/catalog/parsing.ts +2 -1
  66. package/src/codex/catalog/provider-models.ts +15 -9
  67. package/src/codex/control-plane-models.ts +6 -0
  68. package/src/combos/jev-decision-contract.ts +25 -2
  69. package/src/combos/jev.ts +3 -2
  70. package/src/combos/types.ts +1 -1
  71. package/src/config/diagnostics.ts +27 -16
  72. package/src/config/load-degrade.ts +34 -0
  73. package/src/config/schema/anthropic-account-pool.ts +143 -0
  74. package/src/config/schema/config-schema.ts +7 -1
  75. package/src/config/schema/leaf-validators.ts +4 -0
  76. package/src/config.ts +2 -0
  77. package/src/generated/compatibility-version.json +320 -184
  78. package/src/generated/model-metadata.ts +5 -4
  79. package/src/images/loop.ts +2 -1
  80. package/src/integrations/catalog-refresh.ts +1 -1
  81. package/src/integrations/mutation-plan.ts +7 -0
  82. package/src/integrations/registry.ts +8 -0
  83. package/src/integrations/state.ts +9 -2
  84. package/src/integrations/writer.ts +8 -2
  85. package/src/lib/lab-live-route-production.ts +9 -1
  86. package/src/lib/request-execution-budget.ts +236 -58
  87. package/src/lib/spend-pool-alias-validation.ts +79 -0
  88. package/src/lib/spend-pool-continuity.ts +34 -0
  89. package/src/lib/spend-reservation-ledger.ts +412 -50
  90. package/src/lib/state-store-registrations.ts +20 -3
  91. package/src/lib/upstream-retry.ts +17 -5
  92. package/src/lib/workflow-budget.ts +53 -11
  93. package/src/messaging/budget.ts +45 -0
  94. package/src/messaging/discovery.ts +57 -0
  95. package/src/messaging/envelope.ts +49 -0
  96. package/src/messaging/input.ts +37 -0
  97. package/src/messaging/rpc.ts +196 -0
  98. package/src/messaging/send.ts +58 -0
  99. package/src/messaging/socket.ts +72 -0
  100. package/src/messaging/types.ts +29 -0
  101. package/src/oauth/anthropic-account-refusal.ts +51 -17
  102. package/src/oauth/anthropic-account-threshold.ts +8 -2
  103. package/src/oauth/anthropic-continuity.ts +15 -1
  104. package/src/oauth/anthropic-model-quota.ts +120 -48
  105. package/src/oauth/anthropic-model-routes.ts +11 -3
  106. package/src/oauth/anthropic-oauth-definitions.ts +98 -0
  107. package/src/oauth/anthropic-pool-config.ts +30 -0
  108. package/src/oauth/anthropic-rate-limit-policy.ts +64 -9
  109. package/src/oauth/anthropic-routing.ts +1202 -866
  110. package/src/oauth/anthropic-send-ownership.ts +41 -0
  111. package/src/oauth/anthropic.ts +4 -1
  112. package/src/oauth/generic-account-failover.ts +3 -1
  113. package/src/oauth/health.ts +8 -6
  114. package/src/oauth/index.ts +90 -173
  115. package/src/oauth/kiro.ts +22 -9
  116. package/src/oauth/login-cli.ts +2 -0
  117. package/src/oauth/model-discovery-auth.ts +43 -0
  118. package/src/oauth/pool-kernel.ts +11 -5
  119. package/src/oauth/pool-settings-capability.ts +5 -3
  120. package/src/oauth/store-anthropic-instance.ts +87 -0
  121. package/src/oauth/store.ts +67 -9
  122. package/src/oauth/token-guardian.ts +2 -0
  123. package/src/oauth/types.ts +2 -0
  124. package/src/protocols/plan-snapshot.ts +5 -0
  125. package/src/protocols/settings.ts +20 -5
  126. package/src/providers/anthropic-instance-id.ts +47 -0
  127. package/src/providers/anthropic-instance.ts +48 -0
  128. package/src/providers/anthropic-reset-grant-ledger.ts +11 -1
  129. package/src/providers/derive.ts +2 -0
  130. package/src/providers/kiro-models.ts +3 -0
  131. package/src/providers/label.ts +1 -1
  132. package/src/providers/model-rename-fields.ts +2 -0
  133. package/src/providers/quota/account-cache.ts +37 -11
  134. package/src/providers/quota/anthropic-account-quota.ts +93 -0
  135. package/src/providers/quota/anthropic-cooldown-recovery.ts +222 -111
  136. package/src/providers/quota/report-cache.ts +24 -1
  137. package/src/providers/quota/vendor-probes-oauth.ts +46 -14
  138. package/src/providers/quota.ts +22 -32
  139. package/src/providers/registry/entries-core.ts +35 -30
  140. package/src/providers/registry/model-ids.ts +1 -0
  141. package/src/providers/registry/model-seeds.ts +7 -4
  142. package/src/providers/registry/types.ts +3 -0
  143. package/src/providers/registry.ts +3 -3
  144. package/src/responses/spill-store.ts +5 -1
  145. package/src/responses/state/metrics.ts +87 -0
  146. package/src/responses/state/snapshot-codec.ts +6 -0
  147. package/src/responses/state/spill-queue.ts +1 -0
  148. package/src/responses/state/unforced-store-false.ts +55 -0
  149. package/src/responses/state.ts +50 -66
  150. package/src/router.ts +28 -4
  151. package/src/routing/compatibility/assemble.ts +1 -1
  152. package/src/routing/quota.ts +7 -3
  153. package/src/server/auth-cors.ts +5 -0
  154. package/src/server/chat-completions.ts +6 -1
  155. package/src/server/chat-native.ts +45 -25
  156. package/src/server/claude-messages.ts +16 -2
  157. package/src/server/gui-static.ts +38 -4
  158. package/src/server/index/spend-ledger-lifecycle.ts +10 -4
  159. package/src/server/index.ts +4 -2
  160. package/src/server/inference/context.ts +1 -1
  161. package/src/server/lifecycle.ts +1 -1
  162. package/src/server/management/agent-settings-routes.ts +30 -6
  163. package/src/server/management/anthropic-account-threshold.ts +12 -9
  164. package/src/server/management/anthropic-pool-settings.ts +72 -0
  165. package/src/server/management/anthropic-reset-grant-routes.ts +98 -39
  166. package/src/server/management/config-routes.ts +27 -7
  167. package/src/server/management/decision-routes.ts +2 -1
  168. package/src/server/management/integration-routes.ts +25 -2
  169. package/src/server/management/oauth-account-routes.ts +79 -98
  170. package/src/server/management/provider-instance-ownership.ts +44 -0
  171. package/src/server/management/provider-routes.ts +21 -28
  172. package/src/server/management/route-registry.ts +3 -1
  173. package/src/server/management/routing-profile-routes.ts +4 -4
  174. package/src/server/management/system-restart.ts +44 -14
  175. package/src/server/management/system-routes.ts +24 -2
  176. package/src/server/management/vision-sidecar-options.ts +9 -6
  177. package/src/server/management/web-search-sidecar-options.ts +51 -2
  178. package/src/server/management-auth.ts +6 -0
  179. package/src/server/messages-native-eligibility.ts +3 -2
  180. package/src/server/messages-native-oauth.ts +86 -41
  181. package/src/server/messages-native-selector.ts +39 -0
  182. package/src/server/messages-native.ts +84 -25
  183. package/src/server/request-log.ts +5 -0
  184. package/src/server/responses/adapter-continuation.ts +29 -17
  185. package/src/server/responses/adapter-dispatch.ts +47 -17
  186. package/src/server/responses/antigravity-validation-refusal.ts +20 -6
  187. package/src/server/responses/compact.ts +25 -8
  188. package/src/server/responses/compaction-recovery.ts +1 -1
  189. package/src/server/responses/core-combo-native.ts +4 -1
  190. package/src/server/responses/core-combo.ts +16 -11
  191. package/src/server/responses/core-normalize.ts +1 -0
  192. package/src/server/responses/core-options.ts +3 -1
  193. package/src/server/responses/core-replay.ts +5 -0
  194. package/src/server/responses/passthrough-delivery.ts +7 -3
  195. package/src/server/responses/passthrough-dispatch.ts +21 -8
  196. package/src/server/responses/request-prepare.ts +37 -5
  197. package/src/server/responses/request-send-budget.ts +74 -37
  198. package/src/server/responses/request-spend.ts +325 -33
  199. package/src/server/responses/request-transport.ts +132 -52
  200. package/src/server/responses/run-turn-execution.ts +11 -3
  201. package/src/server/responses/sidecar-execution.ts +96 -14
  202. package/src/server/responses-undeclared-tool-guard.ts +5 -1
  203. package/src/server/workflow-refusal.ts +30 -0
  204. package/src/service/ownership-mutation-lease.d.mts +1 -1
  205. package/src/service/ownership-mutation-lease.mjs +5 -7
  206. package/src/sidecar/anthropic-binding.ts +79 -0
  207. package/src/sidecar/auth.ts +76 -2
  208. package/src/types/anthropic-account-pool.ts +33 -0
  209. package/src/types/config.ts +12 -28
  210. package/src/types/provider.ts +5 -0
  211. package/src/types/tools.ts +7 -0
  212. package/src/types.ts +4 -0
  213. package/src/usage/cost.ts +3 -2
  214. package/src/usage/expected-prices.ts +66 -14
  215. package/src/vision/anthropic-describe.ts +16 -3
  216. package/src/vision/index.ts +3 -0
  217. package/src/vision/plan.ts +19 -6
  218. package/src/web-search/alpha-search.ts +7 -1
  219. package/src/web-search/anthropic-executor.ts +16 -4
  220. package/src/web-search/index.ts +7 -3
  221. package/src/web-search/loop.ts +27 -5
  222. package/src/web-search/passthrough-bridge.ts +4 -1
  223. package/src/web-search/sidecar-providers.ts +4 -3
  224. package/gui/dist/assets/App-MbDVfUeC.js +0 -54
  225. package/gui/dist/assets/Tray-CzkxK82A.js +0 -1
  226. package/gui/dist/assets/index-UJt6npXk.js +0 -94
  227. package/gui/dist/assets/quota-summary-DU3sD6Z-.js +0 -1
@@ -23,6 +23,7 @@ export const FILE_INTEGRATION_CLIENTS = [
23
23
  "raycast",
24
24
  "omo",
25
25
  "cline",
26
+ "commandcode",
26
27
  "kilo",
27
28
  "droid",
28
29
  ] as const;
@@ -1,5 +1,6 @@
1
1
  /** Preview and explicitly bound mutations use the existing management authority. */
2
2
  import type { IntegrationMutationPlan, IntegrationPlanOperation } from "../integrations/mutation-plan";
3
+ import type { IntegrationClientId } from "../integrations/registry";
3
4
  import { redactSecretString, redactUserPath } from "../lib/redact";
4
5
  import {
5
6
  CliUsageError, RuntimeApiError, printData, runtimeRequest, terminalSafeText,
@@ -186,9 +187,15 @@ function reportError(error: unknown): number {
186
187
  return 1;
187
188
  }
188
189
 
189
- export async function handleIntegrationPreviewCommand(argv: string[], deps: RuntimeApiDeps = {}): Promise<number> {
190
+ export async function handleIntegrationPreviewCommand(argv: string[], deps: RuntimeApiDeps = {}, expectedClientId?: IntegrationClientId): Promise<number> {
190
191
  try {
191
192
  const intent = parseIntent(argv);
193
+ if (expectedClientId !== undefined && intent.operation === "restore") {
194
+ if (intent.client !== undefined || intent.profile !== undefined) throw new CliUsageError("client-specific restore does not accept --client or --profile", USAGE);
195
+ intent.client = expectedClientId;
196
+ intent.path = `${clientIntegrationPath(expectedClientId)}/restore${intent.preview ? "/preview" : ""}`;
197
+ intent.body.expectedClientId = expectedClientId;
198
+ }
192
199
  const result = await runtimeRequest(intent.path, {
193
200
  method: intent.preview || intent.operation === "restore" ? "POST" : "PUT",
194
201
  redirect: "error", body: JSON.stringify(intent.body),
@@ -13,6 +13,7 @@ import {
13
13
  type RuntimeApiDeps,
14
14
  } from "./runtime-api";
15
15
  import { clientIntegrationPath, validateAsideProfile } from "./integration-input";
16
+ import type { IntegrationClientId } from "../integrations/registry";
16
17
 
17
18
  const CLAUDE_USAGE = `Usage:
18
19
  ocx claude config [status] [--json]
@@ -215,7 +216,11 @@ function singleClientStatusLines(result: unknown): string[] {
215
216
  export async function handleClientIntegrationCommand(
216
217
  argv: string[],
217
218
  deps: RuntimeApiDeps = {},
219
+ expectedClientId?: IntegrationClientId,
218
220
  ): Promise<number> {
221
+ if (expectedClientId !== undefined && argv.some(arg => ["--client", "--profile"].some(flag => arg === flag || arg.startsWith(`${flag}=`)))) {
222
+ return runCliAction(async () => { throw new CliUsageError("client-specific restore does not accept --client or --profile", CLIENT_USAGE); });
223
+ }
219
224
  if ((argv[0] === "history" || argv[0] === "journal") && argv[1] === "remove") {
220
225
  const { handleIntegrationJournalRemove } = await import("./integration-journal");
221
226
  return handleIntegrationJournalRemove(argv.slice(2), deps);
@@ -227,7 +232,7 @@ export async function handleClientIntegrationCommand(
227
232
  if (argv[0] === "preview" || argv.some(arg => ["--preview", "--plan-fingerprint", "--reasoning-default", "--clear-reasoning-defaults"]
228
233
  .some(flag => arg === flag || arg.startsWith(`${flag}=`)))) {
229
234
  const { handleIntegrationPreviewCommand } = await import("./integration-preview");
230
- return handleIntegrationPreviewCommand(argv, deps);
235
+ return handleIntegrationPreviewCommand(argv, deps, expectedClientId);
231
236
  }
232
237
  return runCliAction(async () => {
233
238
  const args = [...argv];
@@ -289,9 +294,12 @@ export async function handleClientIntegrationCommand(
289
294
  if (client !== undefined && profile === undefined) throw new CliUsageError("restore --client requires --profile", CLIENT_USAGE);
290
295
  rejectArgs(args, CLIENT_USAGE);
291
296
  if (!opId) throw new CliUsageError("--op <opId> is required", CLIENT_USAGE);
292
- const result = await runtimeRequest(profile === undefined ? "/api/client-integrations/restore" : `${clientIntegrationPath("aside", profile)}/restore`, {
297
+ const restorePath = expectedClientId !== undefined ? `${clientIntegrationPath(expectedClientId)}/restore`
298
+ : profile === undefined ? "/api/client-integrations/restore" : `${clientIntegrationPath("aside", profile)}/restore`;
299
+ const result = await runtimeRequest(restorePath, {
293
300
  method: "POST",
294
- body: JSON.stringify({ opId, confirmDrift }),
301
+ ...(expectedClientId === undefined ? {} : { redirect: "error" as const }),
302
+ body: JSON.stringify({ opId, confirmDrift, ...(expectedClientId === undefined ? {} : { expectedClientId }) }),
295
303
  }, deps);
296
304
  printData(result, wantsJson, [String((result as Record<string, unknown>).message ?? "Restored.")]);
297
305
  return;
@@ -387,3 +395,24 @@ export async function handleClaudeInterceptCommand(argv: string[], deps: Runtime
387
395
  printData(result, wantsJson, summaryLines(result));
388
396
  });
389
397
  }
398
+
399
+ const COMMANDCODE_USAGE = "Usage: ocx commandcode [status|show|list|enable|disable|history|journal|restore] [--json]";
400
+
401
+ export async function handleCommandcodeCommand(argv: string[], deps: RuntimeApiDeps = {}): Promise<number> {
402
+ const args = [...argv];
403
+ const verbIndex = args.findIndex(arg => !arg.startsWith("-"));
404
+ const action = (verbIndex === -1 ? "status" : args[verbIndex]).toLowerCase();
405
+ const known = ["status", "show", "list", "enable", "disable", "history", "journal", "restore"];
406
+ if (!known.includes(action)) {
407
+ console.error(`unknown commandcode command ${action}`);
408
+ console.error(COMMANDCODE_USAGE);
409
+ return 2;
410
+ }
411
+ const rest = verbIndex === -1 ? args : [...args.slice(0, verbIndex), ...args.slice(verbIndex + 1)];
412
+ const forwarded = action === "restore" ? [action, ...rest] : [action, ...rest, "--client", "commandcode"];
413
+ const code = await handleClientIntegrationCommand(forwarded, deps, action === "restore" ? "commandcode" : undefined);
414
+ if (code === 0 && (action === "enable" || action === "disable")) {
415
+ console.error("Command Code reads providers on startup.");
416
+ }
417
+ return code;
418
+ }
@@ -0,0 +1,34 @@
1
+ import type { MessageKind } from "../messaging/envelope";
2
+ import { isThreadId } from "../messaging/types";
3
+
4
+ export type MessageArgs = { action: "sessions"; json: boolean }
5
+ | { action: "send"; json: boolean; kind: MessageKind; thread?: string; name?: string; inReplyTo?: string };
6
+
7
+ /** Pure pre-parse: unknown/duplicate options and unsupported remote surfaces fail closed. */
8
+ export function parseMessageArgs(argv: readonly string[]): MessageArgs | null {
9
+ const action = argv[0];
10
+ if (action !== "sessions" && action !== "send") return null;
11
+ const seen = new Set<string>();
12
+ const values: Record<string, string> = {};
13
+ for (let index = 1; index < argv.length; index++) {
14
+ const flag = argv[index]!;
15
+ if (seen.has(flag)) return null;
16
+ seen.add(flag);
17
+ if (flag === "--json" || (action === "send" && flag === "--stdin")) continue;
18
+ if (action !== "send" || !["--thread", "--name", "--kind", "--in-reply-to"].includes(flag)) return null;
19
+ const value = argv[++index];
20
+ if (!value || value.startsWith("--")) return null;
21
+ values[flag] = value;
22
+ }
23
+ const json = seen.has("--json");
24
+ if (action === "sessions") return { action, json };
25
+ const thread = values["--thread"], name = values["--name"], inReplyTo = values["--in-reply-to"];
26
+ const kind = values["--kind"] ?? "request";
27
+ if (!seen.has("--stdin") || (thread !== undefined) === (name !== undefined)
28
+ || (thread !== undefined && !isThreadId(thread))
29
+ || (name !== undefined && (!name.trim() || name.length > 4096 || /[\x00-\x1f\x7f-\x9f]/.test(name)))
30
+ || !["request", "response", "notification"].includes(kind)
31
+ || (kind === "response" ? !isThreadId(inReplyTo) : inReplyTo !== undefined)) return null;
32
+ return { action, json, kind: kind as MessageKind, ...(thread ? { thread } : {}),
33
+ ...(name ? { name } : {}), ...(inReplyTo ? { inReplyTo } : {}) };
34
+ }
@@ -0,0 +1,43 @@
1
+ import { MessageBudget } from "../messaging/budget";
2
+ import { readMessageInput } from "../messaging/input";
3
+ import { localSessions, messageFailure, sendLocalMessage } from "../messaging/send";
4
+ import { parseMessageArgs } from "./message-args";
5
+ import { terminalSafeText } from "./runtime-api";
6
+
7
+ /** Run one local messaging operation after pure syntax validation, then release owned resources. */
8
+ export async function runMessageCommand(argv: readonly string[], env: NodeJS.ProcessEnv = process.env): Promise<number> {
9
+ const args = parseMessageArgs(argv);
10
+ if (!args) {
11
+ console.error("Usage: ocx message sessions [--json] | send (--thread <uuid> | --name <exact-name>) --stdin [--kind request|response|notification] [--in-reply-to <uuid>] [--json]");
12
+ return 64;
13
+ }
14
+ const controller = new AbortController();
15
+ const cancel = () => controller.abort();
16
+ process.once("SIGINT", cancel); process.once("SIGTERM", cancel);
17
+ const budget = new MessageBudget(30_000, controller.signal);
18
+ try {
19
+ // Keep home selection on this command path and after syntax validation.
20
+ const { messageCodexHome } = await import("./message-runtime");
21
+ const home = messageCodexHome(env);
22
+ if (args.action === "sessions") {
23
+ const sessions = await localSessions(home, budget);
24
+ if (args.json) console.log(JSON.stringify({ schema: "ocx-message-sessions/1", sessions }));
25
+ else for (const session of sessions) console.log(terminalSafeText(`${session.id}\t${session.status}\t${session.name ?? "(unnamed)"}`));
26
+ return 0;
27
+ }
28
+ const body = await readMessageInput(Bun.stdin.stream(), budget);
29
+ const receipt = await sendLocalMessage({ ...args, body },
30
+ { home, senderId: env.CODEX_THREAD_ID }, budget);
31
+ if (args.json) console.log(JSON.stringify(receipt));
32
+ else console.log(terminalSafeText(`${receipt.status}: ${receipt.messageId}${receipt.error ? ` — ${receipt.error.message}` : " (submitted, not proof of processing)"}`));
33
+ return receipt.status === "queued" ? 0 : receipt.status === "unknown" ? 3 : 1;
34
+ } catch (error) {
35
+ const failure = { schema: "ocx-message-error/1", ...(args.action === "send" ? { status: "not_sent" } : {}), error: messageFailure(error) };
36
+ if (args.json) console.log(JSON.stringify(failure));
37
+ else console.error(failure.error.message);
38
+ return 1;
39
+ } finally {
40
+ budget.dispose();
41
+ process.removeListener("SIGINT", cancel); process.removeListener("SIGTERM", cancel);
42
+ }
43
+ }
@@ -0,0 +1,6 @@
1
+ import { resolveCodexHomeDir } from "../codex/home";
2
+
3
+ /** Resolve the effective existing Codex home using the shared policy, without creating it. */
4
+ export function messageCodexHome(env: NodeJS.ProcessEnv): string {
5
+ return resolveCodexHomeDir({ env });
6
+ }
@@ -129,7 +129,9 @@ async function explain(argv: string[], deps: RuntimeApiDeps): Promise<void> {
129
129
  rejectArgs(args, USAGE);
130
130
  const encoded = encodeURIComponent(requestId);
131
131
  const result = await runtimeRequest(`/api/request-history/${encoded}/route-decision`, {}, deps);
132
- printData(result, wantsJson, wantsJson ? undefined : [JSON.stringify(result, null, 2)]);
132
+ // One entry per line: printData escapes control characters per entry, so a single
133
+ // pretty-printed string would print its line breaks as literal `\x0a`.
134
+ printData(result, wantsJson, wantsJson ? undefined : JSON.stringify(result, null, 2).split("\n"));
133
135
  }
134
136
 
135
137
  async function rebuildIndex(argv: string[], deps: RuntimeApiDeps): Promise<void> {
@@ -8,11 +8,12 @@
8
8
  * show <name> Show provider config details (secrets masked)
9
9
  * set-default <name> Change the default provider
10
10
  */
11
- import { hasOwnProvider, isValidProviderName, loadConfig, sanitizeModelCostsForDisplay, saveConfig, validateConfigCandidate } from "../config";
11
+ import { hasOwnProvider, isValidProviderName, loadConfig, sanitizeModelCostsForDisplay, saveConfig, validateConfigCandidate, withConfigMutationLockSync } from "../config";
12
12
  import { apiKeyTransportConfigError, modelCapabilitiesConfigError, mergeModelCapabilities } from "../config/provider-validation";
13
13
  import { hasHelpFlag, printSubcommandUsage } from "./help";
14
14
  import { getProviderRegistryEntry, PROVIDER_REGISTRY } from "../providers/registry";
15
15
  import { providerConfigSeed } from "../providers/derive";
16
+ import { assertAnthropicInstanceLoginConfig } from "../oauth/store-anthropic-instance";
16
17
  import { dropProviderCustomModels } from "../providers/provider-id-rewrite";
17
18
  import type { OcxProviderConfig } from "../types";
18
19
  import { findLiveProxy } from "../server/proxy-liveness";
@@ -249,6 +250,17 @@ async function handleAdd(args: string[], deps: ProviderCommandDeps): Promise<voi
249
250
 
250
251
  if (responsesPath !== undefined) provConfig.responsesPath = responsesPath;
251
252
  if (authMode !== undefined) provConfig.authMode = authMode as OcxProviderConfig["authMode"];
253
+ if (name === "anthropic2") {
254
+ if (provConfig.adapter !== "anthropic" || provConfig.authMode !== "oauth") delete provConfig.anthropicOAuthInstance;
255
+ if (provConfig.anthropicOAuthInstance) {
256
+ try { assertAnthropicInstanceLoginConfig(config, name); }
257
+ catch {
258
+ console.error("Error: cannot add Pool 2 over an existing custom or unreadable provider configuration; resolve it first.");
259
+ process.exitCode = 2;
260
+ return;
261
+ }
262
+ }
263
+ }
252
264
  if (name === "openai" && (authMode !== undefined || responsesPath !== undefined)
253
265
  && !isCanonicalOpenAiForwardProvider(provConfig)) {
254
266
  console.error("Error: Canonical OpenAI must keep its built-in forward destination and authentication. Use a separate provider name for a custom endpoint.");
@@ -315,11 +327,22 @@ async function handleAdd(args: string[], deps: ProviderCommandDeps): Promise<voi
315
327
  return;
316
328
  }
317
329
  const { initializeProviderModelSelection } = await import("../providers/initial-model-selection");
318
- initializeProviderModelSelection(name, provConfig, existingProvider, config);
319
- config.providers[name] = provConfig;
320
- if (setDefault) config.defaultProvider = name;
321
-
322
- validateAndSave(config);
330
+ let markerCollision = false;
331
+ withConfigMutationLockSync(() => {
332
+ if (provConfig.anthropicOAuthInstance) {
333
+ try { assertAnthropicInstanceLoginConfig(config, name); }
334
+ catch { markerCollision = true; return; }
335
+ }
336
+ initializeProviderModelSelection(name, provConfig, existingProvider, config);
337
+ config.providers[name] = provConfig;
338
+ if (setDefault) config.defaultProvider = name;
339
+ validateAndSave(config);
340
+ });
341
+ if (markerCollision) {
342
+ console.error("Error: provider configuration changed while adding Pool 2; resolve the ownership collision first.");
343
+ process.exitCode = 2;
344
+ return;
345
+ }
323
346
 
324
347
  let sync: LocalSyncResult | undefined;
325
348
  if (wantsSync) {
@@ -8,6 +8,12 @@ export interface CliCommandEntry {
8
8
  }
9
9
 
10
10
  export const CLI_COMMANDS: CliCommandEntry[] = [
11
+ {
12
+ name: "message",
13
+ usage: "ocx message <sessions|send> [options]",
14
+ summary: "Discover loaded local Codex sessions and submit one queued peer message.",
15
+ details: ["Local Unix transport only; starts no daemon. queued is submission, not processing; never replay an unknown send."],
16
+ },
11
17
  {
12
18
  name: "chatgpt",
13
19
  usage: "ocx chatgpt <launch|restore|status>",
@@ -467,8 +473,8 @@ export const CLI_COMMANDS: CliCommandEntry[] = [
467
473
  },
468
474
  {
469
475
  name: "export",
470
- usage: "ocx export --client <opencode|pi|omp|hermes|openclaw|kimi|gajae|dsh|mcode|zcode|prime|aside|raycast|omo|cline|kilo|droid> [--json] [--out <path>] [--force]",
471
- summary: "Print a client config (OpenCode, Pi, OMP, Hermes, OpenClaw, Kimi Code, gjc, DeepSeek Harness, MiniMax Code, ZCode, Prime Agent, Aside, Raycast, omo, Cline, Kilo, Factory Droid) wired to the running proxy.",
476
+ usage: "ocx export --client <opencode|pi|omp|hermes|openclaw|kimi|gajae|dsh|mcode|zcode|commandcode|prime|aside|raycast|omo|cline|kilo|droid> [--json] [--out <path>] [--force]",
477
+ summary: "Print a client config (OpenCode, Pi, OMP, Hermes, OpenClaw, Kimi Code, gjc, DeepSeek Harness, MiniMax Code, ZCode, Command Code, Prime Agent, Aside, Raycast, omo, Cline, Kilo, Factory Droid) wired to the running proxy.",
472
478
  details: [
473
479
  "--json prints the generated document as JSON on stdout; use --out for the client's native format.",
474
480
  "--out <path> writes the native config there and refuses to replace an existing file without --force.",
@@ -598,6 +604,22 @@ export const CLI_COMMANDS: CliCommandEntry[] = [
598
604
  "Select OpenCodex Proxy/<provider>/<model> from ZCode's model picker.",
599
605
  ],
600
606
  },
607
+ {
608
+ name: "commandcode",
609
+ usage: "ocx commandcode [status|show|list|enable|disable|history|journal|restore --op <opId>] [--json]",
610
+ summary: "Connect Command Code CLI to the proxy via its managed provider.",
611
+ details: [
612
+ "Alias of ocx integration client <sub> --client commandcode.",
613
+ "enable manages the opencodex block under the existing provider or providers root in ~/.commandcode/providers.json; disable removes only that block.",
614
+ "Command Code reads providers on startup.",
615
+ "`restore --op <opId>` replays the exact previous managed block; take the id from `ocx commandcode history`.",
616
+ ],
617
+ },
618
+ {
619
+ name: "cmd",
620
+ usage: "ocx cmd [status|show|list|enable|disable|history|journal|restore --op <opId>] [--json]",
621
+ summary: "Alias of ocx commandcode.",
622
+ },
601
623
  {
602
624
  name: "restart",
603
625
  usage: "ocx restart",
@@ -0,0 +1,131 @@
1
+ // Command Code config export.
2
+ import type { ExportContext, ManagedContribution } from "./contracts";
3
+ import { normalizeExportModels, authoritativeContextWindow, singleFragment } from "./model-metadata";
4
+ import { OPENCODE_PROVIDER_ID, LOOPBACK_API_KEY_PLACEHOLDER } from "./constants";
5
+ import { sanitizeCodexReasoningEfforts } from "../../reasoning-effort";
6
+
7
+ export interface CommandCodeModelEntry {
8
+ reasoningEfforts?: string[];
9
+ contextWindow?: number;
10
+ }
11
+
12
+ export interface CommandCodeProviderBlock {
13
+ name: "OpenCodex";
14
+ api: "openai-completions";
15
+ baseURL: string;
16
+ apiKey: string | boolean;
17
+ models: Record<string, CommandCodeModelEntry>;
18
+ }
19
+
20
+ export interface CommandCodeGeneratedConfig {
21
+ provider: Record<string, CommandCodeProviderBlock>;
22
+ /** The root a pre-existing target already uses; see {@link commandCodeProviderRoot}. */
23
+ providers?: Record<string, CommandCodeProviderBlock>;
24
+ }
25
+
26
+ /**
27
+ * LOSSY spelling-collision key for a routed selector — not model identity.
28
+ *
29
+ * One provider model reaches this exporter under interchangeable spellings: the raw
30
+ * selector keeps inner slashes (`command-code/deepseek/deepseek-v4.1-flash`, what
31
+ * `/v1/models` publishes) while the Codex-facing form encodes them as dashes
32
+ * (`command-code/deepseek-deepseek-v4.1-flash`, what `~/.codex/config.toml` stores and
33
+ * what an operator typing `--model` copies). Command Code addresses models by exact key,
34
+ * so a catalog that carries both spellings can resolve the active model against one and
35
+ * miss it in the other.
36
+ *
37
+ * The slash is meaningful: it separates the provider from the model id, and a provider id
38
+ * never contains one. But the encoding is NOT bijective — `p/a/b` and `p/a-b` are
39
+ * different model ids that encode to the same string. That is the same lossy relation
40
+ * `slugEquivalenceKey` documents in src/providers/slug-codec.ts and the same ambiguity
41
+ * `resolveSlugAliasCollisions` guards in the catalog. Callers must therefore never drop
42
+ * a row on this key alone; buildCommandCodeClientConfig additionally compares provider
43
+ * and id before folding two rows into one.
44
+ */
45
+ function canonicalSpellingOf(namespaced: string): string {
46
+ const slash = namespaced.indexOf("/");
47
+ if (slash <= 0) return namespaced;
48
+ return namespaced.slice(0, slash) + "/" + namespaced.slice(slash + 1).replaceAll("/", "-");
49
+ }
50
+
51
+ export function buildCommandCodeClientConfig(ctx: ExportContext): CommandCodeGeneratedConfig {
52
+ const models: Record<string, CommandCodeModelEntry> = {};
53
+ // Fold interchangeable spellings of one model onto a single key. The first
54
+ // occurrence wins per provider+id identity; distinct model ids that happen to
55
+ // share a lossy spelling collision must both remain addressable.
56
+ const emittedIdentitiesByCollision = new Map<string, Set<string>>();
57
+ for (const model of normalizeExportModels(ctx.models)) {
58
+ const emittedKey = model.namespaced;
59
+ const collisionKey = canonicalSpellingOf(model.namespaced);
60
+ const identity = `${model.provider}\u0000${model.id}`;
61
+ const identities = emittedIdentitiesByCollision.get(collisionKey) ?? new Set<string>();
62
+ if (identities.has(identity)) continue;
63
+ identities.add(identity);
64
+ emittedIdentitiesByCollision.set(collisionKey, identities);
65
+ const entry: CommandCodeModelEntry = {};
66
+ const context = authoritativeContextWindow(model.contextWindow);
67
+ if (context !== undefined) {
68
+ entry.contextWindow = context;
69
+ }
70
+ const efforts = sanitizeCodexReasoningEfforts(model.reasoningEfforts)
71
+ ?.filter(effort => ["low", "medium", "high", "xhigh", "max"].includes(effort));
72
+ if (efforts && efforts.length > 0) {
73
+ entry.reasoningEfforts = efforts;
74
+ }
75
+ models[emittedKey] = entry;
76
+ }
77
+ return {
78
+ provider: {
79
+ [OPENCODE_PROVIDER_ID]: {
80
+ name: "OpenCodex",
81
+ api: "openai-completions",
82
+ baseURL: ctx.baseUrl.replace(/\/v1\/?$/, "") + "/v1",
83
+ apiKey: false,
84
+ models,
85
+ },
86
+ },
87
+ };
88
+ }
89
+
90
+ /**
91
+ * The root key Command Code actually reads: `provider`, else `providers`.
92
+ *
93
+ * Verified against the published client (`command-code@1.66.0`, `dist/cli.mjs`):
94
+ * `const o = e.provider ?? e.providers;` — singular wins, and the plural branch is
95
+ * only reached when the singular root is nullish (`null` or `undefined`). Adding a
96
+ * singular root to a document that already carries a plural one therefore does not
97
+ * merge the two: the old entries stay on disk, byte for byte, and become invisible
98
+ * to the consumer.
99
+ *
100
+ * Evaluates nullish precedence before container validation so that non-nullish
101
+ * invalid singular values (such as strings or arrays) remain selected and are refused
102
+ * by the container guard rather than falling through to write an unreachable plural block.
103
+ */
104
+ export function commandCodeProviderRoot(document: unknown): "provider" | "providers" {
105
+ const doc = document as { provider?: unknown; providers?: unknown } | null | undefined;
106
+ if (doc?.provider !== undefined && doc?.provider !== null) return "provider";
107
+ if (doc?.providers !== undefined && doc?.providers !== null) return "providers";
108
+ // Nothing established yet: the singular root is the one this exporter writes.
109
+ return "provider";
110
+ }
111
+
112
+ export function summarizeCommandCode(document: unknown): { modelCount: number; modelsWithoutLimits: number } {
113
+ const doc = document as CommandCodeGeneratedConfig | undefined;
114
+ const root = commandCodeProviderRoot(document);
115
+ const models = Object.values(doc?.[root]?.[OPENCODE_PROVIDER_ID]?.models ?? {}) as CommandCodeModelEntry[];
116
+ return { modelCount: models.length, modelsWithoutLimits: models.filter(model => model.contextWindow === undefined).length };
117
+ }
118
+
119
+ /**
120
+ * The provider block, written under whichever root the target document already uses.
121
+ *
122
+ * `ExportContext` carries the parsed target document so the root can be chosen from
123
+ * what is on disk rather than assumed. A fresh file gets the singular root this
124
+ * exporter has always written; a document that already carries a plural root keeps
125
+ * it, so enabling OpenCodex never makes the user's other providers unreadable.
126
+ */
127
+ export function buildCommandCodeContribution(ctx: ExportContext): ManagedContribution {
128
+ const doc = buildCommandCodeClientConfig(ctx);
129
+ const root = commandCodeProviderRoot(ctx.document);
130
+ return singleFragment("commandcode", [root, OPENCODE_PROVIDER_ID], doc.provider[OPENCODE_PROVIDER_ID]);
131
+ }
@@ -185,6 +185,17 @@ export interface ExportContext {
185
185
  */
186
186
  config?: OcxConfig;
187
187
  droidReasoningDefaults?: DroidReasoningDefaults;
188
+ /**
189
+ * The parsed target document, when the caller has one in hand.
190
+ *
191
+ * A client whose reader picks between two roots needs the bytes on disk to
192
+ * choose: Command Code resolves `document.provider ?? document.providers`, so
193
+ * writing the singular root into a document that already carries the plural one
194
+ * leaves the user's providers unreadable rather than merging with them. Absent
195
+ * for `ocx export`, which has no target file — the builder then writes its
196
+ * default root, exactly as before.
197
+ */
198
+ document?: unknown;
188
199
  }
189
200
 
190
201
  /** Namespaced model selector to one of that model's declared reasoning efforts. */
@@ -206,6 +217,7 @@ export type ExportClientId =
206
217
  | "raycast"
207
218
  | "omo"
208
219
  | "cline"
220
+ | "commandcode"
209
221
  | "kilo"
210
222
  | "droid";
211
223
 
@@ -21,7 +21,7 @@
21
21
  */
22
22
  import { homedir } from "node:os";
23
23
  import { existsSync, lstatSync, readFileSync, realpathSync, statSync } from "node:fs";
24
- import { basename, dirname, isAbsolute, join, resolve } from "node:path";
24
+ import { basename, dirname, isAbsolute, join, resolve, win32 } from "node:path";
25
25
  import { shouldInjectApiAuthHeader, standaloneCodexRoutingTarget } from "../codex/inject";
26
26
  import { FORMAT_MEDIA_TYPE, serializeDocument, type ConfigFormat } from "../integrations/serialize";
27
27
  import { canonicalizeReasoningEfforts } from "../reasoning-effort";
@@ -69,6 +69,18 @@ import { buildKiloClientConfig, summarizeKilo, buildKiloContribution, kiloConfig
69
69
  export { kiloConfigPath, kiloHomeDir, kiloCandidatePath, KILO_CONFIG_CANDIDATES } from "./config-export/kilo";
70
70
  export type { KiloGeneratedConfig, KiloProviderBlock, KiloModelEntry } from "./config-export/kilo";
71
71
  import { droidConfigPath, buildDroidClientConfig, summarizeDroid, buildDroidContribution } from "./config-export/droid";
72
+ import {
73
+ buildCommandCodeClientConfig,
74
+ summarizeCommandCode,
75
+ buildCommandCodeContribution,
76
+ commandCodeProviderRoot,
77
+ type CommandCodeGeneratedConfig,
78
+ type CommandCodeModelEntry,
79
+ type CommandCodeProviderBlock,
80
+ } from "./config-export/commandcode";
81
+
82
+ export type { CommandCodeGeneratedConfig, CommandCodeModelEntry, CommandCodeProviderBlock };
83
+ export { buildCommandCodeClientConfig, summarizeCommandCode, buildCommandCodeContribution, commandCodeProviderRoot };
72
84
 
73
85
 
74
86
 
@@ -474,6 +486,43 @@ export function zcodeConfigPath(env: OpencodeLaunchEnv = process.env, home: stri
474
486
  return join(zcodeHomeDir(env, home), "v2", "config.json");
475
487
  }
476
488
 
489
+ /**
490
+ * The home directory Command Code itself resolves: `env.HOME ?? env.USERPROFILE`
491
+ * (`homeDir15` in the published `command-code@1.66.0` bundle).
492
+ *
493
+ * On POSIX `os.homedir()` already reads `$HOME`, so the two agree and `home` is
494
+ * returned as is. On Windows `os.homedir()` reads `%USERPROFILE%` and ignores
495
+ * `HOME`, which Git for Windows, MSYS2 and Cygwin set, so a user whose `HOME` differs
496
+ * would get a provider block in a store Command Code never opens. Only the OS-default
497
+ * home is replaced: a caller that injects a different root (a test, the writer's
498
+ * `input.home`) keeps it, and a blank or relative value falls back to `home`.
499
+ */
500
+ export function commandCodeUserHome(env: OpencodeLaunchEnv = process.env, home: string = homedir(), platform: NodeJS.Platform = process.platform): string {
501
+ if (platform !== "win32" || home !== homedir()) return home;
502
+ const value = env.HOME ?? env.USERPROFILE;
503
+ return typeof value === "string" && value.trim() && win32.isAbsolute(value) ? value : home;
504
+ }
505
+
506
+ /**
507
+ * Command Code's provider store directory — `.commandcode` under the home the client
508
+ * resolves (see {@link commandCodeUserHome}), with no override.
509
+ *
510
+ * There is deliberately no `COMMANDCODE_HOME` here, unlike the other clients in this
511
+ * file: `grep -c COMMANDCODE_HOME` over the shipped `dist/cli.mjs` and
512
+ * `dist/index.mjs` returns 0. An override we honour but the client ignores is worse
513
+ * than none: `enable` would report success and write a provider block at a path no
514
+ * Command Code process ever opens, and the user would see an empty model list with no
515
+ * error anywhere. An apply against a relocated home is instead refused by `detectDir`
516
+ * not existing.
517
+ */
518
+ export function commandCodeHomeDir(env: OpencodeLaunchEnv = process.env, home: string = homedir(), platform: NodeJS.Platform = process.platform): string {
519
+ return join(commandCodeUserHome(env, home, platform), ".commandcode");
520
+ }
521
+
522
+ export function commandCodeConfigPath(env: OpencodeLaunchEnv = process.env, home: string = homedir(), platform: NodeJS.Platform = process.platform): string {
523
+ return join(commandCodeHomeDir(env, home, platform), "providers.json");
524
+ }
525
+
477
526
  /**
478
527
  * The provider store a current ZCode reads, which is NOT the file above.
479
528
  *
@@ -1487,6 +1536,20 @@ export const EXPORT_CLIENTS: Record<ExportClientId, ExportClientSpec> = {
1487
1536
  // remote binds refuse — same reasoning as MCode.
1488
1537
  loopbackOnly: true,
1489
1538
  },
1539
+ commandcode: {
1540
+ id: "commandcode",
1541
+ filename: "providers.json",
1542
+ destination: env => commandCodeConfigPath(env),
1543
+ // No env var exists behind this integration: buildCommandCodeClientConfig
1544
+ // writes `apiKey: false`, the documented keyless form for a loopback endpoint.
1545
+ apiKeyEnv: "",
1546
+ exportHint: "The provider is written with `apiKey: false` — Command Code treats a keyless loopback endpoint as already authenticated. No key is stored or referenced.",
1547
+ build: buildCommandCodeClientConfig,
1548
+ format: "json",
1549
+ summarize: summarizeCommandCode,
1550
+ buildContribution: buildCommandCodeContribution,
1551
+ loopbackOnly: true,
1552
+ },
1490
1553
  prime: {
1491
1554
  id: "prime",
1492
1555
  filename: "prime-models.json",
@@ -252,6 +252,13 @@ export function reconcileFreshPoolAccountPlans(runtimeConfig: OcxConfig, updates
252
252
  }
253
253
  }
254
254
 
255
+ export interface CodexAuthAccountsListOptions {
256
+ /** Finish deferred registration; only a dashboard session carries that inference consent. */
257
+ validatePending?: boolean;
258
+ /** An operator's explicit refresh command, which may retry a grant already recorded as dead. */
259
+ explicitRefresh?: boolean;
260
+ }
261
+
255
262
  export interface CodexAuthAccountsSnapshot {
256
263
  accounts: CodexAuthAccountDto[];
257
264
  mainIdentityGeneration: number;
@@ -260,7 +267,7 @@ export interface CodexAuthAccountsSnapshot {
260
267
  export async function listCodexAuthAccountsSnapshot(
261
268
  config: OcxConfig,
262
269
  forceRefresh = false,
263
- options: { validatePending?: boolean } = {},
270
+ options: CodexAuthAccountsListOptions = {},
264
271
  ): Promise<CodexAuthAccountsSnapshot> {
265
272
  const runtimeConfig = getRuntimeConfig(config);
266
273
  const poolAccounts = (runtimeConfig.codexAccounts ?? []).filter(isSelectableCodexPoolAccount);
@@ -281,7 +288,8 @@ export async function listCodexAuthAccountsSnapshot(
281
288
  // identity when the switch is on and nothing has been observed yet.
282
289
  const creditsIdentity = runtimeConfig.showCodexCredits === true ? poolQuotaHistoryIdentity(account.id) ?? null : null;
283
290
  const creditsUnobserved = creditsIdentity !== null && !hasCodexCreditsObservation(account.id, creditsIdentity);
284
- quotaResult = await fetchPoolAccountQuota(account.id, forceRefresh || creditsUnobserved, account.plan, getValidCodexToken, options.validatePending === true);
291
+ quotaResult = await fetchPoolAccountQuota(account.id, forceRefresh || creditsUnobserved, account.plan, getValidCodexToken,
292
+ options.validatePending === true, undefined, undefined, options.explicitRefresh === true);
285
293
  } catch (error) {
286
294
  if (!(error instanceof PoolQuotaProbeBusyError)) throw error;
287
295
  quotaResult = {
@@ -447,7 +455,7 @@ export async function refreshCodexQuotaForActivation(config: OcxConfig, accountI
447
455
  export async function listCodexAuthAccounts(
448
456
  config: OcxConfig,
449
457
  forceRefresh = false,
450
- options: { validatePending?: boolean } = {},
458
+ options: CodexAuthAccountsListOptions = {},
451
459
  ): Promise<CodexAuthAccountDto[]> {
452
460
  return (await listCodexAuthAccountsSnapshot(config, forceRefresh, options)).accounts;
453
461
  }