@oh-my-pi/pi-catalog 18.1.6 → 18.1.9

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.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,30 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [18.1.9] - 2026-09-04
6
+
7
+ ### Added
8
+
9
+ - Added the `delegation-bias` capability for tuning how agents delegate work to subagents.
10
+
11
+ ### Changed
12
+
13
+ - Adjusted subagent delegation for GPT-6 and newer OpenAI models to reduce unnecessary delegation.
14
+
15
+ ### Fixed
16
+
17
+ - Fixed `/login zai` for Z.AI GLM Coding Plan by supporting the provider’s updated authentication flow, including local desktop sign-in, remote paste-code completion, and the configurable `ZAI_OAUTH_REDIRECT_URI`.
18
+
19
+ ## [18.1.8] - 2026-09-03
20
+
21
+ ### Added
22
+
23
+ - Added GPT-6 Astra to the OpenAI Codex model catalog, including support for configuration updates and requests using the freeform `apply_patch` tool.
24
+
25
+ ### Fixed
26
+
27
+ - Fixed `omp models refresh` so revoked ChatGPT account tokens no longer prevent the remaining OpenAI Codex models from being discovered.
28
+
5
29
  ## [18.1.6] - 2026-09-03
6
30
 
7
31
  ### Added
@@ -36,6 +36,14 @@ export interface AxisDef {
36
36
  }
37
37
  /** Effort tiers accepted by taxonomy collapse/override vocabulary (`Effort` ∪ `"off"`). */
38
38
  export declare const EFFORT_TIERS: readonly string[];
39
+ /**
40
+ * How hard agent prompts push subagent delegation for a model lineage
41
+ * (`delegation-bias` axis). `eager` is the unassigned default: the prompt
42
+ * actively pushes fan-out. `restrained` keeps fan-out for genuinely parallel
43
+ * slices but forbids reflexive scouts and single-agent babysitting. `gated`
44
+ * forbids subagents unless the user or a skill asks.
45
+ */
46
+ export declare const DELEGATION_BIASES: readonly ["eager", "restrained", "gated"];
39
47
  /** Narrow a KDL string to an effort tier (`Effort` ∪ `"off"`). */
40
48
  export declare function isEffortTier(value: string): value is Effort | "off";
41
49
  /** Narrow a KDL string to a thinking control mode. */
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Delegation bias: how hard the coding agent's prompts push subagent
3
+ * delegation for a model lineage. Authored on the `delegation-bias` catalog
4
+ * axis in `rules/classes/*.kdl` so appetite corrections live beside the other
5
+ * lineage truths instead of as revision compares in TypeScript.
6
+ *
7
+ * Resolved through the cascade at prompt-build time (session start, model
8
+ * switch) rather than baked onto `Model`: bundled rows are frozen by the
9
+ * generator, and the bias is read once per prompt rebuild, not per request.
10
+ */
11
+ import type { Model } from "../types.js";
12
+ import { DELEGATION_BIASES } from "./axes.js";
13
+ /** One of `DELEGATION_BIASES`; see that constant for the semantics of each tier. */
14
+ export type DelegationBias = (typeof DELEGATION_BIASES)[number];
15
+ /**
16
+ * Delegation bias for a built model; `eager` when no rule assigns one.
17
+ * Callers: system-prompt and tool-description rendering in the coding agent.
18
+ */
19
+ export declare function resolveDelegationBias(model: Model): DelegationBias;
@@ -407,7 +407,7 @@ export interface CompiledOAuthRequest {
407
407
  headers: Record<string, string>;
408
408
  timeoutMs?: number;
409
409
  }
