claude-use 11.32.0 → 11.34.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.
package/dist/cli.cjs CHANGED
@@ -26973,6 +26973,9 @@ function isHttpProvider(provider) {
26973
26973
  function isCodexProvider(provider) {
26974
26974
  return provider.kind === "codex";
26975
26975
  }
26976
+ function isRouterProvider(provider) {
26977
+ return provider.kind === "router";
26978
+ }
26976
26979
  function isAntigravityProvider(provider) {
26977
26980
  return provider.kind === "antigravity";
26978
26981
  }
@@ -26987,7 +26990,7 @@ function isTimeZone(name) {
26987
26990
  return false;
26988
26991
  }
26989
26992
  }
26990
- var import_node_path4, CATEGORY_NAMES, OVERRIDABLE_CATEGORIES, CategoryMapSchema, DURATION_RE, DurationSchema, WhenConditionObjectSchema, WhenSchema, EntryValueSchema, ENTRY_KEY_RE, EntriesSchema, LaunchSchema, CREDENTIAL_TARGETS, PROVIDER_CREDENTIAL_TARGETS, CREDENTIAL_TARGET_VARS, ArgvSchema, CommandSourceOptions, EnvCredentialSourceSchema, FileCredentialSourceSchema, CommandCredentialSourceSchema, OpCredentialSourceSchema, KeychainCredentialSourceSchema, LiteralCredentialSourceSchema, CredentialSourceSchema, RemoteCredentialSourceSchema, CREDENTIAL_CACHE_STORES, CredentialCacheSchema, CredentialSchema, ProviderCredentialSchema, RESERVED_PROVIDER_ENV_KEYS, ProviderEnvSchema, PROVIDER_KINDS, ANTIGRAVITY_MODES, CLAUDE_TIERS, ANTIGRAVITY_EFFORTS, ANTIGRAVITY_DEFAULT_MODE, ANTIGRAVITY_DEFAULT_MODEL, ANTIGRAVITY_DEFAULT_TIER_MODELS, ANTIGRAVITY_DEFAULT_EFFORT, AntigravityModelTargetSchema, AntigravityProviderConfigSchema, CODEX_EFFORTS, CODEX_LOGINS, CODEX_DEFAULT_LOGIN, CODEX_DEFAULT_MODEL, CODEX_DEFAULT_TIER_MODELS, CODEX_DEFAULT_EFFORT, CodexProviderConfigSchema, ProviderRouteSchema, PickerModelSchema, PickerModelsSchema, ProviderCatalogueSchema, HttpProviderSchema, CodexProviderSchema, AntigravityProviderSchema, ProviderSchema, ConfigProfileSchema, POOL_SELECTOR_PREFIX, POOL_NAME_PATTERN, IDENTITY_NAME_PATTERN, PoolNameSchema, SELECTOR_RE, IdentitySelectorSchema, PoolMemberSchema, POOL_PREFERENCES, PoolPreferenceSchema, WHOLE_PERCENT_MAX, CompactAtUtilisationSchema, PoolSchema, WEEKDAYS, AnchorSchema, JOB_WINDOWS, JobTriggerSchema, JobTargetSchema, JobSchema, DirectoryRuleSchema, DirectoryRulesSchema, PortableConfigSchema, HEADROOM_MODES, HEADROOM_CCR_MODES, HEADROOM_ROLLOUT_CHANNELS, INTERCEPT_CHANNELS, READ_MATURATION_CHANNELS, HeadroomGlobalConfigObjectSchema, HeadroomGlobalConfigSchema, HEADROOM_DEFAULT_SOURCE, HEADROOM_DEFAULT_IDLE_SHUTDOWN_MINUTES, FRONTDOOR_DEFAULT_IDLE_SHUTDOWN_MINUTES, FrontDoorGlobalConfigSchema, UPDATE_MODES, UpdateGlobalConfigSchema, GlobalConfigSchema, IdentitySchema, CategoryClassificationSchema, CategoryClassificationOverlaySchema, SHIPPED_CATEGORY_DEFAULTS;
26993
+ var import_node_path4, CATEGORY_NAMES, OVERRIDABLE_CATEGORIES, CategoryMapSchema, DURATION_RE, DurationSchema, WhenConditionObjectSchema, WhenSchema, EntryValueSchema, ENTRY_KEY_RE, EntriesSchema, LaunchSchema, CREDENTIAL_TARGETS, PROVIDER_CREDENTIAL_TARGETS, CREDENTIAL_TARGET_VARS, ArgvSchema, CommandSourceOptions, EnvCredentialSourceSchema, FileCredentialSourceSchema, CommandCredentialSourceSchema, OpCredentialSourceSchema, KeychainCredentialSourceSchema, LiteralCredentialSourceSchema, CredentialSourceSchema, RemoteCredentialSourceSchema, CREDENTIAL_CACHE_STORES, CredentialCacheSchema, CredentialSchema, ProviderCredentialSchema, RESERVED_PROVIDER_ENV_KEYS, ProviderEnvSchema, PROVIDER_KINDS, ANTIGRAVITY_MODES, CLAUDE_TIERS, ANTIGRAVITY_EFFORTS, ANTIGRAVITY_DEFAULT_MODE, ANTIGRAVITY_DEFAULT_MODEL, ANTIGRAVITY_DEFAULT_TIER_MODELS, ANTIGRAVITY_DEFAULT_EFFORT, AntigravityModelTargetSchema, AntigravityProviderConfigSchema, CODEX_EFFORTS, CODEX_LOGINS, CODEX_DEFAULT_LOGIN, CODEX_DEFAULT_MODEL, CODEX_DEFAULT_TIER_MODELS, CODEX_DEFAULT_EFFORT, CodexProviderConfigSchema, ProviderRouteSchema, PickerModelSchema, PickerModelsSchema, ProviderCatalogueSchema, HttpProviderSchema, CodexProviderSchema, RouterProviderSchema, AntigravityProviderSchema, ProviderSchema, SELECTION_MODES, VirtualModelSchema, ModelPricesSchema, ModelsConfigSchema, ModelsLayerSchema, ConfigProfileSchema, POOL_SELECTOR_PREFIX, POOL_NAME_PATTERN, IDENTITY_NAME_PATTERN, PoolNameSchema, SELECTOR_RE, IdentitySelectorSchema, PoolMemberSchema, POOL_PREFERENCES, PoolPreferenceSchema, WHOLE_PERCENT_MAX, CompactAtUtilisationSchema, PoolSchema, WEEKDAYS, AnchorSchema, JOB_WINDOWS, JobTriggerSchema, JobTargetSchema, JobSchema, DirectoryRuleSchema, DirectoryRulesSchema, PortableConfigSchema, HEADROOM_MODES, HEADROOM_CCR_MODES, HEADROOM_ROLLOUT_CHANNELS, INTERCEPT_CHANNELS, READ_MATURATION_CHANNELS, HeadroomGlobalConfigObjectSchema, HeadroomGlobalConfigSchema, HEADROOM_DEFAULT_SOURCE, HEADROOM_DEFAULT_IDLE_SHUTDOWN_MINUTES, FRONTDOOR_DEFAULT_IDLE_SHUTDOWN_MINUTES, FrontDoorGlobalConfigSchema, UPDATE_MODES, UpdateGlobalConfigSchema, GlobalConfigSchema, IdentitySchema, CategoryClassificationSchema, CategoryClassificationOverlaySchema, SHIPPED_CATEGORY_DEFAULTS;
26991
26994
  var init_schema = __esm({
26992
26995
  "src/config/schema.ts"() {
26993
26996
  "use strict";
@@ -27032,6 +27035,8 @@ var init_schema = __esm({
27032
27035
  delay: external_exports.string().regex(DURATION_RE, "must be a duration such as 5s or 500ms").optional(),
27033
27036
  /** Whether the launcher waits for a key press after its own output before it starts claude. Takes the place of `delay` when both are set. Applies only when a terminal is watching. */
27034
27037
  pause: external_exports.boolean().optional(),
27038
+ /** Whether a provider session routes provider-qualified model names (`z/glm-5.3`, `auto`) through the `models` block to the provider that serves them, instead of sending every request to the launch provider. */
27039
+ routeByName: external_exports.boolean().optional(),
27035
27040
  /** Whether the launcher's report, for a launch that picks from a pool, lists every member the pick ranked with why each stands where it does, and not only the member it picked. */
27036
27041
  explain: external_exports.boolean().optional()
27037
27042
  });
@@ -27092,7 +27097,7 @@ var init_schema = __esm({
27092
27097
  ProviderEnvSchema = external_exports.record(external_exports.string().min(1), external_exports.string()).refine((env) => !Object.keys(env).some((key) => RESERVED_PROVIDER_ENV_KEYS.includes(key)), {
27093
27098
  message: `env may not set ${RESERVED_PROVIDER_ENV_KEYS.join(", ")}: the credential block's target sets one and agent-shim removes the others`
27094
27099
  });
27095
- PROVIDER_KINDS = ["http", "codex", "antigravity"];
27100
+ PROVIDER_KINDS = ["http", "codex", "antigravity", "router"];
27096
27101
  ANTIGRAVITY_MODES = ["cloud", "local"];
27097
27102
  CLAUDE_TIERS = ["fable", "opus", "sonnet", "haiku"];
27098
27103
  ANTIGRAVITY_EFFORTS = ["none", "low", "medium", "high", "xhigh", "max"];
@@ -27205,6 +27210,11 @@ var init_schema = __esm({
27205
27210
  pickerModels: PickerModelsSchema.optional(),
27206
27211
  codex: CodexProviderConfigSchema.optional()
27207
27212
  });
27213
+ RouterProviderSchema = external_exports.strictObject({
27214
+ $schema: external_exports.string().optional(),
27215
+ kind: external_exports.literal("router"),
27216
+ displayName: external_exports.string().min(1)
27217
+ });
27208
27218
  AntigravityProviderSchema = external_exports.strictObject({
27209
27219
  $schema: external_exports.string().optional(),
27210
27220
  kind: external_exports.literal("antigravity"),
@@ -27215,14 +27225,55 @@ var init_schema = __esm({
27215
27225
  pickerModels: PickerModelsSchema.optional(),
27216
27226
  antigravity: AntigravityProviderConfigSchema.optional()
27217
27227
  });
27218
- ProviderSchema = external_exports.discriminatedUnion("kind", [HttpProviderSchema, CodexProviderSchema, AntigravityProviderSchema]);
27228
+ ProviderSchema = external_exports.discriminatedUnion("kind", [HttpProviderSchema, CodexProviderSchema, AntigravityProviderSchema, RouterProviderSchema]);
27229
+ SELECTION_MODES = ["ordered", "most-allowance", "soonest-reset", "spread", "adaptive", "lowest-latency", "highest-success", "cheapest"];
27230
+ VirtualModelSchema = external_exports.strictObject({
27231
+ /** How the virtual model chooses its member for a request. */
27232
+ mode: external_exports.enum(SELECTION_MODES),
27233
+ /** The members to choose among, in preference order where the mode reads order. Each names a target (`z/glm-5.3`), an account model (`acct:work/opus`), another virtual model, or a family (`family:<canonical>`). */
27234
+ members: external_exports.array(external_exports.string().min(1)).min(1)
27235
+ });
27236
+ ModelPricesSchema = external_exports.strictObject({
27237
+ input: external_exports.number().positive(),
27238
+ output: external_exports.number().positive()
27239
+ });
27240
+ ModelsConfigSchema = external_exports.strictObject({
27241
+ /** Virtual models, by name. */
27242
+ virtual: external_exports.record(external_exports.string().min(1), VirtualModelSchema).optional(),
27243
+ /** Which model ref each Claude tier (`fable`, `opus`, `sonnet`, `haiku`) points at: a concrete target, an account model, a virtual model, or a family. */
27244
+ tiers: external_exports.strictObject({
27245
+ fable: external_exports.string().min(1).optional(),
27246
+ opus: external_exports.string().min(1).optional(),
27247
+ sonnet: external_exports.string().min(1).optional(),
27248
+ haiku: external_exports.string().min(1).optional()
27249
+ }).optional(),
27250
+ /** Prices per model ref, for the `cheapest` mode. */
27251
+ prices: external_exports.record(external_exports.string().min(1), ModelPricesSchema).optional(),
27252
+ /** Model refs hidden from the picker and from routing, whatever else names them. */
27253
+ hide: external_exports.array(external_exports.string().min(1)).optional(),
27254
+ /** When set, the only model refs visible; everything else is hidden. */
27255
+ show: external_exports.array(external_exports.string().min(1)).optional()
27256
+ });
27257
+ ModelsLayerSchema = external_exports.strictObject({
27258
+ virtual: external_exports.record(external_exports.string().min(1), external_exports.union([VirtualModelSchema, external_exports.null()])).optional(),
27259
+ tiers: external_exports.strictObject({
27260
+ fable: external_exports.union([external_exports.string().min(1), external_exports.null()]).optional(),
27261
+ opus: external_exports.union([external_exports.string().min(1), external_exports.null()]).optional(),
27262
+ sonnet: external_exports.union([external_exports.string().min(1), external_exports.null()]).optional(),
27263
+ haiku: external_exports.union([external_exports.string().min(1), external_exports.null()]).optional()
27264
+ }).optional(),
27265
+ prices: external_exports.record(external_exports.string().min(1), external_exports.union([ModelPricesSchema, external_exports.null()])).optional(),
27266
+ hide: external_exports.array(external_exports.string().min(1)).optional(),
27267
+ show: external_exports.array(external_exports.string().min(1)).optional()
27268
+ });
27219
27269
  ConfigProfileSchema = external_exports.strictObject({
27220
27270
  $schema: external_exports.string().optional(),
27221
27271
  description: external_exports.string().optional(),
27222
27272
  extends: external_exports.array(external_exports.string().min(1)).optional(),
27223
27273
  categories: CategoryMapSchema.optional(),
27224
27274
  entries: EntriesSchema.optional(),
27225
- launch: LaunchSchema.optional()
27275
+ launch: LaunchSchema.optional(),
27276
+ models: ModelsLayerSchema.optional()
27226
27277
  });
27227
27278
  POOL_SELECTOR_PREFIX = "pool:";
27228
27279
  POOL_NAME_PATTERN = "[A-Za-z0-9][A-Za-z0-9._-]*";
@@ -27333,6 +27384,7 @@ var init_schema = __esm({
27333
27384
  frontdoor: FrontDoorGlobalConfigSchema.optional(),
27334
27385
  update: UpdateGlobalConfigSchema.optional(),
27335
27386
  pools: external_exports.record(PoolNameSchema, PoolSchema).optional(),
27387
+ models: ModelsConfigSchema.optional(),
27336
27388
  jobs: external_exports.record(PoolNameSchema, JobSchema).optional()
27337
27389
  });
27338
27390
  IdentitySchema = external_exports.strictObject({
@@ -31833,7 +31885,8 @@ function profileLayers(rootName, load, startId) {
31833
31885
  ...source.profile.categories === void 0 ? {} : { categories: source.profile.categories },
31834
31886
  ...source.profile.entries === void 0 ? {} : { entries: source.profile.entries },
31835
31887
  ...source.entryOrder === void 0 ? {} : { entryOrder: source.entryOrder },
31836
- ...source.profile.launch === void 0 ? {} : { launch: source.profile.launch }
31888
+ ...source.profile.launch === void 0 ? {} : { launch: source.profile.launch },
31889
+ ...source.profile.models === void 0 ? {} : { models: source.profile.models }
31837
31890
  });
31838
31891
  nextId += 1;
31839
31892
  }
@@ -31921,7 +31974,8 @@ function assembleCascade(input2) {
31921
31974
  ...source.config.categories === void 0 ? {} : { categories: source.config.categories },
31922
31975
  ...source.config.entries === void 0 ? {} : { entries: source.config.entries },
31923
31976
  ...source.entryOrder === void 0 ? {} : { entryOrder: source.entryOrder },
31924
- ...source.config.launch === void 0 ? {} : { launch: source.config.launch }
31977
+ ...source.config.launch === void 0 ? {} : { launch: source.config.launch },
31978
+ ...source.config.models === void 0 ? {} : { models: source.config.models }
31925
31979
  });
31926
31980
  nextId += 1;
31927
31981
  }
@@ -32539,6 +32593,7 @@ function flattenLayers(layers, options) {
32539
32593
  const rules = /* @__PURE__ */ new Map();
32540
32594
  const launch = {};
32541
32595
  const diagnostics = [];
32596
+ let models;
32542
32597
  for (const layer of layers) {
32543
32598
  if (layer.categories !== void 0) {
32544
32599
  for (const [name, value2] of Object.entries(layer.categories)) {
@@ -32577,6 +32632,9 @@ function flattenLayers(layers, options) {
32577
32632
  launch.explain = layer.launch.explain;
32578
32633
  }
32579
32634
  }
32635
+ if (layer.models !== void 0) {
32636
+ models = mergeModels(models, layer.models);
32637
+ }
32580
32638
  if (layer.entries === void 0) {
32581
32639
  continue;
32582
32640
  }
@@ -32639,7 +32697,7 @@ function flattenLayers(layers, options) {
32639
32697
  rules.set(pattern, rule);
32640
32698
  }
32641
32699
  }
32642
- return { categories, rules, launch, diagnostics };
32700
+ return { categories, rules, launch, ...models === void 0 ? {} : { models }, diagnostics };
32643
32701
  }
32644
32702
  function orderedKeys(layer) {
32645
32703
  const present = new Set(Object.keys(layer.entries ?? {}));
@@ -32664,6 +32722,67 @@ function matchingRules(flattened, relPath) {
32664
32722
  }
32665
32723
  return matches.sort((a10, b) => compareSpecificity(b, a10));
32666
32724
  }
32725
+ function mergeModels(current, layer) {
32726
+ const pieces = { ...current ?? {} };
32727
+ if (layer.virtual !== void 0) {
32728
+ const virtual = {};
32729
+ for (const [name, definition] of Object.entries(current?.virtual ?? {})) {
32730
+ if (layer.virtual[name] === void 0) {
32731
+ virtual[name] = definition;
32732
+ }
32733
+ }
32734
+ for (const [name, definition] of Object.entries(layer.virtual)) {
32735
+ if (definition !== null) {
32736
+ virtual[name] = definition;
32737
+ }
32738
+ }
32739
+ pieces.virtual = virtual;
32740
+ }
32741
+ if (layer.tiers !== void 0) {
32742
+ const tiers = {};
32743
+ for (const tier of ["fable", "opus", "sonnet", "haiku"]) {
32744
+ const ref = layer.tiers[tier];
32745
+ const inherited = current?.tiers?.[tier];
32746
+ if (ref !== null && ref !== void 0) {
32747
+ tiers[tier] = ref;
32748
+ } else if (ref === void 0 && inherited !== void 0) {
32749
+ tiers[tier] = inherited;
32750
+ }
32751
+ }
32752
+ pieces.tiers = tiers;
32753
+ }
32754
+ if (layer.prices !== void 0) {
32755
+ const priced = {};
32756
+ for (const [ref, prices] of Object.entries(current?.prices ?? {})) {
32757
+ if (layer.prices[ref] === void 0) {
32758
+ priced[ref] = prices;
32759
+ }
32760
+ }
32761
+ for (const [ref, prices] of Object.entries(layer.prices)) {
32762
+ if (prices !== null) {
32763
+ priced[ref] = prices;
32764
+ }
32765
+ }
32766
+ pieces.prices = priced;
32767
+ }
32768
+ if (layer.hide !== void 0) {
32769
+ pieces.hide = layer.hide;
32770
+ }
32771
+ if (layer.show !== void 0) {
32772
+ pieces.show = layer.show;
32773
+ }
32774
+ const merged = modelsOf(pieces);
32775
+ return Object.keys(merged).length === 0 ? void 0 : merged;
32776
+ }
32777
+ function modelsOf(pieces) {
32778
+ return {
32779
+ ...pieces.virtual === void 0 || Object.keys(pieces.virtual).length === 0 ? {} : { virtual: pieces.virtual },
32780
+ ...pieces.tiers === void 0 || Object.keys(pieces.tiers).length === 0 ? {} : { tiers: pieces.tiers },
32781
+ ...pieces.prices === void 0 || Object.keys(pieces.prices).length === 0 ? {} : { prices: pieces.prices },
32782
+ ...pieces.hide === void 0 || pieces.hide.length === 0 ? {} : { hide: [...pieces.hide] },
32783
+ ...pieces.show === void 0 || pieces.show.length === 0 ? {} : { show: [...pieces.show] }
32784
+ };
32785
+ }
32667
32786
  var init_flatten = __esm({
32668
32787
  "src/resolve/flatten.ts"() {
32669
32788
  "use strict";
@@ -34323,7 +34442,7 @@ var init_package = __esm({
34323
34442
  "package.json"() {
34324
34443
  package_default = {
34325
34444
  name: "claude-use",
34326
- version: "11.32.0",
34445
+ version: "11.34.0",
34327
34446
  description: "A profile manager and launcher for Claude Code that lets one person run multiple logins from one machine while controlling what gets shared between them.",
34328
34447
  license: "MIT",
34329
34448
  author: "Joseph Mearman <joseph@mearman.co.uk>",
@@ -36003,7 +36122,7 @@ function describeProviderEndpoint(provider) {
36003
36122
  if (isAntigravityProvider(provider)) {
36004
36123
  return (provider.antigravity?.mode ?? ANTIGRAVITY_DEFAULT_MODE) === "local" ? "antigravity local (ACP daemon)" : "antigravity cloud (Gemini API)";
36005
36124
  }
36006
- return provider.baseUrl;
36125
+ return isRouterProvider(provider) ? "the models block" : provider.baseUrl;
36007
36126
  }
36008
36127
  function isEmptyCodexConfig(config2) {
36009
36128
  return config2 === void 0 || config2.defaultModel === void 0 && config2.effort === void 0 && config2.login === void 0 && (config2.models === void 0 || Object.keys(config2.models).length === 0);
@@ -36025,10 +36144,16 @@ function addProvider(paths, name, input2) {
36025
36144
  if (kind === "antigravity" && input2.baseUrl !== void 0) {
36026
36145
  throw new ProviderKindMismatchError("An antigravity provider has no base URL: the launcher points its sessions at the front-door daemon. Drop --base-url.");
36027
36146
  }
36147
+ if (kind === "router" && input2.baseUrl !== void 0) {
36148
+ throw new ProviderKindMismatchError("A router provider has no base URL: it resolves each request's model name through the models block. Drop --base-url.");
36149
+ }
36028
36150
  if (kind === "http" && input2.baseUrl === void 0) {
36029
36151
  throw new ProviderKindMismatchError("An http provider needs --base-url.");
36030
36152
  }
36031
- if (kind !== "http" && input2.catalogue !== void 0) {
36153
+ if (kind === "router" && (input2.sources.length > 0 || input2.target !== void 0 || input2.env !== void 0 || input2.pickerModels !== void 0)) {
36154
+ throw new ProviderKindMismatchError("A router provider has no credential, env or picker models of its own: the models block's targets carry their own.");
36155
+ }
36156
+ if (kind !== "http" && kind !== "router" && input2.catalogue !== void 0) {
36032
36157
  throw new ProviderKindMismatchError("A model catalogue applies only to an http provider.");
36033
36158
  }
36034
36159
  if (kind !== "codex" && !isEmptyCodexConfig(input2.codex)) {
@@ -36044,7 +36169,7 @@ function addProvider(paths, name, input2) {
36044
36169
  ...input2.pickerModels === void 0 || input2.pickerModels.length === 0 ? {} : { pickerModels: input2.pickerModels }
36045
36170
  };
36046
36171
  const parsed = ProviderSchema.safeParse(
36047
- kind === "codex" ? { kind, ...shared, ...isEmptyCodexConfig(input2.codex) ? {} : { codex: input2.codex } } : kind === "antigravity" ? { kind, ...shared, ...isEmptyAntigravityConfig(input2.antigravity) ? {} : { antigravity: input2.antigravity } } : { ...shared, baseUrl: input2.baseUrl, ...input2.catalogue === void 0 ? {} : { catalogue: input2.catalogue } }
36172
+ kind === "router" ? { kind, displayName: input2.displayName } : kind === "codex" ? { kind, ...shared, ...isEmptyCodexConfig(input2.codex) ? {} : { codex: input2.codex } } : kind === "antigravity" ? { kind, ...shared, ...isEmptyAntigravityConfig(input2.antigravity) ? {} : { antigravity: input2.antigravity } } : { ...shared, baseUrl: input2.baseUrl, ...input2.catalogue === void 0 ? {} : { catalogue: input2.catalogue } }
36048
36173
  );
36049
36174
  if (!parsed.success) {
36050
36175
  throw new ConfigValidationError(providerJsonPath(paths, name), parsed.error.issues);
@@ -36058,15 +36183,18 @@ function updateProvider(paths, name, input2) {
36058
36183
  throw new ProviderNotFoundError(name);
36059
36184
  }
36060
36185
  const unset = new Set(input2.unsetEnv);
36061
- const env = Object.fromEntries(Object.entries({ ...existing.env, ...input2.env }).filter(([key]) => !unset.has(key)));
36186
+ const existingEnv = isRouterProvider(existing) ? {} : existing.env;
36187
+ const env = Object.fromEntries(Object.entries({ ...existingEnv, ...input2.env }).filter(([key]) => !unset.has(key)));
36062
36188
  const unsetPicker = new Set(input2.unsetPickerModels);
36063
36189
  const added = new Map((input2.pickerModels ?? []).map((entry) => [entry.model, entry]));
36190
+ const existingPicker = isRouterProvider(existing) ? [] : existing.pickerModels;
36064
36191
  const pickerModels = [
36065
- ...(existing.pickerModels ?? []).filter((entry) => !unsetPicker.has(entry.model)).map((entry) => added.get(entry.model) ?? entry),
36066
- ...[...added.values()].filter((entry) => !(existing.pickerModels ?? []).some((kept) => kept.model === entry.model))
36192
+ ...(existingPicker ?? []).filter((entry) => !unsetPicker.has(entry.model)).map((entry) => added.get(entry.model) ?? entry),
36193
+ ...[...added.values()].filter((entry) => !(existingPicker ?? []).some((kept) => kept.model === entry.model))
36067
36194
  ];
36068
- const target = input2.target ?? existing.credential.target;
36069
- const cache = input2.cache === void 0 ? existing.credential.cache : input2.cache === false ? void 0 : input2.cache;
36195
+ const router = isRouterProvider(existing);
36196
+ const target = router ? void 0 : input2.target ?? existing.credential.target;
36197
+ const cache = router ? void 0 : input2.cache === void 0 ? existing.credential.cache : input2.cache === false ? void 0 : input2.cache;
36070
36198
  if (isCodexProvider(existing) && input2.baseUrl !== void 0) {
36071
36199
  throw new ProviderKindMismatchError(`Provider "${name}" is a codex provider, which has no base URL.`);
36072
36200
  }
@@ -36084,10 +36212,12 @@ function updateProvider(paths, name, input2) {
36084
36212
  }
36085
36213
  const shared = {
36086
36214
  ...input2.displayName === void 0 ? {} : { displayName: input2.displayName },
36087
- credential: {
36088
- sources: input2.sources ?? existing.credential.sources,
36089
- ...target === void 0 ? {} : { target },
36090
- ...cache === void 0 ? {} : { cache }
36215
+ ...router ? {} : {
36216
+ credential: {
36217
+ sources: input2.sources ?? existing.credential.sources,
36218
+ ...target === void 0 ? {} : { target },
36219
+ ...cache === void 0 ? {} : { cache }
36220
+ }
36091
36221
  },
36092
36222
  env: Object.keys(env).length === 0 ? void 0 : env,
36093
36223
  pickerModels: pickerModels.length === 0 ? void 0 : pickerModels
@@ -36107,6 +36237,8 @@ function updateProvider(paths, name, input2) {
36107
36237
  ...existing.antigravity?.models === void 0 && input2.antigravity?.models === void 0 ? {} : { models: { ...existing.antigravity?.models, ...input2.antigravity?.models } }
36108
36238
  };
36109
36239
  candidate = { ...existing, ...shared, antigravity: isEmptyAntigravityConfig(antigravity) ? void 0 : antigravity };
36240
+ } else if (router) {
36241
+ candidate = { kind: "router", ...shared };
36110
36242
  } else {
36111
36243
  const catalogue = input2.catalogue === void 0 ? existing.catalogue : input2.catalogue === false ? void 0 : input2.catalogue;
36112
36244
  candidate = { ...existing, ...shared, catalogue, ...input2.baseUrl === void 0 ? {} : { baseUrl: input2.baseUrl } };
@@ -36156,6 +36288,9 @@ function resolveProvider(params) {
36156
36288
  return selection;
36157
36289
  }
36158
36290
  const { name, definition } = selection.provider;
36291
+ if (isRouterProvider(definition)) {
36292
+ return { ok: true, provider: { name, definition, credential: { target: "bearer", token: "", source: { env: "AGENT_SHIM_ROUTER" }, warnings: [] } }, warnings: [] };
36293
+ }
36159
36294
  if (params.credentials === void 0) {
36160
36295
  return { ok: false, status: 1, message: `agent-shim: provider ${name} needs its credential resolved, but this launcher has no credential port wired` };
36161
36296
  }
@@ -63361,7 +63496,7 @@ function buildEnv(params) {
63361
63496
  env.CLAUDE_CONFIG_DIR = import_node_path40.default.join(params.identitiesDir, params.resolvedIdentityName);
63362
63497
  }
63363
63498
  if (params.provider !== void 0) {
63364
- const providerEnv = params.provider.definition.env ?? {};
63499
+ const providerEnv = params.provider.definition.kind !== void 0 && params.provider.definition.kind !== "http" ? {} : params.provider.definition.env ?? {};
63365
63500
  providerCustomHeaders = providerEnv.ANTHROPIC_CUSTOM_HEADERS;
63366
63501
  env.ANTHROPIC_BASE_URL = void 0;
63367
63502
  env.AGENT_SHIM_PROVIDER = params.provider.definition.displayName;
@@ -65065,8 +65200,8 @@ function catalogueRows(provider, models) {
65065
65200
  return filterCatalogue(models, provider.catalogue).map((model) => ({ model: model.id, label: labelOf(model.id), description: describedAs(model.id, model.name === void 0 ? "Listed by the provider" : `Listed by the provider as ${model.name}`), behavesAs: TIER_BEHAVES_AS[tier] })).sort((left, right) => left.model.localeCompare(right.model));
65066
65201
  }
65067
65202
  function providerModelRows(provider, catalogue = []) {
65068
- const derived2 = provider.kind === "codex" ? codexRows(provider) : provider.kind === "antigravity" ? antigravityRows(provider) : httpRows(provider);
65069
- const declared = (provider.pickerModels ?? []).map(declaredRow);
65203
+ const derived2 = provider.kind === "codex" ? codexRows(provider) : provider.kind === "antigravity" ? antigravityRows(provider) : provider.kind === "router" ? [] : httpRows(provider);
65204
+ const declared = provider.kind === "router" ? [] : (provider.pickerModels ?? []).map(declaredRow);
65070
65205
  const declaredModels = new Set(declared.map((row) => row.model));
65071
65206
  const named = [...derived2.filter((row) => !declaredModels.has(row.model)), ...declared];
65072
65207
  const taken = new Set(named.map((row) => labelOf(row.model)));
@@ -65684,7 +65819,7 @@ function resolveLaunch(params) {
65684
65819
  });
65685
65820
  const credentialNames = decided.identityCredentialBlock === void 0 ? [] : Object.keys(credentialVariables(decided.identityCredentialBlock.target ?? "bearer", ""));
65686
65821
  const environment = [.../* @__PURE__ */ new Set([...Object.keys(built).filter((name) => built[name] !== env[name]), ...credentialNames])].sort();
65687
- const credential = decided.provider !== void 0 ? { subject: "provider", name: decided.provider.name, summary: summariseCredential(decided.provider.definition.credential) } : decided.identityCredentialBlock !== void 0 && decided.farmIdentity !== void 0 ? { subject: "identity", name: decided.farmIdentity, summary: summariseCredential(decided.identityCredentialBlock) } : void 0;
65822
+ const credential = decided.provider !== void 0 ? isRouterProvider(decided.provider.definition) ? void 0 : { subject: "provider", name: decided.provider.name, summary: summariseCredential(decided.provider.definition.credential) } : decided.identityCredentialBlock !== void 0 && decided.farmIdentity !== void 0 ? { subject: "identity", name: decided.farmIdentity, summary: summariseCredential(decided.identityCredentialBlock) } : void 0;
65688
65823
  return {
65689
65824
  decision: decided.decision,
65690
65825
  flags: decided.flags,
@@ -66256,7 +66391,7 @@ function createProviderLookup(ports) {
66256
66391
  return {
66257
66392
  baseUrl,
66258
66393
  apiKey: () => {
66259
- const resolution = resolveCredential({ credential: definition.credential, env: ports.env, port: ports.credentials, subject: `provider ${name}` });
66394
+ const resolution = resolveCredential({ credential: isRouterProvider(definition) ? { sources: [] } : definition.credential, env: ports.env, port: ports.credentials, subject: `provider ${name}` });
66260
66395
  if (!resolution.ok) {
66261
66396
  throw new Error(resolution.message);
66262
66397
  }
@@ -113623,11 +113758,12 @@ function cachedState(cacheEnv, owner, block2) {
113623
113758
  function buildCredentialReport(provider, identity, identityName, cacheEnv) {
113624
113759
  const identityCredential = identity?.credential === void 0 ? void 0 : summariseCredential(identity.credential);
113625
113760
  const identityCached = identity?.credential === void 0 || identityName === void 0 ? void 0 : cachedState(cacheEnv, `identity ${identityName}`, identity.credential);
113626
- const providerCached = provider?.definition === void 0 ? void 0 : cachedState(cacheEnv, `provider ${provider.name}`, provider.definition.credential);
113761
+ const providerCredential = provider?.definition !== void 0 && !isRouterProvider(provider.definition) ? provider.definition.credential : void 0;
113762
+ const providerCached = providerCredential === void 0 || provider === void 0 ? void 0 : cachedState(cacheEnv, `provider ${provider.name}`, providerCredential);
113627
113763
  return {
113628
113764
  applies: provider !== void 0 ? "provider" : identityCredential !== void 0 ? "identity" : "stored-login",
113629
113765
  ...provider === void 0 ? {} : {
113630
- provider: provider.problem === void 0 ? { name: provider.name, credential: summariseCredential(provider.definition.credential), ...providerCached === void 0 ? {} : { cached: providerCached } } : { name: provider.name, problem: provider.problem }
113766
+ provider: provider.problem === void 0 ? { name: provider.name, ...providerCredential === void 0 ? {} : { credential: summariseCredential(providerCredential), ...providerCached === void 0 ? {} : { cached: providerCached } } } : { name: provider.name, problem: provider.problem }
113631
113767
  },
113632
113768
  ...identityCredential === void 0 ? {} : { identity: identityCredential },
113633
113769
  ...identityCached === void 0 ? {} : { identityCached }
@@ -113722,7 +113858,7 @@ function formatCheckReport(report) {
113722
113858
  const { credential } = report;
113723
113859
  if (credential.provider !== void 0) {
113724
113860
  lines.push(
113725
- ` Provider ${credential.provider.name}: ${credential.provider.credential === void 0 ? `unusable: ${credential.provider.problem}` : formatCredentialSummary(credential.provider.credential)}${credential.provider.cached === void 0 ? "" : `; ${formatCachedCredentialState(credential.provider.cached)}`}`
113861
+ ` Provider ${credential.provider.name}: ${credential.provider.credential === void 0 ? `unusable: ${credential.provider.problem ?? ""}` : formatCredentialSummary(credential.provider.credential)}${credential.provider.cached === void 0 ? "" : `; ${formatCachedCredentialState(credential.provider.cached)}`}`
113726
113862
  );
113727
113863
  }
113728
113864
  if (credential.identity !== void 0) {
@@ -119011,6 +119147,162 @@ init_credentialCache();
119011
119147
  init_realCredentialCache();
119012
119148
  init_source();
119013
119149
 
119150
+ // src/modelsStore.ts
119151
+ init_store();
119152
+ init_schema();
119153
+ function readModels(paths) {
119154
+ return readGlobalConfig(paths)?.models;
119155
+ }
119156
+ function writeModels(paths, models) {
119157
+ const emptied = models !== void 0 && Object.keys(models).length === 0 ? void 0 : models;
119158
+ applyPatch(paths.globalConfigFile, GlobalConfigSchema, { models: emptied }, { defaults: {} });
119159
+ }
119160
+ function stripEmpty(models) {
119161
+ const kept = {};
119162
+ if (models.virtual !== void 0 && Object.keys(models.virtual).length > 0) {
119163
+ kept.virtual = models.virtual;
119164
+ }
119165
+ if (models.tiers !== void 0 && Object.keys(models.tiers).length > 0) {
119166
+ kept.tiers = models.tiers;
119167
+ }
119168
+ if (models.prices !== void 0 && Object.keys(models.prices).length > 0) {
119169
+ kept.prices = models.prices;
119170
+ }
119171
+ if (models.hide !== void 0 && models.hide.length > 0) {
119172
+ kept.hide = models.hide;
119173
+ }
119174
+ if (models.show !== void 0 && models.show.length > 0) {
119175
+ kept.show = models.show;
119176
+ }
119177
+ return kept;
119178
+ }
119179
+ var VirtualModelNotFoundError = class extends Error {
119180
+ constructor(name) {
119181
+ super(`No virtual model named "${name}".`);
119182
+ this.name = "VirtualModelNotFoundError";
119183
+ }
119184
+ };
119185
+ function memberKindOf(ref, models) {
119186
+ if (ref.startsWith("acct:")) {
119187
+ return "account";
119188
+ }
119189
+ if (ref.startsWith("family:")) {
119190
+ return "family";
119191
+ }
119192
+ return models?.virtual !== void 0 && ref in models.virtual ? "virtual" : "provider";
119193
+ }
119194
+ function expandMembers(name, models) {
119195
+ const virtual = models?.virtual ?? {};
119196
+ const expanded = [];
119197
+ const walk2 = (current, chain) => {
119198
+ const nested = virtual[current];
119199
+ if (nested !== void 0) {
119200
+ if (chain.includes(current)) {
119201
+ throw new Error(`virtual model cycle: ${[...chain, current].join(" -> ")}`);
119202
+ }
119203
+ for (const member of nested.members) {
119204
+ walk2(member, [...chain, current]);
119205
+ }
119206
+ return;
119207
+ }
119208
+ if (!expanded.includes(current)) {
119209
+ expanded.push(current);
119210
+ }
119211
+ };
119212
+ const top = virtual[name];
119213
+ if (top === void 0) {
119214
+ throw new VirtualModelNotFoundError(name);
119215
+ }
119216
+ for (const member of top.members) {
119217
+ walk2(member, [name]);
119218
+ }
119219
+ return expanded;
119220
+ }
119221
+ function setVirtualModel(paths, name, model) {
119222
+ const current = readModels(paths) ?? {};
119223
+ writeModels(paths, { ...current, virtual: { ...current.virtual ?? {}, [name]: model } });
119224
+ }
119225
+ function removeVirtualModel(paths, name) {
119226
+ const current = readModels(paths);
119227
+ if (current?.virtual?.[name] === void 0) {
119228
+ throw new VirtualModelNotFoundError(name);
119229
+ }
119230
+ const virtual = Object.fromEntries(Object.entries(current.virtual ?? {}).filter(([existing]) => existing !== name));
119231
+ writeModels(paths, stripEmpty({ ...current, virtual: Object.keys(virtual).length === 0 ? void 0 : virtual }));
119232
+ }
119233
+ function setPrice(paths, ref, prices) {
119234
+ const current = readModels(paths) ?? {};
119235
+ const priced = Object.fromEntries(Object.entries(current.prices ?? {}).filter(([existing]) => existing !== ref));
119236
+ const next = prices === void 0 ? priced : { ...priced, [ref]: prices };
119237
+ writeModels(paths, stripEmpty({ ...current, prices: Object.keys(next).length === 0 ? void 0 : next }));
119238
+ }
119239
+ function setTier(paths, tier, ref) {
119240
+ const current = readModels(paths) ?? {};
119241
+ const tiers = {};
119242
+ const merged = { ...current.tiers ?? {}, [tier]: ref };
119243
+ for (const [key, value2] of Object.entries(merged)) {
119244
+ if (value2 !== void 0) {
119245
+ tiers[key] = value2;
119246
+ }
119247
+ }
119248
+ writeModels(paths, stripEmpty({ ...current, tiers: Object.keys(tiers).length === 0 ? void 0 : tiers }));
119249
+ }
119250
+
119251
+ // src/models/doctor.ts
119252
+ function modelsFindings(input2) {
119253
+ const findings = [];
119254
+ const { models } = input2;
119255
+ const providers = new Set(input2.providers);
119256
+ const identities = new Set(input2.identities);
119257
+ const virtualNames = new Set(Object.keys(models.virtual ?? {}));
119258
+ for (const [name, model] of Object.entries(models.virtual ?? {})) {
119259
+ for (const member of model.members) {
119260
+ const kind = memberKindOf(member, models);
119261
+ if (kind === "provider" && !member.includes("/")) {
119262
+ findings.push({ severity: "fail", message: `Virtual model "${name}" names member "${member}", which is neither a defined virtual model nor a provider model (a provider model is <provider>/<model>).` });
119263
+ } else if (kind === "provider" && !providers.has(member.split("/")[0] ?? "")) {
119264
+ findings.push({ severity: "fail", message: `Virtual model "${name}" names member "${member}", but no provider "${member.split("/")[0] ?? ""}" is defined.` });
119265
+ }
119266
+ if (kind === "virtual" && !virtualNames.has(member)) {
119267
+ findings.push({ severity: "fail", message: `Virtual model "${name}" names member "${member}", but no virtual model "${member}" is defined.` });
119268
+ }
119269
+ if (kind === "account") {
119270
+ const identity = member.slice("acct:".length).split("/")[0] ?? "";
119271
+ if (!identities.has(identity)) {
119272
+ findings.push({ severity: "fail", message: `Virtual model "${name}" names member "${member}", but no identity "${identity}" is defined.` });
119273
+ }
119274
+ }
119275
+ }
119276
+ try {
119277
+ expandMembers(name, models);
119278
+ } catch (error63) {
119279
+ findings.push({ severity: "fail", message: `Virtual model "${name}" cannot be expanded: ${error63 instanceof Error ? error63.message : String(error63)}` });
119280
+ }
119281
+ if (model.mode === "cheapest") {
119282
+ const expanded = expandMembers(name, models);
119283
+ const unpriced = expanded.filter((member) => models.prices?.[member] === void 0 && memberKindOf(member, models) !== "virtual");
119284
+ if (unpriced.length > 0) {
119285
+ findings.push({ severity: "warn", message: `Virtual model "${name}" chooses by price, but no prices are set for: ${unpriced.join(", ")}.` });
119286
+ }
119287
+ }
119288
+ }
119289
+ for (const [tier, ref] of Object.entries(models.tiers ?? {})) {
119290
+ const kind = memberKindOf(ref, models);
119291
+ const known = kind === "virtual" ? virtualNames.has(ref) : kind === "provider" ? providers.has(ref.split("/")[0] ?? "") : true;
119292
+ if (!known) {
119293
+ findings.push({ severity: "fail", message: `Tier ${tier} points at "${ref}", which names nothing defined.` });
119294
+ }
119295
+ }
119296
+ const hidden = new Set(models.hide ?? []);
119297
+ const shown = new Set(models.show ?? []);
119298
+ for (const ref of hidden) {
119299
+ if (shown.has(ref)) {
119300
+ findings.push({ severity: "fail", message: `Model ref "${ref}" is both hidden and in the show-only list.` });
119301
+ }
119302
+ }
119303
+ return findings;
119304
+ }
119305
+
119014
119306
  // src/headroom/allowlistDrift.ts
119015
119307
  init_earlierRelease();
119016
119308
  init_state2();
@@ -119197,7 +119489,8 @@ var DOCTOR_SECTIONS = [
119197
119489
  "categories-local",
119198
119490
  "active-identity",
119199
119491
  "headroom",
119200
- "frontdoor"
119492
+ "frontdoor",
119493
+ "models"
119201
119494
  ];
119202
119495
  function refinePathShadow(status, ownExecutablePath, realpath) {
119203
119496
  if (status.status !== "shadowed") {
@@ -119320,9 +119613,11 @@ function pushProvider(push, entry, cacheEnv, signIn) {
119320
119613
  if (validated2.ignored.length > 0) {
119321
119614
  push("provider", "warn", describeIgnoredKeys(entry.path, validated2.ignored), entry.name);
119322
119615
  }
119323
- const cache = cacheClause(cacheEnv, `provider ${entry.name}`, validated2.data.credential);
119324
- push("provider", cache.unreadable ? "fail" : "pass", `${entry.name} is valid (${describeProviderEndpoint(validated2.data)}, credential ${describeCredential(validated2.data.credential)})${cache.text}.`, entry.name);
119325
- if (validated2.data.env?.ENABLE_TOOL_SEARCH === void 0) {
119616
+ const router = isRouterProvider(validated2.data);
119617
+ const noCache = { unreadable: false, text: "" };
119618
+ const cache = router ? noCache : cacheClause(cacheEnv, `provider ${entry.name}`, validated2.data.credential);
119619
+ push("provider", cache.unreadable ? "fail" : "pass", router ? `${entry.name} is valid (${describeProviderEndpoint(validated2.data)})` : `${entry.name} is valid (${describeProviderEndpoint(validated2.data)}, credential ${describeCredential(validated2.data.credential)})${cache.text}.`, entry.name);
119620
+ if (!router && validated2.data.env?.ENABLE_TOOL_SEARCH === void 0) {
119326
119621
  push("provider", "warn", `${entry.name} does not set ENABLE_TOOL_SEARCH: a session on this provider keeps Claude Code's own API as its base URL, so it defers MCP tool loading and sends tool_reference payloads the upstream backend must understand. Set ENABLE_TOOL_SEARCH=false in the provider's env block to load tools upfront instead, when the backend does not support them.`, entry.name);
119327
119622
  }
119328
119623
  if (signIn !== void 0 && isCodexProvider(validated2.data) && validated2.data.codex?.login === "chatgpt-sign-in") {
@@ -119349,6 +119644,9 @@ function pushLegacyName(push, params) {
119349
119644
  );
119350
119645
  }
119351
119646
  }
119647
+ function parsedModelsOf(paths) {
119648
+ return readGlobalConfig(paths)?.models;
119649
+ }
119352
119650
  function runDoctor(params) {
119353
119651
  const findings = [];
119354
119652
  const push = (section, severity, message, subject) => {
@@ -119550,6 +119848,17 @@ function runDoctor(params) {
119550
119848
  }
119551
119849
  }
119552
119850
  }
119851
+ {
119852
+ const models = params.models;
119853
+ if (models === void 0) {
119854
+ push("models", "pass", "No models block configured.");
119855
+ } else {
119856
+ for (const finding of modelsFindings({ models, providers: params.providers.map((entry) => entry.name), identities: params.identities.map((entry) => entry.name) })) {
119857
+ push("models", finding.severity, finding.message);
119858
+ }
119859
+ push("models", "pass", "The models block is consistent.");
119860
+ }
119861
+ }
119553
119862
  if (params.categoriesLocal.raw === void 0) {
119554
119863
  push("categories-local", "pass", "No categories.local.json configured.");
119555
119864
  } else {
@@ -119644,6 +119953,7 @@ function runDoctor(params) {
119644
119953
  return { findings, ok: !findings.some((finding) => finding.severity === "fail") };
119645
119954
  }
119646
119955
  var SECTION_TITLES = {
119956
+ models: "Virtual models",
119647
119957
  "ambient-credential": "Ambient-credential exposure",
119648
119958
  "binary-discovery": "Claude Code binary discovery",
119649
119959
  "claude-shim": "`claude` command shim",
@@ -119776,6 +120086,7 @@ function collectDoctorReport(params) {
119776
120086
  providers,
119777
120087
  directoryRules: { path: paths.directoryRulesFile, raw: realFsPort.readFileUtf8(paths.directoryRulesFile) },
119778
120088
  globalConfig: { path: paths.globalConfigFile, raw: realFsPort.readFileUtf8(paths.globalConfigFile) },
120089
+ models: parsedModelsOf(paths),
119779
120090
  categoriesLocal: { path: paths.categoriesLocalFile, raw: realFsPort.readFileUtf8(paths.categoriesLocalFile) },
119780
120091
  activeIdentity: { path: paths.activeIdentityFile, raw: realFsPort.readFileUtf8(paths.activeIdentityFile) },
119781
120092
  binaryDiscovery,
@@ -125209,7 +125520,7 @@ var CachedCredentialStateSchema = external_exports.union([
125209
125520
  external_exports.strictObject({ store: external_exports.enum(CREDENTIAL_CACHE_STORES), status: external_exports.enum(["fresh", "expired"]), ageMs: external_exports.number(), expiresInMs: external_exports.number().optional() })
125210
125521
  ]);
125211
125522
  var CheckCredentialProviderSchema = external_exports.union([
125212
- external_exports.strictObject({ name: external_exports.string(), credential: CredentialSummarySchema, cached: CachedCredentialStateSchema.optional() }),
125523
+ external_exports.strictObject({ name: external_exports.string(), credential: CredentialSummarySchema.optional(), cached: CachedCredentialStateSchema.optional() }),
125213
125524
  external_exports.strictObject({ name: external_exports.string(), problem: external_exports.string() })
125214
125525
  ]);
125215
125526
  var CheckCredentialSchema = external_exports.strictObject({
@@ -127858,7 +128169,7 @@ var ProviderValueSchema = external_exports.strictObject({
127858
128169
  displayName: external_exports.string(),
127859
128170
  baseUrl: external_exports.string().optional(),
127860
128171
  codex: CodexProviderConfigSchema.optional(),
127861
- credential: CredentialSummarySchema2,
128172
+ credential: CredentialSummarySchema2.optional(),
127862
128173
  env: external_exports.record(external_exports.string(), external_exports.string()).optional()
127863
128174
  });
127864
128175
  var ConfigNameInputSchema = external_exports.strictObject({ name: external_exports.string().min(1) });
@@ -128008,9 +128319,8 @@ function providerValue(name, provider) {
128008
128319
  name,
128009
128320
  kind: provider.kind ?? "http",
128010
128321
  displayName: provider.displayName,
128011
- ...isCodexProvider(provider) ? provider.codex === void 0 ? {} : { codex: provider.codex } : isAntigravityProvider(provider) ? provider.antigravity === void 0 ? {} : { antigravity: provider.antigravity } : { baseUrl: provider.baseUrl },
128012
- credential: summariseCredential(provider.credential),
128013
- ...provider.env === void 0 ? {} : { env: provider.env }
128322
+ ...isCodexProvider(provider) ? provider.codex === void 0 ? {} : { codex: provider.codex } : isAntigravityProvider(provider) ? provider.antigravity === void 0 ? {} : { antigravity: provider.antigravity } : isRouterProvider(provider) ? {} : { baseUrl: provider.baseUrl },
128323
+ ...isRouterProvider(provider) ? {} : { credential: summariseCredential(provider.credential), ...provider.env === void 0 ? {} : { env: provider.env } }
128014
128324
  };
128015
128325
  }
128016
128326
  function profileValue(name, paths) {
@@ -128192,7 +128502,7 @@ function createConfigApiRouter(deps) {
128192
128502
  if (input2.baseUrl !== void 0 && isHttpProvider(existing) && input2.baseUrl !== existing.baseUrl && credential?.sources === void 0) {
128193
128503
  throw new ORPCError("BAD_REQUEST", { message: `Changing the base URL of provider "${input2.name}" requires a credential block in the same call: the stored credential is not sent to a different endpoint.` });
128194
128504
  }
128195
- const cache = credential?.cache === void 0 ? void 0 : mergeCredentialCache(credential.cache === false ? { enabled: false } : { ...credential.cache, enabled: true }, existing.credential.cache);
128505
+ const cache = credential?.cache === void 0 || isRouterProvider(existing) ? void 0 : mergeCredentialCache(credential.cache === false ? { enabled: false } : { ...credential.cache, enabled: true }, isRouterProvider(existing) ? void 0 : existing.credential.cache);
128196
128506
  const updated = updateProvider(paths, input2.name, {
128197
128507
  ...input2.displayName === void 0 ? {} : { displayName: input2.displayName },
128198
128508
  ...input2.baseUrl === void 0 ? {} : { baseUrl: input2.baseUrl },
@@ -130798,6 +131108,20 @@ function scopeSessionProviderPath(request7) {
130798
131108
  }
130799
131109
  return { ...request7, url: `${PROVIDER_PATH_PREFIX}${encodeURIComponent(request7.session.provider)}${request7.url}` };
130800
131110
  }
131111
+ function resolveModelTarget(model, models) {
131112
+ if (models === void 0) {
131113
+ return model.includes("/") && !model.startsWith("acct:") ? model.split("/")[0] : void 0;
131114
+ }
131115
+ if (model.includes("/") && !model.startsWith("acct:")) {
131116
+ return model.split("/")[0];
131117
+ }
131118
+ const virtual = models.virtual?.[model];
131119
+ const first = virtual?.members.find((member) => !member.startsWith("acct:") && !member.startsWith("family:"));
131120
+ if (first === void 0) {
131121
+ return void 0;
131122
+ }
131123
+ return first.includes("/") ? first.split("/")[0] : resolveModelTarget(first, models);
131124
+ }
130801
131125
  function createProviderRouteResolver(deps) {
130802
131126
  const oauthRoute = createPassthroughRoute("anthropic", { baseUrl: `https://${CONNECT_INTERCEPT_HOST}:${String(HTTPS_PORT)}`, stripPrefix: void 0, headroomUpstream: void 0 });
130803
131127
  const antigravityQuotaSources = /* @__PURE__ */ new Map();
@@ -130910,6 +131234,9 @@ function createProviderRouteResolver(deps) {
130910
131234
  )
130911
131235
  };
130912
131236
  }
131237
+ if (isRouterProvider(definition)) {
131238
+ return { ok: true, route: passthroughFor(`router:${provider}`, { baseUrl: `http://127.0.0.1:${String(deps.directPort())}`, stripPrefix: `${PROVIDER_PATH_PREFIX}${encodeURIComponent(provider)}`, headroomUpstream: directOrigin2(deps.directPort()) }) };
131239
+ }
130913
131240
  const httpProvider = definition;
130914
131241
  return {
130915
131242
  ok: true,
@@ -130949,11 +131276,28 @@ function createProviderRouteResolver(deps) {
130949
131276
  visited.add(providerName);
130950
131277
  }
130951
131278
  let routes;
131279
+ let isRouter;
130952
131280
  try {
130953
131281
  const definition = providerName === void 0 ? void 0 : loadProvider(deps.providersDir, providerName, deps.fs);
130954
131282
  routes = definition === void 0 || !isHttpProvider(definition) ? void 0 : definition.routes;
131283
+ isRouter = definition !== void 0 && isRouterProvider(definition);
130955
131284
  } catch {
130956
131285
  routes = void 0;
131286
+ isRouter = false;
131287
+ }
131288
+ if (isRouter) {
131289
+ const scan2 = await scanRequestHead(current, false);
131290
+ if (scan2.replayed !== void 0) {
131291
+ replay = scan2.replayed;
131292
+ }
131293
+ const target = scan2.model === void 0 ? void 0 : resolveModelTarget(scan2.model, deps.models?.());
131294
+ if (target !== void 0) {
131295
+ const rest2 = path65.slice(`${PROVIDER_PATH_PREFIX}${encodeURIComponent(providerName ?? "")}`.length);
131296
+ const query2 = current.url.includes("?") ? current.url.slice(current.url.indexOf("?")) : "";
131297
+ const carried = scan2.replayed ?? current;
131298
+ current = { ...current, url: `${PROVIDER_PATH_PREFIX}${encodeURIComponent(target)}${rest2}${query2}`, body: carried.body, headers: carried.headers };
131299
+ continue;
131300
+ }
130957
131301
  }
130958
131302
  if (routes === void 0 || routes.length === 0) {
130959
131303
  const resolution = resolve2(current);
@@ -134171,6 +134515,8 @@ function realFrontDoorSupervisorPorts(paths) {
134171
134515
  const rcControlToken = (0, import_node_crypto25.randomUUID)();
134172
134516
  const resolveRoute = rcObservingResolver(
134173
134517
  createProviderRouteResolver({
134518
+ // Read live so a models-block edit reaches the next request without a door restart.
134519
+ models: () => readModels(paths),
134174
134520
  fs: realFsPort,
134175
134521
  providersDir: paths.providersDir,
134176
134522
  codexPorts,
@@ -145433,6 +145779,7 @@ function registerCompletionCommand(program2) {
145433
145779
  var import_node_child_process8 = require("node:child_process");
145434
145780
  init_commandDeps();
145435
145781
  init_cliError();
145782
+ init_schema();
145436
145783
  init_credential();
145437
145784
  init_credentialCache();
145438
145785
 
@@ -145501,6 +145848,9 @@ function credentialSubject(deps, name, asProvider) {
145501
145848
  if (provider === void 0) {
145502
145849
  throw new ProviderNotFoundError(name);
145503
145850
  }
145851
+ if (isRouterProvider(provider)) {
145852
+ throw new UsageError(`Provider "${name}" is a router: it has no credential of its own.`);
145853
+ }
145504
145854
  return { name, subject: `provider ${name}`, credential: provider.credential };
145505
145855
  }
145506
145856
  const identity = readIdentity(deps.paths, name);
@@ -146539,11 +146889,11 @@ function toProviderView(name, provider) {
146539
146889
  name,
146540
146890
  kind: provider.kind ?? "http",
146541
146891
  displayName: provider.displayName,
146542
- ...isCodexProvider(provider) ? provider.codex === void 0 ? {} : { codex: provider.codex } : isAntigravityProvider(provider) ? provider.antigravity === void 0 ? {} : { antigravity: provider.antigravity } : { baseUrl: provider.baseUrl },
146543
- credential: summariseCredential(provider.credential),
146544
- ...provider.env === void 0 ? {} : { env: provider.env },
146545
- ...provider.pickerModels === void 0 ? {} : { pickerModels: provider.pickerModels },
146546
- ...isCodexProvider(provider) || isAntigravityProvider(provider) || provider.catalogue === void 0 ? {} : { catalogue: provider.catalogue }
146892
+ ...isCodexProvider(provider) ? provider.codex === void 0 ? {} : { codex: provider.codex } : isAntigravityProvider(provider) ? provider.antigravity === void 0 ? {} : { antigravity: provider.antigravity } : isRouterProvider(provider) ? {} : { baseUrl: provider.baseUrl },
146893
+ ...isRouterProvider(provider) ? {} : { credential: summariseCredential(provider.credential) },
146894
+ ...!isRouterProvider(provider) && provider.env !== void 0 ? { env: provider.env } : {},
146895
+ ...!isRouterProvider(provider) && provider.pickerModels !== void 0 ? { pickerModels: provider.pickerModels } : {},
146896
+ ...isCodexProvider(provider) || isAntigravityProvider(provider) || isRouterProvider(provider) || provider.catalogue === void 0 ? {} : { catalogue: provider.catalogue }
146547
146897
  };
146548
146898
  }
146549
146899
  function antigravityConfigFromOptions(options) {
@@ -146651,7 +147001,7 @@ function registerProviderCommand(program2, deps) {
146651
147001
  ...antigravity === void 0 ? {} : { antigravity }
146652
147002
  });
146653
147003
  reportMutation(options.json, { action: "created", kind: "provider", name, value: created }, () => {
146654
- console.log(`Created provider "${name}" (${describeProviderEndpoint(created)}, credential ${describeCredential(created.credential)}).`);
147004
+ console.log(`Created provider "${name}" (${describeProviderEndpoint(created)}${isRouterProvider(created) ? "" : `, credential ${describeCredential(created.credential)}`}).`);
146655
147005
  });
146656
147006
  }),
146657
147007
  [
@@ -146685,12 +147035,13 @@ function registerProviderCommand(program2, deps) {
146685
147035
  }
146686
147036
  const codex = codexConfigFromOptions(options);
146687
147037
  const antigravity = antigravityConfigFromOptions(options);
146688
- const cache = cacheChange(options, readProvider(paths, name)?.credential.cache);
147038
+ const existingForCache = readProvider(paths, name);
147039
+ const cache = cacheChange(options, existingForCache !== void 0 && !isRouterProvider(existingForCache) ? existingForCache.credential.cache : void 0);
146689
147040
  if (options.unsetCatalogue === true && hasCatalogueOptions(options)) {
146690
147041
  throw new UsageError("--unset-catalogue cannot be combined with another --catalogue option.");
146691
147042
  }
146692
147043
  const existingProvider = readProvider(paths, name);
146693
- const catalogue = options.unsetCatalogue === true ? false : catalogueFromOptions(options, existingProvider !== void 0 && !isCodexProvider(existingProvider) && !isAntigravityProvider(existingProvider) ? existingProvider.catalogue : void 0);
147044
+ const catalogue = options.unsetCatalogue === true ? false : catalogueFromOptions(options, existingProvider !== void 0 && !isCodexProvider(existingProvider) && !isAntigravityProvider(existingProvider) && !isRouterProvider(existingProvider) ? existingProvider.catalogue : void 0);
146694
147045
  const updated = updateProvider(paths, name, {
146695
147046
  ...codex === void 0 ? {} : { codex },
146696
147047
  ...antigravity === void 0 ? {} : { antigravity },
@@ -146706,7 +147057,7 @@ function registerProviderCommand(program2, deps) {
146706
147057
  ...catalogue === void 0 ? {} : { catalogue }
146707
147058
  });
146708
147059
  reportMutation(json2, { action: "updated", kind: "provider", name, value: updated }, () => {
146709
- console.log(`Updated provider "${name}" (${describeProviderEndpoint(updated)}, credential ${describeCredential(updated.credential)}).`);
147060
+ console.log(`Updated provider "${name}" (${describeProviderEndpoint(updated)}${isRouterProvider(updated) ? "" : `, credential ${describeCredential(updated.credential)}`}).`);
146710
147061
  });
146711
147062
  }),
146712
147063
  [
@@ -146764,16 +147115,18 @@ function registerProviderCommand(program2, deps) {
146764
147115
  console.log(`Antigravity effort: ${config2.effort}`);
146765
147116
  console.log(`Antigravity degrade down tiers: ${config2.degradeDownTiers ? "on" : "off"}`);
146766
147117
  console.log(`Endpoint: ${describeProviderEndpoint(found)}`);
146767
- } else {
147118
+ } else if (!isRouterProvider(found)) {
146768
147119
  console.log(`Base URL: ${found.baseUrl}`);
146769
147120
  }
146770
- console.log(`Credential: ${describeCredential(found.credential)}`);
146771
- const env = Object.entries(found.env ?? {});
147121
+ if (!isRouterProvider(found)) {
147122
+ console.log(`Credential: ${describeCredential(found.credential)}`);
147123
+ }
147124
+ const env = Object.entries(isRouterProvider(found) ? {} : found.env ?? {});
146772
147125
  console.log(`Environment: ${env.length === 0 ? "(none)" : env.map(([key, value2]) => `${key}=${value2}`).join(", ")}`);
146773
- if (found.pickerModels !== void 0) {
147126
+ if (!isRouterProvider(found) && found.pickerModels !== void 0) {
146774
147127
  console.log(`Picker models: ${found.pickerModels.map((entry) => `${entry.model} (${entry.tier})`).join(", ")}`);
146775
147128
  }
146776
- if (!isCodexProvider(found) && !isAntigravityProvider(found) && found.catalogue !== void 0) {
147129
+ if (!isCodexProvider(found) && !isAntigravityProvider(found) && !isRouterProvider(found) && found.catalogue !== void 0) {
146777
147130
  const { tier, include, exclude, url: url2 } = found.catalogue;
146778
147131
  console.log(`Catalogue: tier ${tier}${include === void 0 ? "" : `, include ${include.join(" ")}`}${exclude === void 0 ? "" : `, exclude ${exclude.join(" ")}`}${url2 === void 0 ? "" : `, url ${url2}`} (see \`provider models ${name}\`)`);
146779
147132
  }
@@ -146786,7 +147139,7 @@ function registerProviderCommand(program2, deps) {
146786
147139
  if (found === void 0) {
146787
147140
  throw new ProviderNotFoundError(name);
146788
147141
  }
146789
- if (isCodexProvider(found) || isAntigravityProvider(found) || found.catalogue === void 0) {
147142
+ if (isCodexProvider(found) || isAntigravityProvider(found) || isRouterProvider(found) || found.catalogue === void 0) {
146790
147143
  throw new UsageError(`Provider "${name}" has no catalogue setting. Set one with \`agent-shim provider set ${name} --catalogue-tier <tier>\`.`);
146791
147144
  }
146792
147145
  const catalogueSetting = found.catalogue;
@@ -146828,6 +147181,8 @@ init_providersStore();
146828
147181
  init_modelPicker();
146829
147182
  init_providerCatalogue();
146830
147183
  init_realPorts();
147184
+ init_schema();
147185
+ init_cliError();
146831
147186
 
146832
147187
  // src/models/identity.ts
146833
147188
  var NON_IDENTITY_BRACKET_RE = /\[[^\]]*\]/g;
@@ -146978,8 +147333,8 @@ function matchModels(models) {
146978
147333
  }
146979
147334
  function registerModelsCommand(program2, deps) {
146980
147335
  const { paths } = deps;
146981
- const modelsCommand = program2.command("model").description("Inspect the models the defined providers offer: which names are the same model across providers, and which only look alike.");
146982
- withExamples(modelsCommand, ["agent-shim model match"]);
147336
+ const modelsCommand = program2.command("model").description("Define and inspect the models the providers offer and the virtual models chosen among them.");
147337
+ withExamples(modelsCommand, ["agent-shim model match", "agent-shim model add fast --mode soonest-reset --member z/glm-5.3 --member m/MiniMax-M3"]);
146983
147338
  withExamples(
146984
147339
  modelsCommand.command("match").description("List every model every provider offers, grouped into the ones that are the same model across providers, with the pairs that are merely similar named beside them.").option("--json", "Print the match as JSON."),
146985
147340
  ["agent-shim model match"]
@@ -147002,6 +147357,114 @@ function registerModelsCommand(program2, deps) {
147002
147357
  console.log(` similar: ${left.provider}/${left.model} ~ ${right.provider}/${right.model}`);
147003
147358
  }
147004
147359
  });
147360
+ withExamples(
147361
+ modelsCommand.command("add <name>").description("Define a virtual model: a named choice over members, taken by its mode.").requiredOption("--mode <mode>", "How the virtual model chooses its member.", (value2) => asMode(value2)).option("--member <ref>", "One member it chooses among: a provider model (z/glm-5.3), an account model (acct:work/opus), another virtual model, or a family (family:<canonical>). Repeatable; order is the preference where the mode reads it.", collectRepeated),
147362
+ ["agent-shim model add fast --mode soonest-reset --member z/glm-5.3 --member m/MiniMax-M3"]
147363
+ ).action((name, options) => {
147364
+ if (options.member === void 0 || options.member.length === 0) {
147365
+ throw new UsageError("A virtual model needs at least one member: pass --member <ref> (repeatable).");
147366
+ }
147367
+ setVirtualModel(paths, name, { mode: options.mode, members: options.member });
147368
+ console.log(`Defined virtual model "${name}" (${options.mode}): ${options.member.join(", ")}`);
147369
+ });
147370
+ withExamples(
147371
+ modelsCommand.command("set <name>").description("Change a virtual model's mode or replace its member list; members not named are kept.").option("--mode <mode>", "The new mode.", (value2) => asMode(value2)).option("--member <ref>", "Add or replace one member (repeatable).", collectRepeated),
147372
+ ["agent-shim model set fast --mode most-allowance"]
147373
+ ).action((name, options) => {
147374
+ const existing = readModels(paths)?.virtual?.[name];
147375
+ if (existing === void 0) {
147376
+ throw new VirtualModelNotFoundError(name);
147377
+ }
147378
+ if (options.mode === void 0 && options.member === void 0) {
147379
+ throw new UsageError("Nothing to change: pass --mode or --member.");
147380
+ }
147381
+ const members2 = options.member === void 0 ? existing.members : [.../* @__PURE__ */ new Set([...existing.members, ...options.member])];
147382
+ setVirtualModel(paths, name, { mode: options.mode ?? existing.mode, members: members2 });
147383
+ console.log(`Updated virtual model "${name}" (${options.mode ?? existing.mode}): ${members2.join(", ")}`);
147384
+ });
147385
+ withExamples(
147386
+ modelsCommand.command("remove <name>").description("Remove a virtual model definition.").option("--yes", "Remove without asking for confirmation.").option("--json", "Print the result as JSON."),
147387
+ ["agent-shim model remove fast --yes"]
147388
+ ).action(async (name, options) => {
147389
+ await confirmRemoval(deps, options.yes, `virtual model "${name}"`);
147390
+ removeVirtualModel(paths, name);
147391
+ reportMutation(options.json, { action: "removed", kind: "model", name, value: void 0 }, () => {
147392
+ console.log(`Removed virtual model "${name}".`);
147393
+ });
147394
+ });
147395
+ withExamples(
147396
+ modelsCommand.command("tier <tier>").description("Point one Claude tier (fable, opus, sonnet, haiku) at a model ref: a concrete target, an account model, a virtual model, or a family.").option("--ref <ref>", "The model ref the tier points at. Omit with --clear to reset the tier to its per-provider behaviour.").option("--clear", "Reset the tier to its per-provider behaviour."),
147397
+ ["agent-shim model tier opus --ref fast", "agent-shim model tier opus --clear"]
147398
+ ).action((tier, options) => {
147399
+ const which = asTier(tier);
147400
+ if (options.clear === true) {
147401
+ setTier(paths, which, void 0);
147402
+ console.log(`Tier ${which} reset to its per-provider behaviour.`);
147403
+ return;
147404
+ }
147405
+ if (options.ref === void 0) {
147406
+ throw new UsageError("Pass --ref <ref>, or --clear to reset the tier.");
147407
+ }
147408
+ setTier(paths, which, options.ref);
147409
+ console.log(`Tier ${which} points at ${options.ref}.`);
147410
+ });
147411
+ withExamples(
147412
+ modelsCommand.command("price <ref>").description("Set a model ref's prices, in USD per million tokens, for the cheapest mode.").option("--input <usd>", "The input price per million tokens.", (value2) => asPrice(value2)).option("--output <usd>", "The output price per million tokens.", (value2) => asPrice(value2)).option("--clear", "Remove the ref's prices instead."),
147413
+ ["agent-shim model price z/glm-5.3 --input 0.6 --output 2.2"]
147414
+ ).action((ref, options) => {
147415
+ if (options.clear !== true && (options.input === void 0 || options.output === void 0)) {
147416
+ throw new UsageError("Pass both --input and --output, or --clear to remove the ref's prices.");
147417
+ }
147418
+ setPrice(paths, ref, options.clear === true ? void 0 : { input: options.input ?? 0, output: options.output ?? 0 });
147419
+ console.log(options.clear === true ? `Removed prices for ${ref}.` : `Prices for ${ref}: ${String(options.input)} in, ${String(options.output)} out per million tokens.`);
147420
+ });
147421
+ withExamples(
147422
+ modelsCommand.command("list").description("List the defined virtual models, the tier pointers and the visibility filter.").option("--json", "Print the models block as JSON."),
147423
+ ["agent-shim model list"]
147424
+ ).action((options) => {
147425
+ const found = readModels(paths);
147426
+ if (options.json === true) {
147427
+ printJson(found ?? null);
147428
+ return;
147429
+ }
147430
+ if (found === void 0) {
147431
+ console.log("No models block is configured.");
147432
+ return;
147433
+ }
147434
+ for (const [name, model] of Object.entries(found.virtual ?? {})) {
147435
+ console.log(`${name} (${model.mode}): ${model.members.join(", ")}`);
147436
+ }
147437
+ for (const [tier, ref] of Object.entries(found.tiers ?? {})) {
147438
+ console.log(`tier ${tier} -> ${ref}`);
147439
+ }
147440
+ if (found.hide !== void 0) {
147441
+ console.log(`hidden: ${found.hide.join(", ")}`);
147442
+ }
147443
+ if (found.show !== void 0) {
147444
+ console.log(`visible only: ${found.show.join(", ")}`);
147445
+ }
147446
+ });
147447
+ }
147448
+ function asMode(value2) {
147449
+ const mode = SELECTION_MODES.find((candidate) => candidate === value2);
147450
+ if (mode === void 0) {
147451
+ throw new UsageError(`Unknown mode "${value2}". Known modes: ${SELECTION_MODES.join(", ")}.`);
147452
+ }
147453
+ return mode;
147454
+ }
147455
+ function asPrice(value2) {
147456
+ const parsed = Number(value2);
147457
+ if (!Number.isFinite(parsed) || parsed <= 0) {
147458
+ throw new UsageError(`"${value2}" is not a price: pass a positive number of US dollars.`);
147459
+ }
147460
+ return parsed;
147461
+ }
147462
+ function asTier(value2) {
147463
+ const tier = CLAUDE_TIERS.find((candidate) => candidate === value2);
147464
+ if (tier === void 0) {
147465
+ throw new UsageError(`Unknown tier "${value2}". Known tiers: ${CLAUDE_TIERS.join(", ")}.`);
147466
+ }
147467
+ return tier;
147005
147468
  }
147006
147469
 
147007
147470
  // src/directoryRules.ts