@bitkyc08/opencodex 2.10.1 → 2.10.2

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 (57) hide show
  1. package/bin/ocx.mjs +18 -9
  2. package/gui/dist/assets/index-BKVqyYqT.js +70 -0
  3. package/gui/dist/assets/{index-Cd6_PBKn.css → index-Ca_3269W.css} +1 -1
  4. package/gui/dist/index.html +2 -2
  5. package/gui/dist/provider-icons/commandcode-color.svg +1 -0
  6. package/gui/dist/provider-icons/openai.svg +1 -1
  7. package/package.json +1 -1
  8. package/src/adapters/command-code.ts +453 -0
  9. package/src/adapters/google.ts +3 -0
  10. package/src/cli/claude.ts +37 -22
  11. package/src/cli/index.ts +16 -3
  12. package/src/cli/launcher-context.ts +77 -0
  13. package/src/codex/admission.ts +1 -1
  14. package/src/codex/app-server-processes.ts +44 -1
  15. package/src/codex/catalog/sync.ts +22 -3
  16. package/src/codex/catalog-write-serialization.ts +1 -1
  17. package/src/codex/codex-write-lock.ts +1 -1
  18. package/src/codex/convergence-types.ts +1 -1
  19. package/src/codex/desired-state.ts +27 -7
  20. package/src/codex/history-job.ts +1 -1
  21. package/src/codex/history-lock.ts +1 -1
  22. package/src/codex/history-worker.ts +1 -1
  23. package/src/codex/internal/history-writer.ts +1 -1
  24. package/src/codex/transition-state.ts +1 -1
  25. package/src/codex/user-identity.ts +1 -1
  26. package/src/config.ts +6 -1
  27. package/src/integrations/config-io.ts +1 -1
  28. package/src/integrations/journal.ts +1 -1
  29. package/src/integrations/merge.ts +1 -1
  30. package/src/integrations/ownership.ts +1 -1
  31. package/src/integrations/registry.ts +1 -1
  32. package/src/integrations/serialize.ts +1 -1
  33. package/src/integrations/state.ts +1 -1
  34. package/src/integrations/store.ts +1 -1
  35. package/src/integrations/writer.ts +1 -1
  36. package/src/lib/bounded-body.ts +3 -1
  37. package/src/lib/bun-runtime.ts +21 -17
  38. package/src/lib/bun-stream-caps.ts +1 -1
  39. package/src/lib/local-management-attestation.ts +51 -0
  40. package/src/lib/shadow-call.ts +4 -4
  41. package/src/oauth/command-code.ts +239 -0
  42. package/src/oauth/health.ts +46 -2
  43. package/src/oauth/index.ts +38 -3
  44. package/src/providers/command-code-efforts.ts +85 -0
  45. package/src/providers/google-vertex-location.ts +14 -0
  46. package/src/providers/registry.ts +138 -26
  47. package/src/routing/capability.ts +1 -0
  48. package/src/server/adapter-resolve.ts +3 -0
  49. package/src/server/auth-cors.ts +6 -1
  50. package/src/server/index.ts +44 -2
  51. package/src/server/management/integration-routes.ts +1 -1
  52. package/src/server/management/native-integration-routes.ts +2 -2
  53. package/src/server/responses/core.ts +13 -9
  54. package/src/storage/scanner.ts +1 -1
  55. package/src/types.ts +6 -0
  56. package/src/usage/log.ts +1 -1
  57. package/gui/dist/assets/index-ChZQsmBY.js +0 -70