410
- /** Loopback callback configuration for authorization-code logins. */
410
+ /** Callback transport configuration for authorization-code logins. */
411
411
  export interface CompiledCallback {
412
412
  port: number;
413
413
  path: string;
@@ -415,8 +415,10 @@ export interface CompiledCallback {
415
415
  redirectUri?: CompiledAuthValue;
416
416
  portFallback: boolean;
417
417
  manualOnly: boolean;
418
+ /** Temporarily receive a custom-scheme redirect through the native OS handler. */
419
+ nativeScheme: boolean;
418
420
  }
419
- /** Authorization-code login through the loopback callback server. */
421
+ /** Authorization-code login through a loopback, native-scheme, or manual callback. */
420
422
  export interface CompiledOAuthCodeLogin {
421
423
  kind: "oauth-code";
422
424
  clientId?: CompiledAuthValue;
@@ -26,6 +26,13 @@ export interface CodexModelDiscoveryOptions {
26
26
  export interface CodexModelDiscoveryResult {
27
27
  models: ModelSpec<"openai-codex-responses">[];
28
28
  etag?: string;
29
+ /**
30
+ * Set when the backend rejected the credential itself (401/403, e.g.
31
+ * `token_revoked`); `models` is empty. A definitive per-account denial,
32
+ * unlike the `null` result for transport/parse failures, so multi-account
33
+ * discovery can skip the account instead of aborting.
34
+ */
35
+ rejectedStatus?: 401 | 403;
29
36
  }
30
37
  /**
31
38
  * Fetches model metadata from Codex backend and normalizes it for pi model management.
@@ -700,6 +700,13 @@ export interface ResolvedOpenAIResponsesCompat extends ResolvedOpenAISharedCompa
700
700
  * transport; earlier ids reject the value.
701
701
  */
702
702
  supportsAllTurnsReasoningContext: boolean;
703
+ /**
704
+ * Whether a `configuration_update` input item may change `reasoning.effort`
705
+ * mid-conversation while the request-level effort stays byte-stable for
706
+ * prompt caching. Rule-owned: GPT-6 Astra only; every other model rejects
707
+ * the item type with 400.
708
+ */
709
+ supportsConfigurationUpdate: boolean;
703
710
  /** Inject the `# Juice: 0 !important` developer item when reasoning is forced off (gpt-5.6+). */
704
711
  requiresReasoningOffJuiceInstruction: boolean;
705
712
  /**
@@ -4,8 +4,12 @@
4
4
  export declare const CODEX_BASE_URL = "https://chatgpt.com/backend-api";
5
5
  /**
6
6
  * Pinned OpenAI Codex client version (corresponds to @openai/codex package version).
7
+ *
8
+ * The backend version-gates model availability against this value on both
9
+ * `/models?client_version=` and `/responses` (`gpt-6-astra` requires ≥ 0.153.0);
10
+ * an older pin silently hides newer SKUs from discovery.
7
11
  */
8
- export declare const CODEX_CLIENT_VERSION = "0.144.1";
12
+ export declare const CODEX_CLIENT_VERSION = "0.153.0";
9
13
  export declare const OPENAI_HEADERS: {
10
14
  readonly BETA: "OpenAI-Beta";
11
15
  /** Codex feature-negotiation header; values identify opt-in wire protocols. */
@@ -28,18 +32,32 @@ export declare const OPENAI_HEADERS: {
28
32
  readonly ATTESTATION: "x-oai-attestation";
29
33
  /** Client-declared data residency for region-pinned enterprise workspaces. */
30
34
  readonly RESIDENCY: "x-openai-internal-codex-residency";
35
+ /**
36
+ * Model routing hint (codex-rs `X_CODEX_ROUTING_HINT_HEADER`): `model=<slug>`
37
+ * or `model=<slug>;tier=<service_tier>`; sent on every ChatGPT-OAuth
38
+ * Responses, compaction, and WebSocket handshake request. Built by
39
+ * {@link codexRoutingHint}.
40
+ */
41
+ readonly ROUTING_HINT: "x-codex-routing-hint";
31
42
  };
32
43
  export declare const OPENAI_HEADER_VALUES: {
33
44
  readonly BETA_RESPONSES: "responses=experimental";
34
45
  readonly BETA_RESPONSES_WEBSOCKETS_V2: "responses_websockets=2026-02-06";
35
46
  readonly REMOTE_COMPACTION_V2: "remote_compaction_v2";
36
- readonly ORIGINATOR_CODEX: "pi";
47
+ readonly ORIGINATOR_CODEX: "omp";
37
48
  };
38
49
  export declare const URL_PATHS: {
39
50
  readonly RESPONSES: "/responses";
40
51
  readonly CODEX_RESPONSES: "/codex/responses";
41
52
  };
42
53
  export declare const JWT_CLAIM_PATH: "https://api.openai.com/auth";
54
+ /**
55
+ * Build the `x-codex-routing-hint` value for a request (codex-rs
56
+ * `build_routing_hint_header`): the requested model slug plus the explicit
57
+ * service tier when one is set. Callers set it only on ChatGPT-OAuth requests
58
+ * to the Codex backend; API-key OpenAI traffic never carries it.
59
+ */
60
+ export declare function codexRoutingHint(model: string, serviceTier: string | null | undefined): string;
43
61
  /**
44
62
  * Extract account ID from a Codex JWT access token.
45
63
  * Returns undefined if the token is not a valid Codex JWT.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@oh-my-pi/pi-catalog",
4
- "version": "18.1.6",
4
+ "version": "18.1.9",
5
5
  "description": "Model catalog for omp: bundled model database, provider discovery descriptors, model identity, classification, and equivalence",
6
6
  "homepage": "https://omp.sh",
7
7
  "author": "Stencil Labs, Inc.",
@@ -35,12 +35,12 @@
35
35
  "gen:proto": "bun scripts/generate-protocols.ts"
36
36
  },
37
37
  "dependencies": {
38
- "@oh-my-pi/omptype": "18.1.6",
39
- "@oh-my-pi/pi-utils": "18.1.6"
38
+ "@oh-my-pi/omptype": "18.1.9",
39
+ "@oh-my-pi/pi-utils": "18.1.9"
40
40
  },
41
41
  "devDependencies": {
42
42
  "@bgotink/kdl": "0.4.0",
43
- "@oh-my-pi/pi-ai": "18.1.6",
43
+ "@oh-my-pi/pi-ai": "18.1.9",
44
44
  "@types/bun": "^1.3.14"
45
45
  },
46
46
  "engines": {
@@ -44,6 +44,15 @@ const EFFORTS = ["minimal", "low", "medium", "high", "xhigh", "max"] as const;
44
44
 
45
45
  /** Effort tiers accepted by taxonomy collapse/override vocabulary (`Effort` ∪ `"off"`). */
46
46
  export const EFFORT_TIERS: readonly string[] = [...EFFORTS, "off"];
47
+
48
+ /**
49
+ * How hard agent prompts push subagent delegation for a model lineage
50
+ * (`delegation-bias` axis). `eager` is the unassigned default: the prompt
51
+ * actively pushes fan-out. `restrained` keeps fan-out for genuinely parallel
52
+ * slices but forbids reflexive scouts and single-agent babysitting. `gated`
53
+ * forbids subagents unless the user or a skill asks.
54
+ */
55
+ export const DELEGATION_BIASES = ["eager", "restrained", "gated"] as const;
47
56
  const THINKING_MODES = [
48
57
  "effort",
49
58
  "budget",
@@ -128,6 +137,7 @@ export const AXES: Readonly<Record<string, AxisDef>> = {
128
137
  "strict-responses-pairing": wire("strictResponsesPairing", ["openai-responses"]),
129
138
  "requires-reasoning-off-juice-instruction": wire("requiresReasoningOffJuiceInstruction", ["openai-responses"]),
130
139
  "supports-all-turns-reasoning-context": wire("supportsAllTurnsReasoningContext", ["openai-responses"]),
140
+ "supports-configuration-update": wire("supportsConfigurationUpdate", ["openai-responses"]),
131
141
  "strip-deepseek-special-tokens": wire("stripDeepseekSpecialTokens", OAI),
132
142
  "stream-markup-healing-pattern": wire("streamMarkupHealingPattern", OAI, "scalar", [
133
143
  "kimi",
@@ -260,6 +270,7 @@ export const AXES: Readonly<Record<string, AxisDef>> = {
260
270
  "context-promotion-target": { key: "contextPromotionTarget", set: "catalog", shape: "scalar" },
261
271
  "context-window-floor": { key: "contextWindowFloor", set: "catalog", shape: "scalar" },
262
272
  "cost-patch": { key: "costPatch", set: "catalog", shape: "object" },
273
+ "delegation-bias": { key: "delegationBias", set: "catalog", shape: "scalar", values: DELEGATION_BIASES },
263
274
  "edit-revision": { key: "editRevision", set: "catalog", shape: "scalar" },
264
275
  "input-modalities": { key: "inputModalities", set: "catalog", shape: "array", values: ["text", "image"] },
265
276
  "limits-patch": { key: "limitsPatch", set: "catalog", shape: "object" },
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Delegation bias: how hard the coding agent's prompts push subagent
3
+ * delegation for a model lineage. Authored on the `delegation-bias` catalog
4
+ * axis in `rules/classes/*.kdl` so appetite corrections live beside the other
5
+ * lineage truths instead of as revision compares in TypeScript.
6
+ *
7
+ * Resolved through the cascade at prompt-build time (session start, model
8
+ * switch) rather than baked onto `Model`: bundled rows are frozen by the
9
+ * generator, and the bias is read once per prompt rebuild, not per request.
10
+ */
11
+ import type { Model } from "../types";
12
+ import { DELEGATION_BIASES } from "./axes";
13
+ import { resolveCascade } from "./cascade";
14
+
15
+ /** One of `DELEGATION_BIASES`; see that constant for the semantics of each tier. */
16
+ export type DelegationBias = (typeof DELEGATION_BIASES)[number];
17
+
18
+ function isDelegationBias(value: unknown): value is DelegationBias {
19
+ return typeof value === "string" && (DELEGATION_BIASES as readonly string[]).includes(value);
20
+ }
21
+
22
+ /**
23
+ * Delegation bias for a built model; `eager` when no rule assigns one.
24
+ * Callers: system-prompt and tool-description rendering in the coding agent.
25
+ */
26
+ export function resolveDelegationBias(model: Model): DelegationBias {
27
+ const { identity } = model;
28
+ const bias = resolveCascade({
29
+ provider: model.provider,
30
+ class: identity.class,
31
+ model: model.id,
32
+ reasoning: Boolean(model.reasoning),
33
+ ...(identity.family !== undefined && { family: identity.family }),
34
+ ...(identity.revision !== undefined && { revision: identity.revision }),
35
+ }).catalog.delegationBias;
36
+ return isDelegationBias(bias) ? bias : "eager";
37
+ }
@@ -714,6 +714,7 @@ function resolveOpenAIResponsesPolicy(
714
714
  supportsImageDetailOriginal: !isXaiHost && !modelMatchesHost(hostModel, "githubCopilot"),
715
715
  supportsReasoningSummary: !isXaiHost,
716
716
  supportsAllTurnsReasoningContext: false,
717
+ supportsConfigurationUpdate: false,
717
718
  requiresReasoningOffJuiceInstruction: false,
718
719
  stripImageInput: false,
719
720
  thinkingLoopGuard: undefined,
@@ -815,6 +816,7 @@ function pickResponsesOnly(compat: ResolvedOpenAIResponsesCompat): ResponsesOnly
815
816
  supportsImageDetailOriginal: compat.supportsImageDetailOriginal,
816
817
  supportsObfuscationOptOut: compat.supportsObfuscationOptOut,
817
818
  supportsAllTurnsReasoningContext: compat.supportsAllTurnsReasoningContext,
819
+ supportsConfigurationUpdate: compat.supportsConfigurationUpdate,
818
820
  officialEndpoint: compat.officialEndpoint,
819
821
  harmonyLeakMitigation: compat.harmonyLeakMitigation,
820
822
  cacheControlFormat: compat.cacheControlFormat,
@@ -271,7 +271,7 @@ auth "anthropic" {
271
271
  state "hex" // hex | uuid | none
272
272
  authorize-params { code "true" } // standard=#false drops client_id/response_type/redirect_uri/scope/PKCE/state
273
273
  instructions "Complete login in your browser…"
274
- callback port=54545 path="/callback" hostname="localhost" redirect-uri="…" redirect-uri-env="VAR" port-fallback=#true manual-only=#false
274
+ callback port=54545 path="/callback" hostname="localhost" redirect-uri="…" redirect-uri-env="VAR" port-fallback=#true manual-only=#false native-scheme=#false
275
275
  token url="https://api.anthropic.com/v1/oauth/token" body="json" { params { state "{state}" } headers { X "y" } }
276
276
  credential {
277
277
  access "access_token" // dot path; `claim="a|b"` reads JWT claims; `literal="…"` pins a value
@@ -8,7 +8,7 @@ auth "openai-codex" {
8
8
  authorize-params {
9
9
  id_token_add_organizations "true"
10
10
  codex_cli_simplified_flow "true"
11
- originator "pi"
11
+ originator "omp"
12
12
  }
13
13
  instructions "A browser window should open. Complete login to finish."
14
14
  // OpenAI only allowlists this exact URI; a busy port must fail rather than fall back.
@@ -4,9 +4,13 @@ auth "zai-coding-plan" {
4
4
  client-id "client_P8X5CMWmlaRO9gyO-KSqtg" env="ZAI_OAUTH_CLIENT_ID"
5
5
  authorize-url "https://chat.z.ai/api/oauth/authorize" env="ZAI_OAUTH_AUTHORIZE_URL"
6
6
  // No PKCE: matches ZCode's authorize request verbatim.
7
- // ZCode registers this exact loopback URI; any other host/port is rejected (#10245).
8
- callback port=9999 path="/callback" hostname="127.0.0.1" redirect-uri="http://127.0.0.1:9999/callback" port-fallback=#false
9
- instructions "Complete Z.ai login in your browser. If the browser cannot reach this machine, paste the final redirect URL or authorization code when prompted."
7
+ // Z.AI's server-side allowlist now rejects every loopback redirect_uri for
8
+ // this client (#10745); only ZCode's desktop scheme still validates. On a
9
+ // supported local desktop, temporarily receive that scheme and restore its
10
+ // previous handler. Remote and unsupported sessions retain manual input.
11
+ // `redirect-uri-env` lets users adapt to further allowlist shifts without a release.
12
+ callback port=0 redirect-uri="zcode://zai-auth/callback" redirect-uri-env="ZAI_OAUTH_REDIRECT_URI" manual-only=#true native-scheme=#true
13
+ instructions "Complete Z.ai login in your browser. On supported local desktops, omp captures the zcode:// callback and restores its previous handler automatically. You can also paste the final redirect URL or authorization code when prompted."
10
14
  token url="https://zcode.z.ai/api/v1/oauth/token" url-env="ZAI_OAUTH_TOKEN_URL" body="json" standard=#false {
11
15
  params {
12
16
  provider "zai"
@@ -30,6 +30,22 @@ class "openai" {
30
30
  thinking-efforts "low" "medium" "high" "xhigh" "max"
31
31
  requires-reasoning-off-juice-instruction #true
32
32
  }
33
+ // Delegation appetite is a lineage trait. GPT-5.6 was trained on Codex's
34
+ // "no subagents unless asked" developer message; GPT-6 fans out on its own
35
+ // and over-delegates under Claude-calibrated prompts (reflexive scouts,
36
+ // single-agent babysitting), so it gets the restrained tier instead.
37
+ revision "=5.6" {
38
+ delegation-bias "gated"
39
+ }
40
+ revision ">=6" {
41
+ delegation-bias "restrained"
42
+ }
43
+ // GPT-6 Astra changes reasoning effort mid-conversation through a
44
+ // `configuration_update` input item so the request-level effort (and the
45
+ // cached prompt prefix) stays put; every other SKU 400s on the item type.
46
+ models "gpt-6-astra" {
47
+ supports-configuration-update #true
48
+ }
33
49
  // Codex SKUs: the advertised 400K figure includes the output budget; the
34
50
  // true prompt window is 272K. Spark budgets are its own family's.
35
51
  family "codex" {
@@ -69,9 +69,9 @@ provider "openai-codex" {
69
69
  }
70
70
  }
71
71
  }
72
- // First-party GPT-5 Responses SKUs support the freeform apply_patch
72
+ // First-party GPT-5/GPT-6 Responses SKUs support the freeform apply_patch
73
73
  // custom tool with a Lark grammar.
74
- revision ">=5 <6" {
74
+ revision ">=5 <7" {
75
75
  apply-patch-tool-type "freeform"
76
76
  }
77
77
  }
@@ -40,7 +40,7 @@ provider "openai" {
40
40
  reasoning-disable-mode "none-effort"
41
41
  }
42
42
  }
43
- revision ">=5 <6" {
43
+ revision ">=5 <7" {
44
44
  apply-patch-tool-type "freeform"
45
45
  }
46
46
  }
@@ -6224,7 +6224,46 @@
6224
6224
  }
6225
6225
  },
6226
6226
  {
6227
- "source": "classes/openai.kdl:36",
6227
+ "source": "classes/openai.kdl:37",
6228
+ "class": "openai",
6229
+ "revision": [
6230
+ {
6231
+ "op": "=",
6232
+ "revision": "5.6.0"
6233
+ }
6234
+ ],
6235
+ "catalog": {
6236
+ "delegationBias": "gated"
6237
+ }
6238
+ },
6239
+ {
6240
+ "source": "classes/openai.kdl:40",
6241
+ "class": "openai",
6242
+ "revision": [
6243
+ {
6244
+ "op": ">=",
6245
+ "revision": "6.0.0"
6246
+ }
6247
+ ],
6248
+ "catalog": {
6249
+ "delegationBias": "restrained"
6250
+ }
6251
+ },
6252
+ {
6253
+ "source": "classes/openai.kdl:46",
6254
+ "class": "openai",
6255
+ "models": [
6256
+ {
6257
+ "kind": "exact",
6258
+ "value": "gpt-6-astra"
6259
+ }
6260
+ ],
6261
+ "wire": {
6262
+ "supportsConfigurationUpdate": true
6263
+ }
6264
+ },
6265
+ {
6266
+ "source": "classes/openai.kdl:52",
6228
6267
  "class": "openai",
6229
6268
  "family": "codex",
6230
6269
  "revision": [
@@ -10650,7 +10689,7 @@
10650
10689
  },
10651
10690
  {
10652
10691
  "op": "<",
10653
- "revision": "6.0.0"
10692
+ "revision": "7.0.0"
10654
10693
  }
10655
10694
  ],
10656
10695
  "catalog": {
@@ -10955,7 +10994,7 @@
10955
10994
  },
10956
10995
  {
10957
10996
  "op": "<",
10958
- "revision": "6.0.0"
10997
+ "revision": "7.0.0"
10959
10998
  }
10960
10999
  ],
10961
11000
  "catalog": {
@@ -14919,7 +14958,7 @@
14919
14958
  "authorizeParams": {
14920
14959
  "id_token_add_organizations": "true",
14921
14960
  "codex_cli_simplified_flow": "true",
14922
- "originator": "pi"
14961
+ "originator": "omp"
14923
14962
  },
14924
14963
  "clientId": {
14925
14964
  "value": "app_EMoamEEZ73f0CkXaXp7hrann"
@@ -14934,6 +14973,7 @@
14934
14973
  "hostname": "localhost",
14935
14974
  "portFallback": false,
14936
14975
  "manualOnly": false,
14976
+ "nativeScheme": false,
14937
14977
  "redirectUri": {
14938
14978
  "value": "http://localhost:1455/auth/callback"
14939
14979
  }
@@ -15031,7 +15071,8 @@
15031
15071
  "path": "/callback",
15032
15072
  "hostname": "localhost",
15033
15073
  "portFallback": true,
15034
- "manualOnly": false
15074
+ "manualOnly": false,
15075
+ "nativeScheme": false
15035
15076
  },
15036
15077
  "token": {
15037
15078
  "url": {
@@ -15153,16 +15194,20 @@
15153
15194
  ]
15154
15195
  },
15155
15196
  "callback": {
15156
- "port": 9999,
15197
+ "port": 0,
15157
15198
  "path": "/callback",
15158
- "hostname": "127.0.0.1",
15159
- "portFallback": false,
15160
- "manualOnly": false,
15199
+ "hostname": "localhost",
15200
+ "portFallback": true,
15201
+ "manualOnly": true,
15202
+ "nativeScheme": true,
15161
15203
  "redirectUri": {
15162
- "value": "http://127.0.0.1:9999/callback"
15204
+ "value": "zcode://zai-auth/callback",
15205
+ "env": [
15206
+ "ZAI_OAUTH_REDIRECT_URI"
15207
+ ]
15163
15208
  }
15164
15209
  },
15165
- "instructions": "Complete Z.ai login in your browser. If the browser cannot reach this machine, paste the final redirect URL or authorization code when prompted.",
15210
+ "instructions": "Complete Z.ai login in your browser. On supported local desktops, omp captures the zcode:// callback and restores its previous handler automatically. You can also paste the final redirect URL or authorization code when prompted.",
15166
15211
  "token": {
15167
15212
  "url": {
15168
15213
  "value": "https://zcode.z.ai/api/v1/oauth/token",
@@ -15203,7 +15248,7 @@
15203
15248
  "refresh": {
15204
15249
  "kind": "none"
15205
15250
  },
15206
- "callbackPort": 9999,
15251
+ "callbackPort": 0,
15207
15252
  "pasteCode": true
15208
15253
  },
15209
15254
  {
@@ -15330,7 +15375,8 @@
15330
15375
  "path": "/callback",
15331
15376
  "hostname": "localhost",
15332
15377
  "portFallback": true,
15333
- "manualOnly": false
15378
+ "manualOnly": false,
15379
+ "nativeScheme": false
15334
15380
  },
15335
15381
  "token": {
15336
15382
  "url": {
@@ -15417,7 +15463,8 @@
15417
15463
  "path": "/callback",
15418
15464
  "hostname": "127.0.0.1",
15419
15465
  "portFallback": true,
15420
- "manualOnly": false
15466
+ "manualOnly": false,
15467
+ "nativeScheme": false
15421
15468
  },
15422
15469
  "token": {
15423
15470
  "url": {
@@ -15497,7 +15544,8 @@
15497
15544
  "path": "/oauth-callback",
15498
15545
  "hostname": "127.0.0.1",
15499
15546
  "portFallback": true,
15500
- "manualOnly": false
15547
+ "manualOnly": false,
15548
+ "nativeScheme": false
15501
15549
  },
15502
15550
  "token": {
15503
15551
  "url": {
@@ -15595,7 +15643,8 @@
15595
15643
  "path": "/oauth2callback",
15596
15644
  "hostname": "127.0.0.1",
15597
15645
  "portFallback": true,
15598
- "manualOnly": false
15646
+ "manualOnly": false,
15647
+ "nativeScheme": false
15599
15648
  },
15600
15649
  "token": {
15601
15650
  "url": {
@@ -15861,6 +15910,7 @@
15861
15910
  "hostname": "localhost",
15862
15911
  "portFallback": true,
15863
15912
  "manualOnly": false,
15913
+ "nativeScheme": false,
15864
15914
  "redirectUri": {
15865
15915
  "env": [
15866
15916
  "GITLAB_REDIRECT_URI"
@@ -15955,6 +16005,7 @@
15955
16005
  "hostname": "localhost",
15956
16006
  "portFallback": true,
15957
16007
  "manualOnly": true,
16008
+ "nativeScheme": false,
15958
16009
  "redirectUri": {
15959
16010
  "value": "vscode://gitlab.gitlab-workflow/authentication"
15960
16011
  }
@@ -422,7 +422,7 @@ export interface CompiledOAuthRequest {
422
422
  timeoutMs?: number;
423
423
  }
424
424
 
425
- /** Loopback callback configuration for authorization-code logins. */
425
+ /** Callback transport configuration for authorization-code logins. */
426
426
  export interface CompiledCallback {
427
427
  port: number;
428
428
  path: string;
@@ -430,9 +430,11 @@ export interface CompiledCallback {
430
430
  redirectUri?: CompiledAuthValue;
431
431
  portFallback: boolean;
432
432
  manualOnly: boolean;
433
+ /** Temporarily receive a custom-scheme redirect through the native OS handler. */
434
+ nativeScheme: boolean;
433
435
  }
434
436
 
435
- /** Authorization-code login through the loopback callback server. */
437
+ /** Authorization-code login through a loopback, native-scheme, or manual callback. */
436
438
  export interface CompiledOAuthCodeLogin {
437
439
  kind: "oauth-code";
438
440
  clientId?: CompiledAuthValue;
@@ -110,6 +110,13 @@ export interface CodexModelDiscoveryOptions {
110
110
  export interface CodexModelDiscoveryResult {
111
111
  models: ModelSpec<"openai-codex-responses">[];
112
112
  etag?: string;
113
+ /**
114
+ * Set when the backend rejected the credential itself (401/403, e.g.
115
+ * `token_revoked`); `models` is empty. A definitive per-account denial,
116
+ * unlike the `null` result for transport/parse failures, so multi-account
117
+ * discovery can skip the account instead of aborting.
118
+ */
119
+ rejectedStatus?: 401 | 403;
113
120
  }
114
121
 
115
122
  /**
@@ -139,6 +146,9 @@ export async function fetchCodexModels(options: CodexModelDiscoveryOptions): Pro
139
146
  continue;
140
147
  }
141
148
 
149
+ if (response.status === 401 || response.status === 403) {
150
+ return { models: [], rejectedStatus: response.status };
151
+ }
142
152
  if (!response.ok) {
143
153
  continue;
144
154
  }