agent-shim 11.34.0 → 11.36.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
@@ -31706,6 +31706,196 @@ var init_identity = __esm({
31706
31706
  }
31707
31707
  });
31708
31708
 
31709
+ // src/configProfilesStore.ts
31710
+ function profileJsonPath(paths, name) {
31711
+ return import_node_path12.default.join(paths.configProfilesDir, `${name}.json`);
31712
+ }
31713
+ function profileExists(paths, name) {
31714
+ return import_node_fs5.default.existsSync(profileJsonPath(paths, name));
31715
+ }
31716
+ function requireProfileExists(paths, name) {
31717
+ if (!profileExists(paths, name)) {
31718
+ throw new ProfileNotFoundError(name);
31719
+ }
31720
+ }
31721
+ function readProfile(paths, name) {
31722
+ return readJson(profileJsonPath(paths, name), ConfigProfileSchema);
31723
+ }
31724
+ function createProfile(paths, name, extendsList, description) {
31725
+ if (profileExists(paths, name)) {
31726
+ throw new ProfileAlreadyExistsError(name);
31727
+ }
31728
+ const filePath = profileJsonPath(paths, name);
31729
+ const parsed = ConfigProfileSchema.safeParse({
31730
+ ...description === void 0 ? {} : { description },
31731
+ ...extendsList !== void 0 && extendsList.length > 0 ? { extends: [...extendsList] } : {}
31732
+ });
31733
+ if (!parsed.success) {
31734
+ throw new ConfigValidationError(filePath, parsed.error.issues);
31735
+ }
31736
+ writeJsonAtomic(filePath, parsed.data);
31737
+ return parsed.data;
31738
+ }
31739
+ function listProfiles(paths) {
31740
+ if (!import_node_fs5.default.existsSync(paths.configProfilesDir)) {
31741
+ return [];
31742
+ }
31743
+ const names = import_node_fs5.default.readdirSync(paths.configProfilesDir, { withFileTypes: true }).filter((entry) => entry.isFile() && entry.name.endsWith(".json")).map((entry) => entry.name.slice(0, -".json".length)).sort();
31744
+ const result = [];
31745
+ for (const name of names) {
31746
+ const profile = readProfile(paths, name);
31747
+ if (profile !== void 0) {
31748
+ result.push({ name, profile });
31749
+ }
31750
+ }
31751
+ return result;
31752
+ }
31753
+ function globalConfigPath(paths) {
31754
+ return paths.globalConfigFile;
31755
+ }
31756
+ function readGlobalConfig(paths) {
31757
+ return readJson(globalConfigPath(paths), GlobalConfigSchema);
31758
+ }
31759
+ function setGlobalDefaultProfile(paths, name) {
31760
+ return applyPatch(
31761
+ globalConfigPath(paths),
31762
+ GlobalConfigSchema,
31763
+ { defaultConfigProfile: name },
31764
+ { defaults: {} }
31765
+ );
31766
+ }
31767
+ function validateCategoryNames(patch) {
31768
+ for (const key of Object.keys(patch)) {
31769
+ if (!isOverridableCategory(key)) {
31770
+ throw new InvalidCategoryNameError(key);
31771
+ }
31772
+ }
31773
+ }
31774
+ function setProfileCategories(paths, name, patch) {
31775
+ requireProfileExists(paths, name);
31776
+ const expandedPatch = expandAllCategoryKey(patch);
31777
+ validateCategoryNames(expandedPatch);
31778
+ const existing = readProfile(paths, name) ?? {};
31779
+ const mergedCategories = { ...existing.categories, ...expandedPatch };
31780
+ return applyPatch(profileJsonPath(paths, name), ConfigProfileSchema, { categories: mergedCategories });
31781
+ }
31782
+ function setProfileEntries(paths, name, patch) {
31783
+ requireProfileExists(paths, name);
31784
+ const existing = readProfile(paths, name) ?? {};
31785
+ const mergedEntries = { ...existing.entries, ...patch };
31786
+ return applyPatch(profileJsonPath(paths, name), ConfigProfileSchema, { entries: mergedEntries });
31787
+ }
31788
+ function setProfileLaunchFlags(paths, name, patch) {
31789
+ requireProfileExists(paths, name);
31790
+ const existing = readProfile(paths, name) ?? {};
31791
+ const mergedLaunch = { ...existing.launch, ...patch };
31792
+ return applyPatch(profileJsonPath(paths, name), ConfigProfileSchema, {
31793
+ // Read as `unknown` so the check sees the `undefined` a cleared key holds, which LaunchFlags' optional properties hide from the value type.
31794
+ launch: Object.values(mergedLaunch).every((value2) => value2 === void 0) ? void 0 : mergedLaunch
31795
+ });
31796
+ }
31797
+ function setProfileMetadata(paths, name, patch) {
31798
+ requireProfileExists(paths, name);
31799
+ return applyPatch(profileJsonPath(paths, name), ConfigProfileSchema, {
31800
+ ...patch.extends === void 0 ? {} : { extends: patch.extends.length === 0 ? void 0 : [...patch.extends] },
31801
+ ...patch.description === void 0 ? {} : { description: patch.description === false ? void 0 : patch.description }
31802
+ });
31803
+ }
31804
+ function removeProfile(paths, name) {
31805
+ requireProfileExists(paths, name);
31806
+ import_node_fs5.default.rmSync(profileJsonPath(paths, name));
31807
+ }
31808
+ function applyProfileChange(paths, name, change) {
31809
+ let touched = false;
31810
+ if (change.category !== void 0) {
31811
+ setProfileCategories(paths, name, change.category);
31812
+ touched = true;
31813
+ }
31814
+ if (change.entry !== void 0) {
31815
+ setProfileEntries(paths, name, change.entry);
31816
+ touched = true;
31817
+ }
31818
+ if (change.extends !== void 0 || change.description !== void 0) {
31819
+ setProfileMetadata(paths, name, {
31820
+ ...change.extends === void 0 ? {} : { extends: change.extends === false ? [] : change.extends },
31821
+ ...change.description === void 0 ? {} : { description: change.description }
31822
+ });
31823
+ touched = true;
31824
+ }
31825
+ const launchPatch = {};
31826
+ if (change.launchSkipPermissions !== void 0) {
31827
+ launchPatch.skipPermissions = change.launchSkipPermissions;
31828
+ }
31829
+ if (change.launchRemoteControl !== void 0) {
31830
+ launchPatch.remoteControl = change.launchRemoteControl;
31831
+ }
31832
+ if (change.launchHeadroom !== void 0) {
31833
+ launchPatch.headroom = change.launchHeadroom;
31834
+ }
31835
+ if (change.launchTrackUsage !== void 0) {
31836
+ launchPatch.trackUsage = change.launchTrackUsage;
31837
+ }
31838
+ if (change.launchProvider !== void 0) {
31839
+ launchPatch.provider = change.launchProvider === false ? void 0 : change.launchProvider;
31840
+ }
31841
+ if (change.launchClaudeVersion !== void 0) {
31842
+ launchPatch.claudeVersion = change.launchClaudeVersion === false ? void 0 : change.launchClaudeVersion;
31843
+ }
31844
+ if (change.launchDelay !== void 0) {
31845
+ launchPatch.delay = change.launchDelay === false ? void 0 : change.launchDelay;
31846
+ }
31847
+ if (change.launchPause !== void 0) {
31848
+ launchPatch.pause = change.launchPause;
31849
+ }
31850
+ if (change.launchExplain !== void 0) {
31851
+ launchPatch.explain = change.launchExplain;
31852
+ }
31853
+ if (change.launchRouteByName !== void 0) {
31854
+ launchPatch.routeByName = change.launchRouteByName;
31855
+ }
31856
+ if (Object.keys(launchPatch).length > 0) {
31857
+ setProfileLaunchFlags(paths, name, launchPatch);
31858
+ touched = true;
31859
+ }
31860
+ return touched;
31861
+ }
31862
+ var import_node_fs5, import_node_path12, ProfileNotFoundError, ProfileAlreadyExistsError, InvalidCategoryNameError;
31863
+ var init_configProfilesStore = __esm({
31864
+ "src/configProfilesStore.ts"() {
31865
+ "use strict";
31866
+ import_node_fs5 = __toESM(require("node:fs"), 1);
31867
+ import_node_path12 = __toESM(require("node:path"), 1);
31868
+ init_store();
31869
+ init_schema();
31870
+ init_cliError();
31871
+ init_load();
31872
+ ProfileNotFoundError = class extends CliError {
31873
+ constructor(profileName) {
31874
+ super(`No configuration profile named "${profileName}". Run \`agent-shim profile add ${profileName}\` first.`);
31875
+ this.profileName = profileName;
31876
+ this.name = "ProfileNotFoundError";
31877
+ }
31878
+ profileName;
31879
+ };
31880
+ ProfileAlreadyExistsError = class extends CliError {
31881
+ constructor(profileName) {
31882
+ super(`A configuration profile named "${profileName}" already exists.`);
31883
+ this.profileName = profileName;
31884
+ this.name = "ProfileAlreadyExistsError";
31885
+ }
31886
+ profileName;
31887
+ };
31888
+ InvalidCategoryNameError = class extends CliError {
31889
+ constructor(categoryName) {
31890
+ super(`"${categoryName}" is not a category a configuration profile may toggle (runtime, history, knowledge, settings).`);
31891
+ this.categoryName = categoryName;
31892
+ this.name = "InvalidCategoryNameError";
31893
+ }
31894
+ categoryName;
31895
+ };
31896
+ }
31897
+ });
31898
+
31709
31899
  // src/launcher/lock.ts