@@ -0,0 +1,239 @@
1
+ import type { OAuthController, OAuthCredentials } from "./types";
2
+ import { homedir } from "node:os";
3
+ import { join } from "node:path";
4
+ import { isAddrInUse } from "../server/ports";
5
+ import { parseCallbackInput } from "./callback-server";
6
+
7
+ const COMMAND_CODE_STUDIO_URL = "https://commandcode.ai";
8
+ const COMMAND_CODE_CALLBACK_PORT = 5959;
9
+ const LOGIN_TIMEOUT_MS = 120_000;
10
+ const CALLBACK_PATH = "/callback";
11
+
12
+ interface CommandCodeCallback {
13
+ apiKey: string;
14
+ state: string;
15
+ userId: string;
16
+ userName: string;
17
+ keyName: string;
18
+ }
19
+
20
+ interface CommandCodeLocalAuth {
21
+ apiKey?: unknown;
22
+ userId?: unknown;
23
+ }
24
+
25
+ export interface CommandCodeLoginOptions {
26
+ /** Add-account and reauthentication flows must select a fresh browser identity. */
27
+ importLocal?: "fallback" | "off";
28
+ }
29
+
30
+ export function shouldImportLocalCommandCodeAuth(options: CommandCodeLoginOptions = {}): boolean {
31
+ return options.importLocal !== "off";
32
+ }
33
+
34
+ async function importLocalCommandCodeAuth(signal?: AbortSignal): Promise<OAuthCredentials | undefined> {
35
+ if (signal?.aborted) {
36
+ throw signal.reason ?? new DOMException("Command Code login aborted", "AbortError");
37
+ }
38
+ let parsed: CommandCodeLocalAuth;
39
+ try {
40
+ parsed = JSON.parse(await Bun.file(join(homedir(), ".commandcode", "auth.json")).text()) as CommandCodeLocalAuth;
41
+ } catch {
42
+ return undefined;
43
+ }
44
+ if (typeof parsed.apiKey !== "string" || parsed.apiKey.length === 0) return undefined;
45
+ let accountId: string | undefined;
46
+ try {
47
+ const response = await fetch("https://api.commandcode.ai/alpha/whoami", {
48
+ headers: { Authorization: `Bearer ${parsed.apiKey}`, Accept: "application/json" },
49
+ signal: signal ? AbortSignal.any([signal, AbortSignal.timeout(10_000)]) : AbortSignal.timeout(10_000),
50
+ });
51
+ if (!response.ok) return undefined;
52
+ // Carry the validated whoami identity so an imported credential keeps multi-account
53
+ // semantics even when the local auth.json omits userId.
54
+ const body = (await response.json()) as { user?: { id?: unknown } };
55
+ if (typeof body.user?.id === "string" && body.user.id.length > 0) accountId = body.user.id;
56
+ } catch (error) {
57
+ if (signal?.aborted) throw signal.reason ?? new DOMException("Command Code login aborted", "AbortError");
58
+ return undefined;
59
+ }
60
+ if (!accountId && typeof parsed.userId === "string" && parsed.userId.length > 0) accountId = parsed.userId;
61
+ return {
62
+ access: parsed.apiKey,
63
+ refresh: parsed.apiKey,
64
+ expires: Number.MAX_SAFE_INTEGER,
65
+ ...(accountId ? { accountId } : {}),
66
+ source: "local-cli",
67
+ };
68
+ }
69
+
70
+ function randomState(): string {
71
+ const bytes = new Uint8Array(32);
72
+ crypto.getRandomValues(bytes);
73
+ return Buffer.from(bytes).toString("base64url");
74
+ }
75
+
76
+ export function parseCommandCodeCallback(value: unknown, expectedState: string): CommandCodeCallback {
77
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
78
+ throw new Error("Command Code callback must be an object");
79
+ }
80
+ const body = value as Record<string, unknown>;
81
+ if (body.state !== expectedState) throw new Error("Command Code OAuth state mismatch");
82
+ for (const field of ["apiKey", "userId", "userName", "keyName"] as const) {
83
+ if (typeof body[field] !== "string" || body[field].length === 0) {
84
+ throw new Error(`Command Code callback missing ${field}`);
85
+ }
86
+ }
87
+ return body as unknown as CommandCodeCallback;
88
+ }
89
+
90
+ function createCallbackServer(state: string): {
91
+ servers: Array<ReturnType<typeof Bun.serve>>;
92
+ callback: Promise<CommandCodeCallback>;
93
+ } {
94
+ let resolve!: (value: CommandCodeCallback) => void;
95
+ const callback = new Promise<CommandCodeCallback>((res) => { resolve = res; });
96
+ const fetch = async (request: Request): Promise<Response> => {
97
+ const url = new URL(request.url);
98
+ const origin = request.headers.get("origin");
99
+ const headers = new Headers({
100
+ "Content-Type": "application/json",
101
+ "Access-Control-Allow-Origin": origin === COMMAND_CODE_STUDIO_URL ? origin : COMMAND_CODE_STUDIO_URL,
102
+ "Access-Control-Allow-Methods": "POST, OPTIONS",
103
+ "Access-Control-Allow-Headers": "Content-Type",
104
+ });
105
+ if (request.method === "OPTIONS") return new Response(null, { status: 204, headers });
106
+ if (url.pathname !== CALLBACK_PATH) return Response.json({ success: false, error: "Not found" }, { status: 404, headers });
107
+ if (request.method !== "POST") return Response.json({ success: false, error: "Method not allowed" }, { status: 405, headers });
108
+ try {
109
+ const body = await request.json();
110
+ const parsed = parseCommandCodeCallback(body, state);
111
+ queueMicrotask(() => resolve(parsed));
112
+ return Response.json({ success: true }, { headers });
113
+ } catch (error) {
114
+ const message = error instanceof Error ? error.message : String(error);
115
+ return Response.json({ success: false, error: message }, { status: 400, headers });
116
+ }
117
+ };
118
+ const create = (port: number): Array<ReturnType<typeof Bun.serve>> => {
119
+ // The advertised callback host is `127.0.0.1`; on Windows `localhost` commonly resolves to `::1`
120
+ // first, so also bind the IPv6 loopback best-effort (mirrors the shared OAuthCallbackFlow).
121
+ const servers = [Bun.serve({ hostname: "127.0.0.1", port, fetch })];
122
+ try {
123
+ servers.push(Bun.serve({ hostname: "::1", port: servers[0].port, fetch }));
124
+ } catch (error) {
125
+ if (isAddrInUse(error)) {
126
+ for (const server of servers) server.stop(true);
127
+ throw error;
128
+ }
129
+ // IPv6 unsupported (EAFNOSUPPORT etc.) degrades to the IPv4-only listener.
130
+ }
131
+ return servers;
132
+ };
133
+ try {
134
+ return { servers: create(COMMAND_CODE_CALLBACK_PORT), callback };
135
+ } catch {
136
+ return { servers: create(0), callback };
137
+ }
138
+ }
139
+
140
+ /** Validate a raw pasted Command Code API key and return the validated identity. */
141
+ async function validatePastedApiKey(apiKey: string): Promise<{ userId: string; userName: string } | undefined> {
142
+ try {
143
+ const response = await fetch("https://api.commandcode.ai/alpha/whoami", {
144
+ headers: { Authorization: `Bearer ${apiKey}`, Accept: "application/json" },
145
+ signal: AbortSignal.timeout(10_000),
146
+ });
147
+ if (!response.ok) return undefined;
148
+ const body = (await response.json()) as { user?: { id?: unknown; userName?: unknown } };
149
+ const userId = body.user?.id;
150
+ const userName = body.user?.userName;
151
+ if (typeof userId !== "string" || typeof userName !== "string") return undefined;
152
+ if (!userId.trim() || !userName.trim()) return undefined;
153
+ return { userId, userName };
154
+ } catch {
155
+ return undefined;
156
+ }
157
+ }
158
+
159
+ /** Manual-paste fallback: a raw API key, or a pasted callback JSON/URL that carries `apiKey`. */
160
+ function parsePastedCommandCodeInput(input: string, expectedState: string): CommandCodeCallback | undefined {
161
+ const trimmed = input.trim();
162
+ if (!trimmed) return undefined;
163
+ if (trimmed.startsWith("{")) {
164
+ try {
165
+ return parseCommandCodeCallback(JSON.parse(trimmed) as unknown, expectedState);
166
+ } catch {
167
+ return undefined;
168
+ }
169
+ }
170
+ const parsed = parseCallbackInput(trimmed);
171
+ const apiKey = parsed.code?.trim();
172
+ if (!apiKey) return undefined;
173
+ // A URL/query-shaped paste is an authorization response and must carry a matching state,
174
+ // mirroring the shared OAuth callback flow; a stale or attacker-supplied URL from another
175
+ // session must not be accepted. Raw in-session keys are exempt (no state to compare).
176
+ if (parsed.kind !== "raw" && parsed.state !== expectedState) return undefined;
177
+ return { apiKey, state: expectedState, userId: "", userName: "", keyName: "manual" };
178
+ }
179
+
180
+ export async function loginCommandCode(ctrl: OAuthController, options: CommandCodeLoginOptions = {}): Promise<OAuthCredentials> {
181
+ if (ctrl.signal?.aborted) {
182
+ throw ctrl.signal.reason ?? new DOMException("Command Code login aborted", "AbortError");
183
+ }
184
+ if (shouldImportLocalCommandCodeAuth(options)) {
185
+ const local = await importLocalCommandCodeAuth(ctrl.signal);
186
+ if (local) {
187
+ ctrl.onProgress?.("Imported existing Command Code CLI authentication.");
188
+ return local;
189
+ }
190
+ }
191
+ const state = randomState();
192
+ let servers: Array<ReturnType<typeof Bun.serve>> = [];
193
+ let timeoutId: ReturnType<typeof setTimeout> | undefined;
194
+ try {
195
+ const created = createCallbackServer(state);
196
+ servers = created.servers;
197
+ const callbackUrl = `http://127.0.0.1:${servers[0].port}${CALLBACK_PATH}`;
198
+ const authUrl = `${COMMAND_CODE_STUDIO_URL}/studio/auth/cli?callback=${encodeURIComponent(callbackUrl)}&state=${encodeURIComponent(state)}`;
199
+ ctrl.onAuth?.({ url: authUrl, instructions: "Sign in with Command Code in the browser." });
200
+ ctrl.onProgress?.("Waiting for Command Code authentication...");
201
+ const timeout = new Promise<never>((_, reject) => {
202
+ timeoutId = setTimeout(() => reject(new Error("Command Code OAuth callback timed out")), LOGIN_TIMEOUT_MS);
203
+ ctrl.signal?.addEventListener("abort", () => { if (timeoutId) clearTimeout(timeoutId); reject(ctrl.signal?.reason); }, { once: true });
204
+ });
205
+ const manual = ctrl.onManualCodeInput
206
+ ? (async (): Promise<CommandCodeCallback> => {
207
+ while (true) {
208
+ // The loop keeps waiting until a valid paste arrives; invalid pastes re-prompt.
209
+ // Yield between iterations so an abort signal can interrupt a fast re-prompt loop.
210
+ if (ctrl.signal?.aborted) throw ctrl.signal.reason ?? new DOMException("Command Code login aborted", "AbortError");
211
+ const input = await ctrl.onManualCodeInput?.(state);
212
+ if (input === undefined) continue;
213
+ const pasted = parsePastedCommandCodeInput(input, state);
214
+ if (!pasted) continue;
215
+ const identity = await validatePastedApiKey(pasted.apiKey);
216
+ if (identity) return { ...pasted, ...identity };
217
+ await new Promise(resolve => setTimeout(resolve, 0));
218
+ }
219
+ })()
220
+ : undefined;
221
+ const result = await Promise.race([created.callback, timeout, ...(manual ? [manual] : [])]);
222
+ if (result === undefined) throw new Error("Command Code OAuth callback cancelled");
223
+ return {
224
+ access: result.apiKey,
225
+ refresh: result.apiKey,
226
+ expires: Number.MAX_SAFE_INTEGER,
227
+ accountId: result.userId,
228
+ source: "oauth",
229
+ };
230
+ } finally {
231
+ if (timeoutId) clearTimeout(timeoutId);
232
+ for (const server of servers) server.stop(true);
233
+ }
234
+ }
235
+
236
+ export async function refreshCommandCodeToken(apiKey: string): Promise<OAuthCredentials> {
237
+ if (!apiKey) throw new Error("Command Code API key missing; run ocx login command-code");
238
+ return { access: apiKey, refresh: apiKey, expires: Number.MAX_SAFE_INTEGER, source: "oauth" };
239
+ }
@@ -4,6 +4,13 @@ import { isAccountNeedsReauth } from "../codex/account-runtime-state";
4
4
  import { getCodexAccountCredential, listCodexAccountIds } from "../codex/account-store";
