agent-shim 8.32.0 → 8.34.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.cjs +2054 -148
- package/dist/index.cjs +143 -61
- package/dist/index.mjs +143 -61
- package/dist/types/index.d.ts +939 -41
- package/package.json +2 -1
package/dist/index.cjs
CHANGED
|
@@ -368,6 +368,7 @@ var categories_default_default = {
|
|
|
368
368
|
// src/config/schema.ts
|
|
369
369
|
var import_node_path2 = __toESM(require("node:path"), 1);
|
|
370
370
|
var import_zod = require("zod");
|
|
371
|
+
var import_trilean = require("trilean");
|
|
371
372
|
|
|
372
373
|
// src/versionDiscovery.ts
|
|
373
374
|
var import_node_os = __toESM(require("node:os"), 1);
|
|
@@ -498,13 +499,14 @@ var CategoryMapSchema = import_zod.z.strictObject({
|
|
|
498
499
|
}).transform((input) => expandAllCategoryKey(input));
|
|
499
500
|
var DURATION_RE = /^(?:0|[1-9][0-9]*)(?:ms|s|m|h|d|w)$/;
|
|
500
501
|
var DurationSchema = import_zod.z.string().regex(DURATION_RE);
|
|
501
|
-
var
|
|
502
|
+
var WhenConditionObjectSchema = import_zod.z.strictObject({
|
|
502
503
|
newerThan: DurationSchema.optional(),
|
|
503
504
|
olderThan: DurationSchema.optional(),
|
|
504
505
|
maxSizeBytes: import_zod.z.int().positive().optional(),
|
|
505
506
|
branch: import_zod.z.string().min(1).optional(),
|
|
506
507
|
env: import_zod.z.record(import_zod.z.string().min(1), import_zod.z.string()).optional()
|
|
507
508
|
});
|
|
509
|
+
var WhenSchema = import_zod.z.union([WhenConditionObjectSchema, import_trilean.PredicateNodeSchema]);
|
|
508
510
|
var EntryValueSchema = import_zod.z.union([
|
|
509
511
|
import_zod.z.boolean(),
|
|
510
512
|
import_zod.z.strictObject({ value: import_zod.z.boolean(), when: WhenSchema })
|
|
@@ -621,11 +623,14 @@ var IDENTITY_NAME_PATTERN = "[A-Za-z0-9][A-Za-z0-9._@-]*";
|
|
|
621
623
|
var PoolNameSchema = import_zod.z.string().min(1).regex(new RegExp(`^${POOL_NAME_PATTERN}$`));
|
|
622
624
|
var SELECTOR_RE = new RegExp(`^(${POOL_SELECTOR_PREFIX}${POOL_NAME_PATTERN}|${IDENTITY_NAME_PATTERN})$`);
|
|
623
625
|
var IdentitySelectorSchema = import_zod.z.string().min(1).regex(SELECTOR_RE);
|
|
624
|
-
var PoolMemberSchema = import_zod.z.string().min(1).regex(SELECTOR_RE);
|
|
626
|
+
var PoolMemberSchema = import_zod.z.union([import_zod.z.string().min(1).regex(SELECTOR_RE), import_zod.z.strictObject({ identity: import_zod.z.string().min(1).regex(SELECTOR_RE), when: WhenSchema })]);
|
|
627
|
+
function poolMemberIdentity(member) {
|
|
628
|
+
return typeof member === "string" ? member : member.identity;
|
|
629
|
+
}
|
|
625
630
|
var POOL_PREFERENCES = ["score", "listed"];
|
|
626
631
|
var PoolPreferenceSchema = import_zod.z.enum(POOL_PREFERENCES);
|
|
627
632
|
var PoolSchema = import_zod.z.strictObject({
|
|
628
|
-
identities: import_zod.z.array(PoolMemberSchema).min(1).refine((members) => new Set(members).size === members.length, { message: "pool members must be unique" }),
|
|
633
|
+
identities: import_zod.z.array(PoolMemberSchema).min(1).refine((members) => new Set(members.map(poolMemberIdentity)).size === members.length, { message: "pool members must be unique" }),
|
|
629
634
|
preference: PoolPreferenceSchema.optional()
|
|
630
635
|
});
|
|
631
636
|
var DirectoryRuleSchema = ConfigProfileSchema.omit({ description: true }).extend({
|
|
@@ -969,6 +974,7 @@ function classifyEntries(names, options) {
|
|
|
969
974
|
|
|
970
975
|
// src/resolve/conditions.ts
|
|
971
976
|
var import_picomatch2 = __toESM(require("picomatch"), 1);
|
|
977
|
+
var import_trilean2 = require("trilean");
|
|
972
978
|
var MILLISECONDS_PER_UNIT = Object.freeze({
|
|
973
979
|
ms: 1,
|
|
974
980
|
s: 1e3,
|
|
@@ -999,52 +1005,87 @@ function matchBranch(pattern, branch, detached = false) {
|
|
|
999
1005
|
}
|
|
1000
1006
|
return (0, import_picomatch2.default)(pattern, { dot: true, nocase: false })(branch);
|
|
1001
1007
|
}
|
|
1008
|
+
var evaluator = (0, import_trilean2.createSyncEvaluator)({});
|
|
1009
|
+
function resolversOf(context) {
|
|
1010
|
+
const pool = context.pool;
|
|
1011
|
+
const values = {
|
|
1012
|
+
now: context.nowMs,
|
|
1013
|
+
...context.fact?.latestMtimeMs === void 0 ? {} : { "entry.latestMtimeMs": context.fact.latestMtimeMs },
|
|
1014
|
+
...context.fact?.totalSizeBytes === void 0 ? {} : { "entry.totalSizeBytes": context.fact.totalSizeBytes },
|
|
1015
|
+
...context.branch === void 0 ? {} : { "repo.branch": context.branch },
|
|
1016
|
+
"repo.detached": context.branchDetached ?? false,
|
|
1017
|
+
...pool?.fiveHour === void 0 ? {} : { "quota.fiveHour.remaining": pool.fiveHour.remaining, "quota.fiveHour.utilization": pool.fiveHour.utilization, "quota.fiveHour.hoursUntilReset": pool.fiveHour.hoursUntilReset },
|
|
1018
|
+
...pool?.sevenDay === void 0 ? {} : { "quota.sevenDay.remaining": pool.sevenDay.remaining, "quota.sevenDay.utilization": pool.sevenDay.utilization, "quota.sevenDay.hoursUntilReset": pool.sevenDay.hoursUntilReset },
|
|
1019
|
+
...pool?.burnPerHour === void 0 ? {} : { "quota.burnPerHour": pool.burnPerHour },
|
|
1020
|
+
...pool?.resuming === void 0 ? {} : { "session.resuming": pool.resuming },
|
|
1021
|
+
...pool?.lastPickHoursAgo === void 0 ? {} : { "session.lastPickHoursAgo": pool.lastPickHoursAgo }
|
|
1022
|
+
};
|
|
1023
|
+
return {
|
|
1024
|
+
resolveValue: (key) => {
|
|
1025
|
+
const wrap = (value2) => ({ found: true, value: typeof value2 === "number" ? { kind: "number", value: value2 } : typeof value2 === "string" ? { kind: "text", value: value2 } : { kind: "boolean", value: value2 } });
|
|
1026
|
+
if (typeof key !== "string") {
|
|
1027
|
+
return { found: false };
|
|
1028
|
+
}
|
|
1029
|
+
if (key.startsWith("env.")) {
|
|
1030
|
+
const value2 = context.env[key.slice("env.".length)];
|
|
1031
|
+
return value2 === void 0 ? { found: false } : wrap(value2);
|
|
1032
|
+
}
|
|
1033
|
+
const value = values[key];
|
|
1034
|
+
return value === void 0 ? { found: false } : wrap(value);
|
|
1035
|
+
},
|
|
1036
|
+
// This embedding provides the reference namespace only: a tree that asks for a lookup or a collection finds neither, which the evaluator carries as indeterminate rather than letting the tree pretend an answer.
|
|
1037
|
+
resolveLookup: () => ({ found: false }),
|
|
1038
|
+
resolveCollection: () => []
|
|
1039
|
+
};
|
|
1040
|
+
}
|
|
1041
|
+
function fieldPredicate(field, when, context) {
|
|
1042
|
+
switch (field) {
|
|
1043
|
+
case "newerThan": {
|
|
1044
|
+
const window = parseDuration(when.newerThan ?? "");
|
|
1045
|
+
return { kind: "compare", op: "gte", left: { kind: "reference", key: "entry.latestMtimeMs" }, right: { kind: "numberLiteral", value: context.nowMs - window } };
|
|
1046
|
+
}
|
|
1047
|
+
case "olderThan": {
|
|
1048
|
+
const window = parseDuration(when.olderThan ?? "");
|
|
1049
|
+
return { kind: "compare", op: "lt", left: { kind: "reference", key: "entry.latestMtimeMs" }, right: { kind: "numberLiteral", value: context.nowMs - window } };
|
|
1050
|
+
}
|
|
1051
|
+
case "maxSizeBytes":
|
|
1052
|
+
return { kind: "compare", op: "lte", left: { kind: "reference", key: "entry.totalSizeBytes" }, right: { kind: "numberLiteral", value: when.maxSizeBytes ?? 0 } };
|
|
1053
|
+
case "branch":
|
|
1054
|
+
return { kind: "allOf", operands: [{ kind: "textCompare", op: "portableMatches", left: { kind: "reference", key: "repo.branch" }, right: { kind: "textLiteral", value: when.branch ?? "" } }, { kind: "compare", op: "eq", left: { kind: "reference", key: "repo.detached" }, right: { kind: "booleanLiteral", value: false } }] };
|
|
1055
|
+
case "env": {
|
|
1056
|
+
const entries = Object.entries(when.env ?? {});
|
|
1057
|
+
return { kind: "allOf", operands: entries.map(([name, expected]) => ({ kind: "textCompare", op: "equals", left: { kind: "reference", key: `env.${name}` }, right: { kind: "textLiteral", value: expected } })) };
|
|
1058
|
+
}
|
|
1059
|
+
}
|
|
1060
|
+
return { kind: "allOf", operands: [] };
|
|
1061
|
+
}
|
|
1002
1062
|
function evaluateWhen(when, context) {
|
|
1003
1063
|
if (when === void 0) {
|
|
1004
|
-
return { passed: true, checked: [], failed: [] };
|
|
1064
|
+
return { status: "definite", passed: true, checked: [], failed: [] };
|
|
1065
|
+
}
|
|
1066
|
+
if ("kind" in when) {
|
|
1067
|
+
const result = evaluator.evaluatePredicate(when, void 0, resolversOf(context));
|
|
1068
|
+
return result.status === "indeterminate" ? { status: "indeterminate", reason: result.reason.message, checked: ["predicate"] } : { status: "definite", passed: result.value, checked: ["predicate"], failed: result.value ? [] : ["predicate"] };
|
|
1005
1069
|
}
|
|
1006
1070
|
const checked = [];
|
|
1007
1071
|
const failed = [];
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
const latest = context.fact?.latestMtimeMs;
|
|
1012
|
-
if (latest === void 0 || context.nowMs - latest > window) {
|
|
1013
|
-
failed.push("newerThan");
|
|
1014
|
-
}
|
|
1015
|
-
}
|
|
1016
|
-
if (when.olderThan !== void 0) {
|
|
1017
|
-
checked.push("olderThan");
|
|
1018
|
-
const window = parseDuration(when.olderThan);
|
|
1019
|
-
const latest = context.fact?.latestMtimeMs;
|
|
1020
|
-
if (latest === void 0 || context.nowMs - latest <= window) {
|
|
1021
|
-
failed.push("olderThan");
|
|
1022
|
-
}
|
|
1023
|
-
}
|
|
1024
|
-
if (when.maxSizeBytes !== void 0) {
|
|
1025
|
-
checked.push("maxSizeBytes");
|
|
1026
|
-
const total = context.fact?.totalSizeBytes;
|
|
1027
|
-
if (total === void 0 || total > when.maxSizeBytes) {
|
|
1028
|
-
failed.push("maxSizeBytes");
|
|
1072
|
+
for (const field of ["newerThan", "olderThan", "maxSizeBytes", "branch", "env"]) {
|
|
1073
|
+
if (when[field] === void 0) {
|
|
1074
|
+
continue;
|
|
1029
1075
|
}
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
failed.push("branch");
|
|
1076
|
+
checked.push(field);
|
|
1077
|
+
const result = evaluator.evaluatePredicate(fieldPredicate(field, when, context), void 0, resolversOf(context));
|
|
1078
|
+
if (result.status === "indeterminate") {
|
|
1079
|
+
return { status: "indeterminate", reason: result.reason.message, checked };
|
|
1035
1080
|
}
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
checked.push("env");
|
|
1039
|
-
const mismatch = Object.entries(when.env).some(([name, expected]) => context.env[name] !== expected);
|
|
1040
|
-
if (mismatch) {
|
|
1041
|
-
failed.push("env");
|
|
1081
|
+
if (!result.value) {
|
|
1082
|
+
failed.push(field);
|
|
1042
1083
|
}
|
|
1043
1084
|
}
|
|
1044
|
-
return { passed: failed.length === 0, checked, failed };
|
|
1085
|
+
return { status: "definite", passed: failed.length === 0, checked, failed };
|
|
1045
1086
|
}
|
|
1046
1087
|
function isVacuousWhen(when) {
|
|
1047
|
-
return when !== void 0 && Object.keys(when).length === 0;
|
|
1088
|
+
return when !== void 0 && !("kind" in when) && Object.keys(when).length === 0;
|
|
1048
1089
|
}
|
|
1049
1090
|
|
|
1050
1091
|
// src/resolve/match.ts
|
|
@@ -1415,10 +1456,10 @@ function selectRule(relPath, flattened, context) {
|
|
|
1415
1456
|
...context.branchDetached === void 0 ? {} : { branchDetached: context.branchDetached },
|
|
1416
1457
|
env: context.env
|
|
1417
1458
|
});
|
|
1418
|
-
if (evaluation.passed) {
|
|
1459
|
+
if (evaluation.status === "definite" && evaluation.passed) {
|
|
1419
1460
|
return { rule, eliminated };
|
|
1420
1461
|
}
|
|
1421
|
-
eliminated.push({ rule, failed: evaluation.failed });
|
|
1462
|
+
eliminated.push({ rule, failed: evaluation.status === "definite" ? evaluation.failed : [`${evaluation.checked.join(", ")} could not be decided: ${evaluation.reason}`] });
|
|
1422
1463
|
}
|
|
1423
1464
|
return { eliminated };
|
|
1424
1465
|
}
|
|
@@ -1652,7 +1693,10 @@ function planFarm(params) {
|
|
|
1652
1693
|
var ENTER_EVERYTHING = () => true;
|
|
1653
1694
|
function readsSubtreeAggregates(rule) {
|
|
1654
1695
|
const when = rule.when;
|
|
1655
|
-
|
|
1696
|
+
if (when === void 0) {
|
|
1697
|
+
return false;
|
|
1698
|
+
}
|
|
1699
|
+
return "kind" in when || when.newerThan !== void 0 || when.olderThan !== void 0 || when.maxSizeBytes !== void 0;
|
|
1656
1700
|
}
|
|
1657
1701
|
function hasUnboundedDepth(pattern) {
|
|
1658
1702
|
return pattern.includes("**") || /[{(]/.test(pattern);
|
|
@@ -5355,7 +5399,7 @@ var import_undici = require("undici");
|
|
|
5355
5399
|
// package.json
|
|
5356
5400
|
var package_default = {
|
|
5357
5401
|
name: "agent-shim",
|
|
5358
|
-
version: "8.
|
|
5402
|
+
version: "8.34.0",
|
|
5359
5403
|
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.",
|
|
5360
5404
|
license: "MIT",
|
|
5361
5405
|
author: "Joseph Mearman <joseph@mearman.co.uk>",
|
|
@@ -5411,6 +5455,7 @@ var package_default = {
|
|
|
5411
5455
|
commander: "^15.0.0",
|
|
5412
5456
|
cosmiconfig: "^10.0.1",
|
|
5413
5457
|
picomatch: "^4.0.7",
|
|
5458
|
+
trilean: "1.7.1",
|
|
5414
5459
|
undici: "7.29.1",
|
|
5415
5460
|
zod: "^4.6.1"
|
|
5416
5461
|
},
|
|
@@ -6646,12 +6691,48 @@ function assessIdentity(member, nowMs) {
|
|
|
6646
6691
|
...sevenDayBurn === void 0 ? {} : { sevenDayBurn }
|
|
6647
6692
|
};
|
|
6648
6693
|
}
|
|
6694
|
+
function poolFactsOf(member, nowMs, resuming, sticky) {
|
|
6695
|
+
const unified = member.snapshot?.providers[ANTHROPIC_PROVIDER]?.rateLimit?.unified;
|
|
6696
|
+
const window = (which) => {
|
|
6697
|
+
const raw = unified?.[which];
|
|
6698
|
+
if (raw?.utilization === void 0) {
|
|
6699
|
+
return void 0;
|
|
6700
|
+
}
|
|
6701
|
+
if (raw.resetsAt === void 0) {
|
|
6702
|
+
return void 0;
|
|
6703
|
+
}
|
|
6704
|
+
return { remaining: Math.max(0, 1 - raw.utilization), utilization: raw.utilization, hoursUntilReset: Math.max(0, (Date.parse(raw.resetsAt) - nowMs) / MS_PER_HOUR) };
|
|
6705
|
+
};
|
|
6706
|
+
const burn = windowBurn(member.records, "fiveHour");
|
|
6707
|
+
return {
|
|
6708
|
+
...window("fiveHour") === void 0 ? {} : { fiveHour: window("fiveHour") },
|
|
6709
|
+
...window("sevenDay") === void 0 ? {} : { sevenDay: window("sevenDay") },
|
|
6710
|
+
...burn === void 0 ? {} : { burnPerHour: burn * MS_PER_HOUR },
|
|
6711
|
+
resuming,
|
|
6712
|
+
...sticky?.identity === member.identity ? { lastPickHoursAgo: Math.max(0, (nowMs - Date.parse(sticky.at)) / MS_PER_HOUR) } : {}
|
|
6713
|
+
};
|
|
6714
|
+
}
|
|
6649
6715
|
function rankPool(input) {
|
|
6650
6716
|
const { members, nowMs } = input;
|
|
6651
|
-
const assessments = members.map((member) => assess(member, nowMs));
|
|
6717
|
+
const assessments = members.map((member) => ({ member, ...assess(member, nowMs) }));
|
|
6652
6718
|
const demands = assessments.flatMap(({ candidate, burn }) => burn === void 0 ? [] : [burn * capacityOf(candidate.plan)]);
|
|
6653
6719
|
const sharedDemand = demands.length === 0 ? void 0 : Math.max(...demands);
|
|
6654
|
-
const
|
|
6720
|
+
const guarded = assessments.map((assessment) => {
|
|
6721
|
+
const { candidate } = assessment;
|
|
6722
|
+
if (candidate.class === "ineligible" || assessment.member.policy === void 0) {
|
|
6723
|
+
return assessment;
|
|
6724
|
+
}
|
|
6725
|
+
const context = { nowMs, env: {}, pool: poolFactsOf(assessment.member, nowMs, input.resuming, input.sticky) };
|
|
6726
|
+
const verdict = evaluateWhen(assessment.member.policy, context);
|
|
6727
|
+
if (verdict.status === "indeterminate") {
|
|
6728
|
+
return { ...assessment, candidate: { ...candidate, policyDemoted: true, reasons: [`policy undecided (${verdict.checked.join(", ") === "predicate" ? "predicate" : verdict.checked.join(", ")}): ${verdict.reason}`, ...candidate.reasons] } };
|
|
6729
|
+
}
|
|
6730
|
+
if (verdict.passed) {
|
|
6731
|
+
return assessment;
|
|
6732
|
+
}
|
|
6733
|
+
return { ...assessment, candidate: { ...candidate, class: "ineligible", reasons: [`skipped by policy (${verdict.checked.join(", ")}: did not hold)`, ...candidate.reasons] } };
|
|
6734
|
+
});
|
|
6735
|
+
const candidates = guarded.map((assessment) => {
|
|
6655
6736
|
const { candidate, fiveHour, burn } = assessment;
|
|
6656
6737
|
const pace = burn ?? (sharedDemand === void 0 ? void 0 : sharedDemand / capacityOf(candidate.plan));
|
|
6657
6738
|
const { sevenDay, sevenDayBurn } = assessment;
|
|
@@ -6677,7 +6758,7 @@ function rankPool(input) {
|
|
|
6677
6758
|
return { ...candidate, feasible: false, reasons: [...drySpots, ...candidate.reasons] };
|
|
6678
6759
|
});
|
|
6679
6760
|
const ordered = input.preference === "listed" ? [...candidates] : [...candidates].sort(
|
|
6680
|
-
(left, right) => CLASS_ORDER[left.class] - CLASS_ORDER[right.class] || Number(right.feasible) - Number(left.feasible) || (right.score ?? 0) - (left.score ?? 0) || left.identity.localeCompare(right.identity)
|
|
6761
|
+
(left, right) => CLASS_ORDER[left.class] - CLASS_ORDER[right.class] || Number(left.policyDemoted ?? false) - Number(right.policyDemoted ?? false) || Number(right.feasible) - Number(left.feasible) || (right.score ?? 0) - (left.score ?? 0) || left.identity.localeCompare(right.identity)
|
|
6681
6762
|
);
|
|
6682
6763
|
const sticky = input.sticky;
|
|
6683
6764
|
const stickyIndex = sticky === void 0 ? -1 : ordered.findIndex((candidate) => candidate.identity === sticky.identity);
|
|
@@ -6848,27 +6929,27 @@ function rankNamedPool(input, poolName, stack, sticky) {
|
|
|
6848
6929
|
throw new PoolGraphError(`No pool named "${poolName}". Run \`agent-shim pool add ${poolName} --identity <name>...\` first.`);
|
|
6849
6930
|
}
|
|
6850
6931
|
const childStack = [...stack, poolName];
|
|
6851
|
-
const direct = pool.identities.filter((entry) => poolNameOf(entry) === void 0);
|
|
6852
|
-
const missing = direct.filter((entry) => !input.identityExists(entry)).map((
|
|
6853
|
-
const loaded = new Map(loadPoolMembers(input.fs, input.paths, direct.filter(input.identityExists), input.nowMs).map((member) => [member.identity, member]));
|
|
6932
|
+
const direct = pool.identities.filter((entry) => poolNameOf(poolMemberIdentity(entry)) === void 0);
|
|
6933
|
+
const missing = direct.filter((entry) => !input.identityExists(poolMemberIdentity(entry))).map((entry) => ({ pool: poolName, identity: poolMemberIdentity(entry) }));
|
|
6934
|
+
const loaded = new Map(loadPoolMembers(input.fs, input.paths, direct.filter((entry) => input.identityExists(poolMemberIdentity(entry))).map(poolMemberIdentity), input.nowMs).map((member) => [member.identity, member]));
|
|
6854
6935
|
const members = [];
|
|
6855
6936
|
for (const entry of pool.identities) {
|
|
6856
|
-
const nestedName = poolNameOf(entry);
|
|
6937
|
+
const nestedName = poolNameOf(poolMemberIdentity(entry));
|
|
6857
6938
|
if (nestedName === void 0) {
|
|
6858
|
-
const member = loaded.get(entry);
|
|
6939
|
+
const member = loaded.get(poolMemberIdentity(entry));
|
|
6859
6940
|
if (member !== void 0) {
|
|
6860
|
-
members.push(member);
|
|
6941
|
+
members.push(typeof entry === "string" ? member : { ...member, policy: entry.when });
|
|
6861
6942
|
}
|
|
6862
6943
|
continue;
|
|
6863
6944
|
}
|
|
6864
6945
|
if (input.pools[nestedName] === void 0) {
|
|
6865
|
-
throw new PoolGraphError(`Pool "${poolName}" member "${entry}" names a pool that is not defined.`);
|
|
6946
|
+
throw new PoolGraphError(`Pool "${poolName}" member "${poolMemberIdentity(entry)}" names a pool that is not defined.`);
|
|
6866
6947
|
}
|
|
6867
6948
|
if (childStack.includes(nestedName)) {
|
|
6868
|
-
throw new PoolGraphError(`Pool "${poolName}" member "${entry}" closes a cycle: ${[...childStack.slice(childStack.indexOf(nestedName)), nestedName].join(" -> ")}. A pool cannot nest itself, directly or through another pool.`);
|
|
6949
|
+
throw new PoolGraphError(`Pool "${poolName}" member "${poolMemberIdentity(entry)}" closes a cycle: ${[...childStack.slice(childStack.indexOf(nestedName)), nestedName].join(" -> ")}. A pool cannot nest itself, directly or through another pool.`);
|
|
6869
6950
|
}
|
|
6870
6951
|
const nested = nestedMember(input, nestedName, childStack, sticky);
|
|
6871
|
-
members.push(nested.member);
|
|
6952
|
+
members.push(typeof entry === "string" ? nested.member : { ...nested.member, policy: entry.when });
|
|
6872
6953
|
missing.push(...nested.missing);
|
|
6873
6954
|
}
|
|
6874
6955
|
const ranking = rankPool({
|
|
@@ -7129,7 +7210,7 @@ function writePools(paths, pools) {
|
|
|
7129
7210
|
function poolCycleOf(pools, name) {
|
|
7130
7211
|
const walk = (current, path32) => {
|
|
7131
7212
|
for (const entry of pools[current]?.identities ?? []) {
|
|
7132
|
-
const nested = poolNameOf(entry);
|
|
7213
|
+
const nested = poolNameOf(poolMemberIdentity(entry));
|
|
7133
7214
|
if (nested === void 0) {
|
|
7134
7215
|
continue;
|
|
7135
7216
|
}
|
|
@@ -7150,9 +7231,10 @@ function poolCycleOf(pools, name) {
|
|
|
7150
7231
|
}
|
|
7151
7232
|
function validateMembers(pools, name, members) {
|
|
7152
7233
|
for (const entry of members) {
|
|
7153
|
-
const
|
|
7234
|
+
const identity = poolMemberIdentity(entry);
|
|
7235
|
+
const nested = poolNameOf(identity);
|
|
7154
7236
|
if (nested !== void 0 && nested !== name && pools[nested] === void 0) {
|
|
7155
|
-
throw new UsageError(`Member "${
|
|
7237
|
+
throw new UsageError(`Member "${identity}" of pool "${name}" names a pool that is not defined. Run \`agent-shim pool add ${nested} --identity <name>...\` first.`);
|
|
7156
7238
|
}
|
|
7157
7239
|
}
|
|
7158
7240
|
const cycle = poolCycleOf({ ...pools, [name]: { identities: [...members] } }, name);
|
|
@@ -9857,16 +9939,16 @@ function runDoctor(params) {
|
|
|
9857
9939
|
const validatedGlobalConfig = params.globalConfig.raw === void 0 ? void 0 : validateJson(GlobalConfigSchema, params.globalConfig);
|
|
9858
9940
|
const pools = validatedGlobalConfig?.ok === true ? validatedGlobalConfig.data.pools ?? {} : {};
|
|
9859
9941
|
for (const [poolName, pool] of Object.entries(pools)) {
|
|
9860
|
-
const missing = pool.identities.filter((member) => poolNameOf(member) === void 0 && !validIdentityNames.has(member));
|
|
9942
|
+
const missing = pool.identities.filter((member) => poolNameOf(poolMemberIdentity(member)) === void 0 && !validIdentityNames.has(poolMemberIdentity(member)));
|
|
9861
9943
|
const undefinedPools = pool.identities.flatMap((member) => {
|
|
9862
|
-
const nested = poolNameOf(member);
|
|
9944
|
+
const nested = poolNameOf(poolMemberIdentity(member));
|
|
9863
9945
|
return nested === void 0 || nested in pools ? [] : [nested];
|
|
9864
9946
|
});
|
|
9865
9947
|
if (missing.length === 0 && undefinedPools.length === 0) {
|
|
9866
|
-
push("pool", "pass", `${poolName} is valid (${pool.identities.join(", ")}).`, poolName);
|
|
9948
|
+
push("pool", "pass", `${poolName} is valid (${pool.identities.map(poolMemberIdentity).join(", ")}).`, poolName);
|
|
9867
9949
|
} else {
|
|
9868
9950
|
const problems = [
|
|
9869
|
-
...missing.map((member) => `identity "${member}", which does not exist`),
|
|
9951
|
+
...missing.map((member) => `identity "${poolMemberIdentity(member)}", which does not exist`),
|
|
9870
9952
|
...undefinedPools.map((nested) => `pool "${nested}", which is not defined`)
|
|
9871
9953
|
];
|
|
9872
9954
|
push("pool", "fail", `Pool "${poolName}" names ${problems.join(" and ")}.`, poolName);
|