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/index.cjs CHANGED
@@ -1456,6 +1456,9 @@ function flattenLayers(layers, options) {
1456
1456
  if (layer.launch.explain !== void 0) {
1457
1457
  launch.explain = layer.launch.explain;
1458
1458
  }
1459
+ if (layer.launch.routeByName !== void 0) {
1460
+ launch.routeByName = layer.launch.routeByName;
1461
+ }
1459
1462
  }
1460
1463
  if (layer.models !== void 0) {
1461
1464
  models = mergeModels(models, layer.models);
@@ -2886,7 +2889,7 @@ var init_capability = __esm({
2886
2889
  });
2887
2890
 
2888
2891
  // src/frontdoor/route.ts
2889
- var IDENTITY_HEADER, SESSION_HEADER, PROVIDER_HEADER, HEADROOM_FLAG_HEADER, PROJECT_ID_HEADER, AUTH_HEADER;
2892
+ var IDENTITY_HEADER, SESSION_HEADER, PROVIDER_HEADER, HEADROOM_FLAG_HEADER, ROUTE_BY_NAME_HEADER, PROJECT_ID_HEADER, AUTH_HEADER;
2890
2893
  var init_route = __esm({
2891
2894
  "src/frontdoor/route.ts"() {
2892
2895
  "use strict";
@@ -2894,6 +2897,7 @@ var init_route = __esm({
2894
2897
  SESSION_HEADER = "x-agent-shim-session";
2895
2898
  PROVIDER_HEADER = "x-agent-shim-provider";
2896
2899
  HEADROOM_FLAG_HEADER = "x-agent-shim-headroom";
2900
+ ROUTE_BY_NAME_HEADER = "x-agent-shim-route-by-name";
2897
2901
  PROJECT_ID_HEADER = "x-headroom-project-id";
2898
2902
  AUTH_HEADER = "x-agent-shim-auth";
2899
2903
  }
@@ -3102,7 +3106,7 @@ var init_package = __esm({
3102
3106
  "package.json"() {
3103
3107
  package_default = {
3104
3108
  name: "agent-shim",
3105
- version: "11.34.0",
3109
+ version: "11.36.0",
3106
3110
  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.",
3107
3111
  license: "MIT",
3108
3112
  author: "Joseph Mearman <joseph@mearman.co.uk>",
@@ -6257,6 +6261,196 @@ var init_poolPick = __esm({
6257
6261
  }
6258
6262
  });
6259
6263
 
6264
+ // src/configProfilesStore.ts
6265
+ function profileJsonPath(paths, name) {
6266
+ return import_node_path22.default.join(paths.configProfilesDir, `${name}.json`);
6267
+ }
6268
+ function profileExists(paths, name) {
6269
+ return import_node_fs3.default.existsSync(profileJsonPath(paths, name));
6270
+ }
6271
+ function requireProfileExists(paths, name) {
6272
+ if (!profileExists(paths, name)) {
6273
+ throw new ProfileNotFoundError(name);
6274
+ }
6275
+ }
6276
+ function readProfile(paths, name) {
6277
+ return readJson(profileJsonPath(paths, name), ConfigProfileSchema);
6278
+ }
6279
+ function createProfile(paths, name, extendsList, description) {
6280
+ if (profileExists(paths, name)) {
6281
+ throw new ProfileAlreadyExistsError(name);
6282
+ }
6283
+ const filePath = profileJsonPath(paths, name);
6284
+ const parsed = ConfigProfileSchema.safeParse({
6285
+ ...description === void 0 ? {} : { description },
6286
+ ...extendsList !== void 0 && extendsList.length > 0 ? { extends: [...extendsList] } : {}
6287
+ });
6288
+ if (!parsed.success) {
6289
+ throw new ConfigValidationError(filePath, parsed.error.issues);
6290
+ }
6291
+ writeJsonAtomic(filePath, parsed.data);
6292
+ return parsed.data;
6293
+ }
6294
+ function listProfiles(paths) {
6295
+ if (!import_node_fs3.default.existsSync(paths.configProfilesDir)) {
6296
+ return [];
6297
+ }
6298
+ const names = import_node_fs3.default.readdirSync(paths.configProfilesDir, { withFileTypes: true }).filter((entry) => entry.isFile() && entry.name.endsWith(".json")).map((entry) => entry.name.slice(0, -".json".length)).sort();
6299
+ const result = [];
6300
+ for (const name of names) {
6301
+ const profile = readProfile(paths, name);
6302
+ if (profile !== void 0) {
6303
+ result.push({ name, profile });
6304
+ }
6305
+ }
6306
+ return result;
6307
+ }
6308
+ function globalConfigPath(paths) {
6309
+ return paths.globalConfigFile;
6310
+ }
6311
+ function readGlobalConfig(paths) {
6312
+ return readJson(globalConfigPath(paths), GlobalConfigSchema);
6313
+ }
6314
+ function setGlobalDefaultProfile(paths, name) {
6315
+ return applyPatch(
6316
+ globalConfigPath(paths),
6317
+ GlobalConfigSchema,
6318
+ { defaultConfigProfile: name },
6319
+ { defaults: {} }
6320
+ );
6321
+ }
6322
+ function validateCategoryNames(patch) {
6323
+ for (const key of Object.keys(patch)) {
6324
+ if (!isOverridableCategory(key)) {
6325
+ throw new InvalidCategoryNameError(key);
6326
+ }
6327
+ }
6328
+ }
6329
+ function setProfileCategories(paths, name, patch) {
6330
+ requireProfileExists(paths, name);
6331
+ const expandedPatch = expandAllCategoryKey(patch);
6332
+ validateCategoryNames(expandedPatch);
6333
+ const existing = readProfile(paths, name) ?? {};
6334
+ const mergedCategories = { ...existing.categories, ...expandedPatch };
6335
+ return applyPatch(profileJsonPath(paths, name), ConfigProfileSchema, { categories: mergedCategories });
6336
+ }
6337
+ function setProfileEntries(paths, name, patch) {
6338
+ requireProfileExists(paths, name);
6339
+ const existing = readProfile(paths, name) ?? {};
6340
+ const mergedEntries = { ...existing.entries, ...patch };
6341
+ return applyPatch(profileJsonPath(paths, name), ConfigProfileSchema, { entries: mergedEntries });
6342
+ }
6343
+ function setProfileLaunchFlags(paths, name, patch) {
6344
+ requireProfileExists(paths, name);
6345
+ const existing = readProfile(paths, name) ?? {};
6346
+ const mergedLaunch = { ...existing.launch, ...patch };
6347
+ return applyPatch(profileJsonPath(paths, name), ConfigProfileSchema, {
6348
+ // Read as `unknown` so the check sees the `undefined` a cleared key holds, which LaunchFlags' optional properties hide from the value type.
6349
+ launch: Object.values(mergedLaunch).every((value) => value === void 0) ? void 0 : mergedLaunch
6350
+ });
6351
+ }
6352
+ function setProfileMetadata(paths, name, patch) {
6353
+ requireProfileExists(paths, name);
6354
+ return applyPatch(profileJsonPath(paths, name), ConfigProfileSchema, {
6355
+ ...patch.extends === void 0 ? {} : { extends: patch.extends.length === 0 ? void 0 : [...patch.extends] },
6356
+ ...patch.description === void 0 ? {} : { description: patch.description === false ? void 0 : patch.description }
6357
+ });
6358
+ }
6359
+ function removeProfile(paths, name) {
6360
+ requireProfileExists(paths, name);
6361
+ import_node_fs3.default.rmSync(profileJsonPath(paths, name));
6362
+ }
6363
+ function applyProfileChange(paths, name, change) {
6364
+ let touched = false;
6365
+ if (change.category !== void 0) {
6366
+ setProfileCategories(paths, name, change.category);
6367
+ touched = true;
6368
+ }
6369
+ if (change.entry !== void 0) {
6370
+ setProfileEntries(paths, name, change.entry);
6371
+ touched = true;
6372
+ }
6373
+ if (change.extends !== void 0 || change.description !== void 0) {
6374
+ setProfileMetadata(paths, name, {
6375
+ ...change.extends === void 0 ? {} : { extends: change.extends === false ? [] : change.extends },
6376
+ ...change.description === void 0 ? {} : { description: change.description }
6377
+ });
6378
+ touched = true;
6379
+ }
6380
+ const launchPatch = {};
6381
+ if (change.launchSkipPermissions !== void 0) {
6382
+ launchPatch.skipPermissions = change.launchSkipPermissions;
6383
+ }
6384
+ if (change.launchRemoteControl !== void 0) {
6385
+ launchPatch.remoteControl = change.launchRemoteControl;
6386
+ }
6387
+ if (change.launchHeadroom !== void 0) {
6388
+ launchPatch.headroom = change.launchHeadroom;
6389
+ }
6390
+ if (change.launchTrackUsage !== void 0) {
6391
+ launchPatch.trackUsage = change.launchTrackUsage;
6392
+ }
6393
+ if (change.launchProvider !== void 0) {
6394
+ launchPatch.provider = change.launchProvider === false ? void 0 : change.launchProvider;
6395
+ }
6396
+ if (change.launchClaudeVersion !== void 0) {
6397
+ launchPatch.claudeVersion = change.launchClaudeVersion === false ? void 0 : change.launchClaudeVersion;
6398
+ }
6399
+ if (change.launchDelay !== void 0) {
6400
+ launchPatch.delay = change.launchDelay === false ? void 0 : change.launchDelay;
6401
+ }
6402
+ if (change.launchPause !== void 0) {
6403
+ launchPatch.pause = change.launchPause;
6404
+ }
6405
+ if (change.launchExplain !== void 0) {
6406
+ launchPatch.explain = change.launchExplain;
6407
+ }
6408
+ if (change.launchRouteByName !== void 0) {
6409
+ launchPatch.routeByName = change.launchRouteByName;
6410
+ }
6411
+ if (Object.keys(launchPatch).length > 0) {
6412
+ setProfileLaunchFlags(paths, name, launchPatch);
6413
+ touched = true;
6414
+ }
6415
+ return touched;
6416
+ }
6417
+ var import_node_fs3, import_node_path22, ProfileNotFoundError, ProfileAlreadyExistsError, InvalidCategoryNameError;
6418
+ var init_configProfilesStore = __esm({
6419
+ "src/configProfilesStore.ts"() {
6420
+ "use strict";
6421
+ import_node_fs3 = __toESM(require("node:fs"), 1);
6422
+ import_node_path22 = __toESM(require("node:path"), 1);
6423
+ init_store();
6424
+ init_schema();
6425
+ init_cliError();
6426
+ init_load();
6427
+ ProfileNotFoundError = class extends CliError {
6428
+ constructor(profileName) {
6429
+ super(`No configuration profile named "${profileName}". Run \`agent-shim profile add ${profileName}\` first.`);
6430
+ this.profileName = profileName;
6431
+ this.name = "ProfileNotFoundError";
6432
+ }
6433
+ profileName;
6434
+ };
6435
+ ProfileAlreadyExistsError = class extends CliError {
6436
+ constructor(profileName) {
6437
+ super(`A configuration profile named "${profileName}" already exists.`);
6438
+ this.profileName = profileName;
6439
+ this.name = "ProfileAlreadyExistsError";
6440
+ }
6441
+ profileName;
6442
+ };
6443
+ InvalidCategoryNameError = class extends CliError {
6444
+ constructor(categoryName) {
6445
+ super(`"${categoryName}" is not a category a configuration profile may toggle (runtime, history, knowledge, settings).`);
6446
+ this.categoryName = categoryName;
6447
+ this.name = "InvalidCategoryNameError";
6448
+ }
6449
+ categoryName;
6450
+ };
6451
+ }
6452
+ });
6453
+
6260
6454
  // src/paths.ts
6261
6455
  function resolveAgentShimHome(env = process.env, home = import_node_os4.default.homedir(), isDirectory = isExistingDirectory) {
6262
6456
  const fromEnv = env.AGENT_SHIM_HOME;
@@ -6981,6 +7175,58 @@ function resolveProvider(params) {
6981
7175
  }
6982
7176
  return { ok: true, provider: { name, definition, credential: resolution.credential }, warnings: resolution.credential.warnings };
6983
7177
  }
7178
+ function resolveRoutedProviderCredentials(params) {
7179
+ const { models } = params;
7180
+ if (models === void 0) {
7181
+ return { ok: true, checked: [] };
7182
+ }
7183
+ const virtualNames = new Set(Object.keys(models.virtual ?? {}));
7184
+ const providerNames = /* @__PURE__ */ new Set();
7185
+ const collect = (ref) => {
7186
+ if (ref.startsWith("acct:") || ref.startsWith("family:") || virtualNames.has(ref)) {
7187
+ return;
7188
+ }
7189
+ const [provider] = ref.split("/", 1);
7190
+ if (provider !== void 0 && provider !== "") {
7191
+ providerNames.add(provider);
7192
+ }
7193
+ };
7194
+ for (const model of Object.values(models.virtual ?? {})) {
7195
+ for (const member of model.members) {
7196
+ collect(member);
7197
+ }
7198
+ }
7199
+ for (const ref of Object.values(models.tiers ?? {})) {
7200
+ collect(ref);
7201
+ }
7202
+ if (providerNames.size === 0) {
7203
+ return { ok: true, checked: [] };
7204
+ }
7205
+ if (params.credentials === void 0) {
7206
+ 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` };
7207
+ }
7208
+ const failures = [];
7209
+ let credentialFailure = false;
7210
+ for (const name of [...providerNames].sort()) {
7211
+ const definition = loadProvider(params.paths.providersDir, name, params.port);
7212
+ if (definition === void 0) {
7213
+ failures.push(`no provider named "${name}"`);
7214
+ continue;
7215
+ }
7216
+ if (isRouterProvider(definition)) {
7217
+ continue;
7218
+ }
7219
+ const resolution = resolveCredential({ credential: definition.credential, env: params.env, port: params.credentials, subject: `provider ${name}` });
7220
+ if (!resolution.ok) {
7221
+ failures.push(resolution.message.replace(/^agent-shim: /, ""));
7222
+ credentialFailure = true;
7223
+ }
7224
+ }
7225
+ if (failures.length > 0) {
7226
+ return { ok: false, status: credentialFailure ? CREDENTIAL_UNAVAILABLE_EXIT : 1, message: `agent-shim: this launch routes model names through the models block, but: ${failures.join("; ")}` };
7227
+ }
7228
+ return { ok: true, checked: [...providerNames].sort() };
7229
+ }
6984
7230
  var import_node_fs6, import_node_path25, ProviderNotFoundError, ProviderAlreadyExistsError, InvalidProviderNameError, PROVIDER_NAME_RE, LEGACY_PROVIDER_FIELDS, LEGACY_ENV_CREDENTIAL_KEYS, LEGACY_LITERAL_PLACEHOLDER, LegacyProviderFileError, ProviderKindMismatchError;
6985
7231
  var init_providersStore = __esm({
6986
7232
  "src/providersStore.ts"() {
@@ -7298,6 +7544,62 @@ var init_claudeShim = __esm({
7298
7544
  }
7299
7545
  });
7300
7546
 
7547
+ // src/modelsStore.ts
7548
+ function readModels(paths) {
7549
+ return readGlobalConfig(paths)?.models;
7550
+ }
7551
+ function memberKindOf(ref, models) {
7552
+ if (ref.startsWith("acct:")) {
7553
+ return "account";
7554
+ }
7555
+ if (ref.startsWith("family:")) {
7556
+ return "family";
7557
+ }
7558
+ return models?.virtual !== void 0 && ref in models.virtual ? "virtual" : "provider";
7559
+ }
7560
+ function expandMembers(name, models) {
7561
+ const virtual = models?.virtual ?? {};
7562
+ const expanded = [];
7563
+ const walk = (current, chain) => {
7564
+ const nested = virtual[current];
7565
+ if (nested !== void 0) {
7566
+ if (chain.includes(current)) {
7567
+ throw new Error(`virtual model cycle: ${[...chain, current].join(" -> ")}`);
7568
+ }
7569
+ for (const member of nested.members) {
7570
+ walk(member, [...chain, current]);
7571
+ }
7572
+ return;
7573
+ }
7574
+ if (!expanded.includes(current)) {
7575
+ expanded.push(current);
7576
+ }
7577
+ };
7578
+ const top = virtual[name];
7579
+ if (top === void 0) {
7580
+ throw new VirtualModelNotFoundError(name);
7581
+ }
7582
+ for (const member of top.members) {
7583
+ walk(member, [name]);
7584
+ }
7585
+ return expanded;
7586
+ }
7587
+ var VirtualModelNotFoundError;
7588
+ var init_modelsStore = __esm({
7589
+ "src/modelsStore.ts"() {
7590
+ "use strict";
7591
+ init_store();
7592
+ init_schema();
7593
+ init_configProfilesStore();
7594
+ VirtualModelNotFoundError = class extends Error {
7595
+ constructor(name) {
7596
+ super(`No virtual model named "${name}".`);
7597
+ this.name = "VirtualModelNotFoundError";
7598
+ }
7599
+ };
7600
+ }
7601
+ });
7602
+
7301
7603
  // src/frontdoor/probe.ts
7302
7604
  function probeFrontDoorSync(port, caPem) {
7303
7605
  refuseToBlockInRole("a synchronous probe of the front door");
@@ -7719,7 +8021,8 @@ var init_argv = __esm({
7719
8021
  { flag: "--remote-control", key: "remoteControl" },
7720
8022
  { flag: "--wait", key: "wait" },
7721
8023
  { flag: "--pause", key: "pause" },
7722
- { flag: "--explain", key: "explain" }
8024
+ { flag: "--explain", key: "explain" },
8025
+ { flag: "--route-by-name", key: "routeByName" }
7723
8026
  ];
7724
8027
  LAUNCHER_FLAG_NAMES = [
7725
8028
  ...VALUED_FLAGS,
@@ -7909,6 +8212,7 @@ function resolveLaunchFlags(params) {
7909
8212
  trackUsage: params.flags?.trackUsage ?? parseEnvBool("AGENT_SHIM_TRACK_USAGE", params.env.AGENT_SHIM_TRACK_USAGE) ?? params.cascade?.trackUsage ?? true,
7910
8213
  pause: params.flags?.pause ?? parseEnvBool("AGENT_SHIM_PAUSE", params.env.AGENT_SHIM_PAUSE) ?? params.cascade?.pause ?? false,
7911
8214
  explain: params.flags?.explain ?? parseEnvBool("AGENT_SHIM_EXPLAIN", params.env.AGENT_SHIM_EXPLAIN) ?? params.cascade?.explain ?? false,
8215
+ routeByName: params.flags?.routeByName ?? parseEnvBool("AGENT_SHIM_ROUTE_BY_NAME", params.env.AGENT_SHIM_ROUTE_BY_NAME) ?? params.cascade?.routeByName ?? false,
7912
8216
  delayMs: resolveDelayMs(params)
7913
8217
  };
7914
8218
  }
@@ -7977,6 +8281,7 @@ function buildEnv(params) {
7977
8281
  { name: SESSION_HEADER, value: params.sessionId },
7978
8282
  { name: AUTH_HEADER, value: params.frontdoor.sessionToken },
7979
8283
  ...params.provider === void 0 ? [] : [{ name: PROVIDER_HEADER, value: params.provider.name }],
8284
+ ...params.routeByName ? [{ name: ROUTE_BY_NAME_HEADER, value: "1" }] : [],
7980
8285
  ...params.headroom === void 0 ? [] : [
7981
8286
  { name: HEADROOM_FLAG_HEADER, value: "1" },
7982
8287
  { name: PROJECT_ID_HEADER, value: params.headroom.projectId }
@@ -8619,8 +8924,40 @@ function providerModelRows(provider, catalogue = []) {
8619
8924
  const taken = new Set(named.map((row) => labelOf(row.model)));
8620
8925
  return [...named, ...catalogueRows(provider, catalogue).filter((row) => !taken.has(labelOf(row.model)))];
8621
8926
  }
8927
+ function routedModelRows(models, providers) {
8928
+ const hidden = new Set(models.hide ?? []);
8929
+ const shown = models.show === void 0 ? void 0 : new Set(models.show);
8930
+ const visible = (model) => shown === void 0 ? !hidden.has(model) : shown.has(model);
8931
+ const tierOf = (model) => {
8932
+ for (const [, provider] of providers) {
8933
+ if (provider.kind !== void 0 && provider.kind !== "http") {
8934
+ continue;
8935
+ }
8936
+ const env = provider.env ?? {};
8937
+ const match = Object.entries(env).find(([, value]) => value === model);
8938
+ if (match?.[0].endsWith("_MODEL") === true) {
8939
+ const tier = match[0].replace("ANTHROPIC_DEFAULT_", "").replace("_MODEL", "").toLowerCase();
8940
+ return tier === "fable" || tier === "opus" || tier === "sonnet" || tier === "haiku" ? tier : void 0;
8941
+ }
8942
+ }
8943
+ return void 0;
8944
+ };
8945
+ const virtual = Object.entries(models.virtual ?? {}).flatMap(([name, definition]) => {
8946
+ if (!visible(name)) {
8947
+ return [];
8948
+ }
8949
+ const first = definition.members.find((member) => member.includes("/"));
8950
+ const tier = first === void 0 ? void 0 : tierOf(first.split("/").slice(1).join("/"));
8951
+ const behavesAs = tier === void 0 ? void 0 : TIER_BEHAVES_AS[tier];
8952
+ return behavesAs === void 0 ? [] : [{ model: name, label: name, description: `Virtual (${definition.mode})`, behavesAs }];
8953
+ });
8954
+ const concrete = providers.flatMap(([name, provider]) => providerModelRows(provider).map((row) => ({ ...row, model: `${name}/${row.model}`, label: `${name} / ${row.label}`, description: `${name}: ${row.description}` })));
8955
+ return [...virtual, ...concrete.filter((row) => visible(row.model))];
8956
+ }
8622
8957
  function modelPickerSettings(provider, catalogue = []) {
8623
- const options = providerModelRows(provider, catalogue);
8958
+ return modelPickerSettingsFromRows(providerModelRows(provider, catalogue));
8959
+ }
8960
+ function modelPickerSettingsFromRows(options) {
8624
8961
  return options.length === 0 ? void 0 : JSON.stringify({ modelPicker: { options, replaceBuiltInOptions: true } });
8625
8962
  }
8626
8963
  var CONTEXT_MARKER_1M, TIER_BEHAVES_AS, TIER_ENV_VARIABLES;
@@ -9057,6 +9394,7 @@ function decideLaunch(params, readOnly) {
9057
9394
  ...parsedArgv.trackUsage === void 0 ? {} : { trackUsage: parsedArgv.trackUsage },
9058
9395
  ...parsedArgv.pause === void 0 ? {} : { pause: parsedArgv.pause },
9059
9396
  ...parsedArgv.explain === void 0 ? {} : { explain: parsedArgv.explain },
9397
+ ...parsedArgv.routeByName === void 0 ? {} : { routeByName: parsedArgv.routeByName },
9060
9398
  ...parsedArgv.delay === void 0 ? {} : { delay: parsedArgv.delay }
9061
9399
  }
9062
9400
  });
@@ -9067,7 +9405,8 @@ function decideLaunch(params, readOnly) {
9067
9405
  }
9068
9406
  const flags = loginlessProvider === void 0 ? requestedFlags : { ...requestedFlags, remoteControl: false };
9069
9407
  const catalogue = selectedProvider === void 0 ? void 0 : parseCatalogueCache(params.fs.readFileUtf8(catalogueCachePath(paths, selectedProvider.name)));
9070
- const pickerSettings = selectedProvider === void 0 ? void 0 : modelPickerSettings(selectedProvider.definition, catalogue?.models);
9408
+ const routesByName = flags.routeByName || selectedProvider !== void 0 && isRouterProvider(selectedProvider.definition);
9409
+ 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);
9071
9410
  const callerSettings = hasSettingsArgument(parsedArgv.rest);
9072
9411
  if (pickerSettings !== void 0 && callerSettings) {
9073
9412
  notes.push("--settings was passed, so /model keeps Claude Code's own model names");
@@ -9169,6 +9508,14 @@ function prepareLaunch(params) {
9169
9508
  if (decided.pinnedVersion !== void 0) {
9170
9509
  rows.push(pinnedVersionRow(decided.pinnedVersion.version, decided.pinnedVersion.source));
9171
9510
  }
9511
+ const routesByName = resolvedFlags.routeByName || resolvedProvider !== void 0 && isRouterProvider(resolvedProvider.definition);
9512
+ if (routesByName) {
9513
+ const check = resolveRoutedProviderCredentials({ paths, port: params.fs, env, ...params.credentials === void 0 ? {} : { credentials: params.credentials }, models: loadConfigFile(paths.globalConfigFile, GlobalConfigSchema, params.fs.readConfigFile)?.config.models });
9514
+ if (!check.ok) {
9515
+ log.error(check.message);
9516
+ proc.exit(check.status);
9517
+ }
9518
+ }
9172
9519
  const frontDoorPort = params.frontdoor;
9173
9520
  const frontDoorEngaged = resolvedProvider !== void 0 || resolvedFlags.headroom || resolvedFlags.trackUsage;
9174
9521
  if (frontDoorEngaged && frontDoorPort === void 0) {
@@ -9200,7 +9547,8 @@ function prepareLaunch(params) {
9200
9547
  ...frontDoor === void 0 ? {} : { frontdoor: frontDoor },
9201
9548
  ...headroom === void 0 ? {} : { headroom },
9202
9549
  sessionId,
9203
- remoteControl: resolvedFlags.remoteControl
9550
+ remoteControl: resolvedFlags.remoteControl,
9551
+ routeByName: routesByName
9204
9552
  });
9205
9553
  const releases = [...headroom === void 0 || headroomPort === void 0 ? [] : [headroomPort.release], ...frontDoorRelease === void 0 ? [] : [frontDoorRelease]];
9206
9554
  const release = () => {
@@ -9227,7 +9575,8 @@ function resolveLaunch(params) {
9227
9575
  ...frontDoor ? { frontdoor: { port: 0, connectPort: 0, trustBundlePath: "", sessionToken: "" } } : {},
9228
9576
  ...decided.flags.headroom ? { headroom: { socketPath: "", projectId: "" } } : {},
9229
9577
  sessionId: "",
9230
- remoteControl: decided.flags.remoteControl
9578
+ remoteControl: decided.flags.remoteControl,
9579
+ routeByName: decided.flags.routeByName
9231
9580
  });
9232
9581
  const credentialNames = decided.identityCredentialBlock === void 0 ? [] : Object.keys(credentialVariables(decided.identityCredentialBlock.target ?? "bearer", ""));
9233
9582
  const environment = [.../* @__PURE__ */ new Set([...Object.keys(built).filter((name) => built[name] !== env[name]), ...credentialNames])].sort();
@@ -9239,7 +9588,7 @@ function resolveLaunch(params) {
9239
9588
  bin: decided.bin,
9240
9589
  args: decided.args,
9241
9590
  ...credential === void 0 ? {} : { credential },
9242
- routing: { frontDoor, headroom: decided.flags.headroom },
9591
+ routing: { frontDoor, headroom: decided.flags.headroom, routeByName: decided.flags.routeByName },
9243
9592
  environment
9244
9593
  };
9245
9594
  }
@@ -9282,14 +9631,18 @@ var init_launcher = __esm({
9282
9631
  init_launchReport();
9283
9632
  init_modelPicker();
9284
9633
  init_providerCatalogue();
9634
+ init_modelsStore();
9635
+ init_providersStore();
9285
9636
  init_pool();
9286
9637
  init_resumeContext();
9287
9638
  init_lock();
9288
9639
  init_spawn();
9289
9640
  init_providersStore();
9641
+ init_load();
9290
9642
  init_flatten();
9291
9643
  init_walk();
9292
9644
  init_schema();
9645
+ init_schema();
9293
9646
  init_credential();
9294
9647
  init_middleware();
9295
9648
  init_preflight();
@@ -13958,189 +14311,7 @@ function collectPoolPick(params) {
13958
14311
 
13959
14312
  // src/poolStore.ts
13960
14313
  init_cliError();
13961
-
13962
- // src/configProfilesStore.ts
13963
- var import_node_fs3 = __toESM(require("node:fs"), 1);
13964
- var import_node_path22 = __toESM(require("node:path"), 1);
13965
- init_store();
13966
- init_schema();
13967
- init_cliError();
13968
- init_load();
13969
- var ProfileNotFoundError = class extends CliError {
13970
- constructor(profileName) {
13971
- super(`No configuration profile named "${profileName}". Run \`agent-shim profile add ${profileName}\` first.`);
13972
- this.profileName = profileName;
13973
- this.name = "ProfileNotFoundError";
13974
- }
13975
- profileName;
13976
- };
13977
- var ProfileAlreadyExistsError = class extends CliError {
13978
- constructor(profileName) {
13979
- super(`A configuration profile named "${profileName}" already exists.`);
13980
- this.profileName = profileName;
13981
- this.name = "ProfileAlreadyExistsError";
13982
- }
13983
- profileName;
13984
- };
13985
- var InvalidCategoryNameError = class extends CliError {
13986
- constructor(categoryName) {
13987
- super(`"${categoryName}" is not a category a configuration profile may toggle (runtime, history, knowledge, settings).`);
13988
- this.categoryName = categoryName;
13989
- this.name = "InvalidCategoryNameError";
13990
- }
13991
- categoryName;
13992
- };
13993
- function profileJsonPath(paths, name) {
13994
- return import_node_path22.default.join(paths.configProfilesDir, `${name}.json`);
13995
- }
13996
- function profileExists(paths, name) {
13997
- return import_node_fs3.default.existsSync(profileJsonPath(paths, name));
13998
- }
13999
- function requireProfileExists(paths, name) {
14000
- if (!profileExists(paths, name)) {
14001
- throw new ProfileNotFoundError(name);
14002
- }
14003
- }
14004
- function readProfile(paths, name) {
14005
- return readJson(profileJsonPath(paths, name), ConfigProfileSchema);
14006
- }
14007
- function createProfile(paths, name, extendsList, description) {
14008
- if (profileExists(paths, name)) {
14009
- throw new ProfileAlreadyExistsError(name);
14010
- }
14011
- const filePath = profileJsonPath(paths, name);
14012
- const parsed = ConfigProfileSchema.safeParse({
14013
- ...description === void 0 ? {} : { description },
14014
- ...extendsList !== void 0 && extendsList.length > 0 ? { extends: [...extendsList] } : {}
14015
- });
14016
- if (!parsed.success) {
14017
- throw new ConfigValidationError(filePath, parsed.error.issues);
14018
- }
14019
- writeJsonAtomic(filePath, parsed.data);
14020
- return parsed.data;
14021
- }
14022
- function listProfiles(paths) {
14023
- if (!import_node_fs3.default.existsSync(paths.configProfilesDir)) {
14024
- return [];
14025
- }
14026
- const names = import_node_fs3.default.readdirSync(paths.configProfilesDir, { withFileTypes: true }).filter((entry) => entry.isFile() && entry.name.endsWith(".json")).map((entry) => entry.name.slice(0, -".json".length)).sort();
14027
- const result = [];
14028
- for (const name of names) {
14029
- const profile = readProfile(paths, name);
14030
- if (profile !== void 0) {
14031
- result.push({ name, profile });
14032
- }
14033
- }
14034
- return result;
14035
- }
14036
- function globalConfigPath(paths) {
14037
- return paths.globalConfigFile;
14038
- }
14039
- function readGlobalConfig(paths) {
14040
- return readJson(globalConfigPath(paths), GlobalConfigSchema);
14041
- }
14042
- function setGlobalDefaultProfile(paths, name) {
14043
- return applyPatch(
14044
- globalConfigPath(paths),
14045
- GlobalConfigSchema,
14046
- { defaultConfigProfile: name },
14047
- { defaults: {} }
14048
- );
14049
- }
14050
- function validateCategoryNames(patch) {
14051
- for (const key of Object.keys(patch)) {
14052
- if (!isOverridableCategory(key)) {
14053
- throw new InvalidCategoryNameError(key);
14054
- }
14055
- }
14056
- }
14057
- function setProfileCategories(paths, name, patch) {
14058
- requireProfileExists(paths, name);
14059
- const expandedPatch = expandAllCategoryKey(patch);
14060
- validateCategoryNames(expandedPatch);
14061
- const existing = readProfile(paths, name) ?? {};
14062
- const mergedCategories = { ...existing.categories, ...expandedPatch };
14063
- return applyPatch(profileJsonPath(paths, name), ConfigProfileSchema, { categories: mergedCategories });
14064
- }
14065
- function setProfileEntries(paths, name, patch) {
14066
- requireProfileExists(paths, name);
14067
- const existing = readProfile(paths, name) ?? {};
14068
- const mergedEntries = { ...existing.entries, ...patch };
14069
- return applyPatch(profileJsonPath(paths, name), ConfigProfileSchema, { entries: mergedEntries });
14070
- }
14071
- function setProfileLaunchFlags(paths, name, patch) {
14072
- requireProfileExists(paths, name);
14073
- const existing = readProfile(paths, name) ?? {};
14074
- const mergedLaunch = { ...existing.launch, ...patch };
14075
- return applyPatch(profileJsonPath(paths, name), ConfigProfileSchema, {
14076
- // Read as `unknown` so the check sees the `undefined` a cleared key holds, which LaunchFlags' optional properties hide from the value type.
14077
- launch: Object.values(mergedLaunch).every((value) => value === void 0) ? void 0 : mergedLaunch
14078
- });
14079
- }
14080
- function setProfileMetadata(paths, name, patch) {
14081
- requireProfileExists(paths, name);
14082
- return applyPatch(profileJsonPath(paths, name), ConfigProfileSchema, {
14083
- ...patch.extends === void 0 ? {} : { extends: patch.extends.length === 0 ? void 0 : [...patch.extends] },
14084
- ...patch.description === void 0 ? {} : { description: patch.description === false ? void 0 : patch.description }
14085
- });
14086
- }
14087
- function removeProfile(paths, name) {
14088
- requireProfileExists(paths, name);
14089
- import_node_fs3.default.rmSync(profileJsonPath(paths, name));
14090
- }
14091
- function applyProfileChange(paths, name, change) {
14092
- let touched = false;
14093
- if (change.category !== void 0) {
14094
- setProfileCategories(paths, name, change.category);
14095
- touched = true;
14096
- }
14097
- if (change.entry !== void 0) {
14098
- setProfileEntries(paths, name, change.entry);
14099
- touched = true;
14100
- }
14101
- if (change.extends !== void 0 || change.description !== void 0) {
14102
- setProfileMetadata(paths, name, {
14103
- ...change.extends === void 0 ? {} : { extends: change.extends === false ? [] : change.extends },
14104
- ...change.description === void 0 ? {} : { description: change.description }
14105
- });
14106
- touched = true;
14107
- }
14108
- const launchPatch = {};
14109
- if (change.launchSkipPermissions !== void 0) {
14110
- launchPatch.skipPermissions = change.launchSkipPermissions;
14111
- }
14112
- if (change.launchRemoteControl !== void 0) {
14113
- launchPatch.remoteControl = change.launchRemoteControl;
14114
- }
14115
- if (change.launchHeadroom !== void 0) {
14116
- launchPatch.headroom = change.launchHeadroom;
14117
- }
14118
- if (change.launchTrackUsage !== void 0) {
14119
- launchPatch.trackUsage = change.launchTrackUsage;
14120
- }
14121
- if (change.launchProvider !== void 0) {
14122
- launchPatch.provider = change.launchProvider === false ? void 0 : change.launchProvider;
14123
- }
14124
- if (change.launchClaudeVersion !== void 0) {
14125
- launchPatch.claudeVersion = change.launchClaudeVersion === false ? void 0 : change.launchClaudeVersion;
14126
- }
14127
- if (change.launchDelay !== void 0) {
14128
- launchPatch.delay = change.launchDelay === false ? void 0 : change.launchDelay;
14129
- }
14130
- if (change.launchPause !== void 0) {
14131
- launchPatch.pause = change.launchPause;
14132
- }
14133
- if (change.launchExplain !== void 0) {
14134
- launchPatch.explain = change.launchExplain;
14135
- }
14136
- if (Object.keys(launchPatch).length > 0) {
14137
- setProfileLaunchFlags(paths, name, launchPatch);
14138
- touched = true;
14139
- }
14140
- return touched;
14141
- }
14142
-
14143
- // src/poolStore.ts
14314
+ init_configProfilesStore();
14144
14315
  init_store();
14145
14316
  init_schema();
14146
14317
  init_identity();
@@ -15221,53 +15392,8 @@ init_credentialCache();
15221
15392
  init_realCredentialCache();
15222
15393
  init_source();
15223
15394
 
15224
- // src/modelsStore.ts
15225
- init_store();
15226
- init_schema();
15227
- var VirtualModelNotFoundError = class extends Error {
15228
- constructor(name) {
15229
- super(`No virtual model named "${name}".`);
15230
- this.name = "VirtualModelNotFoundError";
15231
- }
15232
- };
15233
- function memberKindOf(ref, models) {
15234
- if (ref.startsWith("acct:")) {
15235
- return "account";
15236
- }
15237
- if (ref.startsWith("family:")) {
15238
- return "family";
15239
- }
15240
- return models?.virtual !== void 0 && ref in models.virtual ? "virtual" : "provider";
15241
- }
15242
- function expandMembers(name, models) {
15243
- const virtual = models?.virtual ?? {};
15244
- const expanded = [];
15245
- const walk = (current, chain) => {
15246
- const nested = virtual[current];
15247
- if (nested !== void 0) {
15248
- if (chain.includes(current)) {
15249
- throw new Error(`virtual model cycle: ${[...chain, current].join(" -> ")}`);
15250
- }
15251
- for (const member of nested.members) {
15252
- walk(member, [...chain, current]);
15253
- }
15254
- return;
15255
- }
15256
- if (!expanded.includes(current)) {
15257
- expanded.push(current);
15258
- }
15259
- };
15260
- const top = virtual[name];
15261
- if (top === void 0) {
15262
- throw new VirtualModelNotFoundError(name);
15263
- }
15264
- for (const member of top.members) {
15265
- walk(member, [name]);
15266
- }
15267
- return expanded;
15268
- }
15269
-
15270
15395
  // src/models/doctor.ts
15396
+ init_modelsStore();
15271
15397
  function modelsFindings(input) {
15272
15398
  const findings = [];
15273
15399
  const { models } = input;
@@ -15322,6 +15448,9 @@ function modelsFindings(input) {
15322
15448
  return findings;
15323
15449
  }
15324
15450
 
15451
+ // src/doctorReport.ts
15452
+ init_configProfilesStore();
15453
+
15325
15454
  // src/headroom/allowlistDrift.ts
15326
15455
  init_earlierRelease();
15327
15456
  init_state2();
@@ -16264,6 +16393,7 @@ var import_client2 = require("@orpc/client");
16264
16393
  var import_openapi3 = require("@orpc/openapi");
16265
16394
  init_cliError();
16266
16395
  init_schema();
16396
+ init_configProfilesStore();
16267
16397
  init_credential();
16268
16398
 
16269
16399
  // src/credentialCacheChange.ts
@@ -16472,7 +16602,8 @@ var ConfigProfileSetInputSchema = import_zod24.z.strictObject({
16472
16602
  claudeVersion: import_zod24.z.union([import_zod24.z.string().min(1), import_zod24.z.literal(false)]).optional(),
16473
16603
  delay: import_zod24.z.union([import_zod24.z.string().regex(DURATION_RE), import_zod24.z.literal(false)]).optional(),
16474
16604
  pause: import_zod24.z.boolean().optional(),
16475
- explain: import_zod24.z.boolean().optional()
16605
+ explain: import_zod24.z.boolean().optional(),
16606
+ routeByName: import_zod24.z.boolean().optional()
16476
16607
  }).optional()
16477
16608
  });
16478
16609
  var ConfigProfileSetOutputSchema = storedMutationOutput("profile", "updated", ProfileValueSchema);
@@ -16684,7 +16815,8 @@ function createConfigApiRouter(deps) {
16684
16815
  ...launch?.claudeVersion === void 0 ? {} : { launchClaudeVersion: launch.claudeVersion },
16685
16816
  ...launch?.delay === void 0 ? {} : { launchDelay: launch.delay },
16686
16817
  ...launch?.pause === void 0 ? {} : { launchPause: launch.pause },
16687
- ...launch?.explain === void 0 ? {} : { launchExplain: launch.explain }
16818
+ ...launch?.explain === void 0 ? {} : { launchExplain: launch.explain },
16819
+ ...launch?.routeByName === void 0 ? {} : { launchRouteByName: launch.routeByName }
16688
16820
  });
16689
16821
  return { action: "updated", kind: "profile", name: input.name, value: profileValue(input.name, paths) };
16690
16822
  })
@@ -16995,6 +17127,7 @@ var LaunchFlagsSchema = import_zod26.z.strictObject({
16995
17127
  trackUsage: import_zod26.z.boolean(),
16996
17128
  pause: import_zod26.z.boolean(),
16997
17129
  explain: import_zod26.z.boolean(),
17130
+ routeByName: import_zod26.z.boolean(),
16998
17131
  /** How long the launch waits after its own output before it starts claude, in milliseconds. */
16999
17132
  delayMs: import_zod26.z.number()
17000
17133
  });
@@ -17008,7 +17141,7 @@ var LaunchResolveOutputSchema = import_zod26.z.strictObject({
17008
17141
  args: import_zod26.z.readonly(import_zod26.z.array(import_zod26.z.string())),
17009
17142
  /** The credential the launch would authenticate with, by target and source kinds. Absent when none applies. */
17010
17143
  credential: import_zod26.z.strictObject({ subject: import_zod26.z.enum(["provider", "identity"]), name: import_zod26.z.string(), summary: CredentialSummarySchema }).optional(),
17011
- routing: import_zod26.z.strictObject({ frontDoor: import_zod26.z.boolean(), headroom: import_zod26.z.boolean() }),
17144
+ routing: import_zod26.z.strictObject({ frontDoor: import_zod26.z.boolean(), headroom: import_zod26.z.boolean(), routeByName: import_zod26.z.boolean() }),
17012
17145
  /** The names of the environment variables the launch would set or unset, sorted. Values are not reported. */
17013
17146
  environment: import_zod26.z.readonly(import_zod26.z.array(import_zod26.z.string())),
17014
17147
  warnings: import_zod26.z.readonly(import_zod26.z.array(import_zod26.z.string()))
@@ -19639,6 +19772,7 @@ init_guard();
19639
19772
  init_paths();
19640
19773
  init_cliError();
19641
19774
  init_schema();
19775
+ init_configProfilesStore();
19642
19776
  init_providersStore();
19643
19777
  init_launcher();
19644
19778
  init_spawn();