5
5
  import { MAIN_CODEX_ACCOUNT_ID } from "../codex/main-account";
6
6
  import { configuredAdminToken } from "../lib/admin-secrets";
7
+ import { readRuntimePort } from "../config";
8
+ import {
9
+ LOCAL_ATTESTATION_CHALLENGE_HEADER,
10
+ LOCAL_ATTESTATION_PROOF_HEADER,
11
+ createLocalAttestationChallenge,
12
+ verifyLocalAttestationProof,
13
+ } from "../lib/local-management-attestation";
7
14
  import { maskAccountId } from "../lib/privacy";
8
15
  import { findLiveProxy, probeHostname } from "../server/proxy-liveness";
9
16
  import { loadAuthStore, peekAuthStore, peekOAuthRefreshIntent, readOAuthRefreshIntent } from "./store";
@@ -328,6 +335,7 @@ type LiveProxyCodexHealthResult = {
328
335
  async function fetchCodexHealthFromLiveProxy(
329
336
  fetchImpl: typeof fetch = fetch,
330
337
  findLiveProxyImpl: typeof findLiveProxy = findLiveProxy,
338
+ readRuntimePortImpl: typeof readRuntimePort = readRuntimePort,
331
339
  ): Promise<LiveProxyCodexHealthResult> {
332
340
  const live = await findLiveProxyImpl();
333
341
  if (!live) return { source: "unavailable", entries: null };
@@ -335,8 +343,39 @@ async function fetchCodexHealthFromLiveProxy(
335
343
  // interchangeable with the admin credential even on loopback.
336
344
  const token = configuredAdminToken();
337
345
  const headers: Record<string, string> = {};
338
- if (token) headers.Authorization = `Bearer ${token}`;
339
346
  try {
347
+ if (token) {
348
+ // Public /healthz identity is intentionally forgeable enough for liveness, not
349
+ // strong enough to receive a bearer. Prove the listener knows the per-process
350
+ // secret stored in the protected runtime record before attaching the admin token.
351
+ if (live.source !== "runtime" || live.pid === null) {
352
+ return { source: "management-api-unavailable", entries: null };
353
+ }
354
+ const attestedPid = live.pid;
355
+ const runtime = readRuntimePortImpl(attestedPid);
356
+ if (!runtime?.attestationSecret || runtime.port !== live.port) {
357
+ return { source: "management-api-unavailable", entries: null };
358
+ }
359
+ const challenge = createLocalAttestationChallenge();
360
+ const proofResponse = await fetchImpl(
361
+ `http://${probeHostname(live.hostname)}:${live.port}/healthz`,
362
+ {
363
+ headers: { [LOCAL_ATTESTATION_CHALLENGE_HEADER]: challenge },
364
+ signal: AbortSignal.timeout(4000),
365
+ },
366
+ );
367
+ const proof = proofResponse.headers.get(LOCAL_ATTESTATION_PROOF_HEADER);
368
+ if (!proofResponse.ok || !verifyLocalAttestationProof(
369
+ runtime.attestationSecret,
370
+ challenge,
371
+ attestedPid,
372
+ live.port,
373
+ proof,
374
+ )) {
375
+ return { source: "management-api-unavailable", entries: null };
376
+ }
377
+ headers.Authorization = `Bearer ${token}`;
378
+ }
340
379
  const res = await fetchImpl(
341
380
  `http://${probeHostname(live.hostname)}:${live.port}/api/codex-auth/accounts`,
342
381
  { headers, signal: AbortSignal.timeout(4000) },
@@ -387,10 +426,15 @@ export async function collectOAuthHealthEntriesForCli(
387
426
  deps: {
388
427
  fetchImpl?: typeof fetch;
389
428
  findLiveProxyImpl?: typeof findLiveProxy;
429
+ readRuntimePortImpl?: typeof readRuntimePort;
390
430
  } = {},
391
431
  ): Promise<OAuthCliHealthReport> {
392
432
  const entries = collectOAuthHealthEntries(now, { observeOnly: true, includeLocalCodex: false });
393
- const remote = await fetchCodexHealthFromLiveProxy(deps.fetchImpl, deps.findLiveProxyImpl);
433
+ const remote = await fetchCodexHealthFromLiveProxy(
434
+ deps.fetchImpl,
435
+ deps.findLiveProxyImpl,
436
+ deps.readRuntimePortImpl,
437
+ );
394
438
  if (remote.entries) {
395
439
  for (const entry of remote.entries) entries.push(entry);
396
440
  return { entries, codexHealthSource: "management-api" };
@@ -12,6 +12,7 @@ import { loginChatGPT, refreshChatGPTToken } from "./chatgpt";
12
12
  import { loginAntigravity, refreshAntigravityToken } from "./google-antigravity";
13
13
  import { loginCursor, refreshCursorToken } from "./cursor";
14
14
  import { loginGithubCopilot, refreshGithubCopilotToken, validateCopilotApiBaseUrl } from "./github-copilot";
15
+ import { loginCommandCode, refreshCommandCodeToken } from "./command-code";
15
16
  import { deriveOAuthDefaultModel, deriveOAuthProviderConfig } from "../providers/derive";
16
17
  import { apiKeyPoolEntryId, sanitizeApiKeyValue } from "../providers/api-keys";
17
18
  import { effectiveGoogleMode, getProviderRegistryEntry, providerMatchesRegistryTransport } from "../providers/registry";
@@ -160,6 +161,14 @@ function oauthDefaultModel(id: string): string {
160
161
  }
161
162
 
162
163
  export const OAUTH_PROVIDERS: Record<string, OAuthProviderDef> = {
164
+ "command-code": {
165
+ // Add-account/reauth must not reimport the current local CLI credential.
166
+ login: (ctrl, opts) => loginCommandCode(ctrl, { importLocal: opts?.forceLogin ? "off" : "fallback" }),
167
+ refresh: refreshCommandCodeToken,
168
+ providerConfig: oauthConfig("command-code"),
169
+ defaultModel: oauthDefaultModel("command-code"),
170
+ defaultRefreshPolicy: "disabled",
171
+ },
163
172
  xai: {
164
173
  // forceLogin skips the local grok-cli import so a SECOND account can be chosen in the browser.
165
174
  login: (ctrl, opts) => loginXai(ctrl, { importLocal: opts?.forceLogin ? "off" : "fallback" }),
@@ -722,12 +731,25 @@ const OAUTH_RECONCILE_FIELDS: (keyof OcxProviderConfig)[] = [
722
731
  const GOOGLE_ANTIGRAVITY_PROVIDER = "google-antigravity";
723
732
  const GOOGLE_ANTIGRAVITY_STATIC_CATALOG_VERSION = 1 as const;
724
733
 
734
+ /** Only migrate the three-model experimental seed; an operator's later `liveModels: false` wins. */
735
+ function isLegacyCommandCodeStaticCatalog(provider: OcxProviderConfig): boolean {
736
+ return provider.liveModels === false
737
+ && provider.defaultModel === "deepseek-v4-flash"
738
+ && JSON.stringify(provider.models) === JSON.stringify(["deepseek-v4-flash", "kimi-k3", "glm-5.2"]);
739
+ }
740
+
725
741
  export function reconcileOAuthProviders(config: OcxConfig): boolean {
726
742
  let changed = false;
727
743
  const migrateAntigravityStaticCatalog =
728
744
  config.googleAntigravityStaticCatalogVersion !== GOOGLE_ANTIGRAVITY_STATIC_CATALOG_VERSION;
729
745
  for (const [name, prov] of Object.entries(config.providers)) {
730
746
  const def = OAUTH_PROVIDERS[name];
747
+ if (name === "command-code" && isLegacyCommandCodeStaticCatalog(prov)) {
748
+ // The former experimental preset was the exact three-model seed above. It was not a user
749
+ // choice to disable discovery, so promote only that shape to the account live catalog.
750
+ prov.liveModels = true;
751
+ changed = true;
752
+ }
731
753
  // Normalize the canonical row before the OAuth-only reconciliation guard. The old GUI and a
732
754
  // manual edit both persist the same bare `true`, with no source metadata, so every ambiguous
733
755
  // pre-marker value is reset once. A deliberate live-discovery choice can be re-enabled after
@@ -761,7 +783,10 @@ export function reconcileOAuthProviders(config: OcxConfig): boolean {
761
783
  changed = true;
762
784
  }
763
785
  // Heal a defaultModel that no longer exists in the refreshed list (e.g. a deprecated snapshot).
764
- if (prov.defaultModel && preset.defaultModel && !(prov.models ?? []).includes(prov.defaultModel)) {
786
+ // Skip providers without a static preset `models` list: for live-discovery providers
787
+ // (e.g. command-code OAuth) the account-scoped catalog is not enumerable here, so any
788
+ // persisted defaultModel is a user selection and must not be overwritten by the seed.
789
+ if (prov.defaultModel && preset.defaultModel && preset.models && preset.models.length > 0 && !(prov.models ?? []).includes(prov.defaultModel)) {
765
790
  prov.defaultModel = preset.defaultModel;
766
791
  changed = true;
767
792
  }
@@ -836,9 +861,15 @@ export function upsertOAuthProvider(config: OcxConfig, provider: string): void {
836
861
  // reset once; users who deliberately forced discovery can re-enable it after migration.
837
862
  const preserveExistingLiveModels = provider !== GOOGLE_ANTIGRAVITY_PROVIDER
838
863
  || config.googleAntigravityStaticCatalogVersion === GOOGLE_ANTIGRAVITY_STATIC_CATALOG_VERSION;
839
- if (preserveExistingLiveModels && typeof existing?.liveModels === "boolean") {
864
+ if (preserveExistingLiveModels && typeof existing?.liveModels === "boolean" && !isLegacyCommandCodeStaticCatalog(existing)) {
840
865
  next.liveModels = existing.liveModels;
841
866
  }
867
+ // The Command Code protocol-version pin is an operator compatibility control. A re-login,
868
+ // add-account, or reauth rebuilds the row from the preset, which has no version; carry the
869
+ // existing pin so authentication changes do not silently revert the documented control.
870
+ if (existing?.commandCodeVersion !== undefined) {
871
+ next.commandCodeVersion = existing.commandCodeVersion;
872
+ }
842
873
  if (existing && getProviderRegistryEntry(provider)?.allowKeyAuthOverride === true) {
843
874
  // Shared sanitizeApiKeyValue trim / no-CRLF checks from api-key pool writes.
844
875
  let storedApiKey = sanitizeApiKeyValue(existing.apiKey);
@@ -1095,7 +1126,11 @@ export function submitManualLoginCode(provider: string, input: string): { ok: tr
1095
1126
  // protected. Early posts (flow not yet waiting, no expectedState) are stashed and
1096
1127
  // re-validated by the callback loop.
1097
1128
  const parsed = parseCallbackInput(trimmed);
1098
- if (!parsed.code) return { ok: false, error: "no authorization code found in input" };
1129
+ // Command Code's manual fallback accepts a pasted JSON callback payload
1130
+ // (`{ apiKey, state, ... }`) which has no `code` param. Let it through the
1131
+ // shared gate so the provider-specific parser can validate it.
1132
+ const isCommandCodeJson = provider === "command-code" && trimmed.startsWith("{") && !parsed.code;
1133
+ if (!parsed.code && !isCommandCodeJson) return { ok: false, error: "no authorization code found in input" };
1099
1134
  if (parsed.kind !== "raw" && slot.expectedState !== undefined) {
1100
1135
  if (parsed.state === undefined) return { ok: false, error: "redirect URL is missing the state parameter" };
1101
1136
  if (parsed.state !== slot.expectedState) return { ok: false, error: "state mismatch — paste the redirect URL from THIS login attempt" };
@@ -0,0 +1,85 @@
1
+ import { readBoundedResponseBody } from "../lib/bounded-body";
2
+
3
+ const COMMAND_CODE_MODEL_EFFORTS = {
4
+ "deepseek/deepseek-v4-pro": {
5
+ efforts: ["high", "max"],
6
+ profileUrl: "https://commandcode.ai/models/deepseek-v4-pro",
7
+ },
8
+ "deepseek/deepseek-v4-flash": {
9
+ efforts: ["high", "max"],
10
+ profileUrl: "https://commandcode.ai/models/deepseek-v4-flash",
11
+ },
12
+ "zai-org/glm-5.2": {
13
+ efforts: ["high", "max"],
14
+ profileUrl: "https://commandcode.ai/models/glm-5-2",
15
+ },
16
+ } as const;
17
+
18
+ /**
19
+ * Official Command Code model-profile facts, not a model catalog. Models remain
20
+ * account-scoped and come exclusively from the authenticated /provider/v1/models endpoint.
21
+ */
22
+ export const COMMAND_CODE_MODEL_REASONING_EFFORTS: Record<string, string[]> = Object.fromEntries(
23
+ Object.entries(COMMAND_CODE_MODEL_EFFORTS).map(([id, row]) => [id, [...row.efforts]]),
24
+ );
25
+
26
+ const refreshedEfforts = new Map<string, string[]>();
27
+
28
+ function keyFor(modelId: string): string {
29
+ return modelId.trim().toLowerCase();
30
+ }
31
+
32
+ export function commandCodeReasoningEfforts(modelId: string): readonly string[] | undefined {
33
+ const key = keyFor(modelId);
34
+ return refreshedEfforts.get(key) ?? COMMAND_CODE_MODEL_REASONING_EFFORTS[key];
35
+ }
36
+
37
+ function parsedProfileEfforts(page: string): string[] | undefined {
38
+ const match = page.match(/Reasoning efforts\s+([^.;]+?)\s+are supported;\s*([^.]*)/i);
39
+ if (!match) return undefined;
40
+ const listed = match[1]!.toLowerCase().match(/\b(?:low|medium|high|xhigh|max)\b/g) ?? [];
41
+ const mapped = match[2]!.toLowerCase().match(/\b(?:low|medium|high|xhigh|max)\s+maps to\s+(?:low|medium|high|xhigh|max)\b/g) ?? [];
42
+ const normalized = new Set(listed);
43
+ for (const mapping of mapped) {
44
+ const [, source, target] = mapping.match(/(low|medium|high|xhigh|max)\s+maps to\s+(low|medium|high|xhigh|max)/) ?? [];
45
+ if (source && target) {
46
+ normalized.delete(source);
47
+ normalized.add(target);
48
+ }
49
+ }
50
+ return normalized.size > 0 ? [...normalized] : [];
51
+ }
52
+
53
+ /**
54
+ * Refresh one stale effort record only after the upstream rejects an effort request.
55
+ * A failed or unparseable public profile deliberately leaves the known table unchanged.
56
+ */
57
+ export async function refreshCommandCodeReasoningEfforts(
58
+ modelId: string,
59
+ fetchFn: typeof globalThis.fetch = globalThis.fetch,
60
+ ): Promise<readonly string[] | undefined> {
61
+ const key = keyFor(modelId);
62
+ const profile = COMMAND_CODE_MODEL_EFFORTS[key as keyof typeof COMMAND_CODE_MODEL_EFFORTS];
63
+ if (!profile) return undefined;
64
+ try {
65
+ const response = await fetchFn(profile.profileUrl, {
66
+ headers: { Accept: "text/html" },
67
+ signal: AbortSignal.timeout(10_000),
68
+ });
69
+ if (!response.ok) return undefined;
70
+ // Bound the profile page before parsing: a large or malformed page must not
71
+ // allocate unbounded memory on the request path.
72
+ const observed = await readBoundedResponseBody(response, { maxBytes: 256 * 1024 });
73
+ if (!observed.displaySafe) return undefined;
74
+ const efforts = parsedProfileEfforts(observed.text);
75
+ if (efforts === undefined) return undefined;
76
+ refreshedEfforts.set(key, efforts);
77
+ return efforts;
78
+ } catch {
79
+ return undefined;
80
+ }
81
+ }
82
+
83
+ export function resetCommandCodeReasoningEffortsForTest(): void {
84
+ refreshedEfforts.clear();
85
+ }
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Vertex regional hosts are formed as `<location>-aiplatform.googleapis.com`.
3
+ * Restricting the location to one lowercase DNS label keeps user configuration
4
+ * from changing the request authority while remaining forward-compatible with
5
+ * new Google regions and multi-regions.
6
+ */
7
+ const GOOGLE_VERTEX_LOCATION_LABEL = /^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/;
8
+
9
+ export function googleVertexLocationConfigError(location: unknown): string | null {
10
+ if (typeof location !== "string" || !GOOGLE_VERTEX_LOCATION_LABEL.test(location)) {
11
+ return "Vertex AI location must be a single lowercase Google Cloud location label (for example, us-central1 or global)";
12
+ }
13
+ return null;
14
+ }