claude-use 11.40.5 → 11.42.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
@@ -26990,7 +26990,7 @@ function isTimeZone(name) {
26990
26990
  return false;
26991
26991
  }
26992
26992
  }
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;
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, FamilySettingsSchema, 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;
26994
26994
  var init_schema = __esm({
26995
26995
  "src/config/schema.ts"() {
26996
26996
  "use strict";
@@ -27237,6 +27237,14 @@ var init_schema = __esm({
27237
27237
  input: external_exports.number().positive(),
27238
27238
  output: external_exports.number().positive()
27239
27239
  });
27240
+ FamilySettingsSchema = external_exports.strictObject({
27241
+ names: external_exports.array(external_exports.string().min(1)).optional(),
27242
+ mode: external_exports.enum(SELECTION_MODES).optional(),
27243
+ context: external_exports.number().int().positive().optional(),
27244
+ vision: external_exports.boolean().optional(),
27245
+ tools: external_exports.boolean().optional(),
27246
+ thinking: external_exports.boolean().optional()
27247
+ });
27240
27248
  ModelsConfigSchema = external_exports.strictObject({
27241
27249
  /** Virtual models, by name. */
27242
27250
  virtual: external_exports.record(external_exports.string().min(1), VirtualModelSchema).optional(),
@@ -27252,7 +27260,13 @@ var init_schema = __esm({
27252
27260
  /** Model refs hidden from the picker and from routing, whatever else names them. */
27253
27261
  hide: external_exports.array(external_exports.string().min(1)).optional(),
27254
27262
  /** When set, the only model refs visible; everything else is hidden. */
27255
- show: external_exports.array(external_exports.string().min(1)).optional()
27263
+ show: external_exports.array(external_exports.string().min(1)).optional(),
27264
+ /** Assertions that each group of refs is one model under several names, overriding what the names alone say. */
27265
+ same: external_exports.array(external_exports.array(external_exports.string().min(1)).min(2)).optional(),
27266
+ /** Assertions that each pair of refs is two models however alike their names look. */
27267
+ distinct: external_exports.array(external_exports.tuple([external_exports.string().min(1), external_exports.string().min(1)])).optional(),
27268
+ /** Per-family settings and the names the normaliser cannot know, by family key. */
27269
+ families: external_exports.record(external_exports.string().min(1), FamilySettingsSchema).optional()
27256
27270
  });
27257
27271
  ModelsLayerSchema = external_exports.strictObject({
27258
27272
  virtual: external_exports.record(external_exports.string().min(1), external_exports.union([VirtualModelSchema, external_exports.null()])).optional(),
@@ -27264,7 +27278,10 @@ var init_schema = __esm({
27264
27278
  }).optional(),
27265
27279
  prices: external_exports.record(external_exports.string().min(1), external_exports.union([ModelPricesSchema, external_exports.null()])).optional(),
27266
27280
  hide: external_exports.array(external_exports.string().min(1)).optional(),
27267
- show: external_exports.array(external_exports.string().min(1)).optional()
27281
+ show: external_exports.array(external_exports.string().min(1)).optional(),
27282
+ same: external_exports.array(external_exports.array(external_exports.string().min(1)).min(2)).optional(),
27283
+ distinct: external_exports.array(external_exports.tuple([external_exports.string().min(1), external_exports.string().min(1)])).optional(),
27284
+ families: external_exports.record(external_exports.string().min(1), external_exports.union([FamilySettingsSchema, external_exports.null()])).optional()
27268
27285
  });
27269
27286
  ConfigProfileSchema = external_exports.strictObject({
27270
27287
  $schema: external_exports.string().optional(),
@@ -27511,6 +27528,9 @@ function pruneDeadFrontDoorDirectRecords(fs26, recordsDir, records, liveness) {
27511
27528
  }
27512
27529
  }
27513
27530
  }
27531
+ function recordOf(details) {
27532
+ return details === void 0 ? {} : { sessionId: details.sessionId, ...details.models === void 0 ? {} : { models: details.models } };
27533
+ }
27514
27534
  function writeFrontDoorSession(fs26, sessionsDir, session) {
27515
27535
  fs26.mkdirPrivate(sessionsDir);
27516
27536
  fs26.writeFilePrivate(import_node_path5.default.join(sessionsDir, `${String(session.pid)}.json`), `${JSON.stringify(session, null, 2)}
@@ -27563,14 +27583,31 @@ function liveSessionTokens(fs26, sessionsDir) {
27563
27583
  }
27564
27584
  return tokens;
27565
27585
  }
27586
+ function readFrontDoorSessionModels(fs26, sessionsDir, sessionId) {
27587
+ for (const name of fs26.readdir(sessionsDir)) {
27588
+ if (!name.endsWith(".json")) {
27589
+ continue;
27590
+ }
27591
+ try {
27592
+ const parsed = FrontDoorSessionSchema.safeParse(JSON.parse(fs26.readFileUtf8(import_node_path5.default.join(sessionsDir, name)) ?? ""));
27593
+ if (parsed.success && parsed.data.sessionId === sessionId) {
27594
+ return parsed.data.models;
27595
+ }
27596
+ } catch {
27597
+ continue;
27598
+ }
27599
+ }
27600
+ return void 0;
27601
+ }
27566
27602
  var import_node_path5, FRONT_DOOR_PROTOCOL, FrontDoorSessionSchema, FrontDoorStateSchema, MAX_TCP_PORT, FrontDoorDirectRecordSchema, RECORD_TEMPORARY_FILE;
27567
27603
  var init_state = __esm({
27568
27604
  "src/frontdoor/state.ts"() {
27569
27605
  "use strict";
27570
27606
  import_node_path5 = __toESM(require("node:path"), 1);
27571
27607
  init_zod();
27608
+ init_schema();
27572
27609
  FRONT_DOOR_PROTOCOL = 4;
27573
- FrontDoorSessionSchema = external_exports.strictObject({ pid: external_exports.number().int().positive(), startedAt: external_exports.number(), token: external_exports.string().min(1), supervisorPid: external_exports.number().int().positive().optional() });
27610
+ FrontDoorSessionSchema = external_exports.strictObject({ pid: external_exports.number().int().positive(), startedAt: external_exports.number(), token: external_exports.string().min(1), supervisorPid: external_exports.number().int().positive().optional(), sessionId: external_exports.string().min(1).optional(), models: ModelsConfigSchema.optional() });
27574
27611
  FrontDoorStateSchema = external_exports.strictObject({
27575
27612
  /**
27576
27613
  * The launcher-to-door wire protocol this supervisor speaks, written once it is serving; absent in state written by a release that predates the field, which `ensureFrontDoor` reads as protocol 0. A launcher replaces a door whose protocol is lower than its own (see `FRONT_DOOR_PROTOCOL`).
@@ -32125,7 +32162,8 @@ function assembleCascade(input2) {
32125
32162
  ...config2.categories === void 0 ? {} : { categories: config2.categories },
32126
32163
  ...config2.entries === void 0 ? {} : { entries: config2.entries },
32127
32164
  ...entryOrder === void 0 ? {} : { entryOrder },
32128
- ...config2.launch === void 0 ? {} : { launch: config2.launch }
32165
+ ...config2.launch === void 0 ? {} : { launch: config2.launch },
32166
+ ...config2.models === void 0 ? {} : { models: config2.models }
32129
32167
  });
32130
32168
  nextId += 1;
32131
32169
  }
@@ -32964,6 +33002,26 @@ function mergeModels(current, layer) {
32964
33002
  if (layer.show !== void 0) {
32965
33003
  pieces.show = layer.show;
32966
33004
  }
33005
+ if (layer.same !== void 0) {
33006
+ pieces.same = [...current?.same ?? [], ...layer.same.filter((group) => !(current?.same ?? []).some((known) => known.length === group.length && known.every((ref, index) => ref === group[index])))];
33007
+ }
33008
+ if (layer.distinct !== void 0) {
33009
+ pieces.distinct = [...current?.distinct ?? [], ...layer.distinct.filter(([left, right]) => !(current?.distinct ?? []).some(([a10, b]) => a10 === left && b === right))];
33010
+ }
33011
+ if (layer.families !== void 0) {
33012
+ const families = {};
33013
+ for (const [key, settings2] of Object.entries(current?.families ?? {})) {
33014
+ if (layer.families[key] === void 0) {
33015
+ families[key] = settings2;
33016
+ }
33017
+ }
33018
+ for (const [key, settings2] of Object.entries(layer.families)) {
33019
+ if (settings2 !== null) {
33020
+ families[key] = settings2;
33021
+ }
33022
+ }
33023
+ pieces.families = families;
33024
+ }
32967
33025
  const merged = modelsOf(pieces);
32968
33026
  return Object.keys(merged).length === 0 ? void 0 : merged;
32969
33027
  }
@@ -32973,7 +33031,10 @@ function modelsOf(pieces) {
32973
33031
  ...pieces.tiers === void 0 || Object.keys(pieces.tiers).length === 0 ? {} : { tiers: pieces.tiers },
32974
33032
  ...pieces.prices === void 0 || Object.keys(pieces.prices).length === 0 ? {} : { prices: pieces.prices },
32975
33033
  ...pieces.hide === void 0 || pieces.hide.length === 0 ? {} : { hide: [...pieces.hide] },
32976
- ...pieces.show === void 0 || pieces.show.length === 0 ? {} : { show: [...pieces.show] }
33034
+ ...pieces.show === void 0 || pieces.show.length === 0 ? {} : { show: [...pieces.show] },
33035
+ ...pieces.same === void 0 || pieces.same.length === 0 ? {} : { same: pieces.same.map((group) => [...group]) },
33036
+ ...pieces.distinct === void 0 || pieces.distinct.length === 0 ? {} : { distinct: pieces.distinct.map(([left, right]) => [left, right]) },
33037
+ ...pieces.families === void 0 || Object.keys(pieces.families).length === 0 ? {} : { families: pieces.families }
32977
33038
  };
32978
33039
  }
32979
33040
  var init_flatten = __esm({
@@ -34636,7 +34697,7 @@ var init_package = __esm({
34636
34697
  "package.json"() {
34637
34698
  package_default = {
34638
34699
  name: "claude-use",
34639
- version: "11.40.5",
34700
+ version: "11.42.0",
34640
34701
  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.",
34641
34702
  license: "MIT",
34642
34703
  author: "Joseph Mearman <joseph@mearman.co.uk>",
@@ -36211,6 +36272,219 @@ var init_realCredentialCache = __esm({
36211
36272
  }
36212
36273
  });
36213
36274
 
36275
+ // src/models/identity.ts
36276
+ function withoutContextMarker(model) {
36277
+ return model.toLowerCase().endsWith(CONTEXT_MARKER_1M) ? model.slice(0, -CONTEXT_MARKER_1M.length) : model;
36278
+ }
36279
+ function canonicalText(name) {
36280
+ return name.trim().toLowerCase().replace(NON_IDENTITY_BRACKET_RE, "").replace(/[\s_]+/g, "-").replace(/([a-z])(\d+(?:\.\d+)+)/g, "$1-$2").replace(/-+/g, "-").replace(/^-|-$/g, "");
36281
+ }
36282
+ function splitVariants(tokens) {
36283
+ const variants = [];
36284
+ let end = tokens.length;
36285
+ for (; ; ) {
36286
+ const token = tokens[end - 1];
36287
+ if (token === void 0 || !KNOWN_VARIANTS.has(token)) {
36288
+ return { familyTokens: tokens.slice(0, end), variants };
36289
+ }
36290
+ variants.unshift(token);
36291
+ end -= 1;
36292
+ }
36293
+ }
36294
+ function versionOf(tokens) {
36295
+ for (let index = 0; index < tokens.length; index += 1) {
36296
+ const token = tokens[index];
36297
+ const next = tokens[index + 1];
36298
+ if (token === void 0) {
36299
+ return "";
36300
+ }
36301
+ if (/^\d+$/.test(token) && next !== void 0 && /^\d+$/.test(next)) {
36302
+ return `${token}.${next}`;
36303
+ }
36304
+ const dotted = /^\d+(?:\.\d+)+$/.exec(token);
36305
+ if (dotted !== null) {
36306
+ return dotted[0];
36307
+ }
36308
+ }
36309
+ return "";
36310
+ }
36311
+ function modelIdentity(rawName) {
36312
+ const segments = rawName.trim().toLowerCase().split("/");
36313
+ const stripped = canonicalText(segments[segments.length - 1] ?? "").split(":")[0] ?? "";
36314
+ const withoutDate = stripped.replace(DATE_STAMP_RE, "");
36315
+ const tokens = withoutDate.split("-").filter((token) => token !== "");
36316
+ const { familyTokens, variants } = splitVariants(tokens);
36317
+ const version2 = versionOf(familyTokens);
36318
+ const versionless = familyTokens.filter((token, index) => {
36319
+ if (version2 === "") {
36320
+ return true;
36321
+ }
36322
+ const dotted = /^\d+(?:\.\d+)+$/.test(token);
36323
+ const previous = familyTokens[index - 1];
36324
+ const next = familyTokens[index + 1];
36325
+ const insideVersionRun = dotted || /^\d+$/.test(token) && (previous !== void 0 && /^\d+$/.test(previous) || next !== void 0 && /^\d+$/.test(next));
36326
+ return !insideVersionRun;
36327
+ });
36328
+ const family = versionless.join("-");
36329
+ const tokenVendor = familyTokens.find((token) => Object.keys(VENDOR_BY_TOKEN).some((key) => token === key || token.startsWith(key)));
36330
+ const namespace = segments.length >= 2 ? (segments[0] ?? "").split(":").pop() ?? "" : "";
36331
+ const namespaceVendor = VENDOR_BY_NAMESPACE[namespace] ?? "";
36332
+ const tokenVendorName = tokenVendor === void 0 ? "" : VENDOR_BY_TOKEN[Object.keys(VENDOR_BY_TOKEN).find((key) => tokenVendor === key || tokenVendor.startsWith(key)) ?? ""] ?? "";
36333
+ return {
36334
+ vendor: tokenVendorName === "" ? namespaceVendor : tokenVendorName,
36335
+ vendorConflict: tokenVendorName !== "" && namespaceVendor !== "" && tokenVendorName !== namespaceVendor,
36336
+ family,
36337
+ version: version2,
36338
+ variant: variants.join("-"),
36339
+ familyAndVersion: version2 === "" ? family : `${family}-${version2.replace(/\./g, "-")}`
36340
+ };
36341
+ }
36342
+ function relateModels(left, right) {
36343
+ const a10 = modelIdentity(left);
36344
+ const b = modelIdentity(right);
36345
+ if (a10.familyAndVersion !== b.familyAndVersion) {
36346
+ return sameFamilyOtherVersion(a10, b) ? "similar" : "distinct";
36347
+ }
36348
+ if (a10.variant !== b.variant || a10.vendorConflict || b.vendorConflict || a10.vendor !== "" && b.vendor !== "" && a10.vendor !== b.vendor) {
36349
+ return "similar";
36350
+ }
36351
+ return "same";
36352
+ }
36353
+ function sameFamilyOtherVersion(a10, b) {
36354
+ if (a10.family !== b.family) {
36355
+ return false;
36356
+ }
36357
+ if (a10.vendor !== "" && b.vendor !== "" && a10.vendor !== b.vendor) {
36358
+ return false;
36359
+ }
36360
+ return true;
36361
+ }
36362
+ var NON_IDENTITY_BRACKET_RE, CONTEXT_MARKER_1M, DATE_STAMP_RE, KNOWN_VARIANTS, VENDOR_BY_NAMESPACE, VENDOR_BY_TOKEN;
36363
+ var init_identity2 = __esm({
36364
+ "src/models/identity.ts"() {
36365
+ "use strict";
36366
+ NON_IDENTITY_BRACKET_RE = /\[[^\]]*\]/g;
36367
+ CONTEXT_MARKER_1M = "[1m]";
36368
+ DATE_STAMP_RE = /-(?:19|20)\d{2}(?:0[1-9]|1[0-2])(?:0[1-9]|[12]\d|3[01])$/;
36369
+ KNOWN_VARIANTS = /* @__PURE__ */ new Set(["high", "medium", "low", "thinking", "xhigh", "max", "highspeed", "sol", "terra", "luna", "mini", "flash-lite", "turbo"]);
36370
+ VENDOR_BY_NAMESPACE = Object.freeze({
36371
+ anthropic: "anthropic",
36372
+ google: "google",
36373
+ openai: "openai",
36374
+ zai: "zai",
36375
+ "z-ai": "zai",
36376
+ minimax: "minimax",
36377
+ qwen: "qwen",
36378
+ deepseek: "deepseek",
36379
+ moonshot: "moonshot",
36380
+ meta: "meta",
36381
+ mistral: "mistral"
36382
+ });
36383
+ VENDOR_BY_TOKEN = Object.freeze({
36384
+ claude: "anthropic",
36385
+ gemini: "google",
36386
+ antigravity: "google",
36387
+ gpt: "openai",
36388
+ glm: "zai",
36389
+ minimax: "minimax",
36390
+ qwen: "qwen",
36391
+ deepseek: "deepseek",
36392
+ kimi: "moonshot",
36393
+ llama: "meta",
36394
+ mistral: "mistral",
36395
+ mixtral: "mistral"
36396
+ });
36397
+ }
36398
+ });
36399
+
36400
+ // src/models/families.ts
36401
+ function modelOf(ref) {
36402
+ const slash = ref.indexOf("/");
36403
+ return slash === -1 ? ref : ref.slice(slash + 1);
36404
+ }
36405
+ function familyKeyOf(rawModel) {
36406
+ const identity = modelIdentity(rawModel);
36407
+ return identity.variant === "" ? identity.familyAndVersion : `${identity.familyAndVersion}${VARIANT_SEPARATOR}${identity.variant}`;
36408
+ }
36409
+ function assertionsOf(models) {
36410
+ return { same: models?.same ?? [], distinct: models?.distinct ?? [] };
36411
+ }
36412
+ function sameModel(left, right, assertions) {
36413
+ if (assertions.distinct.some(([a10, b]) => a10 === left && b === right || a10 === right && b === left)) {
36414
+ return false;
36415
+ }
36416
+ const leftGroup = assertions.same.find((group) => group.includes(left));
36417
+ const rightGroup = assertions.same.find((group) => group.includes(right));
36418
+ if (leftGroup !== void 0 && leftGroup === rightGroup) {
36419
+ return true;
36420
+ }
36421
+ if (leftGroup !== void 0 && !leftGroup.includes(right) || rightGroup !== void 0 && !rightGroup.includes(left)) {
36422
+ return false;
36423
+ }
36424
+ return relateModels(modelOf(left), modelOf(right)) === "same";
36425
+ }
36426
+ function pinnedTo(settings2, ref) {
36427
+ return settings2?.names?.some((name) => name === ref || name === modelOf(ref)) === true;
36428
+ }
36429
+ function buildFamilies(refs, models) {
36430
+ const assertions = assertionsOf(models);
36431
+ const settingsByKey = models?.families ?? {};
36432
+ const groups = [];
36433
+ for (const ref of refs) {
36434
+ const pinnedKey = Object.entries(settingsByKey).find(([, settings2]) => pinnedTo(settings2, ref))?.[0];
36435
+ const joined2 = groups.find((group) => pinnedKey === void 0 ? group.refs.some((first) => sameModel(first, ref, assertions)) : group.key === pinnedKey);
36436
+ if (joined2 !== void 0) {
36437
+ joined2.refs.push(ref);
36438
+ } else {
36439
+ groups.push({ key: pinnedKey ?? familyKeyOf(modelOf(ref)), refs: [ref] });
36440
+ }
36441
+ }
36442
+ return groups.map((group) => ({ key: group.key, refs: group.refs, settings: settingsByKey[group.key] ?? {} }));
36443
+ }
36444
+ function familyNamed(families, member) {
36445
+ if (!member.startsWith(FAMILY_PREFIX)) {
36446
+ return void 0;
36447
+ }
36448
+ const key = member.slice(FAMILY_PREFIX.length);
36449
+ return families.find((family) => family.key === key);
36450
+ }
36451
+ function familyCapabilities(settings2) {
36452
+ return { vision: settings2.vision ?? true, tools: settings2.tools ?? true, thinking: settings2.thinking ?? true };
36453
+ }
36454
+ function familyMode(settings2) {
36455
+ return settings2.mode ?? "ordered";
36456
+ }
36457
+ function sharedFamilies(families) {
36458
+ return families.filter((family) => family.refs.length > 1);
36459
+ }
36460
+ function expandFamilyMembers(members2, families) {
36461
+ const expanded = [];
36462
+ for (const member of members2) {
36463
+ for (const ref of member.startsWith(FAMILY_PREFIX) ? familyNamed(families, member)?.refs ?? [] : [member]) {
36464
+ if (!expanded.includes(ref)) {
36465
+ expanded.push(ref);
36466
+ }
36467
+ }
36468
+ }
36469
+ return expanded;
36470
+ }
36471
+ function familyOfRef(families, ref) {
36472
+ return families.find((family) => family.refs.includes(ref));
36473
+ }
36474
+ function accountRefsOf(models) {
36475
+ const named = [...(models?.same ?? []).flat(), ...Object.values(models?.families ?? {}).flatMap((settings2) => settings2.names ?? [])];
36476
+ return [...new Set(named.filter((ref) => ref.startsWith("acct:")))];
36477
+ }
36478
+ var FAMILY_PREFIX, VARIANT_SEPARATOR;
36479
+ var init_families = __esm({
36480
+ "src/models/families.ts"() {
36481
+ "use strict";
36482
+ init_identity2();
36483
+ FAMILY_PREFIX = "family:";
36484
+ VARIANT_SEPARATOR = "+";
36485
+ }
36486
+ });
36487
+
36214
36488
  // src/providersStore.ts
36215
36489
  function providerJsonPath(paths, name) {
36216
36490
  return import_node_path29.default.join(paths.providersDir, `${name}.json`);
@@ -36505,8 +36779,15 @@ function resolveRoutedProviderCredentials(params) {
36505
36779
  }
36506
36780
  const virtualNames = new Set(Object.keys(models.virtual ?? {}));
36507
36781
  const providerNames = /* @__PURE__ */ new Set();
36782
+ const families = () => buildFamilies(params.targets?.() ?? [], models);
36508
36783
  const collect = (ref) => {
36509
- if (ref.startsWith("acct:") || ref.startsWith("family:") || virtualNames.has(ref)) {
36784
+ if (ref.startsWith(FAMILY_PREFIX)) {
36785
+ for (const target of expandFamilyMembers([ref], families())) {
36786
+ collect(target);
36787
+ }
36788
+ return;
36789
+ }
36790
+ if (ref.startsWith("acct:") || virtualNames.has(ref)) {
36510
36791
  return;
36511
36792
  }
36512
36793
  const [provider] = ref.split("/", 1);
@@ -36563,6 +36844,7 @@ var init_providersStore = __esm({
36563
36844
  init_cliError();
36564
36845
  init_credential();
36565
36846
  init_walk();
36847
+ init_families();
36566
36848
  ProviderNotFoundError = class extends CliError {
36567
36849
  constructor(name) {
36568
36850
  super(`No provider named "${name}". Run \`agent-shim provider add ${name}\` first.`);
@@ -62673,7 +62955,7 @@ function ensureFrontDoor(params) {
62673
62955
  if (state?.port !== void 0 && state.connectPort !== void 0) {
62674
62956
  if (supervisorPid === params.launcherPid && params.replace !== true && ports.isFrontDoorSupervisor(supervisorPid)) {
62675
62957
  const token = (0, import_node_crypto11.randomUUID)();
62676
- writeFrontDoorSession(ports.fs, paths.frontdoorSessionsDir, { pid: params.launcherPid, startedAt: ports.now(), token, supervisorPid });
62958
+ writeFrontDoorSession(ports.fs, paths.frontdoorSessionsDir, { pid: params.launcherPid, startedAt: ports.now(), token, supervisorPid, ...recordOf(params.session) });
62677
62959
  return { port: state.port, connectPort: state.connectPort, token };
62678
62960
  }
62679
62961
  const verdict = verifyWithRetry(state.port);
@@ -62687,7 +62969,7 @@ function ensureFrontDoor(params) {
62687
62969
  }
62688
62970
  if (verdict.ok) {
62689
62971
  const token = (0, import_node_crypto11.randomUUID)();
62690
- writeFrontDoorSession(ports.fs, paths.frontdoorSessionsDir, { pid: params.launcherPid, startedAt: ports.now(), token, supervisorPid });
62972
+ writeFrontDoorSession(ports.fs, paths.frontdoorSessionsDir, { pid: params.launcherPid, startedAt: ports.now(), token, supervisorPid, ...recordOf(params.session) });
62691
62973
  return { port: state.port, connectPort: state.connectPort, token };
62692
62974
  }
62693
62975
  lastRejection = `the listener on 127.0.0.1:${String(state.port)} (recorded for pid ${String(supervisorPid)}) failed authentication: ${verdict.reason}`;
@@ -62953,8 +63235,8 @@ function realRestartFrontDoor(paths, spawnDaemon) {
62953
63235
  }
62954
63236
  function realFrontDoorPort(paths, spawnDaemon) {
62955
63237
  return {
62956
- ensure: (inheritedExtraCaCerts) => {
62957
- const up2 = ensureFrontDoor({ paths, launcherPid: process.pid, ports: realEnsurePorts(paths, spawnDaemon) });
63238
+ ensure: (inheritedExtraCaCerts, session) => {
63239
+ const up2 = ensureFrontDoor({ paths, launcherPid: process.pid, ports: realEnsurePorts(paths, spawnDaemon), ...session === void 0 ? {} : { session } });
62958
63240
  const trust = resolveTrustBundle({ caCertFile: paths.frontdoorCaCertFile, bundlesDir: paths.frontdoorCaBundlesDir, variable: "NODE_EXTRA_CA_CERTS", inherited: inheritedExtraCaCerts, fs: realTrustBundleFs });
62959
63241
  return {
62960
63242
  port: up2.port,
@@ -63756,6 +64038,14 @@ function buildEnv(params) {
63756
64038
  env[key] = value2;
63757
64039
  }
63758
64040
  }
64041
+ if (params.routeByName) {
64042
+ for (const tier of CLAUDE_TIERS) {
64043
+ const ref = params.tierModels?.[tier];
64044
+ if (ref !== void 0) {
64045
+ env[`ANTHROPIC_DEFAULT_${tier.toUpperCase()}_MODEL`] = ref;
64046
+ }
64047
+ }
64048
+ }
63759
64049
  if (params.provider !== void 0) {
63760
64050
  env.ANTHROPIC_AUTH_TOKEN = params.remoteControl ? void 0 : PROVIDER_SESSION_PLACEHOLDER;
63761
64051
  env.ANTHROPIC_API_KEY = void 0;
@@ -63798,6 +64088,7 @@ var init_flags = __esm({
63798
64088
  init_envBool();
63799
64089
  init_cliError();
63800
64090
  init_conditions();
64091
+ init_schema();
63801
64092
  init_credential();
63802
64093
  init_headers();
63803
64094
  init_capability();
@@ -64176,131 +64467,6 @@ var init_launchReport = __esm({
64176
64467
  }
64177
64468
  });
64178
64469
 
64179
- // src/models/identity.ts
64180
- function withoutContextMarker(model) {
64181
- return model.toLowerCase().endsWith(CONTEXT_MARKER_1M) ? model.slice(0, -CONTEXT_MARKER_1M.length) : model;
64182
- }
64183
- function canonicalText(name) {
64184
- return name.trim().toLowerCase().replace(NON_IDENTITY_BRACKET_RE, "").replace(/[\s_]+/g, "-").replace(/([a-z])(\d+(?:\.\d+)+)/g, "$1-$2").replace(/-+/g, "-").replace(/^-|-$/g, "");
64185
- }
64186
- function splitVariants(tokens) {
64187
- const variants = [];
64188
- let end = tokens.length;
64189
- for (; ; ) {
64190
- const token = tokens[end - 1];
64191
- if (token === void 0 || !KNOWN_VARIANTS.has(token)) {
64192
- return { familyTokens: tokens.slice(0, end), variants };
64193
- }
64194
- variants.unshift(token);
64195
- end -= 1;
64196
- }
64197
- }
64198
- function versionOf(tokens) {
64199
- for (let index = 0; index < tokens.length; index += 1) {
64200
- const token = tokens[index];
64201
- const next = tokens[index + 1];
64202
- if (token === void 0) {
64203
- return "";
64204
- }
64205
- if (/^\d+$/.test(token) && next !== void 0 && /^\d+$/.test(next)) {
64206
- return `${token}.${next}`;
64207
- }
64208
- const dotted = /^\d+(?:\.\d+)+$/.exec(token);
64209
- if (dotted !== null) {
64210
- return dotted[0];
64211
- }
64212
- }
64213
- return "";
64214
- }
64215
- function modelIdentity(rawName) {
64216
- const segments = rawName.trim().toLowerCase().split("/");
64217
- const stripped = canonicalText(segments[segments.length - 1] ?? "").split(":")[0] ?? "";
64218
- const withoutDate = stripped.replace(DATE_STAMP_RE, "");
64219
- const tokens = withoutDate.split("-").filter((token) => token !== "");
64220
- const { familyTokens, variants } = splitVariants(tokens);
64221
- const version2 = versionOf(familyTokens);
64222
- const versionless = familyTokens.filter((token, index) => {
64223
- if (version2 === "") {
64224
- return true;
64225
- }
64226
- const dotted = /^\d+(?:\.\d+)+$/.test(token);
64227
- const previous = familyTokens[index - 1];
64228
- const next = familyTokens[index + 1];
64229
- const insideVersionRun = dotted || /^\d+$/.test(token) && (previous !== void 0 && /^\d+$/.test(previous) || next !== void 0 && /^\d+$/.test(next));
64230
- return !insideVersionRun;
64231
- });
64232
- const family = versionless.join("-");
64233
- const tokenVendor = familyTokens.find((token) => Object.keys(VENDOR_BY_TOKEN).some((key) => token === key || token.startsWith(key)));
64234
- const namespace = segments.length >= 2 ? (segments[0] ?? "").split(":").pop() ?? "" : "";
64235
- const namespaceVendor = VENDOR_BY_NAMESPACE[namespace] ?? "";
64236
- const tokenVendorName = tokenVendor === void 0 ? "" : VENDOR_BY_TOKEN[Object.keys(VENDOR_BY_TOKEN).find((key) => tokenVendor === key || tokenVendor.startsWith(key)) ?? ""] ?? "";
64237
- return {
64238
- vendor: tokenVendorName === "" ? namespaceVendor : tokenVendorName,
64239
- vendorConflict: tokenVendorName !== "" && namespaceVendor !== "" && tokenVendorName !== namespaceVendor,
64240
- family,
64241
- version: version2,
64242
- variant: variants.join("-"),
64243
- familyAndVersion: version2 === "" ? family : `${family}-${version2.replace(/\./g, "-")}`
64244
- };
64245
- }
64246
- function relateModels(left, right) {
64247
- const a10 = modelIdentity(left);
64248
- const b = modelIdentity(right);
64249
- if (a10.familyAndVersion !== b.familyAndVersion) {
64250
- return sameFamilyOtherVersion(a10, b) ? "similar" : "distinct";
64251
- }
64252
- if (a10.variant !== b.variant || a10.vendorConflict || b.vendorConflict || a10.vendor !== "" && b.vendor !== "" && a10.vendor !== b.vendor) {
64253
- return "similar";
64254
- }
64255
- return "same";
64256
- }
64257
- function sameFamilyOtherVersion(a10, b) {
64258
- if (a10.family !== b.family) {
64259
- return false;
64260
- }
64261
- if (a10.vendor !== "" && b.vendor !== "" && a10.vendor !== b.vendor) {
64262
- return false;
64263
- }
64264
- return true;
64265
- }
64266
- var NON_IDENTITY_BRACKET_RE, CONTEXT_MARKER_1M, DATE_STAMP_RE, KNOWN_VARIANTS, VENDOR_BY_NAMESPACE, VENDOR_BY_TOKEN;
64267
- var init_identity2 = __esm({
64268
- "src/models/identity.ts"() {
64269
- "use strict";
64270
- NON_IDENTITY_BRACKET_RE = /\[[^\]]*\]/g;
64271
- CONTEXT_MARKER_1M = "[1m]";
64272
- DATE_STAMP_RE = /-(?:19|20)\d{2}(?:0[1-9]|1[0-2])(?:0[1-9]|[12]\d|3[01])$/;
64273
- KNOWN_VARIANTS = /* @__PURE__ */ new Set(["high", "medium", "low", "thinking", "xhigh", "max", "highspeed", "sol", "terra", "luna", "mini", "flash-lite", "turbo"]);
64274
- VENDOR_BY_NAMESPACE = Object.freeze({
64275
- anthropic: "anthropic",
64276
- google: "google",
64277
- openai: "openai",
64278
- zai: "zai",
64279
- "z-ai": "zai",
64280
- minimax: "minimax",
64281
- qwen: "qwen",
64282
- deepseek: "deepseek",
64283
- moonshot: "moonshot",
64284
- meta: "meta",
64285
- mistral: "mistral"
64286
- });
64287
- VENDOR_BY_TOKEN = Object.freeze({
64288
- claude: "anthropic",
64289
- gemini: "google",
64290
- antigravity: "google",
64291
- gpt: "openai",
64292
- glm: "zai",
64293
- minimax: "minimax",
64294
- qwen: "qwen",
64295
- deepseek: "deepseek",
64296
- kimi: "moonshot",
64297
- llama: "meta",
64298
- mistral: "mistral",
64299
- mixtral: "mistral"
64300
- });
64301
- }
64302
- });
64303
-
64304
64470
  // src/selection/engine.ts
64305
64471
  function compareMaybe(left, right, preferHigh) {
64306
64472
  if (left === void 0 && right === void 0) {
@@ -65443,7 +65609,7 @@ function catalogueUrls(provider, catalogue) {
65443
65609
  function isRecord9(value2) {
65444
65610
  return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
65445
65611
  }
65446
- function modelOf(entry) {
65612
+ function modelOf2(entry) {
65447
65613
  if (typeof entry === "string") {
65448
65614
  return entry.trim() === "" ? void 0 : { id: entry.trim() };
65449
65615
  }
@@ -65459,7 +65625,7 @@ function parseCatalogueBody(body) {
65459
65625
  const seen = /* @__PURE__ */ new Set();
65460
65626
  const models = [];
65461
65627
  for (const entry of list) {
65462
- const model = modelOf(entry);
65628
+ const model = modelOf2(entry);
65463
65629
  if (model !== void 0 && !seen.has(model.id)) {
65464
65630
  seen.add(model.id);
65465
65631
  models.push(model);
@@ -65524,6 +65690,156 @@ var init_providerCatalogue = __esm({
65524
65690
  }
65525
65691
  });
65526
65692
 
65693
+ // src/modelsStore.ts
65694
+ function readModels(paths) {
65695
+ return readGlobalConfig(paths)?.models;
65696
+ }
65697
+ function writeModels(paths, models) {
65698
+ const emptied = models !== void 0 && Object.keys(models).length === 0 ? void 0 : models;
65699
+ applyPatch(paths.globalConfigFile, GlobalConfigSchema, { models: emptied }, { defaults: {} });
65700
+ }
65701
+ function stripEmpty(models) {
65702
+ const kept = {};
65703
+ if (models.virtual !== void 0 && Object.keys(models.virtual).length > 0) {
65704
+ kept.virtual = models.virtual;
65705
+ }
65706
+ if (models.tiers !== void 0 && Object.keys(models.tiers).length > 0) {
65707
+ kept.tiers = models.tiers;
65708
+ }
65709
+ if (models.prices !== void 0 && Object.keys(models.prices).length > 0) {
65710
+ kept.prices = models.prices;
65711
+ }
65712
+ if (models.hide !== void 0 && models.hide.length > 0) {
65713
+ kept.hide = models.hide;
65714
+ }
65715
+ if (models.show !== void 0 && models.show.length > 0) {
65716
+ kept.show = models.show;
65717
+ }
65718
+ if (models.same !== void 0 && models.same.length > 0) {
65719
+ kept.same = models.same;
65720
+ }
65721
+ if (models.distinct !== void 0 && models.distinct.length > 0) {
65722
+ kept.distinct = models.distinct;
65723
+ }
65724
+ if (models.families !== void 0 && Object.keys(models.families).length > 0) {
65725
+ kept.families = models.families;
65726
+ }
65727
+ return kept;
65728
+ }
65729
+ function memberKindOf(ref, models) {
65730
+ if (ref.startsWith("acct:")) {
65731
+ return "account";
65732
+ }
65733
+ if (ref.startsWith("family:")) {
65734
+ return "family";
65735
+ }
65736
+ return models?.virtual !== void 0 && ref in models.virtual ? "virtual" : "provider";
65737
+ }
65738
+ function expandMembers(name, models) {
65739
+ const virtual = models?.virtual ?? {};
65740
+ const expanded = [];
65741
+ const walk2 = (current, chain) => {
65742
+ const nested = virtual[current];
65743
+ if (nested !== void 0) {
65744
+ if (chain.includes(current)) {
65745
+ throw new Error(`virtual model cycle: ${[...chain, current].join(" -> ")}`);
65746
+ }
65747
+ for (const member of nested.members) {
65748
+ walk2(member, [...chain, current]);
65749
+ }
65750
+ return;
65751
+ }
65752
+ if (!expanded.includes(current)) {
65753
+ expanded.push(current);
65754
+ }
65755
+ };
65756
+ const top = virtual[name];
65757
+ if (top === void 0) {
65758
+ throw new VirtualModelNotFoundError(name);
65759
+ }
65760
+ for (const member of top.members) {
65761
+ walk2(member, [name]);
65762
+ }
65763
+ return expanded;
65764
+ }
65765
+ function setVirtualModel(paths, name, model) {
65766
+ const current = readModels(paths) ?? {};
65767
+ writeModels(paths, { ...current, virtual: { ...current.virtual ?? {}, [name]: model } });
65768
+ }
65769
+ function removeVirtualModel(paths, name) {
65770
+ const current = readModels(paths);
65771
+ if (current?.virtual?.[name] === void 0) {
65772
+ throw new VirtualModelNotFoundError(name);
65773
+ }
65774
+ const virtual = Object.fromEntries(Object.entries(current.virtual ?? {}).filter(([existing]) => existing !== name));
65775
+ writeModels(paths, stripEmpty({ ...current, virtual: Object.keys(virtual).length === 0 ? void 0 : virtual }));
65776
+ }
65777
+ function setPrice(paths, ref, prices) {
65778
+ const current = readModels(paths) ?? {};
65779
+ const priced = Object.fromEntries(Object.entries(current.prices ?? {}).filter(([existing]) => existing !== ref));
65780
+ const next = prices === void 0 ? priced : { ...priced, [ref]: prices };
65781
+ writeModels(paths, stripEmpty({ ...current, prices: Object.keys(next).length === 0 ? void 0 : next }));
65782
+ }
65783
+ function setTier(paths, tier, ref) {
65784
+ const current = readModels(paths) ?? {};
65785
+ const tiers = {};
65786
+ const merged = { ...current.tiers ?? {}, [tier]: ref };
65787
+ for (const [key, value2] of Object.entries(merged)) {
65788
+ if (value2 !== void 0) {
65789
+ tiers[key] = value2;
65790
+ }
65791
+ }
65792
+ writeModels(paths, stripEmpty({ ...current, tiers: Object.keys(tiers).length === 0 ? void 0 : tiers }));
65793
+ }
65794
+ function addSameGroup(paths, refs) {
65795
+ const current = readModels(paths) ?? {};
65796
+ const overlapping = (current.same ?? []).filter((group) => group.some((ref) => refs.includes(ref)));
65797
+ const rest = (current.same ?? []).filter((group) => !overlapping.includes(group));
65798
+ const joined2 = [.../* @__PURE__ */ new Set([...overlapping.flat(), ...refs])];
65799
+ writeModels(paths, stripEmpty({ ...current, same: [...rest, joined2] }));
65800
+ }
65801
+ function addDistinctPair(paths, left, right) {
65802
+ const current = readModels(paths) ?? {};
65803
+ const known = (current.distinct ?? []).some(([a10, b]) => a10 === left && b === right || a10 === right && b === left);
65804
+ if (!known) {
65805
+ writeModels(paths, stripEmpty({ ...current, distinct: [...current.distinct ?? [], [left, right]] }));
65806
+ }
65807
+ }
65808
+ function removeAssertionsNaming(paths, ref) {
65809
+ const current = readModels(paths);
65810
+ if (current === void 0) {
65811
+ return 0;
65812
+ }
65813
+ const same = (current.same ?? []).filter((group) => !group.includes(ref));
65814
+ const distinct = (current.distinct ?? []).filter(([left, right]) => left !== ref && right !== ref);
65815
+ const removed = (current.same ?? []).length - same.length + ((current.distinct ?? []).length - distinct.length);
65816
+ if (removed > 0) {
65817
+ writeModels(paths, stripEmpty({ ...current, same: same.length === 0 ? void 0 : same, distinct: distinct.length === 0 ? void 0 : distinct }));
65818
+ }
65819
+ return removed;
65820
+ }
65821
+ function setFamily(paths, key, settings2) {
65822
+ const current = readModels(paths) ?? {};
65823
+ const others = Object.fromEntries(Object.entries(current.families ?? {}).filter(([existing]) => existing !== key));
65824
+ const next = settings2 === void 0 ? others : { ...others, [key]: settings2 };
65825
+ writeModels(paths, stripEmpty({ ...current, families: Object.keys(next).length === 0 ? void 0 : next }));
65826
+ }
65827
+ var VirtualModelNotFoundError;
65828
+ var init_modelsStore = __esm({
65829
+ "src/modelsStore.ts"() {
65830
+ "use strict";
65831
+ init_store();
65832
+ init_schema();
65833
+ init_configProfilesStore();
65834
+ VirtualModelNotFoundError = class extends Error {
65835
+ constructor(name) {
65836
+ super(`No virtual model named "${name}".`);
65837
+ this.name = "VirtualModelNotFoundError";
65838
+ }
65839
+ };
65840
+ }
65841
+ });
65842
+
65527
65843
  // src/launcher/modelPicker.ts
65528
65844
  function labelOf(model) {
65529
65845
  return withoutContextMarker(model);
@@ -65610,30 +65926,29 @@ function routedModelRows(models, providers) {
65610
65926
  const hidden = new Set(models.hide ?? []);
65611
65927
  const shown = models.show === void 0 ? void 0 : new Set(models.show);
65612
65928
  const visible = (model) => shown === void 0 ? !hidden.has(model) : shown.has(model);
65613
- const tierOf = (model) => {
65614
- for (const [, provider] of providers) {
65615
- if (provider.kind !== void 0 && provider.kind !== "http") {
65616
- continue;
65617
- }
65618
- const match = Object.entries(provider.env ?? {}).find(([key, value2]) => value2 === model && key.startsWith("ANTHROPIC_DEFAULT_") && key.endsWith("_MODEL"));
65619
- if (match !== void 0) {
65620
- const tier = match[0].replace("ANTHROPIC_DEFAULT_", "").replace("_MODEL", "").toLowerCase();
65621
- return tier === "fable" || tier === "opus" || tier === "sonnet" || tier === "haiku" ? tier : void 0;
65622
- }
65623
- }
65624
- return void 0;
65625
- };
65929
+ const concrete = providers.flatMap(([name, provider]) => providerModelRows(provider).map((row) => ({ ...row, model: `${name}/${row.model}`, label: `${name} / ${row.label}`, description: `${name}: ${row.description}` })));
65930
+ const concreteByRef = new Map(concrete.map((row) => [row.model, row]));
65931
+ const families = buildFamilies([...concrete.map((row) => row.model), ...accountRefsOf(models)], models);
65932
+ const handlingOf = (refs) => refs.map((ref) => concreteByRef.get(ref)?.behavesAs).find((behavesAs) => behavesAs !== void 0) ?? TIER_BEHAVES_AS.sonnet;
65626
65933
  const virtual = Object.entries(models.virtual ?? {}).flatMap(([name, definition]) => {
65627
65934
  if (!visible(name)) {
65628
65935
  return [];
65629
65936
  }
65630
- const first = definition.members.find((member) => member.includes("/"));
65631
- const tier = first === void 0 ? void 0 : tierOf(first.split("/").slice(1).join("/"));
65632
- const behavesAs = tier === void 0 ? void 0 : TIER_BEHAVES_AS[tier];
65633
- return behavesAs === void 0 ? [] : [{ model: name, label: name, description: `Virtual (${definition.mode})`, behavesAs }];
65937
+ const targets = expandFamilyMembers(safeExpand(name, models), families);
65938
+ return [{ model: name, label: name, description: `Virtual (${definition.mode})`, behavesAs: handlingOf(targets) }];
65634
65939
  });
65635
- const concrete = providers.flatMap(([name, provider]) => providerModelRows(provider).map((row) => ({ ...row, model: `${name}/${row.model}`, label: `${name} / ${row.label}`, description: `${name}: ${row.description}` })));
65636
- return [...virtual, ...concrete.filter((row) => visible(row.model))];
65940
+ const familyRows = sharedFamilies(families).flatMap((family) => {
65941
+ const member = `${FAMILY_PREFIX}${family.key}`;
65942
+ return visible(member) ? [{ model: member, label: family.key, description: `Family (${familyMode(family.settings)}): ${family.refs.join(", ")}`, behavesAs: handlingOf(family.refs) }] : [];
65943
+ });
65944
+ return [...virtual, ...familyRows, ...concrete.filter((row) => visible(row.model))];
65945
+ }
65946
+ function safeExpand(name, models) {
65947
+ try {
65948
+ return expandMembers(name, models);
65949
+ } catch {
65950
+ return models.virtual?.[name]?.members ?? [];
65951
+ }
65637
65952
  }
65638
65953
  function modelPickerSettings(provider, catalogue = []) {
65639
65954
  return modelPickerSettingsFromRows(providerModelRows(provider, catalogue), true);
@@ -65650,6 +65965,8 @@ var init_modelPicker = __esm({
65650
65965
  init_providerCatalogue();
65651
65966
  init_schema();
65652
65967
  init_identity2();
65968
+ init_families();
65969
+ init_modelsStore();
65653
65970
  TIER_BEHAVES_AS = Object.freeze({
65654
65971
  fable: "claude-fable-5-1",
65655
65972
  opus: "claude-opus-5-5",
@@ -65665,114 +65982,6 @@ var init_modelPicker = __esm({
65665
65982
  }
65666
65983
  });
65667
65984
 
65668
- // src/modelsStore.ts
65669
- function readModels(paths) {
65670
- return readGlobalConfig(paths)?.models;
65671
- }
65672
- function writeModels(paths, models) {
65673
- const emptied = models !== void 0 && Object.keys(models).length === 0 ? void 0 : models;
65674
- applyPatch(paths.globalConfigFile, GlobalConfigSchema, { models: emptied }, { defaults: {} });
65675
- }
65676
- function stripEmpty(models) {
65677
- const kept = {};
65678
- if (models.virtual !== void 0 && Object.keys(models.virtual).length > 0) {
65679
- kept.virtual = models.virtual;
65680
- }
65681
- if (models.tiers !== void 0 && Object.keys(models.tiers).length > 0) {
65682
- kept.tiers = models.tiers;
65683
- }
65684
- if (models.prices !== void 0 && Object.keys(models.prices).length > 0) {
65685
- kept.prices = models.prices;
65686
- }
65687
- if (models.hide !== void 0 && models.hide.length > 0) {
65688
- kept.hide = models.hide;
65689
- }
65690
- if (models.show !== void 0 && models.show.length > 0) {
65691
- kept.show = models.show;
65692
- }
65693
- return kept;
65694
- }
65695
- function memberKindOf(ref, models) {
65696
- if (ref.startsWith("acct:")) {
65697
- return "account";
65698
- }
65699
- if (ref.startsWith("family:")) {
65700
- return "family";
65701
- }
65702
- return models?.virtual !== void 0 && ref in models.virtual ? "virtual" : "provider";
65703
- }
65704
- function expandMembers(name, models) {
65705
- const virtual = models?.virtual ?? {};
65706
- const expanded = [];
65707
- const walk2 = (current, chain) => {
65708
- const nested = virtual[current];
65709
- if (nested !== void 0) {
65710
- if (chain.includes(current)) {
65711
- throw new Error(`virtual model cycle: ${[...chain, current].join(" -> ")}`);
65712
- }
65713
- for (const member of nested.members) {
65714
- walk2(member, [...chain, current]);
65715
- }
65716
- return;
65717
- }
65718
- if (!expanded.includes(current)) {
65719
- expanded.push(current);
65720
- }
65721
- };
65722
- const top = virtual[name];
65723
- if (top === void 0) {
65724
- throw new VirtualModelNotFoundError(name);
65725
- }
65726
- for (const member of top.members) {
65727
- walk2(member, [name]);
65728
- }
65729
- return expanded;
65730
- }
65731
- function setVirtualModel(paths, name, model) {
65732
- const current = readModels(paths) ?? {};
65733
- writeModels(paths, { ...current, virtual: { ...current.virtual ?? {}, [name]: model } });
65734
- }
65735
- function removeVirtualModel(paths, name) {
65736
- const current = readModels(paths);
65737
- if (current?.virtual?.[name] === void 0) {
65738
- throw new VirtualModelNotFoundError(name);
65739
- }
65740
- const virtual = Object.fromEntries(Object.entries(current.virtual ?? {}).filter(([existing]) => existing !== name));
65741
- writeModels(paths, stripEmpty({ ...current, virtual: Object.keys(virtual).length === 0 ? void 0 : virtual }));
65742
- }
65743
- function setPrice(paths, ref, prices) {
65744
- const current = readModels(paths) ?? {};
65745
- const priced = Object.fromEntries(Object.entries(current.prices ?? {}).filter(([existing]) => existing !== ref));
65746
- const next = prices === void 0 ? priced : { ...priced, [ref]: prices };
65747
- writeModels(paths, stripEmpty({ ...current, prices: Object.keys(next).length === 0 ? void 0 : next }));
65748
- }
65749
- function setTier(paths, tier, ref) {
65750
- const current = readModels(paths) ?? {};
65751
- const tiers = {};
65752
- const merged = { ...current.tiers ?? {}, [tier]: ref };
65753
- for (const [key, value2] of Object.entries(merged)) {
65754
- if (value2 !== void 0) {
65755
- tiers[key] = value2;
65756
- }
65757
- }
65758
- writeModels(paths, stripEmpty({ ...current, tiers: Object.keys(tiers).length === 0 ? void 0 : tiers }));
65759
- }
65760
- var VirtualModelNotFoundError;
65761
- var init_modelsStore = __esm({
65762
- "src/modelsStore.ts"() {
65763
- "use strict";
65764
- init_store();
65765
- init_schema();
65766
- init_configProfilesStore();
65767
- VirtualModelNotFoundError = class extends Error {
65768
- constructor(name) {
65769
- super(`No virtual model named "${name}".`);
65770
- this.name = "VirtualModelNotFoundError";
65771
- }
65772
- };
65773
- }
65774
- });
65775
-
65776
65985
  // src/launcher/pool.ts
65777
65986
  function isResuming(passthrough) {
65778
65987
  const end = passthrough.indexOf(TERMINATOR3);
@@ -65972,6 +66181,26 @@ var init_launchHook = __esm({
65972
66181
  }
65973
66182
  });
65974
66183
 
66184
+ // src/models/targets.ts
66185
+ function providerModels(paths) {
66186
+ return listProviders(paths).flatMap((entry) => {
66187
+ const catalogue = parseCatalogueCache(realFsPort.readFileUtf8(catalogueCachePath(paths, entry.name)));
66188
+ return providerModelRows(entry.provider, catalogue?.models).map((row) => ({ provider: entry.name, model: row.model }));
66189
+ });
66190
+ }
66191
+ function targetRefs(paths) {
66192
+ return providerModels(paths).map((entry) => `${entry.provider}/${entry.model}`);
66193
+ }
66194
+ var init_targets = __esm({
66195
+ "src/models/targets.ts"() {
66196
+ "use strict";
66197
+ init_modelPicker();
66198
+ init_providerCatalogue();
66199
+ init_providersStore();
66200
+ init_realPorts();
66201
+ }
66202
+ });
66203
+
65975
66204
  // src/launcher.ts
65976
66205
  function resolveIdentityCredential(identity, credential, env, port) {
65977
66206
  if (port === void 0) {
@@ -66163,10 +66392,12 @@ function decideLaunch(params, readOnly) {
66163
66392
  }
66164
66393
  const launchCascade = farmContext?.cascade ?? (params.farm === void 0 ? void 0 : params.farm.loadCascade(configProfileDecision.name, cliOverride));
66165
66394
  let cascadeLaunch;
66395
+ let cascadeModels;
66166
66396
  if (launchCascade !== void 0 && params.farm !== void 0) {
66167
66397
  const assembled = assembleCascade(launchCascade);
66168
66398
  const flattened = flattenLayers(assembled.layers, { home: params.farm.home });
66169
66399
  cascadeLaunch = flattened.launch;
66400
+ cascadeModels = flattened.models;
66170
66401
  if (readOnly || farmContext === void 0) {
66171
66402
  reportDiagnostics(log, [...assembled.diagnostics, ...flattened.diagnostics], { errorsAsWarnings: readOnly });
66172
66403
  }
@@ -66195,7 +66426,9 @@ function decideLaunch(params, readOnly) {
66195
66426
  const flags = loginlessProvider === void 0 ? requestedFlags : { ...requestedFlags, remoteControl: false };
66196
66427
  const catalogue = selectedProvider === void 0 ? void 0 : parseCatalogueCache(params.fs.readFileUtf8(catalogueCachePath(paths, selectedProvider.name)));
66197
66428
  const routesByName = flags.routeByName || selectedProvider !== void 0 && isRouterProvider(selectedProvider.definition);
66198
- const pickerSettings = routesByName ? modelPickerSettingsFromRows(routedModelRows(readModels(paths) ?? {}, listProviders(paths).map((entry) => [entry.name, entry.provider])), selectedProvider !== void 0) : selectedProvider === void 0 ? void 0 : modelPickerSettings(selectedProvider.definition, catalogue?.models);
66429
+ const globalModels = loadConfigFile(paths.globalConfigFile, GlobalConfigSchema, params.fs.readConfigFile)?.config.models;
66430
+ const models = launchCascade !== void 0 && params.farm !== void 0 ? cascadeModels : globalModels;
66431
+ const pickerSettings = routesByName ? modelPickerSettingsFromRows(routedModelRows(models ?? {}, listProviders(paths).map((entry) => [entry.name, entry.provider])), selectedProvider !== void 0) : selectedProvider === void 0 ? void 0 : modelPickerSettings(selectedProvider.definition, catalogue?.models);
66199
66432
  const callerSettings = hasSettingsArgument(parsedArgv.rest);
66200
66433
  if (pickerSettings !== void 0 && callerSettings) {
66201
66434
  notes.push("--settings was passed, so /model keeps Claude Code's own model names");
@@ -66233,6 +66466,8 @@ function decideLaunch(params, readOnly) {
66233
66466
  identityCredential,
66234
66467
  pinnedVersion,
66235
66468
  flags,
66469
+ models,
66470
+ globalModels,
66236
66471
  bin: discovered.path,
66237
66472
  args,
66238
66473
  decision
@@ -66299,7 +66534,7 @@ function prepareLaunch(params) {
66299
66534
  }
66300
66535
  const routesByName = resolvedFlags.routeByName || resolvedProvider !== void 0 && isRouterProvider(resolvedProvider.definition);
66301
66536
  if (routesByName) {
66302
- const check2 = resolveRoutedProviderCredentials({ paths, port: params.fs, env, ...params.credentials === void 0 ? {} : { credentials: params.credentials }, models: loadConfigFile(paths.globalConfigFile, GlobalConfigSchema, params.fs.readConfigFile)?.config.models });
66537
+ const check2 = resolveRoutedProviderCredentials({ paths, port: params.fs, env, ...params.credentials === void 0 ? {} : { credentials: params.credentials }, models: decided.models, targets: () => targetRefs(paths) });
66303
66538
  if (!check2.ok) {
66304
66539
  log.error(check2.message);
66305
66540
  proc.exit(check2.status);
@@ -66311,7 +66546,10 @@ function prepareLaunch(params) {
66311
66546
  log.error("agent-shim: this launch routes through the front-door daemon, but this launcher has no front-door port wired; refusing to launch without it.");
66312
66547
  proc.exit(1);
66313
66548
  }
66314
- const frontDoor = frontDoorEngaged && frontDoorPort !== void 0 ? frontDoorPort.ensure(env.NODE_EXTRA_CA_CERTS) : void 0;
66549
+ const sessionId = params.supervised?.sessionId ?? (0, import_node_crypto18.randomUUID)();
66550
+ const resolvedModels = decided.models ?? (decided.globalModels === void 0 ? void 0 : {});
66551
+ const sessionModels = (0, import_node_util6.isDeepStrictEqual)(resolvedModels, decided.globalModels) ? void 0 : resolvedModels;
66552
+ const frontDoor = frontDoorEngaged && frontDoorPort !== void 0 ? frontDoorPort.ensure(env.NODE_EXTRA_CA_CERTS, { sessionId, ...sessionModels === void 0 ? {} : { models: sessionModels } }) : void 0;
66315
66553
  if (frontDoor?.trustWarning !== void 0) {
66316
66554
  log.warn(frontDoor.trustWarning);
66317
66555
  }
@@ -66325,7 +66563,6 @@ function prepareLaunch(params) {
66325
66563
  }
66326
66564
  rows.push(...routingRows({ frontDoor, headroom, provider: resolvedProvider !== void 0 }));
66327
66565
  const frontDoorRelease = frontDoor === void 0 ? void 0 : frontDoorPort?.release;
66328
- const sessionId = params.supervised?.sessionId ?? (0, import_node_crypto18.randomUUID)();
66329
66566
  const finalEnv = buildEnv({
66330
66567
  baseEnv: env,
66331
66568
  configDirEscapeHatch: configDirEscapeHatchApplies,
@@ -66337,7 +66574,8 @@ function prepareLaunch(params) {
66337
66574
  ...headroom === void 0 ? {} : { headroom },
66338
66575
  sessionId,
66339
66576
  remoteControl: resolvedFlags.remoteControl,
66340
- routeByName: routesByName
66577
+ routeByName: routesByName,
66578
+ ...decided.models?.tiers === void 0 ? {} : { tierModels: decided.models.tiers }
66341
66579
  });
66342
66580
  const releases = [...headroom === void 0 || headroomPort === void 0 ? [] : [headroomPort.release], ...frontDoorRelease === void 0 ? [] : [frontDoorRelease]];
66343
66581
  const release = () => {
@@ -66399,11 +66637,12 @@ function runLaunchPlan(plan, spawn8) {
66399
66637
  function runLauncher(params) {
66400
66638
  params.proc.exit(runLaunchPlan(prepareLaunch(params), params.spawn));
66401
66639
  }
66402
- var import_node_crypto18, import_node_path44;
66640
+ var import_node_crypto18, import_node_util6, import_node_path44;
66403
66641
  var init_launcher = __esm({
66404
66642
  "src/launcher.ts"() {
66405
66643
  "use strict";
66406
66644
  import_node_crypto18 = require("node:crypto");
66645
+ import_node_util6 = require("node:util");
66407
66646
  import_node_path44 = __toESM(require("node:path"), 1);
66408
66647
  init_package();
66409
66648
  init_envBool();
@@ -66420,7 +66659,6 @@ var init_launcher = __esm({
66420
66659
  init_launchReport();
66421
66660
  init_modelPicker();
66422
66661
  init_providerCatalogue();
66423
- init_modelsStore();
66424
66662
  init_providersStore();
66425
66663
  init_pool();
66426
66664
  init_resumeContext();
@@ -66438,6 +66676,7 @@ var init_launcher = __esm({
66438
66676
  init_read();
66439
66677
  init_claudeVersion();
66440
66678
  init_launchHook();
66679
+ init_targets();
66441
66680
  }
66442
66681
  });
66443
66682
 
@@ -119737,6 +119976,8 @@ init_source();
119737
119976
 
119738
119977
  // src/models/doctor.ts
119739
119978
  init_modelsStore();
119979
+ init_families();
119980
+ init_identity2();
119740
119981
  function modelsFindings(input2) {
119741
119982
  const findings = [];
119742
119983
  const { models } = input2;
@@ -119781,6 +120022,38 @@ function modelsFindings(input2) {
119781
120022
  findings.push({ severity: "fail", message: `Tier ${tier} points at "${ref}", which names nothing defined.` });
119782
120023
  }
119783
120024
  }
120025
+ const modelOfRef = (ref) => ref.slice(ref.indexOf("/") + 1);
120026
+ for (const group of models.same ?? []) {
120027
+ for (let outer = 0; outer < group.length; outer += 1) {
120028
+ for (let inner = outer + 1; inner < group.length; inner += 1) {
120029
+ const left = group[outer] ?? "";
120030
+ const right = group[inner] ?? "";
120031
+ if (!left.startsWith("acct:") && !right.startsWith("acct:") && relateModels(modelOfRef(left), modelOfRef(right)) === "distinct") {
120032
+ findings.push({ severity: "warn", message: `"${left}" and "${right}" are asserted to be one model, but their names say they are different models; check the assertion is not a typo.` });
120033
+ }
120034
+ if ((models.distinct ?? []).some(([a10, b]) => a10 === left && b === right || a10 === right && b === left)) {
120035
+ findings.push({ severity: "fail", message: `"${left}" and "${right}" are asserted to be both one model and two models.` });
120036
+ }
120037
+ }
120038
+ }
120039
+ }
120040
+ for (const [name, model] of Object.entries(models.virtual ?? {})) {
120041
+ const concrete = model.members.filter((member) => memberKindOf(member, models) === "provider" && member.includes("/"));
120042
+ const looksAlike = concrete.flatMap((left, index) => concrete.slice(index + 1).filter((right) => relateModels(modelOfRef(left), modelOfRef(right)) === "same").map((right) => [left, right]));
120043
+ for (const [left, right] of looksAlike) {
120044
+ findings.push({ severity: "warn", message: `Virtual model "${name}" lists "${left}" and "${right}", which look like one model; a member ${FAMILY_PREFIX}${familyKeyOf(modelOfRef(left))} names every target of it.` });
120045
+ }
120046
+ }
120047
+ if (input2.targets !== void 0) {
120048
+ const families = buildFamilies(input2.targets, models);
120049
+ for (const [name, model] of Object.entries(models.virtual ?? {})) {
120050
+ for (const member of model.members.filter((entry) => entry.startsWith(FAMILY_PREFIX))) {
120051
+ if (!families.some((family) => `${FAMILY_PREFIX}${family.key}` === member)) {
120052
+ findings.push({ severity: "warn", message: `Virtual model "${name}" names ${member}, but no target the providers offer belongs to that family.` });
120053
+ }
120054
+ }
120055
+ }
120056
+ }
119784
120057
  const hidden = new Set(models.hide ?? []);
119785
120058
  const shown = new Set(models.show ?? []);
119786
120059
  for (const ref of hidden) {
@@ -119792,6 +120065,7 @@ function modelsFindings(input2) {
119792
120065
  }
119793
120066
 
119794
120067
  // src/doctorReport.ts
120068
+ init_targets();
119795
120069
  init_configProfilesStore();
119796
120070
 
119797
120071
  // src/headroom/allowlistDrift.ts
@@ -120344,7 +120618,7 @@ function runDoctor(params) {
120344
120618
  if (models === void 0) {
120345
120619
  push("models", "pass", "No models block configured.");
120346
120620
  } else {
120347
- for (const finding of modelsFindings({ models, providers: params.providers.map((entry) => entry.name), identities: params.identities.map((entry) => entry.name) })) {
120621
+ for (const finding of modelsFindings({ models, providers: params.providers.map((entry) => entry.name), identities: params.identities.map((entry) => entry.name), ...params.modelTargets === void 0 ? {} : { targets: params.modelTargets } })) {
120348
120622
  push("models", finding.severity, finding.message);
120349
120623
  }
120350
120624
  push("models", "pass", "The models block is consistent.");
@@ -120578,6 +120852,7 @@ function collectDoctorReport(params) {
120578
120852
  directoryRules: { path: paths.directoryRulesFile, raw: realFsPort.readFileUtf8(paths.directoryRulesFile) },
120579
120853
  globalConfig: { path: paths.globalConfigFile, raw: realFsPort.readFileUtf8(paths.globalConfigFile) },
120580
120854
  models: parsedModelsOf(paths),
120855
+ modelTargets: targetRefs(paths),
120581
120856
  categoriesLocal: { path: paths.categoriesLocalFile, raw: realFsPort.readFileUtf8(paths.categoriesLocalFile) },
120582
120857
  activeIdentity: { path: paths.activeIdentityFile, raw: realFsPort.readFileUtf8(paths.activeIdentityFile) },
120583
120858
  binaryDiscovery,
@@ -131547,6 +131822,7 @@ function candidateOf(ref, order, facts, isCurrent) {
131547
131822
 
131548
131823
  // src/frontdoor/providerRoute.ts
131549
131824
  init_engine();
131825
+ init_families();
131550
131826
  init_identity2();
131551
131827
  init_route();
131552
131828
  var import_node_stream3 = require("node:stream");
@@ -131637,37 +131913,45 @@ function scopeSessionProviderPath(request7) {
131637
131913
  }
131638
131914
  return { ...request7, url: `${PROVIDER_PATH_PREFIX}${encodeURIComponent(request7.session.provider)}${request7.url}` };
131639
131915
  }
131640
- function resolveRoutedModel(model, providerName, session, includeUnqualified, deps, memory, rotations) {
131641
- const models = deps.models?.();
131916
+ var CHARS_PER_TOKEN2 = 4;
131917
+ function needsOf(scan) {
131918
+ return { hasImage: scan.hasImage === true, hasTools: scan.toolsPresent === true, thinking: scan.thinking === true, contextTokens: Math.ceil((scan.text?.length ?? 0) / CHARS_PER_TOKEN2) };
131919
+ }
131920
+ function resolveRoutedModel(model, providerName, session, includeUnqualified, deps, memory, rotations, needs) {
131921
+ const models = deps.models?.(session);
131642
131922
  const qualified = model.includes("/") && !model.startsWith("acct:") ? model : void 0;
131643
131923
  if (qualified !== void 0) {
131644
131924
  const [provider2, ...rest2] = qualified.split("/");
131645
131925
  const named = rest2.join("/");
131646
131926
  return provider2 === void 0 || named === "" ? void 0 : { provider: provider2, model: withoutContextMarker(named), ref: qualified };
131647
131927
  }
131648
- const virtual = models?.virtual?.[model];
131649
- if (virtual === void 0 || !includeUnqualified) {
131928
+ const isFamily = model.startsWith(FAMILY_PREFIX);
131929
+ const virtual = isFamily ? void 0 : models?.virtual?.[model];
131930
+ if (virtual === void 0 && !isFamily || !includeUnqualified) {
131650
131931
  return void 0;
131651
131932
  }
131652
- const members2 = expandMembers(model, models).filter((member) => !member.startsWith("acct:") && !member.startsWith("family:"));
131933
+ const declared = isFamily ? [model] : expandMembers(model, models);
131934
+ const families = isFamily || declared.some((member) => member.startsWith(FAMILY_PREFIX)) || models?.families !== void 0 ? buildFamilies(deps.targets?.() ?? [], models) : [];
131935
+ const mode = virtual?.mode ?? familyMode(familyNamed(families, model)?.settings ?? {});
131936
+ const members2 = expandFamilyMembers(declared, families).filter((member) => !member.startsWith("acct:"));
131653
131937
  if (members2.length === 0) {
131654
131938
  return void 0;
131655
131939
  }
131656
131940
  const snapshot = deps.usageSnapshotOf?.(session.identity);
131657
131941
  const current = memory.get(session.sessionId ?? "");
131658
- const candidates = members2.map((ref, order) => {
131942
+ const evaluated = members2.map((ref, order) => {
131659
131943
  const [provider2] = ref.split("/");
131660
131944
  const facts = quotaFactsOf(snapshot?.providers[provider2 ?? ""]?.rateLimit?.unified, Date.now());
131661
- return candidateOf(ref, order, {
131945
+ const candidate = candidateOf(ref, order, {
131662
131946
  quota: facts,
131663
131947
  ...deps.observations?.(ref) === void 0 ? {} : { observation: deps.observations(ref) },
131664
131948
  ...models?.prices?.[ref] === void 0 ? {} : { price: models.prices[ref] }
131665
131949
  }, ref === current);
131950
+ return { candidate, capabilities: familyCapabilities(familyOfRef(families, ref)?.settings ?? {}) };
131666
131951
  });
131667
- const evaluated = candidates.map((candidate) => ({ candidate, capabilities: { vision: true, tools: true, thinking: true } }));
131668
131952
  const rotation = rotations.get(model) ?? 0;
131669
131953
  rotations.set(model, rotation + 1);
131670
- const selection = selectMember(virtual.mode, evaluated, { rotation });
131954
+ const selection = selectMember(mode, evaluated, { rotation, ...needs === void 0 ? {} : { needs } });
131671
131955
  if (selection.ref === void 0) {
131672
131956
  return void 0;
131673
131957
  }
@@ -131830,6 +132114,7 @@ function createProviderRouteResolver(deps) {
131830
132114
  const serveScoped = (resolution) => scopedRequest === request7 ? resolution : { ok: true, route: servingRewritten(resolution.route, scopedRequest) };
131831
132115
  let current = scopedRequest;
131832
132116
  let replay;
132117
+ let nameResolved = false;
131833
132118
  const visited = /* @__PURE__ */ new Set();
131834
132119
  for (; ; ) {
131835
132120
  const path65 = new URL(current.url, "http://127.0.0.1").pathname;
@@ -131851,7 +132136,7 @@ function createProviderRouteResolver(deps) {
131851
132136
  routes = void 0;
131852
132137
  isRouter = false;
131853
132138
  }
131854
- const routesByName = (isRouter || current.session.routeByName) && !isRcSelfHostPath(path65);
132139
+ const routesByName = !nameResolved && (isRouter || current.session.routeByName) && !isRcSelfHostPath(path65);
131855
132140
  if (routesByName) {
131856
132141
  const scan2 = await scanRequestHead(current, true);
131857
132142
  if (scan2.replayed === void 0) {
@@ -131859,7 +132144,7 @@ function createProviderRouteResolver(deps) {
131859
132144
  return resolution.ok && replay !== void 0 ? { ok: true, route: servingRewritten(resolution.route, { ...replay, url: current.url }), request: { ...replay, url: current.url } } : resolution.ok ? serveScoped(resolution) : resolution;
131860
132145
  }
131861
132146
  replay = scan2.replayed;
131862
- const account = scan2.model === void 0 ? void 0 : resolveAccountTarget(scan2.model, deps.models?.());
132147
+ const account = scan2.model === void 0 ? void 0 : resolveAccountTarget(scan2.model, deps.models?.(current.session));
131863
132148
  if (account !== void 0) {
131864
132149
  const sessionId = current.session.sessionId ?? "";
131865
132150
  const moved = sessionId !== "" && (deps.accountMoves?.(sessionId, account.identity, account.model) ?? false);
@@ -131869,7 +132154,7 @@ function createProviderRouteResolver(deps) {
131869
132154
  message: moved ? `model "${account.model}" runs under identity "${account.identity}"; this session is being moved there and will resume with it` : `model "${account.model}" runs under identity "${account.identity}", which needs a relaunch this session cannot make; start it there with: claude @${account.identity} --resume`
131870
132155
  };
131871
132156
  }
131872
- const routed = scan2.model === void 0 ? void 0 : resolveRoutedModel(scan2.model, providerName, current.session, isRouter || providerName !== void 0, deps, routingMemory, rotations);
132157
+ const routed = scan2.model === void 0 ? void 0 : resolveRoutedModel(scan2.model, providerName, current.session, isRouter || providerName !== void 0, deps, routingMemory, rotations, needsOf(scan2));
131873
132158
  const requested = scan2.model;
131874
132159
  if (routed !== void 0) {
131875
132160
  routingMemory.set(current.session.sessionId ?? "", routed.ref);
@@ -131888,6 +132173,7 @@ function createProviderRouteResolver(deps) {
131888
132173
  const query2 = current.url.includes("?") ? current.url.slice(current.url.indexOf("?")) : "";
131889
132174
  const carried = replay;
131890
132175
  current = { ...current, url: `${PROVIDER_PATH_PREFIX}${encodeURIComponent(routed.provider)}${rest2}${query2}`, body: carried.body, headers: carried.headers };
132176
+ nameResolved = true;
131891
132177
  continue;
131892
132178
  }
131893
132179
  const resolution = resolve2(current);
@@ -134374,6 +134660,9 @@ data: ${JSON.stringify(envelope)}
134374
134660
  };
134375
134661
  }
134376
134662
 
134663
+ // src/frontdoor/commands.ts
134664
+ init_targets();
134665
+
134377
134666
  // src/frontdoor/rcStream.ts
134378
134667
  var RC_STREAM_EVENT_NAME2 = "client_event";
134379
134668
  var SSE_BYTE_ORDER_MARK = 65279;
@@ -135052,7 +135341,9 @@ function realFrontDoorSupervisorPorts(paths) {
135052
135341
  const resolveRoute = rcObservingResolver(
135053
135342
  createProviderRouteResolver({
135054
135343
  // Read live so a models-block edit reaches the next request without a door restart.
135055
- models: () => readModels(paths),
135344
+ // The block this session launched with when its directory, profile or committed file added definitions of its own; otherwise the global block, read live so an edit applies to the next request with no relaunch.
135345
+ models: (session) => (session.sessionId === void 0 ? void 0 : readFrontDoorSessionModels(realFarmFs, paths.frontdoorSessionsDir, session.sessionId)) ?? readModels(paths),
135346
+ targets: () => targetRefs(paths),
135056
135347
  fs: realFsPort,
135057
135348
  providersDir: paths.providersDir,
135058
135349
  codexPorts,
@@ -147640,12 +147931,10 @@ function registerProviderCommand(program2, deps) {
147640
147931
 
147641
147932
  // src/models.ts
147642
147933
  init_commandDeps();
147643
- init_providersStore();
147644
- init_modelPicker();
147645
- init_providerCatalogue();
147646
- init_realPorts();
147934
+ init_targets();
147647
147935
  init_schema();
147648
147936
  init_cliError();
147937
+ init_families();
147649
147938
  init_identity2();
147650
147939
  init_modelsStore();
147651
147940
  init_realPorts();
@@ -147675,52 +147964,46 @@ function providerQuotaOf(paths) {
147675
147964
  return snapshot === void 0 ? {} : quotaFactsOf(snapshot.providers[provider]?.rateLimit?.unified, Date.now());
147676
147965
  };
147677
147966
  }
147678
- function describeUnroutedMembers(members2) {
147967
+ function describeUnroutedMembers(members2, families) {
147679
147968
  return members2.flatMap((member) => {
147680
147969
  if (member.startsWith("acct:")) {
147681
147970
  const [identity] = member.slice("acct:".length).split("/");
147682
147971
  return [`${member} is served by relaunching the session under identity "${identity ?? ""}", so no quota signal ranks it`];
147683
147972
  }
147684
- return member.startsWith("family:") ? [`${member} is resolved from the live catalogues, which the door does not read yet, so it is not a candidate`] : [];
147973
+ return member.startsWith(FAMILY_PREFIX) && familyNamed(families, member) === void 0 ? [`no target the providers offer belongs to ${member}, so it has nothing to choose among`] : [];
147685
147974
  });
147686
147975
  }
147687
147976
  function explainVirtualModel(paths, name) {
147688
147977
  const models = readModels(paths);
147689
- const definition = models?.virtual?.[name];
147690
- if (definition === void 0) {
147978
+ const virtual = models?.virtual?.[name];
147979
+ const families = buildFamilies(targetRefs(paths), models);
147980
+ const isFamily = name.startsWith(FAMILY_PREFIX);
147981
+ if (virtual === void 0 && !isFamily) {
147691
147982
  throw new UsageError(`No virtual model named "${name}".`);
147692
147983
  }
147984
+ const mode = virtual?.mode ?? familyMode(familyNamed(families, name)?.settings ?? {});
147693
147985
  const quotaOf = providerQuotaOf(paths);
147694
147986
  const observations = createTargetObservationStore(realFarmFs, paths);
147695
- const members2 = expandMembers(name, models);
147696
- const candidates = members2.filter((member) => !member.startsWith("acct:") && !member.startsWith("family:")).map((ref, order) => {
147987
+ const members2 = isFamily ? [name] : expandMembers(name, models);
147988
+ const candidates = expandFamilyMembers(members2, families).filter((member) => !member.startsWith("acct:")).map((ref, order) => {
147697
147989
  const [provider] = ref.split("/");
147698
147990
  return candidateOf(ref, order, { quota: quotaOf(provider ?? ""), ...observations.observation(ref) === void 0 ? {} : { observation: observations.observation(ref) }, ...models?.prices?.[ref] === void 0 ? {} : { price: models.prices[ref] } }, false);
147699
147991
  });
147700
- const evaluated = candidates.map((candidate) => ({ candidate, capabilities: { vision: true, tools: true, thinking: true } }));
147701
- const selection = selectMember(definition.mode, evaluated, {});
147702
- const unrouted = describeUnroutedMembers(members2);
147703
- console.log(`${name} (${definition.mode}) chooses ${selection.ref ?? (candidates.length === 0 ? "nothing by quota" : "nothing")}:`);
147992
+ const evaluated = candidates.map((candidate) => ({ candidate, capabilities: familyCapabilities(familyOfRef(families, candidate.ref)?.settings ?? {}) }));
147993
+ const selection = selectMember(mode, evaluated, {});
147994
+ const unrouted = describeUnroutedMembers(members2, families);
147995
+ console.log(`${name} (${mode}) chooses ${selection.ref ?? (candidates.length === 0 ? "nothing by quota" : "nothing")}:`);
147704
147996
  for (const line of candidates.length === 0 ? unrouted : [...selection.reasons, ...unrouted]) {
147705
147997
  console.log(` ${line}`);
147706
147998
  }
147707
147999
  }
147708
- function providerModels(paths) {
147709
- return listProviders(paths).flatMap((entry) => {
147710
- const catalogue = parseCatalogueCache(realFsPort.readFileUtf8(catalogueCachePath(paths, entry.name)));
147711
- return providerModelRows(entry.provider, catalogue?.models).map((row) => ({ provider: entry.name, model: row.model }));
147712
- });
147713
- }
147714
- function matchModels(models) {
147715
- const same = [];
147716
- for (const model of models) {
147717
- const group = same.find((candidates) => candidates.some((other) => relateModels(other.model, model.model) === "same" && other.provider !== model.provider));
147718
- if (group === void 0) {
147719
- same.push([model]);
147720
- } else {
147721
- group.push(model);
147722
- }
147723
- }
148000
+ function matchModels(models, config2) {
148001
+ const refOf = (model) => `${model.provider}/${model.model}`;
148002
+ const byRef = new Map(models.map((model) => [refOf(model), model]));
148003
+ const families = buildFamilies(models.map(refOf), config2);
148004
+ const familyOf = new Map(families.flatMap((family) => family.refs.map((ref) => [ref, family])));
148005
+ const same = families.map((family) => family.refs.flatMap((ref) => byRef.get(ref) ?? [])).filter((group) => new Set(group.map((entry) => entry.provider)).size > 1);
148006
+ const distinct = config2?.distinct ?? [];
147724
148007
  const similar = [];
147725
148008
  for (let outer = 0; outer < models.length; outer += 1) {
147726
148009
  for (let inner = outer + 1; inner < models.length; inner += 1) {
@@ -147729,18 +148012,19 @@ function matchModels(models) {
147729
148012
  if (left === void 0 || right === void 0 || left.provider === right.provider) {
147730
148013
  continue;
147731
148014
  }
147732
- if (relateModels(left.model, right.model) === "similar" && !same.some((group) => group.includes(left) && group.includes(right))) {
148015
+ const asserted = distinct.some(([a10, b]) => a10 === refOf(left) && b === refOf(right) || a10 === refOf(right) && b === refOf(left));
148016
+ if (!asserted && familyOf.get(refOf(left)) !== familyOf.get(refOf(right)) && relateModels(left.model, right.model) === "similar") {
147733
148017
  similar.push([left, right]);
147734
148018
  }
147735
148019
  }
147736
148020
  }
147737
- return { same: same.filter((group) => group.length > 1), similar };
148021
+ return { same, similar };
147738
148022
  }
147739
148023
  function registerModelsCommand(program2, deps) {
147740
148024
  const { paths } = deps;
147741
148025
  const modelsCommand = program2.command("model").description("Define and inspect the models the providers offer and the virtual models chosen among them.");
147742
148026
  withExamples(
147743
- modelsCommand.command("explain <name>").description("Show which member a virtual model's mode picks over the live signals, and why each candidate stands where it does.").action((name) => {
148027
+ modelsCommand.command("explain <name>").description("Show which member a virtual model's (or a family row's) mode picks over the live signals, and why each candidate stands where it does.").action((name) => {
147744
148028
  explainVirtualModel(paths, name);
147745
148029
  }),
147746
148030
  ["agent-shim model explain fast"]
@@ -147751,7 +148035,7 @@ function registerModelsCommand(program2, deps) {
147751
148035
  ["agent-shim model match"]
147752
148036
  ).action((options) => {
147753
148037
  const models = providerModels(paths);
147754
- const { same, similar } = matchModels(models);
148038
+ const { same, similar } = matchModels(models, readModels(paths));
147755
148039
  if (options.json === true) {
147756
148040
  printJson({ models, same, similar });
147757
148041
  return;
@@ -147830,7 +148114,53 @@ function registerModelsCommand(program2, deps) {
147830
148114
  console.log(options.clear === true ? `Removed prices for ${ref}.` : `Prices for ${ref}: ${String(options.input)} in, ${String(options.output)} out per million tokens.`);
147831
148115
  });
147832
148116
  withExamples(
147833
- modelsCommand.command("list").description("List the defined virtual models, the tier pointers and the visibility filter.").option("--json", "Print the models block as JSON."),
148117
+ modelsCommand.command("same <ref> <ref...>").description("Assert that these refs are one model under several names, which makes them one family a mode can route across."),
148118
+ ["agent-shim model same z/glm-5.1 o/zai-glm-51"]
148119
+ ).action((first, rest) => {
148120
+ addSameGroup(paths, [first, ...rest]);
148121
+ console.log(`Asserted one model: ${[first, ...rest].join(" = ")}`);
148122
+ });
148123
+ withExamples(
148124
+ modelsCommand.command("distinct <left> <right>").description("Assert that two refs are two models, however alike their names look, so they are never put in one family."),
148125
+ ["agent-shim model distinct z/glm-5.1 s/hf:zai-org/GLM-5.1"]
148126
+ ).action((left, right) => {
148127
+ addDistinctPair(paths, left, right);
148128
+ console.log(`Asserted two models: ${left} / ${right}`);
148129
+ });
148130
+ withExamples(
148131
+ modelsCommand.command("unassert <ref>").description("Remove every identity assertion that names this ref."),
148132
+ ["agent-shim model unassert z/glm-5.1"]
148133
+ ).action((ref) => {
148134
+ const removed = removeAssertionsNaming(paths, ref);
148135
+ console.log(removed === 0 ? `No assertion names ${ref}.` : `Removed ${String(removed)} assertion${removed === 1 ? "" : "s"} naming ${ref}.`);
148136
+ });
148137
+ withExamples(
148138
+ modelsCommand.command("family <key>").description("Set one family's own settings: how a row that selects the whole family chooses, the names the normaliser cannot know, and what every target of it can do.").option("--mode <mode>", "How a row selecting the whole family chooses among its targets.", (value2) => asMode(value2)).option("--name <ref>", "Pin a ref or bare model name into the family (repeatable).", collectRepeated).option("--context <tokens>", "The family's context window, in tokens.", (value2) => asPositiveInteger(value2)).option("--vision", "Every target of the family accepts images.").option("--no-vision", "No target of the family accepts images.").option("--tools", "Every target of the family accepts tools.").option("--no-tools", "No target of the family accepts tools.").option("--thinking", "Every target of the family thinks.").option("--no-thinking", "No target of the family thinks.").option("--clear", "Remove the family's settings instead."),
148139
+ ["agent-shim model family glm-5-1 --mode cheapest --no-vision", "agent-shim model family claude-opus-5-5 --name o/opus-latest"]
148140
+ ).action((key, options) => {
148141
+ if (options.clear === true) {
148142
+ setFamily(paths, key, void 0);
148143
+ console.log(`Removed the settings of family ${key}.`);
148144
+ return;
148145
+ }
148146
+ const existing = readModels(paths)?.families?.[key] ?? {};
148147
+ const settings2 = {
148148
+ ...existing,
148149
+ ...options.mode === void 0 ? {} : { mode: options.mode },
148150
+ ...options.name === void 0 ? {} : { names: [.../* @__PURE__ */ new Set([...existing.names ?? [], ...options.name])] },
148151
+ ...options.context === void 0 ? {} : { context: options.context },
148152
+ ...options.vision === void 0 ? {} : { vision: options.vision },
148153
+ ...options.tools === void 0 ? {} : { tools: options.tools },
148154
+ ...options.thinking === void 0 ? {} : { thinking: options.thinking }
148155
+ };
148156
+ if (Object.keys(settings2).length === 0) {
148157
+ throw new UsageError("Nothing to set: pass --mode, --name, --context, a capability flag, or --clear.");
148158
+ }
148159
+ setFamily(paths, key, settings2);
148160
+ console.log(`Family ${key}: ${JSON.stringify(settings2)}`);
148161
+ });
148162
+ withExamples(
148163
+ modelsCommand.command("list").description("List the defined virtual models, the tier pointers, the visibility filter, the identity assertions and the family settings.").option("--json", "Print the models block as JSON."),
147834
148164
  ["agent-shim model list"]
147835
148165
  ).action((options) => {
147836
148166
  const found = readModels(paths);
@@ -147854,8 +148184,24 @@ function registerModelsCommand(program2, deps) {
147854
148184
  if (found.show !== void 0) {
147855
148185
  console.log(`visible only: ${found.show.join(", ")}`);
147856
148186
  }
148187
+ for (const group of found.same ?? []) {
148188
+ console.log(`same: ${group.join(" = ")}`);
148189
+ }
148190
+ for (const [left, right] of found.distinct ?? []) {
148191
+ console.log(`distinct: ${left} / ${right}`);
148192
+ }
148193
+ for (const [key, settings2] of Object.entries(found.families ?? {})) {
148194
+ console.log(`family ${key}: ${JSON.stringify(settings2)}`);
148195
+ }
147857
148196
  });
147858
148197
  }
148198
+ function asPositiveInteger(value2) {
148199
+ const parsed = Number(value2);
148200
+ if (!Number.isInteger(parsed) || parsed <= 0) {
148201
+ throw new UsageError(`"${value2}" is not a token count: pass a positive whole number.`);
148202
+ }
148203
+ return parsed;
148204
+ }
147859
148205
  function asMode(value2) {
147860
148206
  const mode = SELECTION_MODES.find((candidate) => candidate === value2);
147861
148207
  if (mode === void 0) {