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.mjs CHANGED
@@ -1434,6 +1434,9 @@ function flattenLayers(layers, options) {
1434
1434
  if (layer.launch.explain !== void 0) {
1435
1435
  launch.explain = layer.launch.explain;
1436
1436
  }
1437
+ if (layer.launch.routeByName !== void 0) {
1438
+ launch.routeByName = layer.launch.routeByName;
1439
+ }
1437
1440
  }
1438
1441
  if (layer.models !== void 0) {
1439
1442
  models = mergeModels(models, layer.models);
@@ -2862,7 +2865,7 @@ var init_capability = __esm({
2862
2865
  });
2863
2866
 
2864
2867
  // src/frontdoor/route.ts
2865
- var IDENTITY_HEADER, SESSION_HEADER, PROVIDER_HEADER, HEADROOM_FLAG_HEADER, PROJECT_ID_HEADER, AUTH_HEADER;
2868
+ var IDENTITY_HEADER, SESSION_HEADER, PROVIDER_HEADER, HEADROOM_FLAG_HEADER, ROUTE_BY_NAME_HEADER, PROJECT_ID_HEADER, AUTH_HEADER;
2866
2869
  var init_route = __esm({
2867
2870
  "src/frontdoor/route.ts"() {
2868
2871
  "use strict";
@@ -2870,6 +2873,7 @@ var init_route = __esm({
2870
2873
  SESSION_HEADER = "x-agent-shim-session";
2871
2874
  PROVIDER_HEADER = "x-agent-shim-provider";
2872
2875
  HEADROOM_FLAG_HEADER = "x-agent-shim-headroom";
2876
+ ROUTE_BY_NAME_HEADER = "x-agent-shim-route-by-name";
2873
2877
  PROJECT_ID_HEADER = "x-headroom-project-id";
2874
2878
  AUTH_HEADER = "x-agent-shim-auth";
2875
2879
  }
@@ -3078,7 +3082,7 @@ var init_package = __esm({
3078
3082
  "package.json"() {
3079
3083
  package_default = {
3080
3084
  name: "agent-shim",
3081
- version: "11.34.0",
3085
+ version: "11.36.0",
3082
3086
  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.",
3083
3087
  license: "MIT",
3084
3088
  author: "Joseph Mearman <joseph@mearman.co.uk>",
@@ -6231,6 +6235,196 @@ var init_poolPick = __esm({
6231
6235
  }
6232
6236
  });
6233
6237
 
6238
+ // src/configProfilesStore.ts
6239
+ import fs4 from "node:fs";
6240
+ import path22 from "node:path";
6241
+ function profileJsonPath(paths, name) {
6242
+ return path22.join(paths.configProfilesDir, `${name}.json`);
6243
+ }
6244
+ function profileExists(paths, name) {
6245
+ return fs4.existsSync(profileJsonPath(paths, name));
6246
+ }
6247
+ function requireProfileExists(paths, name) {
6248
+ if (!profileExists(paths, name)) {
6249
+ throw new ProfileNotFoundError(name);
6250
+ }
6251
+ }
6252
+ function readProfile(paths, name) {
6253
+ return readJson(profileJsonPath(paths, name), ConfigProfileSchema);
6254
+ }
6255
+ function createProfile(paths, name, extendsList, description) {
6256
+ if (profileExists(paths, name)) {
6257
+ throw new ProfileAlreadyExistsError(name);
6258
+ }
6259
+ const filePath = profileJsonPath(paths, name);
6260
+ const parsed = ConfigProfileSchema.safeParse({
6261
+ ...description === void 0 ? {} : { description },
6262
+ ...extendsList !== void 0 && extendsList.length > 0 ? { extends: [...extendsList] } : {}
6263
+ });
6264
+ if (!parsed.success) {
6265
+ throw new ConfigValidationError(filePath, parsed.error.issues);
6266
+ }
6267
+ writeJsonAtomic(filePath, parsed.data);
6268
+ return parsed.data;
6269
+ }
6270
+ function listProfiles(paths) {
6271
+ if (!fs4.existsSync(paths.configProfilesDir)) {
6272
+ return [];
6273
+ }
6274
+ const names = fs4.readdirSync(paths.configProfilesDir, { withFileTypes: true }).filter((entry) => entry.isFile() && entry.name.endsWith(".json")).map((entry) => entry.name.slice(0, -".json".length)).sort();
6275
+ const result = [];
6276
+ for (const name of names) {
6277
+ const profile = readProfile(paths, name);
6278
+ if (profile !== void 0) {
6279
+ result.push({ name, profile });
6280
+ }
6281
+ }
6282
+ return result;
6283
+ }
6284
+ function globalConfigPath(paths) {
6285
+ return paths.globalConfigFile;
6286
+ }
6287
+ function readGlobalConfig(paths) {
6288
+ return readJson(globalConfigPath(paths), GlobalConfigSchema);
6289
+ }
6290
+ function setGlobalDefaultProfile(paths, name) {
6291
+ return applyPatch(
6292
+ globalConfigPath(paths),
6293
+ GlobalConfigSchema,
6294
+ { defaultConfigProfile: name },
6295
+ { defaults: {} }
6296
+ );
6297
+ }
6298
+ function validateCategoryNames(patch) {
6299
+ for (const key of Object.keys(patch)) {
6300
+ if (!isOverridableCategory(key)) {
6301
+ throw new InvalidCategoryNameError(key);
6302
+ }
6303
+ }
6304
+ }
6305
+ function setProfileCategories(paths, name, patch) {
6306
+ requireProfileExists(paths, name);
6307
+ const expandedPatch = expandAllCategoryKey(patch);
6308
+ validateCategoryNames(expandedPatch);
6309
+ const existing = readProfile(paths, name) ?? {};
6310
+ const mergedCategories = { ...existing.categories, ...expandedPatch };
6311
+ return applyPatch(profileJsonPath(paths, name), ConfigProfileSchema, { categories: mergedCategories });
6312
+ }
6313
+ function setProfileEntries(paths, name, patch) {
6314
+ requireProfileExists(paths, name);
6315
+ const existing = readProfile(paths, name) ?? {};
6316
+ const mergedEntries = { ...existing.entries, ...patch };
6317
+ return applyPatch(profileJsonPath(paths, name), ConfigProfileSchema, { entries: mergedEntries });
6318
+ }
6319
+ function setProfileLaunchFlags(paths, name, patch) {
6320
+ requireProfileExists(paths, name);
6321
+ const existing = readProfile(paths, name) ?? {};
6322
+ const mergedLaunch = { ...existing.launch, ...patch };
6323
+ return applyPatch(profileJsonPath(paths, name), ConfigProfileSchema, {
6324
+ // Read as `unknown` so the check sees the `undefined` a cleared key holds, which LaunchFlags' optional properties hide from the value type.
6325
+ launch: Object.values(mergedLaunch).every((value) => value === void 0) ? void 0 : mergedLaunch
6326
+ });
6327
+ }
6328
+ function setProfileMetadata(paths, name, patch) {
6329
+ requireProfileExists(paths, name);
6330
+ return applyPatch(profileJsonPath(paths, name), ConfigProfileSchema, {
6331
+ ...patch.extends === void 0 ? {} : { extends: patch.extends.length === 0 ? void 0 : [...patch.extends] },
6332
+ ...patch.description === void 0 ? {} : { description: patch.description === false ? void 0 : patch.description }
6333
+ });
6334
+ }
6335
+ function removeProfile(paths, name) {
6336
+ requireProfileExists(paths, name);
6337
+ fs4.rmSync(profileJsonPath(paths, name));
6338
+ }
6339
+ function applyProfileChange(paths, name, change) {
6340
+ let touched = false;
6341
+ if (change.category !== void 0) {
6342
+ setProfileCategories(paths, name, change.category);
6343
+ touched = true;
6344
+ }
6345
+ if (change.entry !== void 0) {
6346
+ setProfileEntries(paths, name, change.entry);
6347
+ touched = true;
6348
+ }
6349
+ if (change.extends !== void 0 || change.description !== void 0) {
6350
+ setProfileMetadata(paths, name, {
6351
+ ...change.extends === void 0 ? {} : { extends: change.extends === false ? [] : change.extends },
6352
+ ...change.description === void 0 ? {} : { description: change.description }
6353
+ });
6354
+ touched = true;
6355
+ }
6356
+ const launchPatch = {};
6357
+ if (change.launchSkipPermissions !== void 0) {
6358
+ launchPatch.skipPermissions = change.launchSkipPermissions;
6359
+ }
6360
+ if (change.launchRemoteControl !== void 0) {
6361
+ launchPatch.remoteControl = change.launchRemoteControl;
6362
+ }
6363
+ if (change.launchHeadroom !== void 0) {
6364
+ launchPatch.headroom = change.launchHeadroom;
6365
+ }
6366
+ if (change.launchTrackUsage !== void 0) {
6367
+ launchPatch.trackUsage = change.launchTrackUsage;
6368
+ }
6369
+ if (change.launchProvider !== void 0) {
6370
+ launchPatch.provider = change.launchProvider === false ? void 0 : change.launchProvider;
6371
+ }
6372
+ if (change.launchClaudeVersion !== void 0) {
6373
+ launchPatch.claudeVersion = change.launchClaudeVersion === false ? void 0 : change.launchClaudeVersion;
6374
+ }
6375
+ if (change.launchDelay !== void 0) {
6376
+ launchPatch.delay = change.launchDelay === false ? void 0 : change.launchDelay;
6377
+ }
6378
+ if (change.launchPause !== void 0) {
6379
+ launchPatch.pause = change.launchPause;
6380
+ }
6381
+ if (change.launchExplain !== void 0) {
6382
+ launchPatch.explain = change.launchExplain;
6383
+ }
6384
+ if (change.launchRouteByName !== void 0) {
6385
+ launchPatch.routeByName = change.launchRouteByName;
6386
+ }
6387
+ if (Object.keys(launchPatch).length > 0) {
6388
+ setProfileLaunchFlags(paths, name, launchPatch);
6389
+ touched = true;
6390
+ }
6391
+ return touched;
6392
+ }
6393
+ var ProfileNotFoundError, ProfileAlreadyExistsError, InvalidCategoryNameError;
6394
+ var init_configProfilesStore = __esm({
6395
+ "src/configProfilesStore.ts"() {
6396
+ "use strict";
6397
+ init_store();
6398
+ init_schema();
6399
+ init_cliError();
6400
+ init_load();
6401
+ ProfileNotFoundError = class extends CliError {
6402
+ constructor(profileName) {
6403
+ super(`No configuration profile named "${profileName}". Run \`agent-shim profile add ${profileName}\` first.`);
6404
+ this.profileName = profileName;
6405
+ this.name = "ProfileNotFoundError";
6406
+ }
6407
+ profileName;
6408
+ };
6409
+ ProfileAlreadyExistsError = class extends CliError {
6410
+ constructor(profileName) {
6411
+ super(`A configuration profile named "${profileName}" already exists.`);
6412
+ this.profileName = profileName;
6413
+ this.name = "ProfileAlreadyExistsError";
6414
+ }
6415
+ profileName;
6416
+ };
6417
+ InvalidCategoryNameError = class extends CliError {
6418
+ constructor(categoryName) {
6419
+ super(`"${categoryName}" is not a category a configuration profile may toggle (runtime, history, knowledge, settings).`);
6420
+ this.categoryName = categoryName;
6421
+ this.name = "InvalidCategoryNameError";
6422
+ }
6423
+ categoryName;
6424
+ };
6425
+ }
6426
+ });
6427
+
6234
6428
  // src/paths.ts
6235
6429
  import fs5 from "node:fs";
6236
6430
  import os5 from "node:os";
@@ -6956,6 +7150,58 @@ function resolveProvider(params) {
6956
7150
  }
6957
7151
  return { ok: true, provider: { name, definition, credential: resolution.credential }, warnings: resolution.credential.warnings };
6958
7152
  }
7153
+ function resolveRoutedProviderCredentials(params) {
7154
+ const { models } = params;
7155
+ if (models === void 0) {
7156
+ return { ok: true, checked: [] };
7157
+ }
7158
+ const virtualNames = new Set(Object.keys(models.virtual ?? {}));
7159
+ const providerNames = /* @__PURE__ */ new Set();
7160
+ const collect = (ref) => {
7161
+ if (ref.startsWith("acct:") || ref.startsWith("family:") || virtualNames.has(ref)) {
7162
+ return;
7163
+ }
7164
+ const [provider] = ref.split("/", 1);
7165
+ if (provider !== void 0 && provider !== "") {
7166
+ providerNames.add(provider);
7167
+ }
7168
+ };
7169
+ for (const model of Object.values(models.virtual ?? {})) {
7170
+ for (const member of model.members) {
7171
+ collect(member);
7172
+ }
7173
+ }
7174
+ for (const ref of Object.values(models.tiers ?? {})) {
7175
+ collect(ref);
7176
+ }
7177
+ if (providerNames.size === 0) {
7178
+ return { ok: true, checked: [] };
7179
+ }
7180
+ if (params.credentials === void 0) {
7181
+ 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` };
7182
+ }
7183
+ const failures = [];
7184
+ let credentialFailure = false;
7185
+ for (const name of [...providerNames].sort()) {
7186
+ const definition = loadProvider(params.paths.providersDir, name, params.port);
7187
+ if (definition === void 0) {
7188
+ failures.push(`no provider named "${name}"`);
7189
+ continue;
7190
+ }
7191
+ if (isRouterProvider(definition)) {
7192
+ continue;
7193
+ }
7194
+ const resolution = resolveCredential({ credential: definition.credential, env: params.env, port: params.credentials, subject: `provider ${name}` });
7195
+ if (!resolution.ok) {
7196
+ failures.push(resolution.message.replace(/^agent-shim: /, ""));
7197
+ credentialFailure = true;
7198
+ }
7199
+ }
7200
+ if (failures.length > 0) {
7201
+ return { ok: false, status: credentialFailure ? CREDENTIAL_UNAVAILABLE_EXIT : 1, message: `agent-shim: this launch routes model names through the models block, but: ${failures.join("; ")}` };
7202
+ }
7203
+ return { ok: true, checked: [...providerNames].sort() };
7204
+ }
6959
7205
  var ProviderNotFoundError, ProviderAlreadyExistsError, InvalidProviderNameError, PROVIDER_NAME_RE, LEGACY_PROVIDER_FIELDS, LEGACY_ENV_CREDENTIAL_KEYS, LEGACY_LITERAL_PLACEHOLDER, LegacyProviderFileError, ProviderKindMismatchError;
6960
7206
  var init_providersStore = __esm({
6961
7207
  "src/providersStore.ts"() {
@@ -7271,6 +7517,62 @@ var init_claudeShim = __esm({
7271
7517
  }
7272
7518
  });
7273
7519
 
7520
+ // src/modelsStore.ts
7521
+ function readModels(paths) {
7522
+ return readGlobalConfig(paths)?.models;
7523
+ }
7524
+ function memberKindOf(ref, models) {
7525
+ if (ref.startsWith("acct:")) {
7526
+ return "account";
7527
+ }
7528
+ if (ref.startsWith("family:")) {
7529
+ return "family";
7530
+ }
7531
+ return models?.virtual !== void 0 && ref in models.virtual ? "virtual" : "provider";
7532
+ }
7533
+ function expandMembers(name, models) {
7534
+ const virtual = models?.virtual ?? {};
7535
+ const expanded = [];
7536
+ const walk = (current, chain) => {
7537
+ const nested = virtual[current];
7538
+ if (nested !== void 0) {
7539
+ if (chain.includes(current)) {
7540
+ throw new Error(`virtual model cycle: ${[...chain, current].join(" -> ")}`);
7541
+ }
7542
+ for (const member of nested.members) {
7543
+ walk(member, [...chain, current]);
7544
+ }
7545
+ return;
7546
+ }
7547
+ if (!expanded.includes(current)) {
7548
+ expanded.push(current);
7549
+ }
7550
+ };
7551
+ const top = virtual[name];
7552
+ if (top === void 0) {
7553
+ throw new VirtualModelNotFoundError(name);
7554
+ }
7555
+ for (const member of top.members) {
7556
+ walk(member, [name]);
7557
+ }
7558
+ return expanded;
7559
+ }
7560
+ var VirtualModelNotFoundError;
7561
+ var init_modelsStore = __esm({
7562
+ "src/modelsStore.ts"() {
7563
+ "use strict";
7564
+ init_store();
7565
+ init_schema();
7566
+ init_configProfilesStore();
7567
+ VirtualModelNotFoundError = class extends Error {
7568
+ constructor(name) {
7569
+ super(`No virtual model named "${name}".`);
7570
+ this.name = "VirtualModelNotFoundError";
7571
+ }
7572
+ };
7573
+ }
7574
+ });
7575
+
7274
7576
  // src/frontdoor/probe.ts
7275
7577
  import { Worker } from "node:worker_threads";
7276
7578
  function probeFrontDoorSync(port, caPem) {
@@ -7692,7 +7994,8 @@ var init_argv = __esm({
7692
7994
  { flag: "--remote-control", key: "remoteControl" },
7693
7995
  { flag: "--wait", key: "wait" },
7694
7996
  { flag: "--pause", key: "pause" },
7695
- { flag: "--explain", key: "explain" }
7997
+ { flag: "--explain", key: "explain" },
7998
+ { flag: "--route-by-name", key: "routeByName" }
7696
7999
  ];
7697
8000
  LAUNCHER_FLAG_NAMES = [
7698
8001
  ...VALUED_FLAGS,
@@ -7883,6 +8186,7 @@ function resolveLaunchFlags(params) {
7883
8186
  trackUsage: params.flags?.trackUsage ?? parseEnvBool("AGENT_SHIM_TRACK_USAGE", params.env.AGENT_SHIM_TRACK_USAGE) ?? params.cascade?.trackUsage ?? true,
7884
8187
  pause: params.flags?.pause ?? parseEnvBool("AGENT_SHIM_PAUSE", params.env.AGENT_SHIM_PAUSE) ?? params.cascade?.pause ?? false,
7885
8188
  explain: params.flags?.explain ?? parseEnvBool("AGENT_SHIM_EXPLAIN", params.env.AGENT_SHIM_EXPLAIN) ?? params.cascade?.explain ?? false,
8189
+ routeByName: params.flags?.routeByName ?? parseEnvBool("AGENT_SHIM_ROUTE_BY_NAME", params.env.AGENT_SHIM_ROUTE_BY_NAME) ?? params.cascade?.routeByName ?? false,
7886
8190
  delayMs: resolveDelayMs(params)
7887
8191
  };
7888
8192
  }
@@ -7951,6 +8255,7 @@ function buildEnv(params) {
7951
8255
  { name: SESSION_HEADER, value: params.sessionId },
7952
8256
  { name: AUTH_HEADER, value: params.frontdoor.sessionToken },
7953
8257
  ...params.provider === void 0 ? [] : [{ name: PROVIDER_HEADER, value: params.provider.name }],
8258
+ ...params.routeByName ? [{ name: ROUTE_BY_NAME_HEADER, value: "1" }] : [],
7954
8259
  ...params.headroom === void 0 ? [] : [
7955
8260
  { name: HEADROOM_FLAG_HEADER, value: "1" },
7956
8261
  { name: PROJECT_ID_HEADER, value: params.headroom.projectId }
@@ -8591,8 +8896,40 @@ function providerModelRows(provider, catalogue = []) {
8591
8896
  const taken = new Set(named.map((row) => labelOf(row.model)));
8592
8897
  return [...named, ...catalogueRows(provider, catalogue).filter((row) => !taken.has(labelOf(row.model)))];
8593
8898
  }
8899
+ function routedModelRows(models, providers) {
8900
+ const hidden = new Set(models.hide ?? []);
8901
+ const shown = models.show === void 0 ? void 0 : new Set(models.show);
8902
+ const visible = (model) => shown === void 0 ? !hidden.has(model) : shown.has(model);
8903
+ const tierOf = (model) => {
8904
+ for (const [, provider] of providers) {
8905
+ if (provider.kind !== void 0 && provider.kind !== "http") {
8906
+ continue;
8907
+ }
8908
+ const env = provider.env ?? {};
8909
+ const match = Object.entries(env).find(([, value]) => value === model);
8910
+ if (match?.[0].endsWith("_MODEL") === true) {
8911
+ const tier = match[0].replace("ANTHROPIC_DEFAULT_", "").replace("_MODEL", "").toLowerCase();
8912
+ return tier === "fable" || tier === "opus" || tier === "sonnet" || tier === "haiku" ? tier : void 0;
8913
+ }
8914
+ }
8915
+ return void 0;
8916
+ };
8917
+ const virtual = Object.entries(models.virtual ?? {}).flatMap(([name, definition]) => {
8918
+ if (!visible(name)) {
8919
+ return [];
8920
+ }
8921
+ const first = definition.members.find((member) => member.includes("/"));
8922
+ const tier = first === void 0 ? void 0 : tierOf(first.split("/").slice(1).join("/"));
8923
+ const behavesAs = tier === void 0 ? void 0 : TIER_BEHAVES_AS[tier];
8924
+ return behavesAs === void 0 ? [] : [{ model: name, label: name, description: `Virtual (${definition.mode})`, behavesAs }];
8925
+ });
8926
+ const concrete = providers.flatMap(([name, provider]) => providerModelRows(provider).map((row) => ({ ...row, model: `${name}/${row.model}`, label: `${name} / ${row.label}`, description: `${name}: ${row.description}` })));
8927
+ return [...virtual, ...concrete.filter((row) => visible(row.model))];
8928
+ }
8594
8929
  function modelPickerSettings(provider, catalogue = []) {
8595
- const options = providerModelRows(provider, catalogue);
8930
+ return modelPickerSettingsFromRows(providerModelRows(provider, catalogue));
8931
+ }
8932
+ function modelPickerSettingsFromRows(options) {
8596
8933
  return options.length === 0 ? void 0 : JSON.stringify({ modelPicker: { options, replaceBuiltInOptions: true } });
8597
8934
  }
8598
8935
  var CONTEXT_MARKER_1M, TIER_BEHAVES_AS, TIER_ENV_VARIABLES;
@@ -9031,6 +9368,7 @@ function decideLaunch(params, readOnly) {
9031
9368
  ...parsedArgv.trackUsage === void 0 ? {} : { trackUsage: parsedArgv.trackUsage },
9032
9369
  ...parsedArgv.pause === void 0 ? {} : { pause: parsedArgv.pause },
9033
9370
  ...parsedArgv.explain === void 0 ? {} : { explain: parsedArgv.explain },
9371
+ ...parsedArgv.routeByName === void 0 ? {} : { routeByName: parsedArgv.routeByName },
9034
9372
  ...parsedArgv.delay === void 0 ? {} : { delay: parsedArgv.delay }
9035
9373
  }
9036
9374
  });
@@ -9041,7 +9379,8 @@ function decideLaunch(params, readOnly) {
9041
9379
  }
9042
9380
  const flags = loginlessProvider === void 0 ? requestedFlags : { ...requestedFlags, remoteControl: false };
9043
9381
  const catalogue = selectedProvider === void 0 ? void 0 : parseCatalogueCache(params.fs.readFileUtf8(catalogueCachePath(paths, selectedProvider.name)));
9044
- const pickerSettings = selectedProvider === void 0 ? void 0 : modelPickerSettings(selectedProvider.definition, catalogue?.models);
9382
+ const routesByName = flags.routeByName || selectedProvider !== void 0 && isRouterProvider(selectedProvider.definition);
9383
+ 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);
9045
9384
  const callerSettings = hasSettingsArgument(parsedArgv.rest);
9046
9385
  if (pickerSettings !== void 0 && callerSettings) {
9047
9386
  notes.push("--settings was passed, so /model keeps Claude Code's own model names");
@@ -9143,6 +9482,14 @@ function prepareLaunch(params) {
9143
9482
  if (decided.pinnedVersion !== void 0) {
9144
9483
  rows.push(pinnedVersionRow(decided.pinnedVersion.version, decided.pinnedVersion.source));
9145
9484
  }
9485
+ const routesByName = resolvedFlags.routeByName || resolvedProvider !== void 0 && isRouterProvider(resolvedProvider.definition);
9486
+ if (routesByName) {
9487
+ 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 });
9488
+ if (!check.ok) {
9489
+ log.error(check.message);
9490
+ proc.exit(check.status);
9491
+ }
9492
+ }
9146
9493
  const frontDoorPort = params.frontdoor;
9147
9494
  const frontDoorEngaged = resolvedProvider !== void 0 || resolvedFlags.headroom || resolvedFlags.trackUsage;
9148
9495
  if (frontDoorEngaged && frontDoorPort === void 0) {
@@ -9174,7 +9521,8 @@ function prepareLaunch(params) {
9174
9521
  ...frontDoor === void 0 ? {} : { frontdoor: frontDoor },
9175
9522
  ...headroom === void 0 ? {} : { headroom },
9176
9523
  sessionId,
9177
- remoteControl: resolvedFlags.remoteControl
9524
+ remoteControl: resolvedFlags.remoteControl,
9525
+ routeByName: routesByName
9178
9526
  });
9179
9527
  const releases = [...headroom === void 0 || headroomPort === void 0 ? [] : [headroomPort.release], ...frontDoorRelease === void 0 ? [] : [frontDoorRelease]];
9180
9528
  const release = () => {
@@ -9201,7 +9549,8 @@ function resolveLaunch(params) {
9201
9549
  ...frontDoor ? { frontdoor: { port: 0, connectPort: 0, trustBundlePath: "", sessionToken: "" } } : {},
9202
9550
  ...decided.flags.headroom ? { headroom: { socketPath: "", projectId: "" } } : {},
9203
9551
  sessionId: "",
9204
- remoteControl: decided.flags.remoteControl
9552
+ remoteControl: decided.flags.remoteControl,
9553
+ routeByName: decided.flags.routeByName
9205
9554
  });
9206
9555
  const credentialNames = decided.identityCredentialBlock === void 0 ? [] : Object.keys(credentialVariables(decided.identityCredentialBlock.target ?? "bearer", ""));
9207
9556
  const environment = [.../* @__PURE__ */ new Set([...Object.keys(built).filter((name) => built[name] !== env[name]), ...credentialNames])].sort();
@@ -9213,7 +9562,7 @@ function resolveLaunch(params) {
9213
9562
  bin: decided.bin,
9214
9563
  args: decided.args,
9215
9564
  ...credential === void 0 ? {} : { credential },
9216
- routing: { frontDoor, headroom: decided.flags.headroom },
9565
+ routing: { frontDoor, headroom: decided.flags.headroom, routeByName: decided.flags.routeByName },
9217
9566
  environment
9218
9567
  };
9219
9568
  }
@@ -9253,14 +9602,18 @@ var init_launcher = __esm({
9253
9602
  init_launchReport();
9254
9603
  init_modelPicker();
9255
9604
  init_providerCatalogue();
9605
+ init_modelsStore();
9606
+ init_providersStore();
9256
9607
  init_pool();
9257
9608
  init_resumeContext();
9258
9609
  init_lock();
9259
9610
  init_spawn();
9260
9611
  init_providersStore();
9612
+ init_load();
9261
9613
  init_flatten();
9262
9614
  init_walk();
9263
9615
  init_schema();
9616
+ init_schema();
9264
9617
  init_credential();
9265
9618
  init_middleware();
9266
9619
  init_preflight();
@@ -13545,189 +13898,7 @@ function collectPoolPick(params) {
13545
13898
 
13546
13899
  // src/poolStore.ts
13547
13900
  init_cliError();
13548
-
13549
- // src/configProfilesStore.ts
13550
- init_store();
13551
- init_schema();
13552
- init_cliError();
13553
- init_load();
13554
- import fs4 from "node:fs";
13555
- import path22 from "node:path";
13556
- var ProfileNotFoundError = class extends CliError {
13557
- constructor(profileName) {
13558
- super(`No configuration profile named "${profileName}". Run \`agent-shim profile add ${profileName}\` first.`);
13559
- this.profileName = profileName;
13560
- this.name = "ProfileNotFoundError";
13561
- }
13562
- profileName;
13563
- };
13564
- var ProfileAlreadyExistsError = class extends CliError {
13565
- constructor(profileName) {
13566
- super(`A configuration profile named "${profileName}" already exists.`);
13567
- this.profileName = profileName;
13568
- this.name = "ProfileAlreadyExistsError";
13569
- }
13570
- profileName;
13571
- };
13572
- var InvalidCategoryNameError = class extends CliError {
13573
- constructor(categoryName) {
13574
- super(`"${categoryName}" is not a category a configuration profile may toggle (runtime, history, knowledge, settings).`);
13575
- this.categoryName = categoryName;
13576
- this.name = "InvalidCategoryNameError";
13577
- }
13578
- categoryName;
13579
- };
13580
- function profileJsonPath(paths, name) {
13581
- return path22.join(paths.configProfilesDir, `${name}.json`);
13582
- }
13583
- function profileExists(paths, name) {
13584
- return fs4.existsSync(profileJsonPath(paths, name));
13585
- }
13586
- function requireProfileExists(paths, name) {
13587
- if (!profileExists(paths, name)) {
13588
- throw new ProfileNotFoundError(name);
13589
- }
13590
- }
13591
- function readProfile(paths, name) {
13592
- return readJson(profileJsonPath(paths, name), ConfigProfileSchema);
13593
- }
13594
- function createProfile(paths, name, extendsList, description) {
13595
- if (profileExists(paths, name)) {
13596
- throw new ProfileAlreadyExistsError(name);
13597
- }
13598
- const filePath = profileJsonPath(paths, name);
13599
- const parsed = ConfigProfileSchema.safeParse({
13600
- ...description === void 0 ? {} : { description },
13601
- ...extendsList !== void 0 && extendsList.length > 0 ? { extends: [...extendsList] } : {}
13602
- });
13603
- if (!parsed.success) {
13604
- throw new ConfigValidationError(filePath, parsed.error.issues);
13605
- }
13606
- writeJsonAtomic(filePath, parsed.data);
13607
- return parsed.data;
13608
- }
13609
- function listProfiles(paths) {
13610
- if (!fs4.existsSync(paths.configProfilesDir)) {
13611
- return [];
13612
- }
13613
- const names = fs4.readdirSync(paths.configProfilesDir, { withFileTypes: true }).filter((entry) => entry.isFile() && entry.name.endsWith(".json")).map((entry) => entry.name.slice(0, -".json".length)).sort();
13614
- const result = [];
13615
- for (const name of names) {
13616
- const profile = readProfile(paths, name);
13617
- if (profile !== void 0) {
13618
- result.push({ name, profile });
13619
- }
13620
- }
13621
- return result;
13622
- }
13623
- function globalConfigPath(paths) {
13624
- return paths.globalConfigFile;
13625
- }
13626
- function readGlobalConfig(paths) {
13627
- return readJson(globalConfigPath(paths), GlobalConfigSchema);
13628
- }
13629
- function setGlobalDefaultProfile(paths, name) {
13630
- return applyPatch(
13631
- globalConfigPath(paths),
13632
- GlobalConfigSchema,
13633
- { defaultConfigProfile: name },
13634
- { defaults: {} }
13635
- );
13636
- }
13637
- function validateCategoryNames(patch) {
13638
- for (const key of Object.keys(patch)) {
13639
- if (!isOverridableCategory(key)) {
13640
- throw new InvalidCategoryNameError(key);
13641
- }
13642
- }
13643
- }
13644
- function setProfileCategories(paths, name, patch) {
13645
- requireProfileExists(paths, name);
13646
- const expandedPatch = expandAllCategoryKey(patch);
13647
- validateCategoryNames(expandedPatch);
13648
- const existing = readProfile(paths, name) ?? {};
13649
- const mergedCategories = { ...existing.categories, ...expandedPatch };
13650
- return applyPatch(profileJsonPath(paths, name), ConfigProfileSchema, { categories: mergedCategories });
13651
- }
13652
- function setProfileEntries(paths, name, patch) {
13653
- requireProfileExists(paths, name);
13654
- const existing = readProfile(paths, name) ?? {};
13655
- const mergedEntries = { ...existing.entries, ...patch };
13656
- return applyPatch(profileJsonPath(paths, name), ConfigProfileSchema, { entries: mergedEntries });
13657
- }
13658
- function setProfileLaunchFlags(paths, name, patch) {
13659
- requireProfileExists(paths, name);
13660
- const existing = readProfile(paths, name) ?? {};
13661
- const mergedLaunch = { ...existing.launch, ...patch };
13662
- return applyPatch(profileJsonPath(paths, name), ConfigProfileSchema, {
13663
- // Read as `unknown` so the check sees the `undefined` a cleared key holds, which LaunchFlags' optional properties hide from the value type.
13664
- launch: Object.values(mergedLaunch).every((value) => value === void 0) ? void 0 : mergedLaunch
13665
- });
13666
- }
13667
- function setProfileMetadata(paths, name, patch) {
13668
- requireProfileExists(paths, name);
13669
- return applyPatch(profileJsonPath(paths, name), ConfigProfileSchema, {
13670
- ...patch.extends === void 0 ? {} : { extends: patch.extends.length === 0 ? void 0 : [...patch.extends] },
13671
- ...patch.description === void 0 ? {} : { description: patch.description === false ? void 0 : patch.description }
13672
- });
13673
- }
13674
- function removeProfile(paths, name) {
13675
- requireProfileExists(paths, name);
13676
- fs4.rmSync(profileJsonPath(paths, name));
13677
- }
13678
- function applyProfileChange(paths, name, change) {
13679
- let touched = false;
13680
- if (change.category !== void 0) {
13681
- setProfileCategories(paths, name, change.category);
13682
- touched = true;
13683
- }
13684
- if (change.entry !== void 0) {
13685
- setProfileEntries(paths, name, change.entry);
13686
- touched = true;
13687
- }
13688
- if (change.extends !== void 0 || change.description !== void 0) {
13689
- setProfileMetadata(paths, name, {
13690
- ...change.extends === void 0 ? {} : { extends: change.extends === false ? [] : change.extends },
13691
- ...change.description === void 0 ? {} : { description: change.description }
13692
- });
13693
- touched = true;
13694
- }
13695
- const launchPatch = {};
13696
- if (change.launchSkipPermissions !== void 0) {
13697
- launchPatch.skipPermissions = change.launchSkipPermissions;
13698
- }
13699
- if (change.launchRemoteControl !== void 0) {
13700
- launchPatch.remoteControl = change.launchRemoteControl;
13701
- }
13702
- if (change.launchHeadroom !== void 0) {
13703
- launchPatch.headroom = change.launchHeadroom;
13704
- }
13705
- if (change.launchTrackUsage !== void 0) {
13706
- launchPatch.trackUsage = change.launchTrackUsage;
13707
- }
13708
- if (change.launchProvider !== void 0) {
13709
- launchPatch.provider = change.launchProvider === false ? void 0 : change.launchProvider;
13710
- }
13711
- if (change.launchClaudeVersion !== void 0) {
13712
- launchPatch.claudeVersion = change.launchClaudeVersion === false ? void 0 : change.launchClaudeVersion;
13713
- }
13714
- if (change.launchDelay !== void 0) {
13715
- launchPatch.delay = change.launchDelay === false ? void 0 : change.launchDelay;
13716
- }
13717
- if (change.launchPause !== void 0) {
13718
- launchPatch.pause = change.launchPause;
13719
- }
13720
- if (change.launchExplain !== void 0) {
13721
- launchPatch.explain = change.launchExplain;
13722
- }
13723
- if (Object.keys(launchPatch).length > 0) {
13724
- setProfileLaunchFlags(paths, name, launchPatch);
13725
- touched = true;
13726
- }
13727
- return touched;
13728
- }
13729
-
13730
- // src/poolStore.ts
13901
+ init_configProfilesStore();
13731
13902
  init_store();
13732
13903
  init_schema();
13733
13904
  init_identity();
@@ -14808,53 +14979,8 @@ init_credentialCache();
14808
14979
  init_realCredentialCache();
14809
14980
  init_source();
14810
14981
 
14811
- // src/modelsStore.ts
14812
- init_store();
14813
- init_schema();
14814
- var VirtualModelNotFoundError = class extends Error {
14815
- constructor(name) {
14816
- super(`No virtual model named "${name}".`);
14817
- this.name = "VirtualModelNotFoundError";
14818
- }
14819
- };
14820
- function memberKindOf(ref, models) {
14821
- if (ref.startsWith("acct:")) {
14822
- return "account";
14823
- }
14824
- if (ref.startsWith("family:")) {
14825
- return "family";
14826
- }
14827
- return models?.virtual !== void 0 && ref in models.virtual ? "virtual" : "provider";
14828
- }
14829
- function expandMembers(name, models) {
14830
- const virtual = models?.virtual ?? {};
14831
- const expanded = [];
14832
- const walk = (current, chain) => {
14833
- const nested = virtual[current];
14834
- if (nested !== void 0) {
14835
- if (chain.includes(current)) {
14836
- throw new Error(`virtual model cycle: ${[...chain, current].join(" -> ")}`);
14837
- }
14838
- for (const member of nested.members) {
14839
- walk(member, [...chain, current]);
14840
- }
14841
- return;
14842
- }
14843
- if (!expanded.includes(current)) {
14844
- expanded.push(current);
14845
- }
14846
- };
14847
- const top = virtual[name];
14848
- if (top === void 0) {
14849
- throw new VirtualModelNotFoundError(name);
14850
- }
14851
- for (const member of top.members) {
14852
- walk(member, [name]);
14853
- }
14854
- return expanded;
14855
- }
14856
-
14857
14982
  // src/models/doctor.ts
14983
+ init_modelsStore();
14858
14984
  function modelsFindings(input) {
14859
14985
  const findings = [];
14860
14986
  const { models } = input;
@@ -14909,6 +15035,9 @@ function modelsFindings(input) {
14909
15035
  return findings;
14910
15036
  }
14911
15037
 
15038
+ // src/doctorReport.ts
15039
+ init_configProfilesStore();
15040
+
14912
15041
  // src/headroom/allowlistDrift.ts
14913
15042
  init_earlierRelease();
14914
15043
  init_state2();
@@ -15849,9 +15978,10 @@ function createCodexApiRouter(deps) {
15849
15978
  // src/frontdoor/configApi.ts
15850
15979
  init_cliError();
15851
15980
  init_schema();
15981
+ init_configProfilesStore();
15982
+ init_credential();
15852
15983
  import { ORPCError as ORPCError2 } from "@orpc/client";
15853
15984
  import { openapi as openapi3 } from "@orpc/openapi";
15854
- init_credential();
15855
15985
 
15856
15986
  // src/credentialCacheChange.ts
15857
15987
  init_cliError();
@@ -16059,7 +16189,8 @@ var ConfigProfileSetInputSchema = z24.strictObject({
16059
16189
  claudeVersion: z24.union([z24.string().min(1), z24.literal(false)]).optional(),
16060
16190
  delay: z24.union([z24.string().regex(DURATION_RE), z24.literal(false)]).optional(),
16061
16191
  pause: z24.boolean().optional(),
16062
- explain: z24.boolean().optional()
16192
+ explain: z24.boolean().optional(),
16193
+ routeByName: z24.boolean().optional()
16063
16194
  }).optional()
16064
16195
  });
16065
16196
  var ConfigProfileSetOutputSchema = storedMutationOutput("profile", "updated", ProfileValueSchema);
@@ -16271,7 +16402,8 @@ function createConfigApiRouter(deps) {
16271
16402
  ...launch?.claudeVersion === void 0 ? {} : { launchClaudeVersion: launch.claudeVersion },
16272
16403
  ...launch?.delay === void 0 ? {} : { launchDelay: launch.delay },
16273
16404
  ...launch?.pause === void 0 ? {} : { launchPause: launch.pause },
16274
- ...launch?.explain === void 0 ? {} : { launchExplain: launch.explain }
16405
+ ...launch?.explain === void 0 ? {} : { launchExplain: launch.explain },
16406
+ ...launch?.routeByName === void 0 ? {} : { launchRouteByName: launch.routeByName }
16275
16407
  });
16276
16408
  return { action: "updated", kind: "profile", name: input.name, value: profileValue(input.name, paths) };
16277
16409
  })
@@ -16582,6 +16714,7 @@ var LaunchFlagsSchema = z26.strictObject({
16582
16714
  trackUsage: z26.boolean(),
16583
16715
  pause: z26.boolean(),
16584
16716
  explain: z26.boolean(),
16717
+ routeByName: z26.boolean(),
16585
16718
  /** How long the launch waits after its own output before it starts claude, in milliseconds. */
16586
16719
  delayMs: z26.number()
16587
16720
  });
@@ -16595,7 +16728,7 @@ var LaunchResolveOutputSchema = z26.strictObject({
16595
16728
  args: z26.readonly(z26.array(z26.string())),
16596
16729
  /** The credential the launch would authenticate with, by target and source kinds. Absent when none applies. */
16597
16730
  credential: z26.strictObject({ subject: z26.enum(["provider", "identity"]), name: z26.string(), summary: CredentialSummarySchema }).optional(),
16598
- routing: z26.strictObject({ frontDoor: z26.boolean(), headroom: z26.boolean() }),
16731
+ routing: z26.strictObject({ frontDoor: z26.boolean(), headroom: z26.boolean(), routeByName: z26.boolean() }),
16599
16732
  /** The names of the environment variables the launch would set or unset, sorted. Values are not reported. */
16600
16733
  environment: z26.readonly(z26.array(z26.string())),
16601
16734
  warnings: z26.readonly(z26.array(z26.string()))
@@ -19226,6 +19359,7 @@ init_guard();
19226
19359
  init_paths();
19227
19360
  init_cliError();
19228
19361
  init_schema();
19362
+ init_configProfilesStore();
19229
19363
  init_providersStore();
19230
19364
  init_launcher();
19231
19365
  init_spawn();