31710
31900
  function identityLockPath(dir, identity) {
31711
31901
  return import_node_path13.default.join(dir, `.${identity}.lock`);
@@ -32631,6 +32821,9 @@ function flattenLayers(layers, options) {
32631
32821
  if (layer.launch.explain !== void 0) {
32632
32822
  launch.explain = layer.launch.explain;
32633
32823
  }
32824
+ if (layer.launch.routeByName !== void 0) {
32825
+ launch.routeByName = layer.launch.routeByName;
32826
+ }
32634
32827
  }
32635
32828
  if (layer.models !== void 0) {
32636
32829
  models = mergeModels(models, layer.models);
@@ -34442,7 +34635,7 @@ var init_package = __esm({
34442
34635
  "package.json"() {
34443
34636
  package_default = {
34444
34637
  name: "agent-shim",
34445
- version: "11.34.0",
34638
+ version: "11.36.0",
34446
34639
  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.",
34447
34640
  license: "MIT",
34448
34641
  author: "Joseph Mearman <joseph@mearman.co.uk>",
@@ -34707,6 +34900,7 @@ function identifyRequest(headers) {
34707
34900
  sessionId: internalHeaderValue(headers, SESSION_HEADER),
34708
34901
  provider: internalHeaderValue(headers, PROVIDER_HEADER),
34709
34902
  headroom: internalHeaderValue(headers, HEADROOM_FLAG_HEADER) === "1",
34903
+ routeByName: internalHeaderValue(headers, ROUTE_BY_NAME_HEADER) === "1",
34710
34904
  projectId: internalHeaderValue(headers, PROJECT_ID_HEADER)
34711
34905
  },
34712
34906
  forwardableHeaders: forwardable
@@ -34726,7 +34920,7 @@ function parseProviderPath(path65) {
34726
34920
  }
34727
34921
  return { provider: decodeURIComponent(tail.slice(0, slash)), rest: tail.slice(slash) };
34728
34922
  }
34729
- var HEADROOM_SESSION_HEADER, INTERNAL_HEADER_NAMES, IDENTITY_HEADER, SESSION_HEADER, PROVIDER_HEADER, HEADROOM_FLAG_HEADER, PROJECT_ID_HEADER, CLIENT_SESSION_HEADER, HEADROOM_BASE_URL_HEADER, AUTH_HEADER, HOP_SECRET_HEADER, HOP_ID_HEADER, PROVIDER_PATH_PREFIX;
34923
+ var HEADROOM_SESSION_HEADER, INTERNAL_HEADER_NAMES, IDENTITY_HEADER, SESSION_HEADER, PROVIDER_HEADER, HEADROOM_FLAG_HEADER, ROUTE_BY_NAME_HEADER, PROJECT_ID_HEADER, CLIENT_SESSION_HEADER, HEADROOM_BASE_URL_HEADER, AUTH_HEADER, HOP_SECRET_HEADER, HOP_ID_HEADER, PROVIDER_PATH_PREFIX;
34730
34924
  var init_route = __esm({
34731
34925
  "src/frontdoor/route.ts"() {
34732
34926
  "use strict";
@@ -34735,6 +34929,7 @@ var init_route = __esm({
34735
34929
  "x-agent-shim-identity",
34736
34930
  "x-agent-shim-session",
34737
34931
  "x-agent-shim-headroom",
34932
+ "x-agent-shim-route-by-name",
34738
34933
  "x-agent-shim-auth",
34739
34934
  "x-agent-shim-provider",
34740
34935
  "x-agent-shim-hop",
@@ -34747,6 +34942,7 @@ var init_route = __esm({
34747
34942
  SESSION_HEADER = "x-agent-shim-session";
34748
34943
  PROVIDER_HEADER = "x-agent-shim-provider";
34749
34944
  HEADROOM_FLAG_HEADER = "x-agent-shim-headroom";
34945
+ ROUTE_BY_NAME_HEADER = "x-agent-shim-route-by-name";
34750
34946
  PROJECT_ID_HEADER = "x-headroom-project-id";
34751
34947
  CLIENT_SESSION_HEADER = "x-claude-code-session-id";
34752
34948
  HEADROOM_BASE_URL_HEADER = "x-headroom-base-url";
@@ -36300,6 +36496,58 @@ function resolveProvider(params) {
36300
36496
  }
36301
36497
  return { ok: true, provider: { name, definition, credential: resolution.credential }, warnings: resolution.credential.warnings };
36302
36498
  }
36499
+ function resolveRoutedProviderCredentials(params) {
36500
+ const { models } = params;
36501
+ if (models === void 0) {
36502
+ return { ok: true, checked: [] };
36503
+ }
36504
+ const virtualNames = new Set(Object.keys(models.virtual ?? {}));
36505
+ const providerNames = /* @__PURE__ */ new Set();
36506
+ const collect = (ref) => {
36507
+ if (ref.startsWith("acct:") || ref.startsWith("family:") || virtualNames.has(ref)) {
36508
+ return;
36509
+ }
36510
+ const [provider] = ref.split("/", 1);
36511
+ if (provider !== void 0 && provider !== "") {
36512
+ providerNames.add(provider);
36513
+ }
36514
+ };
36515
+ for (const model of Object.values(models.virtual ?? {})) {
36516
+ for (const member of model.members) {
36517
+ collect(member);
36518
+ }
36519
+ }
36520
+ for (const ref of Object.values(models.tiers ?? {})) {
36521
+ collect(ref);
36522
+ }
36523
+ if (providerNames.size === 0) {
36524
+ return { ok: true, checked: [] };
36525
+ }
36526
+ if (params.credentials === void 0) {
36527
+ return { ok: false, status: 1, message: `agent-shim: the models block routes to providers ${[...providerNames].sort().join(", ")}, which need their credentials resolved, but this launcher has no credential port wired` };
36528
+ }
36529
+ const failures = [];
36530
+ let credentialFailure = false;
36531
+ for (const name of [...providerNames].sort()) {
36532
+ const definition = loadProvider(params.paths.providersDir, name, params.port);
36533
+ if (definition === void 0) {
36534
+ failures.push(`no provider named "${name}"`);
36535
+ continue;
36536
+ }
36537
+ if (isRouterProvider(definition)) {
36538
+ continue;
36539
+ }
36540
+ const resolution = resolveCredential({ credential: definition.credential, env: params.env, port: params.credentials, subject: `provider ${name}` });
36541
+ if (!resolution.ok) {
36542
+ failures.push(resolution.message.replace(/^agent-shim: /, ""));
36543
+ credentialFailure = true;
36544
+ }
36545
+ }
36546
+ if (failures.length > 0) {
36547
+ return { ok: false, status: credentialFailure ? CREDENTIAL_UNAVAILABLE_EXIT : 1, message: `agent-shim: this launch routes model names through the models block, but: ${failures.join("; ")}` };
36548
+ }
36549
+ return { ok: true, checked: [...providerNames].sort() };
36550
+ }
36303
36551
  var import_node_fs10, import_node_path29, ProviderNotFoundError, ProviderAlreadyExistsError, InvalidProviderNameError, PROVIDER_NAME_RE, LEGACY_PROVIDER_FIELDS, LEGACY_ENV_CREDENTIAL_KEYS, LEGACY_LITERAL_PLACEHOLDER, LegacyProviderFileError, ProviderKindMismatchError;
36304
36552
  var init_providersStore = __esm({
36305
36553
  "src/providersStore.ts"() {
@@ -63266,7 +63514,8 @@ var init_argv = __esm({
63266
63514
  { flag: "--remote-control", key: "remoteControl" },
63267
63515
  { flag: "--wait", key: "wait" },
63268
63516
  { flag: "--pause", key: "pause" },
63269
- { flag: "--explain", key: "explain" }
63517
+ { flag: "--explain", key: "explain" },
63518
+ { flag: "--route-by-name", key: "routeByName" }
63270
63519
  ];
63271
63520
  LAUNCHER_FLAG_NAMES = [
63272
63521
  ...VALUED_FLAGS,
@@ -63456,6 +63705,7 @@ function resolveLaunchFlags(params) {
63456
63705
  trackUsage: params.flags?.trackUsage ?? parseEnvBool("AGENT_SHIM_TRACK_USAGE", params.env.AGENT_SHIM_TRACK_USAGE) ?? params.cascade?.trackUsage ?? true,
63457
63706
  pause: params.flags?.pause ?? parseEnvBool("AGENT_SHIM_PAUSE", params.env.AGENT_SHIM_PAUSE) ?? params.cascade?.pause ?? false,
63458
63707
  explain: params.flags?.explain ?? parseEnvBool("AGENT_SHIM_EXPLAIN", params.env.AGENT_SHIM_EXPLAIN) ?? params.cascade?.explain ?? false,
63708
+ routeByName: params.flags?.routeByName ?? parseEnvBool("AGENT_SHIM_ROUTE_BY_NAME", params.env.AGENT_SHIM_ROUTE_BY_NAME) ?? params.cascade?.routeByName ?? false,
63459
63709
  delayMs: resolveDelayMs(params)
63460
63710
  };
63461
63711
  }
@@ -63524,6 +63774,7 @@ function buildEnv(params) {
63524
63774
  { name: SESSION_HEADER, value: params.sessionId },
63525
63775
  { name: AUTH_HEADER, value: params.frontdoor.sessionToken },
63526
63776
  ...params.provider === void 0 ? [] : [{ name: PROVIDER_HEADER, value: params.provider.name }],
63777
+ ...params.routeByName ? [{ name: ROUTE_BY_NAME_HEADER, value: "1" }] : [],
63527
63778
  ...params.headroom === void 0 ? [] : [
63528
63779
  { name: HEADROOM_FLAG_HEADER, value: "1" },
63529
63780
  { name: PROJECT_ID_HEADER, value: params.headroom.projectId }
@@ -65207,8 +65458,40 @@ function providerModelRows(provider, catalogue = []) {
65207
65458
  const taken = new Set(named.map((row) => labelOf(row.model)));
65208
65459
  return [...named, ...catalogueRows(provider, catalogue).filter((row) => !taken.has(labelOf(row.model)))];
65209
65460
  }
65461
+ function routedModelRows(models, providers) {
65462
+ const hidden = new Set(models.hide ?? []);
65463
+ const shown = models.show === void 0 ? void 0 : new Set(models.show);
65464
+ const visible = (model) => shown === void 0 ? !hidden.has(model) : shown.has(model);
65465
+ const tierOf = (model) => {
65466
+ for (const [, provider] of providers) {
65467
+ if (provider.kind !== void 0 && provider.kind !== "http") {
65468
+ continue;
65469
+ }
65470
+ const env = provider.env ?? {};
65471
+ const match = Object.entries(env).find(([, value2]) => value2 === model);
65472
+ if (match?.[0].endsWith("_MODEL") === true) {
65473
+ const tier = match[0].replace("ANTHROPIC_DEFAULT_", "").replace("_MODEL", "").toLowerCase();
65474
+ return tier === "fable" || tier === "opus" || tier === "sonnet" || tier === "haiku" ? tier : void 0;
65475
+ }
65476
+ }
65477
+ return void 0;
65478
+ };
65479
+ const virtual = Object.entries(models.virtual ?? {}).flatMap(([name, definition]) => {
65480
+ if (!visible(name)) {
65481
+ return [];
65482
+ }
65483
+ const first = definition.members.find((member) => member.includes("/"));
65484
+ const tier = first === void 0 ? void 0 : tierOf(first.split("/").slice(1).join("/"));
65485
+ const behavesAs = tier === void 0 ? void 0 : TIER_BEHAVES_AS[tier];
65486
+ return behavesAs === void 0 ? [] : [{ model: name, label: name, description: `Virtual (${definition.mode})`, behavesAs }];
65487
+ });
65488
+ const concrete = providers.flatMap(([name, provider]) => providerModelRows(provider).map((row) => ({ ...row, model: `${name}/${row.model}`, label: `${name} / ${row.label}`, description: `${name}: ${row.description}` })));
65489
+ return [...virtual, ...concrete.filter((row) => visible(row.model))];
65490
+ }
65210
65491
  function modelPickerSettings(provider, catalogue = []) {
65211
- const options = providerModelRows(provider, catalogue);
65492
+ return modelPickerSettingsFromRows(providerModelRows(provider, catalogue));
65493
+ }
65494
+ function modelPickerSettingsFromRows(options) {
65212
65495
  return options.length === 0 ? void 0 : JSON.stringify({ modelPicker: { options, replaceBuiltInOptions: true } });
65213
65496
  }
65214
65497
  var CONTEXT_MARKER_1M2, TIER_BEHAVES_AS, TIER_ENV_VARIABLES;
@@ -65235,6 +65518,114 @@ var init_modelPicker = __esm({
65235
65518
  }
65236
65519
  });
65237
65520
 
65521
+ // src/modelsStore.ts
65522
+ function readModels(paths) {
65523
+ return readGlobalConfig(paths)?.models;
65524
+ }
65525
+ function writeModels(paths, models) {
65526
+ const emptied = models !== void 0 && Object.keys(models).length === 0 ? void 0 : models;
65527
+ applyPatch(paths.globalConfigFile, GlobalConfigSchema, { models: emptied }, { defaults: {} });
65528
+ }
65529
+ function stripEmpty(models) {
65530
+ const kept = {};
65531
+ if (models.virtual !== void 0 && Object.keys(models.virtual).length > 0) {
65532
+ kept.virtual = models.virtual;
65533
+ }
65534
+ if (models.tiers !== void 0 && Object.keys(models.tiers).length > 0) {
65535
+ kept.tiers = models.tiers;
65536
+ }
65537
+ if (models.prices !== void 0 && Object.keys(models.prices).length > 0) {
65538
+ kept.prices = models.prices;
65539
+ }
65540
+ if (models.hide !== void 0 && models.hide.length > 0) {
65541
+ kept.hide = models.hide;
65542
+ }
65543
+ if (models.show !== void 0 && models.show.length > 0) {
65544
+ kept.show = models.show;
65545
+ }
65546
+ return kept;
65547
+ }
65548
+ function memberKindOf(ref, models) {
65549
+ if (ref.startsWith("acct:")) {
65550
+ return "account";
65551
+ }
65552
+ if (ref.startsWith("family:")) {
65553
+ return "family";
65554
+ }
65555
+ return models?.virtual !== void 0 && ref in models.virtual ? "virtual" : "provider";
65556
+ }
65557
+ function expandMembers(name, models) {
65558
+ const virtual = models?.virtual ?? {};
65559
+ const expanded = [];
65560
+ const walk2 = (current, chain) => {
65561
+ const nested = virtual[current];
65562
+ if (nested !== void 0) {
65563
+ if (chain.includes(current)) {
65564
+ throw new Error(`virtual model cycle: ${[...chain, current].join(" -> ")}`);
65565
+ }
65566
+ for (const member of nested.members) {
65567
+ walk2(member, [...chain, current]);
65568
+ }
65569
+ return;
65570
+ }
65571
+ if (!expanded.includes(current)) {
65572
+ expanded.push(current);
65573
+ }
65574
+ };
65575
+ const top = virtual[name];
65576
+ if (top === void 0) {
65577
+ throw new VirtualModelNotFoundError(name);
65578
+ }
65579
+ for (const member of top.members) {
65580
+ walk2(member, [name]);
65581
+ }
65582
+ return expanded;
65583
+ }
65584
+ function setVirtualModel(paths, name, model) {
65585
+ const current = readModels(paths) ?? {};
65586
+ writeModels(paths, { ...current, virtual: { ...current.virtual ?? {}, [name]: model } });
65587
+ }
65588
+ function removeVirtualModel(paths, name) {
65589
+ const current = readModels(paths);
65590
+ if (current?.virtual?.[name] === void 0) {
65591
+ throw new VirtualModelNotFoundError(name);
65592
+ }
65593
+ const virtual = Object.fromEntries(Object.entries(current.virtual ?? {}).filter(([existing]) => existing !== name));
65594
+ writeModels(paths, stripEmpty({ ...current, virtual: Object.keys(virtual).length === 0 ? void 0 : virtual }));
65595
+ }
65596
+ function setPrice(paths, ref, prices) {
65597
+ const current = readModels(paths) ?? {};
65598
+ const priced = Object.fromEntries(Object.entries(current.prices ?? {}).filter(([existing]) => existing !== ref));
65599
+ const next = prices === void 0 ? priced : { ...priced, [ref]: prices };
65600
+ writeModels(paths, stripEmpty({ ...current, prices: Object.keys(next).length === 0 ? void 0 : next }));
65601
+ }
65602
+ function setTier(paths, tier, ref) {
65603
+ const current = readModels(paths) ?? {};
65604
+ const tiers = {};
65605
+ const merged = { ...current.tiers ?? {}, [tier]: ref };
65606
+ for (const [key, value2] of Object.entries(merged)) {
65607
+ if (value2 !== void 0) {
65608
+ tiers[key] = value2;
65609
+ }
65610
+ }
65611
+ writeModels(paths, stripEmpty({ ...current, tiers: Object.keys(tiers).length === 0 ? void 0 : tiers }));
65612
+ }
65613
+ var VirtualModelNotFoundError;
65614
+ var init_modelsStore = __esm({
65615
+ "src/modelsStore.ts"() {
65616
+ "use strict";
65617
+ init_store();
65618
+ init_schema();
65619
+ init_configProfilesStore();
65620
+ VirtualModelNotFoundError = class extends Error {
65621
+ constructor(name) {
65622
+ super(`No virtual model named "${name}".`);
65623
+ this.name = "VirtualModelNotFoundError";
65624
+ }
65625
+ };
65626
+ }
65627
+ });
65628
+
65238
65629
  // src/launcher/pool.ts
65239
65630
  function isResuming(passthrough) {
65240
65631
  const end = passthrough.indexOf(TERMINATOR3);
@@ -65645,6 +66036,7 @@ function decideLaunch(params, readOnly) {
65645
66036
  ...parsedArgv.trackUsage === void 0 ? {} : { trackUsage: parsedArgv.trackUsage },
65646
66037
  ...parsedArgv.pause === void 0 ? {} : { pause: parsedArgv.pause },
65647
66038
  ...parsedArgv.explain === void 0 ? {} : { explain: parsedArgv.explain },
66039
+ ...parsedArgv.routeByName === void 0 ? {} : { routeByName: parsedArgv.routeByName },
65648
66040
  ...parsedArgv.delay === void 0 ? {} : { delay: parsedArgv.delay }
65649
66041
  }
65650
66042
  });
@@ -65655,7 +66047,8 @@ function decideLaunch(params, readOnly) {
65655
66047
  }
65656
66048
  const flags = loginlessProvider === void 0 ? requestedFlags : { ...requestedFlags, remoteControl: false };
65657
66049
  const catalogue = selectedProvider === void 0 ? void 0 : parseCatalogueCache(params.fs.readFileUtf8(catalogueCachePath(paths, selectedProvider.name)));
65658
- const pickerSettings = selectedProvider === void 0 ? void 0 : modelPickerSettings(selectedProvider.definition, catalogue?.models);
66050
+ const routesByName = flags.routeByName || selectedProvider !== void 0 && isRouterProvider(selectedProvider.definition);
66051
+ const pickerSettings = routesByName ? modelPickerSettingsFromRows(routedModelRows(readModels(paths) ?? {}, listProviders(paths).map((entry) => [entry.name, entry.provider]))) : selectedProvider === void 0 ? void 0 : modelPickerSettings(selectedProvider.definition, catalogue?.models);
65659
66052
  const callerSettings = hasSettingsArgument(parsedArgv.rest);
65660
66053
  if (pickerSettings !== void 0 && callerSettings) {
65661
66054
  notes.push("--settings was passed, so /model keeps Claude Code's own model names");
@@ -65757,6 +66150,14 @@ function prepareLaunch(params) {
65757
66150
  if (decided.pinnedVersion !== void 0) {
65758
66151
  rows.push(pinnedVersionRow(decided.pinnedVersion.version, decided.pinnedVersion.source));
65759
66152
  }
66153
+ const routesByName = resolvedFlags.routeByName || resolvedProvider !== void 0 && isRouterProvider(resolvedProvider.definition);
66154
+ if (routesByName) {
66155
+ 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 });
66156
+ if (!check2.ok) {
66157
+ log.error(check2.message);
66158
+ proc.exit(check2.status);
66159
+ }
66160
+ }
65760
66161
  const frontDoorPort = params.frontdoor;
65761
66162
  const frontDoorEngaged = resolvedProvider !== void 0 || resolvedFlags.headroom || resolvedFlags.trackUsage;
65762
66163
  if (frontDoorEngaged && frontDoorPort === void 0) {
@@ -65788,7 +66189,8 @@ function prepareLaunch(params) {
65788
66189
  ...frontDoor === void 0 ? {} : { frontdoor: frontDoor },
65789
66190
  ...headroom === void 0 ? {} : { headroom },
65790
66191
  sessionId,
65791
- remoteControl: resolvedFlags.remoteControl
66192
+ remoteControl: resolvedFlags.remoteControl,
66193
+ routeByName: routesByName
65792
66194
  });
65793
66195
  const releases = [...headroom === void 0 || headroomPort === void 0 ? [] : [headroomPort.release], ...frontDoorRelease === void 0 ? [] : [frontDoorRelease]];
65794
66196
  const release = () => {
@@ -65815,7 +66217,8 @@ function resolveLaunch(params) {
65815
66217
  ...frontDoor ? { frontdoor: { port: 0, connectPort: 0, trustBundlePath: "", sessionToken: "" } } : {},
65816
66218
  ...decided.flags.headroom ? { headroom: { socketPath: "", projectId: "" } } : {},
65817
66219
  sessionId: "",
65818
- remoteControl: decided.flags.remoteControl
66220
+ remoteControl: decided.flags.remoteControl,
66221
+ routeByName: decided.flags.routeByName
65819
66222
  });
65820
66223
  const credentialNames = decided.identityCredentialBlock === void 0 ? [] : Object.keys(credentialVariables(decided.identityCredentialBlock.target ?? "bearer", ""));
65821
66224
  const environment = [.../* @__PURE__ */ new Set([...Object.keys(built).filter((name) => built[name] !== env[name]), ...credentialNames])].sort();
@@ -65827,7 +66230,7 @@ function resolveLaunch(params) {
65827
66230
  bin: decided.bin,
65828
66231
  args: decided.args,
65829
66232
  ...credential === void 0 ? {} : { credential },
65830
- routing: { frontDoor, headroom: decided.flags.headroom },
66233
+ routing: { frontDoor, headroom: decided.flags.headroom, routeByName: decided.flags.routeByName },
65831
66234
  environment
65832
66235
  };
65833
66236
  }
@@ -65870,14 +66273,18 @@ var init_launcher = __esm({
65870
66273
  init_launchReport();
65871
66274
  init_modelPicker();
65872
66275
  init_providerCatalogue();
66276
+ init_modelsStore();
66277
+ init_providersStore();
65873
66278
  init_pool();
65874
66279
  init_resumeContext();
65875
66280
  init_lock();
65876
66281
  init_spawn();
65877
66282
  init_providersStore();
66283
+ init_load();
65878
66284
  init_flatten();
65879
66285
  init_walk();
65880
66286
  init_schema();
66287
+ init_schema();
65881
66288
  init_credential();
65882
66289
  init_middleware();
65883
66290
  init_preflight();
@@ -111667,189 +112074,7 @@ init_identity();
111667
112074
 
111668
112075
  // src/poolStore.ts
111669
112076
  init_cliError();
111670
-
111671
- // src/configProfilesStore.ts
111672
- var import_node_fs5 = __toESM(require("node:fs"), 1);
111673
- var import_node_path12 = __toESM(require("node:path"), 1);
111674
- init_store();
111675
- init_schema();
111676
- init_cliError();
111677
- init_load();
111678
- var ProfileNotFoundError = class extends CliError {
111679
- constructor(profileName) {
111680
- super(`No configuration profile named "${profileName}". Run \`agent-shim profile add ${profileName}\` first.`);
111681
- this.profileName = profileName;
111682
- this.name = "ProfileNotFoundError";
111683
- }
111684
- profileName;
111685
- };
111686
- var ProfileAlreadyExistsError = class extends CliError {
111687
- constructor(profileName) {
111688
- super(`A configuration profile named "${profileName}" already exists.`);
111689
- this.profileName = profileName;
111690
- this.name = "ProfileAlreadyExistsError";
111691
- }
111692
- profileName;
111693
- };
111694
- var InvalidCategoryNameError = class extends CliError {
111695
- constructor(categoryName) {
111696
- super(`"${categoryName}" is not a category a configuration profile may toggle (runtime, history, knowledge, settings).`);
111697
- this.categoryName = categoryName;
111698
- this.name = "InvalidCategoryNameError";
111699
- }
111700
- categoryName;
111701
- };
111702
- function profileJsonPath(paths, name) {
111703
- return import_node_path12.default.join(paths.configProfilesDir, `${name}.json`);
111704
- }
111705
- function profileExists(paths, name) {
111706
- return import_node_fs5.default.existsSync(profileJsonPath(paths, name));
111707
- }
111708
- function requireProfileExists(paths, name) {
111709
- if (!profileExists(paths, name)) {
111710
- throw new ProfileNotFoundError(name);
111711
- }
111712
- }
111713
- function readProfile(paths, name) {
111714
- return readJson(profileJsonPath(paths, name), ConfigProfileSchema);
111715
- }
111716
- function createProfile(paths, name, extendsList, description) {
111717
- if (profileExists(paths, name)) {
111718
- throw new ProfileAlreadyExistsError(name);
111719
- }
111720
- const filePath = profileJsonPath(paths, name);
111721
- const parsed = ConfigProfileSchema.safeParse({
111722
- ...description === void 0 ? {} : { description },
111723
- ...extendsList !== void 0 && extendsList.length > 0 ? { extends: [...extendsList] } : {}
111724
- });
111725
- if (!parsed.success) {
111726
- throw new ConfigValidationError(filePath, parsed.error.issues);
111727
- }
111728
- writeJsonAtomic(filePath, parsed.data);
111729
- return parsed.data;
111730
- }
111731
- function listProfiles(paths) {
111732
- if (!import_node_fs5.default.existsSync(paths.configProfilesDir)) {
111733
- return [];
111734
- }
111735
- const names = import_node_fs5.default.readdirSync(paths.configProfilesDir, { withFileTypes: true }).filter((entry) => entry.isFile() && entry.name.endsWith(".json")).map((entry) => entry.name.slice(0, -".json".length)).sort();
111736
- const result = [];
111737
- for (const name of names) {
111738
- const profile = readProfile(paths, name);
111739
- if (profile !== void 0) {
111740
- result.push({ name, profile });
111741
- }
111742
- }
111743
- return result;
111744
- }
111745
- function globalConfigPath(paths) {
111746
- return paths.globalConfigFile;
111747
- }
111748
- function readGlobalConfig(paths) {
111749
- return readJson(globalConfigPath(paths), GlobalConfigSchema);
111750
- }
111751
- function setGlobalDefaultProfile(paths, name) {
111752
- return applyPatch(
111753
- globalConfigPath(paths),
111754
- GlobalConfigSchema,
111755
- { defaultConfigProfile: name },
111756
- { defaults: {} }
111757
- );
111758
- }
111759
- function validateCategoryNames(patch) {
111760
- for (const key of Object.keys(patch)) {
111761
- if (!isOverridableCategory(key)) {
111762
- throw new InvalidCategoryNameError(key);
111763
- }
111764
- }
111765
- }
111766
- function setProfileCategories(paths, name, patch) {
111767
- requireProfileExists(paths, name);
111768
- const expandedPatch = expandAllCategoryKey(patch);
111769
- validateCategoryNames(expandedPatch);
111770
- const existing = readProfile(paths, name) ?? {};
111771
- const mergedCategories = { ...existing.categories, ...expandedPatch };
111772
- return applyPatch(profileJsonPath(paths, name), ConfigProfileSchema, { categories: mergedCategories });
111773
- }
111774
- function setProfileEntries(paths, name, patch) {
111775
- requireProfileExists(paths, name);
111776
- const existing = readProfile(paths, name) ?? {};
111777
- const mergedEntries = { ...existing.entries, ...patch };
111778
- return applyPatch(profileJsonPath(paths, name), ConfigProfileSchema, { entries: mergedEntries });
111779
- }
111780
- function setProfileLaunchFlags(paths, name, patch) {
111781
- requireProfileExists(paths, name);
111782
- const existing = readProfile(paths, name) ?? {};
111783
- const mergedLaunch = { ...existing.launch, ...patch };
111784
- return applyPatch(profileJsonPath(paths, name), ConfigProfileSchema, {
111785
- // Read as `unknown` so the check sees the `undefined` a cleared key holds, which LaunchFlags' optional properties hide from the value type.
111786
- launch: Object.values(mergedLaunch).every((value2) => value2 === void 0) ? void 0 : mergedLaunch
111787
- });
111788
- }
111789
- function setProfileMetadata(paths, name, patch) {
111790
- requireProfileExists(paths, name);
111791
- return applyPatch(profileJsonPath(paths, name), ConfigProfileSchema, {
111792
- ...patch.extends === void 0 ? {} : { extends: patch.extends.length === 0 ? void 0 : [...patch.extends] },
111793
- ...patch.description === void 0 ? {} : { description: patch.description === false ? void 0 : patch.description }
111794
- });
111795
- }
111796
- function removeProfile(paths, name) {
111797
- requireProfileExists(paths, name);
111798
- import_node_fs5.default.rmSync(profileJsonPath(paths, name));
111799
- }
111800
- function applyProfileChange(paths, name, change) {
111801
- let touched = false;
111802
- if (change.category !== void 0) {
111803
- setProfileCategories(paths, name, change.category);
111804
- touched = true;
111805
- }
111806
- if (change.entry !== void 0) {
111807
- setProfileEntries(paths, name, change.entry);
111808
- touched = true;
111809
- }
111810
- if (change.extends !== void 0 || change.description !== void 0) {
111811
- setProfileMetadata(paths, name, {
111812
- ...change.extends === void 0 ? {} : { extends: change.extends === false ? [] : change.extends },
111813
- ...change.description === void 0 ? {} : { description: change.description }
111814
- });
111815
- touched = true;
111816
- }
111817
- const launchPatch = {};
111818
- if (change.launchSkipPermissions !== void 0) {
111819
- launchPatch.skipPermissions = change.launchSkipPermissions;
111820
- }
111821
- if (change.launchRemoteControl !== void 0) {
111822
- launchPatch.remoteControl = change.launchRemoteControl;
111823
- }
111824
- if (change.launchHeadroom !== void 0) {
111825
- launchPatch.headroom = change.launchHeadroom;
111826
- }
111827
- if (change.launchTrackUsage !== void 0) {
111828
- launchPatch.trackUsage = change.launchTrackUsage;
111829
- }
111830
- if (change.launchProvider !== void 0) {
111831
- launchPatch.provider = change.launchProvider === false ? void 0 : change.launchProvider;
111832
- }
111833
- if (change.launchClaudeVersion !== void 0) {
111834
- launchPatch.claudeVersion = change.launchClaudeVersion === false ? void 0 : change.launchClaudeVersion;
111835
- }
111836
- if (change.launchDelay !== void 0) {
111837
- launchPatch.delay = change.launchDelay === false ? void 0 : change.launchDelay;
111838
- }
111839
- if (change.launchPause !== void 0) {
111840
- launchPatch.pause = change.launchPause;
111841
- }
111842
- if (change.launchExplain !== void 0) {
111843
- launchPatch.explain = change.launchExplain;
111844
- }
111845
- if (Object.keys(launchPatch).length > 0) {
111846
- setProfileLaunchFlags(paths, name, launchPatch);
111847
- touched = true;
111848
- }
111849
- return touched;
111850
- }
111851
-
111852
- // src/poolStore.ts
112077
+ init_configProfilesStore();
111853
112078
  init_store();
111854
112079
  init_schema();
111855
112080
  init_identity();
@@ -112141,6 +112366,9 @@ function removeIdentity(paths, name) {
112141
112366
  }
112142
112367
  }
112143
112368
 
112369
+ // src/configure.ts
112370
+ init_configProfilesStore();
112371
+
112144
112372
  // src/directoryRulesStore.ts
112145
112373
  init_store();
112146
112374
  init_load();
@@ -113069,6 +113297,7 @@ async function resolveFarmConflicts(params) {
113069
113297
  // src/configProfiles.ts
113070
113298
  init_commandDeps();
113071
113299
  init_cliError();
113300
+ init_configProfilesStore();
113072
113301
  async function ensureProfileExists(deps, name) {
113073
113302
  if (profileExists(deps.paths, name)) {
113074
113303
  return;
@@ -113128,7 +113357,7 @@ function registerProfileCommand(program2, deps) {
113128
113357
  withExamples(
113129
113358
  profile.command("set <name>").description(
113130
113359
  "Update a configuration profile's categories, entries, extends list, description or launch settings. With no options on a terminal, walks through its categories."
113131
- ).option("--category <category=bool>", "Share (true) or hide (false) a whole category (repeatable).", collectBoolPair).option("--entry <path=bool>", "Share (true) or hide (false) one <category>/<path> entry (repeatable).", collectBoolPair).option("--extends <profile>", "Replace the extends list with these profiles (repeatable, in order).", collectRepeated).option("--no-extends", "Clear the extends list.").option("--description <text>", "Replace the description.").option("--no-description", "Clear the description.").option("--launch-skip-permissions", "Launches under this profile skip permission prompts.").option("--no-launch-skip-permissions", "Launches under this profile keep permission prompts.").option("--launch-remote-control", "Launches under this profile enable Remote Control.").option("--no-launch-remote-control", "Launches under this profile leave Remote Control off.").option("--launch-headroom", "Launches under this profile route through headroom.").option("--no-launch-headroom", "Launches under this profile route direct.").option("--launch-track-usage", "Launches under this profile route through the front door so their requests and quota are recorded, with no headroom needed.").option("--no-launch-track-usage", "Launches under this profile are not recorded unless a provider or headroom routes them anyway.").option("--launch-provider <provider>", "Launches under this profile route through this provider.").option("--no-launch-provider", "Clear this profile's provider selection.").option("--launch-claude-version <version>", "Launches under this profile run exactly this installed Claude Code version (such as 2.1.220); a version that is not installed fails the launch.").option("--no-launch-claude-version", "Clear this profile's Claude Code version pin.").option("--launch-delay <duration>", "Launches under this profile wait this long (such as 5s) after the launcher's own output before starting claude, so the output can be read.", parseDurationLiteral).option("--no-launch-delay", "Clear this profile's launch delay.").option("--launch-pause", "Launches under this profile wait for a key press after the launcher's own output before starting claude.").option("--no-launch-pause", "Launches under this profile start claude without waiting for a key press.").option("--launch-explain", "Launches under this profile that pick from a pool list every member the pick ranked and why, in the launcher's report.").option("--no-launch-explain", "Launches under this profile name only the member a pool pick chose.").option("--json", "Print the result as JSON.").action(async (name, allOptions) => {
113360
+ ).option("--category <category=bool>", "Share (true) or hide (false) a whole category (repeatable).", collectBoolPair).option("--entry <path=bool>", "Share (true) or hide (false) one <category>/<path> entry (repeatable).", collectBoolPair).option("--extends <profile>", "Replace the extends list with these profiles (repeatable, in order).", collectRepeated).option("--no-extends", "Clear the extends list.").option("--description <text>", "Replace the description.").option("--no-description", "Clear the description.").option("--launch-skip-permissions", "Launches under this profile skip permission prompts.").option("--no-launch-skip-permissions", "Launches under this profile keep permission prompts.").option("--launch-remote-control", "Launches under this profile enable Remote Control.").option("--no-launch-remote-control", "Launches under this profile leave Remote Control off.").option("--launch-headroom", "Launches under this profile route through headroom.").option("--no-launch-headroom", "Launches under this profile route direct.").option("--launch-track-usage", "Launches under this profile route through the front door so their requests and quota are recorded, with no headroom needed.").option("--no-launch-track-usage", "Launches under this profile are not recorded unless a provider or headroom routes them anyway.").option("--launch-provider <provider>", "Launches under this profile route through this provider.").option("--no-launch-provider", "Clear this profile's provider selection.").option("--launch-claude-version <version>", "Launches under this profile run exactly this installed Claude Code version (such as 2.1.220); a version that is not installed fails the launch.").option("--no-launch-claude-version", "Clear this profile's Claude Code version pin.").option("--launch-delay <duration>", "Launches under this profile wait this long (such as 5s) after the launcher's own output before starting claude, so the output can be read.", parseDurationLiteral).option("--no-launch-delay", "Clear this profile's launch delay.").option("--launch-pause", "Launches under this profile wait for a key press after the launcher's own output before starting claude.").option("--no-launch-pause", "Launches under this profile start claude without waiting for a key press.").option("--launch-explain", "Launches under this profile that pick from a pool list every member the pick ranked and why, in the launcher's report.").option("--no-launch-explain", "Launches under this profile name only the member a pool pick chose.").option("--launch-route-by-name", "Launches under this profile route provider-qualified model names through the models block to the provider that serves them.").option("--no-launch-route-by-name", "Launches under this profile send every request to the launch provider.").option("--json", "Print the result as JSON.").action(async (name, allOptions) => {
113132
113361
  const { json: json2, ...options } = allOptions;
113133
113362
  requireProfileExists(paths, name);
113134
113363
  if (Object.entries(allOptions).every(([key, value2]) => key === "json" || value2 === void 0)) {
@@ -114880,6 +115109,7 @@ var import_node_crypto25 = require("node:crypto");
114880
115109
  var import_node_path53 = __toESM(require("node:path"), 1);
114881
115110
  var import_node_fs19 = __toESM(require("node:fs"), 1);
114882
115111
  init_commandDeps();
115112
+ init_configProfilesStore();
114883
115113
  init_schema();
114884
115114
  init_conditions();
114885
115115
 
@@ -115375,6 +115605,7 @@ var import_node_os7 = __toESM(require("node:os"), 1);
115375
115605
  var import_node_path38 = __toESM(require("node:path"), 1);
115376
115606
  init_package();
115377
115607
  init_commandDeps();
115608
+ init_configProfilesStore();
115378
115609
  init_store();
115379
115610
  init_schema();
115380
115611
  init_realFrontDoorPort();
@@ -115566,6 +115797,7 @@ function registerUpdateCommand(program2, deps, ports = realUpdatePorts) {
115566
115797
 
115567
115798
  // src/jobStore.ts
115568
115799
  init_cliError();
115800
+ init_configProfilesStore();
115569
115801
  init_store();
115570
115802
  init_schema();
115571
115803
  var JobNotFoundError = class extends CliError {
@@ -119147,108 +119379,8 @@ init_credentialCache();
119147
119379
  init_realCredentialCache();
119148
119380
  init_source();
119149
119381
 
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
119382
  // src/models/doctor.ts
119383
+ init_modelsStore();
119252
119384
  function modelsFindings(input2) {
119253
119385
  const findings = [];
119254
119386
  const { models } = input2;
@@ -119303,6 +119435,9 @@ function modelsFindings(input2) {
119303
119435
  return findings;
119304
119436
  }
119305
119437
 
119438
+ // src/doctorReport.ts
119439
+ init_configProfilesStore();
119440
+
119306
119441
  // src/headroom/allowlistDrift.ts
119307
119442
  init_earlierRelease();
119308
119443
  init_state2();
@@ -128126,6 +128261,7 @@ function createCodexApiRouter(deps) {
128126
128261
  // src/frontdoor/configApi.ts
128127
128262
  init_cliError();
128128
128263
  init_schema();
128264
+ init_configProfilesStore();
128129
128265
  init_credential();
128130
128266
  init_identity();
128131
128267
  init_providersStore();
@@ -128207,7 +128343,8 @@ var ConfigProfileSetInputSchema = external_exports.strictObject({
128207
128343
  claudeVersion: external_exports.union([external_exports.string().min(1), external_exports.literal(false)]).optional(),
128208
128344
  delay: external_exports.union([external_exports.string().regex(DURATION_RE), external_exports.literal(false)]).optional(),
128209
128345
  pause: external_exports.boolean().optional(),
128210
- explain: external_exports.boolean().optional()
128346
+ explain: external_exports.boolean().optional(),
128347
+ routeByName: external_exports.boolean().optional()
128211
128348
  }).optional()
128212
128349
  });
128213
128350
  var ConfigProfileSetOutputSchema = storedMutationOutput("profile", "updated", ProfileValueSchema);
@@ -128419,7 +128556,8 @@ function createConfigApiRouter(deps) {
128419
128556
  ...launch?.claudeVersion === void 0 ? {} : { launchClaudeVersion: launch.claudeVersion },
128420
128557
  ...launch?.delay === void 0 ? {} : { launchDelay: launch.delay },
128421
128558
  ...launch?.pause === void 0 ? {} : { launchPause: launch.pause },
128422
- ...launch?.explain === void 0 ? {} : { launchExplain: launch.explain }
128559
+ ...launch?.explain === void 0 ? {} : { launchExplain: launch.explain },
128560
+ ...launch?.routeByName === void 0 ? {} : { launchRouteByName: launch.routeByName }
128423
128561
  });
128424
128562
  return { action: "updated", kind: "profile", name: input2.name, value: profileValue(input2.name, paths) };
128425
128563
  })
@@ -128721,6 +128859,7 @@ var LaunchFlagsSchema = external_exports.strictObject({
128721
128859
  trackUsage: external_exports.boolean(),
128722
128860
  pause: external_exports.boolean(),
128723
128861
  explain: external_exports.boolean(),
128862
+ routeByName: external_exports.boolean(),
128724
128863
  /** How long the launch waits after its own output before it starts claude, in milliseconds. */
128725
128864
  delayMs: external_exports.number()
128726
128865
  });
@@ -128734,7 +128873,7 @@ var LaunchResolveOutputSchema = external_exports.strictObject({
128734
128873
  args: external_exports.readonly(external_exports.array(external_exports.string())),
128735
128874
  /** The credential the launch would authenticate with, by target and source kinds. Absent when none applies. */
128736
128875
  credential: external_exports.strictObject({ subject: external_exports.enum(["provider", "identity"]), name: external_exports.string(), summary: CredentialSummarySchema }).optional(),
128737
- routing: external_exports.strictObject({ frontDoor: external_exports.boolean(), headroom: external_exports.boolean() }),
128876
+ routing: external_exports.strictObject({ frontDoor: external_exports.boolean(), headroom: external_exports.boolean(), routeByName: external_exports.boolean() }),
128738
128877
  /** The names of the environment variables the launch would set or unset, sorted. Values are not reported. */
128739
128878
  environment: external_exports.readonly(external_exports.array(external_exports.string())),
128740
128879
  warnings: external_exports.readonly(external_exports.array(external_exports.string()))
@@ -131108,19 +131247,22 @@ function scopeSessionProviderPath(request7) {
131108
131247
  }
131109
131248
  return { ...request7, url: `${PROVIDER_PATH_PREFIX}${encodeURIComponent(request7.session.provider)}${request7.url}` };
131110
131249
  }
131111
- function resolveModelTarget(model, models) {
131250
+ function resolveModelTarget(model, models, includeUnqualified) {
131112
131251
  if (models === void 0) {
131113
131252
  return model.includes("/") && !model.startsWith("acct:") ? model.split("/")[0] : void 0;
131114
131253
  }
131115
131254
  if (model.includes("/") && !model.startsWith("acct:")) {
131116
131255
  return model.split("/")[0];
131117
131256
  }
131257
+ if (!includeUnqualified) {
131258
+ return void 0;
131259
+ }
131118
131260
  const virtual = models.virtual?.[model];
131119
131261
  const first = virtual?.members.find((member) => !member.startsWith("acct:") && !member.startsWith("family:"));
131120
131262
  if (first === void 0) {
131121
131263
  return void 0;
131122
131264
  }
131123
- return first.includes("/") ? first.split("/")[0] : resolveModelTarget(first, models);
131265
+ return first.includes("/") ? first.split("/")[0] : resolveModelTarget(first, models, true);
131124
131266
  }
131125
131267
  function createProviderRouteResolver(deps) {
131126
131268
  const oauthRoute = createPassthroughRoute("anthropic", { baseUrl: `https://${CONNECT_INTERCEPT_HOST}:${String(HTTPS_PORT)}`, stripPrefix: void 0, headroomUpstream: void 0 });
@@ -131285,12 +131427,17 @@ function createProviderRouteResolver(deps) {
131285
131427
  routes = void 0;
131286
131428
  isRouter = false;
131287
131429
  }
131288
- if (isRouter) {
131430
+ const routesByName = isRouter || current.session.routeByName && providerName !== void 0;
131431
+ if (routesByName) {
131289
131432
  const scan2 = await scanRequestHead(current, false);
131290
131433
  if (scan2.replayed !== void 0) {
131291
131434
  replay = scan2.replayed;
131292
131435
  }
131293
- const target = scan2.model === void 0 ? void 0 : resolveModelTarget(scan2.model, deps.models?.());
131436
+ const target = scan2.model === void 0 || providerName === void 0 ? void 0 : resolveModelTarget(scan2.model, deps.models?.(), isRouter || current.session.routeByName);
131437
+ if (target === providerName) {
131438
+ const resolution = resolve2(current);
131439
+ 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;
131440
+ }
131294
131441
  if (target !== void 0) {
131295
131442
  const rest2 = path65.slice(`${PROVIDER_PATH_PREFIX}${encodeURIComponent(providerName ?? "")}`.length);
131296
131443
  const query2 = current.url.includes("?") ? current.url.slice(current.url.indexOf("?")) : "";
@@ -131372,6 +131519,7 @@ function attachingProviderCredential(route, deps) {
131372
131519
  }
131373
131520
 
131374
131521
  // src/frontdoor/commands.ts
131522
+ init_modelsStore();
131375
131523
  init_realFrontDoorPort();
131376
131524
 
131377
131525
  // src/frontdoor/rcCommands.ts
@@ -145979,6 +146127,7 @@ var import_node_http5 = __toESM(require("node:http"), 1);
145979
146127
  var import_node_path58 = __toESM(require("node:path"), 1);
145980
146128
  var import_node_child_process9 = require("node:child_process");
145981
146129
  init_commandDeps();
146130
+ init_configProfilesStore();
145982
146131
  init_realFrontDoorPort();
145983
146132
  init_trust();
145984
146133
 
@@ -147300,6 +147449,7 @@ function sameFamilyOtherVersion(a10, b) {
147300
147449
  }
147301
147450
 
147302
147451
  // src/models.ts
147452
+ init_modelsStore();
147303
147453
  function providerModels(paths) {
147304
147454
  return listProviders(paths).flatMap((entry) => {
147305
147455
  const catalogue = parseCatalogueCache(realFsPort.readFileUtf8(catalogueCachePath(paths, entry.name)));
@@ -147936,11 +148086,12 @@ Launching:
147936
148086
  --delay <duration> wait this long (5s, 500ms) after the launcher's own output before starting claude
147937
148087
  --[no-]pause wait for a key press after the launcher's own output before starting claude
147938
148088
  --[no-]explain with @pool:<name>, list every member the pick ranked and why, not only the one picked
148089
+ --[no-]route-by-name route provider-qualified model names through the models block to the provider that serves them
147939
148090
  --native run the real claude with nothing from agent-shim applied (no other launch flag allowed)
147940
148091
 
147941
148092
  Environment:
147942
148093
  AGENT_SHIM_IDENTITY, AGENT_SHIM_CONFIG_PROFILE, AGENT_SHIM_SKIP_PERMISSIONS,
147943
- AGENT_SHIM_REMOTE_CONTROL, AGENT_SHIM_HEADROOM, AGENT_SHIM_TRACK_USAGE, AGENT_SHIM_DELAY, AGENT_SHIM_PAUSE, AGENT_SHIM_EXPLAIN, AGENT_SHIM_ALLOW_AMBIENT_CREDENTIAL,
148094
+ AGENT_SHIM_REMOTE_CONTROL, AGENT_SHIM_HEADROOM, AGENT_SHIM_TRACK_USAGE, AGENT_SHIM_DELAY, AGENT_SHIM_PAUSE, AGENT_SHIM_EXPLAIN, AGENT_SHIM_ROUTE_BY_NAME, AGENT_SHIM_ALLOW_AMBIENT_CREDENTIAL,
147944
148095
  AGENT_SHIM_CATEGORY_OVERRIDE, AGENT_SHIM_ENTRY_OVERRIDE, AGENT_SHIM_HOME,
147945
148096
  AGENT_SHIM_DEBUG (print stack traces), NO_COLOR. Booleans are true, false, 1 or 0.
147946
148097
 
@@ -147984,6 +148135,7 @@ function buildProgram(deps) {
147984
148135
 
147985
148136
  // src/runClaude.ts
147986
148137
  init_cliError();
148138
+ init_configProfilesStore();
147987
148139
  init_launchWiring();
147988
148140
  init_paths();
147989
148141
 
@@ -148664,6 +148816,7 @@ function otherLaunchFlags(parsed) {
148664
148816
  ...parsed.delay === void 0 ? [] : ["--delay"],
148665
148817
  ...parsed.pause === void 0 ? [] : ["--[no-]pause"],
148666
148818
  ...parsed.explain === void 0 ? [] : ["--[no-]explain"],
148819
+ ...parsed.routeByName === void 0 ? [] : ["--[no-]route-by-name"],
148667
148820
  ...parsed.headroom === void 0 ? [] : ["--[no-]headroom"],
148668
148821
  ...parsed.trackUsage === void 0 ? [] : ["--[no-]track-usage"],
148669
148822
  ...parsed.skipPermissions === void 0 ? [] : ["--[no-]skip-permissions"],