claude-use 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/README.md +2 -1
- package/dist/cli.cjs +392 -301
- package/dist/index.cjs +312 -240
- package/dist/index.mjs +313 -241
- package/dist/types/index.d.ts +15 -1
- package/package.json +1 -1
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: "claude-use",
|
|
3105
|
-
version: "11.
|
|
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;
|
|
@@ -7298,6 +7492,62 @@ var init_claudeShim = __esm({
|
|
|
7298
7492
|
}
|
|
7299
7493
|
});
|
|
7300
7494
|
|
|
7495
|
+
// src/modelsStore.ts
|
|
7496
|
+
function readModels(paths) {
|
|
7497
|
+
return readGlobalConfig(paths)?.models;
|
|
7498
|
+
}
|
|
7499
|
+
function memberKindOf(ref, models) {
|
|
7500
|
+
if (ref.startsWith("acct:")) {
|
|
7501
|
+
return "account";
|
|
7502
|
+
}
|
|
7503
|
+
if (ref.startsWith("family:")) {
|
|
7504
|
+
return "family";
|
|
7505
|
+
}
|
|
7506
|
+
return models?.virtual !== void 0 && ref in models.virtual ? "virtual" : "provider";
|
|
7507
|
+
}
|
|
7508
|
+
function expandMembers(name, models) {
|
|
7509
|
+
const virtual = models?.virtual ?? {};
|
|
7510
|
+
const expanded = [];
|
|
7511
|
+
const walk = (current, chain) => {
|
|
7512
|
+
const nested = virtual[current];
|
|
7513
|
+
if (nested !== void 0) {
|
|
7514
|
+
if (chain.includes(current)) {
|
|
7515
|
+
throw new Error(`virtual model cycle: ${[...chain, current].join(" -> ")}`);
|
|
7516
|
+
}
|
|
7517
|
+
for (const member of nested.members) {
|
|
7518
|
+
walk(member, [...chain, current]);
|
|
7519
|
+
}
|
|
7520
|
+
return;
|
|
7521
|
+
}
|
|
7522
|
+
if (!expanded.includes(current)) {
|
|
7523
|
+
expanded.push(current);
|
|
7524
|
+
}
|
|
7525
|
+
};
|
|
7526
|
+
const top = virtual[name];
|
|
7527
|
+
if (top === void 0) {
|
|
7528
|
+
throw new VirtualModelNotFoundError(name);
|
|
7529
|
+
}
|
|
7530
|
+
for (const member of top.members) {
|
|
7531
|
+
walk(member, [name]);
|
|
7532
|
+
}
|
|
7533
|
+
return expanded;
|
|
7534
|
+
}
|
|
7535
|
+
var VirtualModelNotFoundError;
|
|
7536
|
+
var init_modelsStore = __esm({
|
|
7537
|
+
"src/modelsStore.ts"() {
|
|
7538
|
+
"use strict";
|
|
7539
|
+
init_store();
|
|
7540
|
+
init_schema();
|
|
7541
|
+
init_configProfilesStore();
|
|
7542
|
+
VirtualModelNotFoundError = class extends Error {
|
|
7543
|
+
constructor(name) {
|
|
7544
|
+
super(`No virtual model named "${name}".`);
|
|
7545
|
+
this.name = "VirtualModelNotFoundError";
|
|
7546
|
+
}
|
|
7547
|
+
};
|
|
7548
|
+
}
|
|
7549
|
+
});
|
|
7550
|
+
|
|
7301
7551
|
// src/frontdoor/probe.ts
|
|
7302
7552
|
function probeFrontDoorSync(port, caPem) {
|
|
7303
7553
|
refuseToBlockInRole("a synchronous probe of the front door");
|
|
@@ -7719,7 +7969,8 @@ var init_argv = __esm({
|
|
|
7719
7969
|
{ flag: "--remote-control", key: "remoteControl" },
|
|
7720
7970
|
{ flag: "--wait", key: "wait" },
|
|
7721
7971
|
{ flag: "--pause", key: "pause" },
|
|
7722
|
-
{ flag: "--explain", key: "explain" }
|
|
7972
|
+
{ flag: "--explain", key: "explain" },
|
|
7973
|
+
{ flag: "--route-by-name", key: "routeByName" }
|
|
7723
7974
|
];
|
|
7724
7975
|
LAUNCHER_FLAG_NAMES = [
|
|
7725
7976
|
...VALUED_FLAGS,
|
|
@@ -7909,6 +8160,7 @@ function resolveLaunchFlags(params) {
|
|
|
7909
8160
|
trackUsage: params.flags?.trackUsage ?? parseEnvBool("AGENT_SHIM_TRACK_USAGE", params.env.AGENT_SHIM_TRACK_USAGE) ?? params.cascade?.trackUsage ?? true,
|
|
7910
8161
|
pause: params.flags?.pause ?? parseEnvBool("AGENT_SHIM_PAUSE", params.env.AGENT_SHIM_PAUSE) ?? params.cascade?.pause ?? false,
|
|
7911
8162
|
explain: params.flags?.explain ?? parseEnvBool("AGENT_SHIM_EXPLAIN", params.env.AGENT_SHIM_EXPLAIN) ?? params.cascade?.explain ?? false,
|
|
8163
|
+
routeByName: params.flags?.routeByName ?? parseEnvBool("AGENT_SHIM_ROUTE_BY_NAME", params.env.AGENT_SHIM_ROUTE_BY_NAME) ?? params.cascade?.routeByName ?? false,
|
|
7912
8164
|
delayMs: resolveDelayMs(params)
|
|
7913
8165
|
};
|
|
7914
8166
|
}
|
|
@@ -7977,6 +8229,7 @@ function buildEnv(params) {
|
|
|
7977
8229
|
{ name: SESSION_HEADER, value: params.sessionId },
|
|
7978
8230
|
{ name: AUTH_HEADER, value: params.frontdoor.sessionToken },
|
|
7979
8231
|
...params.provider === void 0 ? [] : [{ name: PROVIDER_HEADER, value: params.provider.name }],
|
|
8232
|
+
...params.routeByName ? [{ name: ROUTE_BY_NAME_HEADER, value: "1" }] : [],
|
|
7980
8233
|
...params.headroom === void 0 ? [] : [
|
|
7981
8234
|
{ name: HEADROOM_FLAG_HEADER, value: "1" },
|
|
7982
8235
|
{ name: PROJECT_ID_HEADER, value: params.headroom.projectId }
|
|
@@ -8619,8 +8872,40 @@ function providerModelRows(provider, catalogue = []) {
|
|
|
8619
8872
|
const taken = new Set(named.map((row) => labelOf(row.model)));
|
|
8620
8873
|
return [...named, ...catalogueRows(provider, catalogue).filter((row) => !taken.has(labelOf(row.model)))];
|
|
8621
8874
|
}
|
|
8875
|
+
function routedModelRows(models, providers) {
|
|
8876
|
+
const hidden = new Set(models.hide ?? []);
|
|
8877
|
+
const shown = models.show === void 0 ? void 0 : new Set(models.show);
|
|
8878
|
+
const visible = (model) => shown === void 0 ? !hidden.has(model) : shown.has(model);
|
|
8879
|
+
const tierOf = (model) => {
|
|
8880
|
+
for (const [, provider] of providers) {
|
|
8881
|
+
if (provider.kind !== void 0 && provider.kind !== "http") {
|
|
8882
|
+
continue;
|
|
8883
|
+
}
|
|
8884
|
+
const env = provider.env ?? {};
|
|
8885
|
+
const match = Object.entries(env).find(([, value]) => value === model);
|
|
8886
|
+
if (match?.[0].endsWith("_MODEL") === true) {
|
|
8887
|
+
const tier = match[0].replace("ANTHROPIC_DEFAULT_", "").replace("_MODEL", "").toLowerCase();
|
|
8888
|
+
return tier === "fable" || tier === "opus" || tier === "sonnet" || tier === "haiku" ? tier : void 0;
|
|
8889
|
+
}
|
|
8890
|
+
}
|
|
8891
|
+
return void 0;
|
|
8892
|
+
};
|
|
8893
|
+
const virtual = Object.entries(models.virtual ?? {}).flatMap(([name, definition]) => {
|
|
8894
|
+
if (!visible(name)) {
|
|
8895
|
+
return [];
|
|
8896
|
+
}
|
|
8897
|
+
const first = definition.members.find((member) => member.includes("/"));
|
|
8898
|
+
const tier = first === void 0 ? void 0 : tierOf(first.split("/").slice(1).join("/"));
|
|
8899
|
+
const behavesAs = tier === void 0 ? void 0 : TIER_BEHAVES_AS[tier];
|
|
8900
|
+
return behavesAs === void 0 ? [] : [{ model: name, label: name, description: `Virtual (${definition.mode})`, behavesAs }];
|
|
8901
|
+
});
|
|
8902
|
+
const concrete = providers.flatMap(([name, provider]) => providerModelRows(provider).map((row) => ({ ...row, model: `${name}/${row.model}`, label: `${name} / ${row.label}`, description: `${name}: ${row.description}` })));
|
|
8903
|
+
return [...virtual, ...concrete.filter((row) => visible(row.model))];
|
|
8904
|
+
}
|
|
8622
8905
|
function modelPickerSettings(provider, catalogue = []) {
|
|
8623
|
-
|
|
8906
|
+
return modelPickerSettingsFromRows(providerModelRows(provider, catalogue));
|
|
8907
|
+
}
|
|
8908
|
+
function modelPickerSettingsFromRows(options) {
|
|
8624
8909
|
return options.length === 0 ? void 0 : JSON.stringify({ modelPicker: { options, replaceBuiltInOptions: true } });
|
|
8625
8910
|
}
|
|
8626
8911
|
var CONTEXT_MARKER_1M, TIER_BEHAVES_AS, TIER_ENV_VARIABLES;
|
|
@@ -9057,6 +9342,7 @@ function decideLaunch(params, readOnly) {
|
|
|
9057
9342
|
...parsedArgv.trackUsage === void 0 ? {} : { trackUsage: parsedArgv.trackUsage },
|
|
9058
9343
|
...parsedArgv.pause === void 0 ? {} : { pause: parsedArgv.pause },
|
|
9059
9344
|
...parsedArgv.explain === void 0 ? {} : { explain: parsedArgv.explain },
|
|
9345
|
+
...parsedArgv.routeByName === void 0 ? {} : { routeByName: parsedArgv.routeByName },
|
|
9060
9346
|
...parsedArgv.delay === void 0 ? {} : { delay: parsedArgv.delay }
|
|
9061
9347
|
}
|
|
9062
9348
|
});
|
|
@@ -9067,7 +9353,8 @@ function decideLaunch(params, readOnly) {
|
|
|
9067
9353
|
}
|
|
9068
9354
|
const flags = loginlessProvider === void 0 ? requestedFlags : { ...requestedFlags, remoteControl: false };
|
|
9069
9355
|
const catalogue = selectedProvider === void 0 ? void 0 : parseCatalogueCache(params.fs.readFileUtf8(catalogueCachePath(paths, selectedProvider.name)));
|
|
9070
|
-
const
|
|
9356
|
+
const routesByName = flags.routeByName || selectedProvider !== void 0 && isRouterProvider(selectedProvider.definition);
|
|
9357
|
+
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
9358
|
const callerSettings = hasSettingsArgument(parsedArgv.rest);
|
|
9072
9359
|
if (pickerSettings !== void 0 && callerSettings) {
|
|
9073
9360
|
notes.push("--settings was passed, so /model keeps Claude Code's own model names");
|
|
@@ -9200,7 +9487,8 @@ function prepareLaunch(params) {
|
|
|
9200
9487
|
...frontDoor === void 0 ? {} : { frontdoor: frontDoor },
|
|
9201
9488
|
...headroom === void 0 ? {} : { headroom },
|
|
9202
9489
|
sessionId,
|
|
9203
|
-
remoteControl: resolvedFlags.remoteControl
|
|
9490
|
+
remoteControl: resolvedFlags.remoteControl,
|
|
9491
|
+
routeByName: resolvedFlags.routeByName || resolvedProvider !== void 0 && isRouterProvider(resolvedProvider.definition)
|
|
9204
9492
|
});
|
|
9205
9493
|
const releases = [...headroom === void 0 || headroomPort === void 0 ? [] : [headroomPort.release], ...frontDoorRelease === void 0 ? [] : [frontDoorRelease]];
|
|
9206
9494
|
const release = () => {
|
|
@@ -9227,7 +9515,8 @@ function resolveLaunch(params) {
|
|
|
9227
9515
|
...frontDoor ? { frontdoor: { port: 0, connectPort: 0, trustBundlePath: "", sessionToken: "" } } : {},
|
|
9228
9516
|
...decided.flags.headroom ? { headroom: { socketPath: "", projectId: "" } } : {},
|
|
9229
9517
|
sessionId: "",
|
|
9230
|
-
remoteControl: decided.flags.remoteControl
|
|
9518
|
+
remoteControl: decided.flags.remoteControl,
|
|
9519
|
+
routeByName: decided.flags.routeByName
|
|
9231
9520
|
});
|
|
9232
9521
|
const credentialNames = decided.identityCredentialBlock === void 0 ? [] : Object.keys(credentialVariables(decided.identityCredentialBlock.target ?? "bearer", ""));
|
|
9233
9522
|
const environment = [.../* @__PURE__ */ new Set([...Object.keys(built).filter((name) => built[name] !== env[name]), ...credentialNames])].sort();
|
|
@@ -9239,7 +9528,7 @@ function resolveLaunch(params) {
|
|
|
9239
9528
|
bin: decided.bin,
|
|
9240
9529
|
args: decided.args,
|
|
9241
9530
|
...credential === void 0 ? {} : { credential },
|
|
9242
|
-
routing: { frontDoor, headroom: decided.flags.headroom },
|
|
9531
|
+
routing: { frontDoor, headroom: decided.flags.headroom, routeByName: decided.flags.routeByName },
|
|
9243
9532
|
environment
|
|
9244
9533
|
};
|
|
9245
9534
|
}
|
|
@@ -9282,6 +9571,8 @@ var init_launcher = __esm({
|
|
|
9282
9571
|
init_launchReport();
|
|
9283
9572
|
init_modelPicker();
|
|
9284
9573
|
init_providerCatalogue();
|
|
9574
|
+
init_modelsStore();
|
|
9575
|
+
init_providersStore();
|
|
9285
9576
|
init_pool();
|
|
9286
9577
|
init_resumeContext();
|
|
9287
9578
|
init_lock();
|
|
@@ -13958,189 +14249,7 @@ function collectPoolPick(params) {
|
|
|
13958
14249
|
|
|
13959
14250
|
// src/poolStore.ts
|
|
13960
14251
|
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
|
|
14252
|
+
init_configProfilesStore();
|
|
14144
14253
|
init_store();
|
|
14145
14254
|
init_schema();
|
|
14146
14255
|
init_identity();
|
|
@@ -15221,53 +15330,8 @@ init_credentialCache();
|
|
|
15221
15330
|
init_realCredentialCache();
|
|
15222
15331
|
init_source();
|
|
15223
15332
|
|
|
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
15333
|
// src/models/doctor.ts
|
|
15334
|
+
init_modelsStore();
|
|
15271
15335
|
function modelsFindings(input) {
|
|
15272
15336
|
const findings = [];
|
|
15273
15337
|
const { models } = input;
|
|
@@ -15322,6 +15386,9 @@ function modelsFindings(input) {
|
|
|
15322
15386
|
return findings;
|
|
15323
15387
|
}
|
|
15324
15388
|
|
|
15389
|
+
// src/doctorReport.ts
|
|
15390
|
+
init_configProfilesStore();
|
|
15391
|
+
|
|
15325
15392
|
// src/headroom/allowlistDrift.ts
|
|
15326
15393
|
init_earlierRelease();
|
|
15327
15394
|
init_state2();
|
|
@@ -16264,6 +16331,7 @@ var import_client2 = require("@orpc/client");
|
|
|
16264
16331
|
var import_openapi3 = require("@orpc/openapi");
|
|
16265
16332
|
init_cliError();
|
|
16266
16333
|
init_schema();
|
|
16334
|
+
init_configProfilesStore();
|
|
16267
16335
|
init_credential();
|
|
16268
16336
|
|
|
16269
16337
|
// src/credentialCacheChange.ts
|
|
@@ -16472,7 +16540,8 @@ var ConfigProfileSetInputSchema = import_zod24.z.strictObject({
|
|
|
16472
16540
|
claudeVersion: import_zod24.z.union([import_zod24.z.string().min(1), import_zod24.z.literal(false)]).optional(),
|
|
16473
16541
|
delay: import_zod24.z.union([import_zod24.z.string().regex(DURATION_RE), import_zod24.z.literal(false)]).optional(),
|
|
16474
16542
|
pause: import_zod24.z.boolean().optional(),
|
|
16475
|
-
explain: import_zod24.z.boolean().optional()
|
|
16543
|
+
explain: import_zod24.z.boolean().optional(),
|
|
16544
|
+
routeByName: import_zod24.z.boolean().optional()
|
|
16476
16545
|
}).optional()
|
|
16477
16546
|
});
|
|
16478
16547
|
var ConfigProfileSetOutputSchema = storedMutationOutput("profile", "updated", ProfileValueSchema);
|
|
@@ -16684,7 +16753,8 @@ function createConfigApiRouter(deps) {
|
|
|
16684
16753
|
...launch?.claudeVersion === void 0 ? {} : { launchClaudeVersion: launch.claudeVersion },
|
|
16685
16754
|
...launch?.delay === void 0 ? {} : { launchDelay: launch.delay },
|
|
16686
16755
|
...launch?.pause === void 0 ? {} : { launchPause: launch.pause },
|
|
16687
|
-
...launch?.explain === void 0 ? {} : { launchExplain: launch.explain }
|
|
16756
|
+
...launch?.explain === void 0 ? {} : { launchExplain: launch.explain },
|
|
16757
|
+
...launch?.routeByName === void 0 ? {} : { launchRouteByName: launch.routeByName }
|
|
16688
16758
|
});
|
|
16689
16759
|
return { action: "updated", kind: "profile", name: input.name, value: profileValue(input.name, paths) };
|
|
16690
16760
|
})
|
|
@@ -16995,6 +17065,7 @@ var LaunchFlagsSchema = import_zod26.z.strictObject({
|
|
|
16995
17065
|
trackUsage: import_zod26.z.boolean(),
|
|
16996
17066
|
pause: import_zod26.z.boolean(),
|
|
16997
17067
|
explain: import_zod26.z.boolean(),
|
|
17068
|
+
routeByName: import_zod26.z.boolean(),
|
|
16998
17069
|
/** How long the launch waits after its own output before it starts claude, in milliseconds. */
|
|
16999
17070
|
delayMs: import_zod26.z.number()
|
|
17000
17071
|
});
|
|
@@ -17008,7 +17079,7 @@ var LaunchResolveOutputSchema = import_zod26.z.strictObject({
|
|
|
17008
17079
|
args: import_zod26.z.readonly(import_zod26.z.array(import_zod26.z.string())),
|
|
17009
17080
|
/** The credential the launch would authenticate with, by target and source kinds. Absent when none applies. */
|
|
17010
17081
|
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() }),
|
|
17082
|
+
routing: import_zod26.z.strictObject({ frontDoor: import_zod26.z.boolean(), headroom: import_zod26.z.boolean(), routeByName: import_zod26.z.boolean() }),
|
|
17012
17083
|
/** The names of the environment variables the launch would set or unset, sorted. Values are not reported. */
|
|
17013
17084
|
environment: import_zod26.z.readonly(import_zod26.z.array(import_zod26.z.string())),
|
|
17014
17085
|
warnings: import_zod26.z.readonly(import_zod26.z.array(import_zod26.z.string()))
|
|
@@ -19639,6 +19710,7 @@ init_guard();
|
|
|
19639
19710
|
init_paths();
|
|
19640
19711
|
init_cliError();
|
|
19641
19712
|
init_schema();
|
|
19713
|
+
init_configProfilesStore();
|
|
19642
19714
|
init_providersStore();
|
|
19643
19715
|
init_launcher();
|
|
19644
19716
|
init_spawn();
|