agent-shim 11.79.0 → 11.80.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 +1 -1
- package/dist/cli.cjs +152 -78
- package/dist/index.cjs +130 -66
- package/dist/index.mjs +130 -66
- package/dist/types/index.d.ts +2 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -57,7 +57,7 @@ That's it — with no further configuration, everything in `~/.claude` that isn'
|
|
|
57
57
|
- **An identity** is a login: the thing that owns credentials and daemon state, selected with `agent-shim run @<name>` or, once `agent-shim shim enable` has run, `claude @<name>`.
|
|
58
58
|
- **A configuration profile** is a reusable, named bundle of sharing rules, independent of any identity, resolved per working directory via directory rules or a committed `.agent-shim.json`.
|
|
59
59
|
|
|
60
|
-
A third, optional thing sits on top of identities: **a pool** is a named list of them. Select `pool:<name>` where an identity name goes (`claude @pool:subs`) and agent-shim picks the member whose unused quota is closest to expiring, skipping any that are refused right now, using the usage it already records. A pool can instead declare `--preference listed`, which tries the members in the order the pool lists them, skipping only one that is refused right now. A member entry may itself name another pool (`pool:<name>`), which is ranked with its own policy and contributes its pick at that position, so "this identity first, then the fleet" nests the fleet rather than copying its member list; cycles are refused. See [docs/configuration-model.md](docs/configuration-model.md#pools-picking-an-account-at-launch). On a terminal, `agent-shim run` asks which identity to run as when none resolves, when a pool pick would change account, or when the identity is refused right now (`--pick` forces the question, `--no-pick` never asks); see [docs/configuration-model.md](docs/configuration-model.md#choosing-the-identity-at-launch-the-picker).
|
|
60
|
+
A third, optional thing sits on top of identities: **a pool** is a named list of them. Select `pool:<name>` where an identity name goes (`claude @pool:subs`) and agent-shim picks the member whose unused quota is closest to expiring, skipping any that are refused right now, using the usage it already records. A pool can instead declare `--preference listed`, which tries the members in the order the pool lists them, skipping only one that is refused right now. A member entry may itself name another pool (`pool:<name>`), which is ranked with its own policy and contributes its pick at that position, so "this identity first, then the fleet" nests the fleet rather than copying its member list; cycles are refused. Members that hold the same login (the same account in the same organisation) share one quota window, so a pool ranks them as one candidate and never fails over from one to the other; `pool add`, `pool set` and `doctor` warn when a pool lists two of them. See [docs/configuration-model.md](docs/configuration-model.md#pools-picking-an-account-at-launch). On a terminal, `agent-shim run` asks which identity to run as when none resolves, when a pool pick would change account, or when the identity is refused right now (`--pick` forces the question, `--no-pick` never asks); see [docs/configuration-model.md](docs/configuration-model.md#choosing-the-identity-at-launch-the-picker).
|
|
61
61
|
|
|
62
62
|
Every top-level entry in `~/.claude` is classified into one of five categories, shipped as a default map (`config/categories.default.json`):
|
|
63
63
|
|
package/dist/cli.cjs
CHANGED
|
@@ -38192,13 +38192,95 @@ var init_account = __esm({
|
|
|
38192
38192
|
}
|
|
38193
38193
|
});
|
|
38194
38194
|
|
|
38195
|
+
// src/usage/accountDescription.ts
|
|
38196
|
+
function describeAccountOrganisation(account) {
|
|
38197
|
+
const parts = [account.organizationName, account.organizationType].filter((part) => part !== void 0);
|
|
38198
|
+
return parts.length === 0 ? void 0 : parts.join(", ");
|
|
38199
|
+
}
|
|
38200
|
+
function describeAccountPlan(account) {
|
|
38201
|
+
const parts = [account.billingType === void 0 ? void 0 : `billing ${account.billingType}`, account.seatTier === void 0 ? void 0 : `seat tier ${account.seatTier}`].filter((part) => part !== void 0);
|
|
38202
|
+
return parts.length === 0 ? void 0 : parts.join(", ");
|
|
38203
|
+
}
|
|
38204
|
+
var init_accountDescription = __esm({
|
|
38205
|
+
"src/usage/accountDescription.ts"() {
|
|
38206
|
+
"use strict";
|
|
38207
|
+
}
|
|
38208
|
+
});
|
|
38209
|
+
|
|
38210
|
+
// src/identityAccounts.ts
|
|
38211
|
+
function readIdentityAccount(fs31, identitiesDir, identity) {
|
|
38212
|
+
try {
|
|
38213
|
+
const account = readAccountMetadata(fs31, identitiesDir, identity);
|
|
38214
|
+
return account === void 0 ? void 0 : { account };
|
|
38215
|
+
} catch (error63) {
|
|
38216
|
+
if (error63 instanceof AccountMetadataError) {
|
|
38217
|
+
return { problem: error63.message };
|
|
38218
|
+
}
|
|
38219
|
+
throw error63;
|
|
38220
|
+
}
|
|
38221
|
+
}
|
|
38222
|
+
function summariseIdentityAccount(account) {
|
|
38223
|
+
const summary = {
|
|
38224
|
+
...account.emailAddress === void 0 ? {} : { emailAddress: account.emailAddress },
|
|
38225
|
+
...account.organizationName === void 0 ? {} : { organizationName: account.organizationName },
|
|
38226
|
+
...account.organizationType === void 0 ? {} : { organizationType: account.organizationType },
|
|
38227
|
+
...account.organizationRole === void 0 ? {} : { organizationRole: account.organizationRole },
|
|
38228
|
+
...account.billingType === void 0 ? {} : { billingType: account.billingType },
|
|
38229
|
+
...account.seatTier === void 0 ? {} : { seatTier: account.seatTier }
|
|
38230
|
+
};
|
|
38231
|
+
return Object.keys(summary).length === 0 ? void 0 : summary;
|
|
38232
|
+
}
|
|
38233
|
+
function loginKeyOf(account) {
|
|
38234
|
+
return account.accountUuid === void 0 ? void 0 : JSON.stringify([account.accountUuid, account.organizationUuid ?? null]);
|
|
38235
|
+
}
|
|
38236
|
+
function collectByLogin(items, loginOf) {
|
|
38237
|
+
const groups = /* @__PURE__ */ new Map();
|
|
38238
|
+
for (const item of items) {
|
|
38239
|
+
const key = loginOf(item) ?? /* @__PURE__ */ Symbol("no login");
|
|
38240
|
+
const group = groups.get(key);
|
|
38241
|
+
if (group === void 0) {
|
|
38242
|
+
groups.set(key, [item]);
|
|
38243
|
+
} else {
|
|
38244
|
+
group.push(item);
|
|
38245
|
+
}
|
|
38246
|
+
}
|
|
38247
|
+
return [...groups.values()];
|
|
38248
|
+
}
|
|
38249
|
+
function groupByLogin(items, loginOf) {
|
|
38250
|
+
return collectByLogin(items, loginOf).flat();
|
|
38251
|
+
}
|
|
38252
|
+
function groupSharedLogins(items, loginOf) {
|
|
38253
|
+
return collectByLogin(items, loginOf).filter((group) => group.length > 1);
|
|
38254
|
+
}
|
|
38255
|
+
function joinNames(names) {
|
|
38256
|
+
const last = names.at(-1);
|
|
38257
|
+
return names.length < 2 || last === void 0 ? names.join("") : `${names.slice(0, -1).join(", ")} and ${last}`;
|
|
38258
|
+
}
|
|
38259
|
+
function describeAccountHolder(summary) {
|
|
38260
|
+
const organisation = describeAccountOrganisation(summary);
|
|
38261
|
+
if (summary.emailAddress === void 0) {
|
|
38262
|
+
return organisation;
|
|
38263
|
+
}
|
|
38264
|
+
return organisation === void 0 ? summary.emailAddress : `${summary.emailAddress} (${organisation})`;
|
|
38265
|
+
}
|
|
38266
|
+
function describeIdentityAccount(summary) {
|
|
38267
|
+
return [describeAccountHolder(summary), summary.organizationRole === void 0 ? void 0 : `role ${summary.organizationRole}`, describeAccountPlan(summary)].filter((part) => part !== void 0).join("; ");
|
|
38268
|
+
}
|
|
38269
|
+
var init_identityAccounts = __esm({
|
|
38270
|
+
"src/identityAccounts.ts"() {
|
|
38271
|
+
"use strict";
|
|
38272
|
+
init_account();
|
|
38273
|
+
init_accountDescription();
|
|
38274
|
+
}
|
|
38275
|
+
});
|
|
38276
|
+
|
|
38195
38277
|
// package.json
|
|
38196
38278
|
var package_default;
|
|
38197
38279
|
var init_package = __esm({
|
|
38198
38280
|
"package.json"() {
|
|
38199
38281
|
package_default = {
|
|
38200
38282
|
name: "agent-shim",
|
|
38201
|
-
version: "11.
|
|
38283
|
+
version: "11.80.0",
|
|
38202
38284
|
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.",
|
|
38203
38285
|
license: "MIT",
|
|
38204
38286
|
author: "Joseph Mearman <joseph@mearman.co.uk>",
|
|
@@ -38918,6 +39000,9 @@ function assessRefusedNested(member, nested, nowMs) {
|
|
|
38918
39000
|
};
|
|
38919
39001
|
}
|
|
38920
39002
|
function assess(member, nowMs) {
|
|
39003
|
+
if (member.sameLoginAs !== void 0) {
|
|
39004
|
+
return { candidate: { identity: member.identity, class: "ineligible", plan: planOf(member.account), reasons: [`same login as ${member.sameLoginAs}`] } };
|
|
39005
|
+
}
|
|
38921
39006
|
const nested = member.nested;
|
|
38922
39007
|
if (nested === void 0) {
|
|
38923
39008
|
return assessIdentity(member, nowMs);
|
|
@@ -39461,6 +39546,29 @@ function loadPoolMembers(fs31, paths, identities, nowMs) {
|
|
|
39461
39546
|
}
|
|
39462
39547
|
});
|
|
39463
39548
|
}
|
|
39549
|
+
function snapshotAgeKey(member) {
|
|
39550
|
+
return member.snapshot === void 0 ? Number.NEGATIVE_INFINITY : Date.parse(member.snapshot.updatedAt);
|
|
39551
|
+
}
|
|
39552
|
+
function collapseSharedLogins(members2) {
|
|
39553
|
+
const groups = groupSharedLogins(members2, (member) => member.nested === void 0 && member.account !== void 0 ? loginKeyOf(member.account) : void 0);
|
|
39554
|
+
const representativeOf = /* @__PURE__ */ new Map();
|
|
39555
|
+
for (const group of groups) {
|
|
39556
|
+
const representative = group.reduce((freshest, member) => snapshotAgeKey(member) > snapshotAgeKey(freshest) ? member : freshest);
|
|
39557
|
+
for (const member of group) {
|
|
39558
|
+
if (member !== representative) {
|
|
39559
|
+
representativeOf.set(member, representative.identity);
|
|
39560
|
+
}
|
|
39561
|
+
}
|
|
39562
|
+
}
|
|
39563
|
+
return members2.map((member) => {
|
|
39564
|
+
const representative = representativeOf.get(member);
|
|
39565
|
+
return representative === void 0 ? member : { ...member, sameLoginAs: representative };
|
|
39566
|
+
});
|
|
39567
|
+
}
|
|
39568
|
+
function stickyOnRepresentative(sticky, members2) {
|
|
39569
|
+
const twin = sticky === void 0 ? void 0 : members2.find((member) => member.identity === sticky.identity && member.sameLoginAs !== void 0);
|
|
39570
|
+
return sticky === void 0 || twin?.sameLoginAs === void 0 ? sticky : { ...sticky, identity: twin.sameLoginAs };
|
|
39571
|
+
}
|
|
39464
39572
|
function rankPoolGraph(input2) {
|
|
39465
39573
|
return rankNamedPool(input2, input2.poolName, [], input2.sticky);
|
|
39466
39574
|
}
|
|
@@ -39488,13 +39596,15 @@ function rankNamedPool(input2, poolName, stack, sticky) {
|
|
|
39488
39596
|
members2.push(typeof entry === "string" ? nested.member : { ...nested.member, policy: entry.when });
|
|
39489
39597
|
missing.push(...nested.missing);
|
|
39490
39598
|
}
|
|
39599
|
+
const collapsed = collapseSharedLogins(members2);
|
|
39600
|
+
const stickyPick = stickyOnRepresentative(sticky, collapsed);
|
|
39491
39601
|
const ranking = rankPool({
|
|
39492
|
-
members:
|
|
39602
|
+
members: collapsed,
|
|
39493
39603
|
nowMs: input2.nowMs,
|
|
39494
39604
|
resuming: input2.resuming,
|
|
39495
39605
|
...input2.resumeContextTokens === void 0 ? {} : { resumeContextTokens: input2.resumeContextTokens },
|
|
39496
39606
|
...input2.committedContextTokens === void 0 ? {} : { committedContextTokens: input2.committedContextTokens },
|
|
39497
|
-
...
|
|
39607
|
+
...stickyPick === void 0 ? {} : { sticky: stickyPick },
|
|
39498
39608
|
...pool.preference === void 0 ? {} : { preference: pool.preference }
|
|
39499
39609
|
});
|
|
39500
39610
|
return { ranking, missing };
|
|
@@ -39561,6 +39671,7 @@ var init_poolPick = __esm({
|
|
|
39561
39671
|
init_cliError();
|
|
39562
39672
|
init_identity();
|
|
39563
39673
|
init_schema();
|
|
39674
|
+
init_identityAccounts();
|
|
39564
39675
|
init_account();
|
|
39565
39676
|
init_pick();
|
|
39566
39677
|
init_read();
|
|
@@ -117704,77 +117815,8 @@ function registerProfileCommand(program2, deps) {
|
|
|
117704
117815
|
init_providersStore();
|
|
117705
117816
|
init_identity();
|
|
117706
117817
|
init_realPorts();
|
|
117707
|
-
|
|
117708
|
-
|
|
117709
|
-
init_account();
|
|
117710
|
-
|
|
117711
|
-
// src/usage/accountDescription.ts
|
|
117712
|
-
function describeAccountOrganisation(account) {
|
|
117713
|
-
const parts = [account.organizationName, account.organizationType].filter((part) => part !== void 0);
|
|
117714
|
-
return parts.length === 0 ? void 0 : parts.join(", ");
|
|
117715
|
-
}
|
|
117716
|
-
function describeAccountPlan(account) {
|
|
117717
|
-
const parts = [account.billingType === void 0 ? void 0 : `billing ${account.billingType}`, account.seatTier === void 0 ? void 0 : `seat tier ${account.seatTier}`].filter((part) => part !== void 0);
|
|
117718
|
-
return parts.length === 0 ? void 0 : parts.join(", ");
|
|
117719
|
-
}
|
|
117720
|
-
|
|
117721
|
-
// src/identityAccounts.ts
|
|
117722
|
-
function readIdentityAccount(fs31, identitiesDir, identity) {
|
|
117723
|
-
try {
|
|
117724
|
-
const account = readAccountMetadata(fs31, identitiesDir, identity);
|
|
117725
|
-
return account === void 0 ? void 0 : { account };
|
|
117726
|
-
} catch (error63) {
|
|
117727
|
-
if (error63 instanceof AccountMetadataError) {
|
|
117728
|
-
return { problem: error63.message };
|
|
117729
|
-
}
|
|
117730
|
-
throw error63;
|
|
117731
|
-
}
|
|
117732
|
-
}
|
|
117733
|
-
function summariseIdentityAccount(account) {
|
|
117734
|
-
const summary = {
|
|
117735
|
-
...account.emailAddress === void 0 ? {} : { emailAddress: account.emailAddress },
|
|
117736
|
-
...account.organizationName === void 0 ? {} : { organizationName: account.organizationName },
|
|
117737
|
-
...account.organizationType === void 0 ? {} : { organizationType: account.organizationType },
|
|
117738
|
-
...account.organizationRole === void 0 ? {} : { organizationRole: account.organizationRole },
|
|
117739
|
-
...account.billingType === void 0 ? {} : { billingType: account.billingType },
|
|
117740
|
-
...account.seatTier === void 0 ? {} : { seatTier: account.seatTier }
|
|
117741
|
-
};
|
|
117742
|
-
return Object.keys(summary).length === 0 ? void 0 : summary;
|
|
117743
|
-
}
|
|
117744
|
-
function loginKeyOf(account) {
|
|
117745
|
-
return account.accountUuid === void 0 ? void 0 : JSON.stringify([account.accountUuid, account.organizationUuid ?? null]);
|
|
117746
|
-
}
|
|
117747
|
-
function collectByLogin(items, loginOf) {
|
|
117748
|
-
const groups = /* @__PURE__ */ new Map();
|
|
117749
|
-
for (const item of items) {
|
|
117750
|
-
const key = loginOf(item) ?? /* @__PURE__ */ Symbol("no login");
|
|
117751
|
-
const group = groups.get(key);
|
|
117752
|
-
if (group === void 0) {
|
|
117753
|
-
groups.set(key, [item]);
|
|
117754
|
-
} else {
|
|
117755
|
-
group.push(item);
|
|
117756
|
-
}
|
|
117757
|
-
}
|
|
117758
|
-
return [...groups.values()];
|
|
117759
|
-
}
|
|
117760
|
-
function groupByLogin(items, loginOf) {
|
|
117761
|
-
return collectByLogin(items, loginOf).flat();
|
|
117762
|
-
}
|
|
117763
|
-
function groupSharedLogins(items, loginOf) {
|
|
117764
|
-
return collectByLogin(items, loginOf).filter((group) => group.length > 1);
|
|
117765
|
-
}
|
|
117766
|
-
function describeAccountHolder(summary) {
|
|
117767
|
-
const organisation = describeAccountOrganisation(summary);
|
|
117768
|
-
if (summary.emailAddress === void 0) {
|
|
117769
|
-
return organisation;
|
|
117770
|
-
}
|
|
117771
|
-
return organisation === void 0 ? summary.emailAddress : `${summary.emailAddress} (${organisation})`;
|
|
117772
|
-
}
|
|
117773
|
-
function describeIdentityAccount(summary) {
|
|
117774
|
-
return [describeAccountHolder(summary), summary.organizationRole === void 0 ? void 0 : `role ${summary.organizationRole}`, describeAccountPlan(summary)].filter((part) => part !== void 0).join("; ");
|
|
117775
|
-
}
|
|
117776
|
-
|
|
117777
|
-
// src/identityManager.ts
|
|
117818
|
+
init_identityAccounts();
|
|
117819
|
+
init_accountDescription();
|
|
117778
117820
|
async function runIdentityWizard(prompts, paths, name, options = {}) {
|
|
117779
117821
|
if (!IdentitySchema.safeParse({ name, allowAmbientCredential: false }).success) {
|
|
117780
117822
|
throw new InvalidIdentityNameError(name);
|
|
@@ -123234,6 +123276,7 @@ init_realPorts();
|
|
|
123234
123276
|
var import_node_fs20 = __toESM(require("node:fs"), 1);
|
|
123235
123277
|
var import_node_path47 = __toESM(require("node:path"), 1);
|
|
123236
123278
|
init_signIn();
|
|
123279
|
+
init_identityAccounts();
|
|
123237
123280
|
init_load();
|
|
123238
123281
|
init_unrecognisedKeys();
|
|
123239
123282
|
init_schema();
|
|
@@ -123508,6 +123551,27 @@ init_providerAliases();
|
|
|
123508
123551
|
init_providersStore();
|
|
123509
123552
|
init_guard();
|
|
123510
123553
|
init_identity();
|
|
123554
|
+
|
|
123555
|
+
// src/poolSharedLogins.ts
|
|
123556
|
+
init_identityAccounts();
|
|
123557
|
+
init_identity();
|
|
123558
|
+
function sharedLoginMembers(members2, accountOf) {
|
|
123559
|
+
const known = members2.flatMap((identity) => {
|
|
123560
|
+
const account = poolNameOf(identity) === void 0 ? accountOf(identity) : void 0;
|
|
123561
|
+
return account === void 0 ? [] : [{ identity, account }];
|
|
123562
|
+
});
|
|
123563
|
+
return groupSharedLogins(known, (entry) => loginKeyOf(entry.account)).flatMap((group) => {
|
|
123564
|
+
const first = group[0];
|
|
123565
|
+
return first === void 0 ? [] : [{ members: group.map((entry) => entry.identity), account: first.account }];
|
|
123566
|
+
});
|
|
123567
|
+
}
|
|
123568
|
+
function describeSharedLoginMembers(poolName, shared) {
|
|
123569
|
+
const summary = summariseIdentityAccount(shared.account);
|
|
123570
|
+
const holder = summary === void 0 ? void 0 : describeAccountHolder(summary);
|
|
123571
|
+
return `Pool "${poolName}" lists ${joinNames(shared.members)}, which hold the same login${holder === void 0 ? "" : ` (${holder})`}, so they share one quota window. A launch ranks them as one candidate and never fails over from one to another; keep one of them in the pool.`;
|
|
123572
|
+
}
|
|
123573
|
+
|
|
123574
|
+
// src/doctorReport.ts
|
|
123511
123575
|
init_extends();
|
|
123512
123576
|
var DOCTOR_SEVERITIES = ["pass", "warn", "fail"];
|
|
123513
123577
|
var DOCTOR_SECTIONS = [
|
|
@@ -123530,10 +123594,6 @@ var DOCTOR_SECTIONS = [
|
|
|
123530
123594
|
"frontdoor",
|
|
123531
123595
|
"models"
|
|
123532
123596
|
];
|
|
123533
|
-
function joinNames(names) {
|
|
123534
|
-
const last = names.at(-1);
|
|
123535
|
-
return names.length < 2 || last === void 0 ? names.join("") : `${names.slice(0, -1).join(", ")} and ${last}`;
|
|
123536
|
-
}
|
|
123537
123597
|
function refinePathShadow(status, ownExecutablePath, realpath) {
|
|
123538
123598
|
if (status.status !== "shadowed") {
|
|
123539
123599
|
return status;
|
|
@@ -123846,6 +123906,7 @@ function runDoctor(params) {
|
|
|
123846
123906
|
}
|
|
123847
123907
|
const validatedGlobalConfig = params.globalConfig.raw === void 0 ? void 0 : validateJson(GlobalConfigSchema, params.globalConfig);
|
|
123848
123908
|
const pools = validatedGlobalConfig?.ok === true ? validatedGlobalConfig.data.pools ?? {} : {};
|
|
123909
|
+
const accountByIdentity = new Map(params.identities.flatMap((entry) => validIdentityNames.has(entry.name) && entry.account !== void 0 ? [[entry.name, entry.account]] : []));
|
|
123849
123910
|
for (const [poolName, pool] of Object.entries(pools)) {
|
|
123850
123911
|
const missing = pool.identities.filter((member) => poolNameOf(poolMemberIdentity(member)) === void 0 && !validIdentityNames.has(poolMemberIdentity(member)));
|
|
123851
123912
|
const undefinedPools = pool.identities.flatMap((member) => {
|
|
@@ -123861,6 +123922,9 @@ function runDoctor(params) {
|
|
|
123861
123922
|
];
|
|
123862
123923
|
push("pool", "fail", `Pool "${poolName}" names ${problems.join(" and ")}.`, poolName);
|
|
123863
123924
|
}
|
|
123925
|
+
for (const shared of sharedLoginMembers(pool.identities.map(poolMemberIdentity), (identityName) => accountByIdentity.get(identityName))) {
|
|
123926
|
+
push("pool", "warn", describeSharedLoginMembers(poolName, shared), poolName);
|
|
123927
|
+
}
|
|
123864
123928
|
}
|
|
123865
123929
|
const reportedCycles = /* @__PURE__ */ new Set();
|
|
123866
123930
|
for (const poolName of Object.keys(pools).sort()) {
|
|
@@ -156376,6 +156440,7 @@ init_schema();
|
|
|
156376
156440
|
init_realPorts();
|
|
156377
156441
|
init_candidateText();
|
|
156378
156442
|
init_preflight();
|
|
156443
|
+
init_identityAccounts();
|
|
156379
156444
|
function formatPoolPick(report, nowMs) {
|
|
156380
156445
|
const head = report.pick === void 0 ? `Pool ${report.pool}: every member is refused right now${report.earliestReturn === void 0 ? "" : `; ${report.earliestReturn.identity} returns at ${report.earliestReturn.at} (in ${formatAge(Date.parse(report.earliestReturn.at) - nowMs)})`}` : `Pool ${report.pool}: a launch from ${report.directory} would run as ${report.pick}`;
|
|
156381
156446
|
const rows = report.candidates.map((candidate, index) => {
|
|
@@ -156384,6 +156449,11 @@ function formatPoolPick(report, nowMs) {
|
|
|
156384
156449
|
});
|
|
156385
156450
|
return [head, ...rows, ...report.missing.map((name) => ` (skipped: ${name} is not an identity)`), ...report.stickyProblem === void 0 ? [] : [`Note: ${report.stickyProblem}; the last-pick record was ignored.`]];
|
|
156386
156451
|
}
|
|
156452
|
+
function warnSharedLogins(paths, poolName, members2) {
|
|
156453
|
+
for (const shared of sharedLoginMembers(members2, (identity) => readIdentityAccount(realFsPort, paths.identitiesDir, identity)?.account)) {
|
|
156454
|
+
console.error(`agent-shim: warning: ${describeSharedLoginMembers(poolName, shared)}`);
|
|
156455
|
+
}
|
|
156456
|
+
}
|
|
156387
156457
|
function policyNotes(entry) {
|
|
156388
156458
|
const notes = [
|
|
156389
156459
|
...entry?.preference === void 0 ? [] : [`preference: ${entry.preference}`],
|
|
@@ -156416,6 +156486,7 @@ function registerPoolCommand(program2, deps) {
|
|
|
156416
156486
|
reportMutation(options.json, { action: "created", kind: "pool", name, value: created }, () => {
|
|
156417
156487
|
console.log(`Created pool "${name}" with ${members2.join(", ")}.`);
|
|
156418
156488
|
});
|
|
156489
|
+
warnSharedLogins(paths, name, created.identities.map(poolMemberIdentity));
|
|
156419
156490
|
}),
|
|
156420
156491
|
["agent-shim pool add subs --identity work --identity personal", "agent-shim pool add client --identity client-main --identity spare --preference listed"]
|
|
156421
156492
|
);
|
|
@@ -156433,6 +156504,7 @@ function registerPoolCommand(program2, deps) {
|
|
|
156433
156504
|
reportMutation(options.json, { action: "updated", kind: "pool", name, value: updated }, () => {
|
|
156434
156505
|
console.log(`Pool "${name}" now has ${updated.identities.map(poolMemberIdentity).join(", ")}.`);
|
|
156435
156506
|
});
|
|
156507
|
+
warnSharedLogins(paths, name, updated.identities.map(poolMemberIdentity));
|
|
156436
156508
|
}),
|
|
156437
156509
|
["agent-shim pool set subs --identity work --identity personal --identity spare", "agent-shim pool set subs --preference listed", "agent-shim pool set subs --resume-on-limit --compact-before-limit --compact-at-utilisation 85"]
|
|
156438
156510
|
);
|
|
@@ -157481,6 +157553,7 @@ var import_node_path70 = __toESM(require("node:path"), 1);
|
|
|
157481
157553
|
init_commandDeps();
|
|
157482
157554
|
init_realPorts();
|
|
157483
157555
|
init_account();
|
|
157556
|
+
init_accountDescription();
|
|
157484
157557
|
init_signIn();
|
|
157485
157558
|
init_resets();
|
|
157486
157559
|
init_read();
|
|
@@ -157839,6 +157912,7 @@ function promptsIdentityPicker(prompts) {
|
|
|
157839
157912
|
// src/launcher/runPicker.ts
|
|
157840
157913
|
init_cliError();
|
|
157841
157914
|
init_schema();
|
|
157915
|
+
init_identityAccounts();
|
|
157842
157916
|
init_account();
|
|
157843
157917
|
init_candidateText();
|
|
157844
157918
|
init_pick();
|
package/dist/index.cjs
CHANGED
|
@@ -4764,7 +4764,7 @@ var init_package = __esm({
|
|
|
4764
4764
|
"package.json"() {
|
|
4765
4765
|
package_default = {
|
|
4766
4766
|
name: "agent-shim",
|
|
4767
|
-
version: "11.
|
|
4767
|
+
version: "11.80.0",
|
|
4768
4768
|
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.",
|
|
4769
4769
|
license: "MIT",
|
|
4770
4770
|
author: "Joseph Mearman <joseph@mearman.co.uk>",
|
|
@@ -7037,6 +7037,78 @@ var init_account = __esm({
|
|
|
7037
7037
|
}
|
|
7038
7038
|
});
|
|
7039
7039
|
|
|
7040
|
+
// src/usage/accountDescription.ts
|
|
7041
|
+
function describeAccountOrganisation(account) {
|
|
7042
|
+
const parts = [account.organizationName, account.organizationType].filter((part) => part !== void 0);
|
|
7043
|
+
return parts.length === 0 ? void 0 : parts.join(", ");
|
|
7044
|
+
}
|
|
7045
|
+
var init_accountDescription = __esm({
|
|
7046
|
+
"src/usage/accountDescription.ts"() {
|
|
7047
|
+
"use strict";
|
|
7048
|
+
}
|
|
7049
|
+
});
|
|
7050
|
+
|
|
7051
|
+
// src/identityAccounts.ts
|
|
7052
|
+
function readIdentityAccount(fs14, identitiesDir, identity) {
|
|
7053
|
+
try {
|
|
7054
|
+
const account = readAccountMetadata(fs14, identitiesDir, identity);
|
|
7055
|
+
return account === void 0 ? void 0 : { account };
|
|
7056
|
+
} catch (error) {
|
|
7057
|
+
if (error instanceof AccountMetadataError) {
|
|
7058
|
+
return { problem: error.message };
|
|
7059
|
+
}
|
|
7060
|
+
throw error;
|
|
7061
|
+
}
|
|
7062
|
+
}
|
|
7063
|
+
function summariseIdentityAccount(account) {
|
|
7064
|
+
const summary = {
|
|
7065
|
+
...account.emailAddress === void 0 ? {} : { emailAddress: account.emailAddress },
|
|
7066
|
+
...account.organizationName === void 0 ? {} : { organizationName: account.organizationName },
|
|
7067
|
+
...account.organizationType === void 0 ? {} : { organizationType: account.organizationType },
|
|
7068
|
+
...account.organizationRole === void 0 ? {} : { organizationRole: account.organizationRole },
|
|
7069
|
+
...account.billingType === void 0 ? {} : { billingType: account.billingType },
|
|
7070
|
+
...account.seatTier === void 0 ? {} : { seatTier: account.seatTier }
|
|
7071
|
+
};
|
|
7072
|
+
return Object.keys(summary).length === 0 ? void 0 : summary;
|
|
7073
|
+
}
|
|
7074
|
+
function loginKeyOf(account) {
|
|
7075
|
+
return account.accountUuid === void 0 ? void 0 : JSON.stringify([account.accountUuid, account.organizationUuid ?? null]);
|
|
7076
|
+
}
|
|
7077
|
+
function collectByLogin(items, loginOf) {
|
|
7078
|
+
const groups = /* @__PURE__ */ new Map();
|
|
7079
|
+
for (const item of items) {
|
|
7080
|
+
const key = loginOf(item) ?? /* @__PURE__ */ Symbol("no login");
|
|
7081
|
+
const group = groups.get(key);
|
|
7082
|
+
if (group === void 0) {
|
|
7083
|
+
groups.set(key, [item]);
|
|
7084
|
+
} else {
|
|
7085
|
+
group.push(item);
|
|
7086
|
+
}
|
|
7087
|
+
}
|
|
7088
|
+
return [...groups.values()];
|
|
7089
|
+
}
|
|
7090
|
+
function groupSharedLogins(items, loginOf) {
|
|
7091
|
+
return collectByLogin(items, loginOf).filter((group) => group.length > 1);
|
|
7092
|
+
}
|
|
7093
|
+
function joinNames(names) {
|
|
7094
|
+
const last = names.at(-1);
|
|
7095
|
+
return names.length < 2 || last === void 0 ? names.join("") : `${names.slice(0, -1).join(", ")} and ${last}`;
|
|
7096
|
+
}
|
|
7097
|
+
function describeAccountHolder(summary) {
|
|
7098
|
+
const organisation = describeAccountOrganisation(summary);
|
|
7099
|
+
if (summary.emailAddress === void 0) {
|
|
7100
|
+
return organisation;
|
|
7101
|
+
}
|
|
7102
|
+
return organisation === void 0 ? summary.emailAddress : `${summary.emailAddress} (${organisation})`;
|
|
7103
|
+
}
|
|
7104
|
+
var init_identityAccounts = __esm({
|
|
7105
|
+
"src/identityAccounts.ts"() {
|
|
7106
|
+
"use strict";
|
|
7107
|
+
init_account();
|
|
7108
|
+
init_accountDescription();
|
|
7109
|
+
}
|
|
7110
|
+
});
|
|
7111
|
+
|
|
7040
7112
|
// src/usage/rateLimit.ts
|
|
7041
7113
|
function epochSecondsToIso(value) {
|
|
7042
7114
|
if (value === void 0) {
|
|
@@ -7404,6 +7476,9 @@ function assessRefusedNested(member, nested, nowMs) {
|
|
|
7404
7476
|
};
|
|
7405
7477
|
}
|
|
7406
7478
|
function assess(member, nowMs) {
|
|
7479
|
+
if (member.sameLoginAs !== void 0) {
|
|
7480
|
+
return { candidate: { identity: member.identity, class: "ineligible", plan: planOf(member.account), reasons: [`same login as ${member.sameLoginAs}`] } };
|
|
7481
|
+
}
|
|
7407
7482
|
const nested = member.nested;
|
|
7408
7483
|
if (nested === void 0) {
|
|
7409
7484
|
return assessIdentity(member, nowMs);
|
|
@@ -7876,6 +7951,29 @@ function loadPoolMembers(fs14, paths, identities, nowMs) {
|
|
|
7876
7951
|
}
|
|
7877
7952
|
});
|
|
7878
7953
|
}
|
|
7954
|
+
function snapshotAgeKey(member) {
|
|
7955
|
+
return member.snapshot === void 0 ? Number.NEGATIVE_INFINITY : Date.parse(member.snapshot.updatedAt);
|
|
7956
|
+
}
|
|
7957
|
+
function collapseSharedLogins(members) {
|
|
7958
|
+
const groups = groupSharedLogins(members, (member) => member.nested === void 0 && member.account !== void 0 ? loginKeyOf(member.account) : void 0);
|
|
7959
|
+
const representativeOf = /* @__PURE__ */ new Map();
|
|
7960
|
+
for (const group of groups) {
|
|
7961
|
+
const representative = group.reduce((freshest, member) => snapshotAgeKey(member) > snapshotAgeKey(freshest) ? member : freshest);
|
|
7962
|
+
for (const member of group) {
|
|
7963
|
+
if (member !== representative) {
|
|
7964
|
+
representativeOf.set(member, representative.identity);
|
|
7965
|
+
}
|
|
7966
|
+
}
|
|
7967
|
+
}
|
|
7968
|
+
return members.map((member) => {
|
|
7969
|
+
const representative = representativeOf.get(member);
|
|
7970
|
+
return representative === void 0 ? member : { ...member, sameLoginAs: representative };
|
|
7971
|
+
});
|
|
7972
|
+
}
|
|
7973
|
+
function stickyOnRepresentative(sticky, members) {
|
|
7974
|
+
const twin = sticky === void 0 ? void 0 : members.find((member) => member.identity === sticky.identity && member.sameLoginAs !== void 0);
|
|
7975
|
+
return sticky === void 0 || twin?.sameLoginAs === void 0 ? sticky : { ...sticky, identity: twin.sameLoginAs };
|
|
7976
|
+
}
|
|
7879
7977
|
function rankPoolGraph(input) {
|
|
7880
7978
|
return rankNamedPool(input, input.poolName, [], input.sticky);
|
|
7881
7979
|
}
|
|
@@ -7903,13 +8001,15 @@ function rankNamedPool(input, poolName, stack, sticky) {
|
|
|
7903
8001
|
members.push(typeof entry === "string" ? nested.member : { ...nested.member, policy: entry.when });
|
|
7904
8002
|
missing.push(...nested.missing);
|
|
7905
8003
|
}
|
|
8004
|
+
const collapsed = collapseSharedLogins(members);
|
|
8005
|
+
const stickyPick = stickyOnRepresentative(sticky, collapsed);
|
|
7906
8006
|
const ranking = rankPool({
|
|
7907
|
-
members,
|
|
8007
|
+
members: collapsed,
|
|
7908
8008
|
nowMs: input.nowMs,
|
|
7909
8009
|
resuming: input.resuming,
|
|
7910
8010
|
...input.resumeContextTokens === void 0 ? {} : { resumeContextTokens: input.resumeContextTokens },
|
|
7911
8011
|
...input.committedContextTokens === void 0 ? {} : { committedContextTokens: input.committedContextTokens },
|
|
7912
|
-
...
|
|
8012
|
+
...stickyPick === void 0 ? {} : { sticky: stickyPick },
|
|
7913
8013
|
...pool.preference === void 0 ? {} : { preference: pool.preference }
|
|
7914
8014
|
});
|
|
7915
8015
|
return { ranking, missing };
|
|
@@ -7997,6 +8097,7 @@ var init_poolPick = __esm({
|
|
|
7997
8097
|
init_cliError();
|
|
7998
8098
|
init_identity();
|
|
7999
8099
|
init_schema();
|
|
8100
|
+
init_identityAccounts();
|
|
8000
8101
|
init_account();
|
|
8001
8102
|
init_pick();
|
|
8002
8103
|
init_read();
|
|
@@ -17084,65 +17185,7 @@ init_realPorts();
|
|
|
17084
17185
|
var import_node_fs10 = __toESM(require("node:fs"), 1);
|
|
17085
17186
|
var import_node_path29 = __toESM(require("node:path"), 1);
|
|
17086
17187
|
init_signIn();
|
|
17087
|
-
|
|
17088
|
-
// src/identityAccounts.ts
|
|
17089
|
-
init_account();
|
|
17090
|
-
|
|
17091
|
-
// src/usage/accountDescription.ts
|
|
17092
|
-
function describeAccountOrganisation(account) {
|
|
17093
|
-
const parts = [account.organizationName, account.organizationType].filter((part) => part !== void 0);
|
|
17094
|
-
return parts.length === 0 ? void 0 : parts.join(", ");
|
|
17095
|
-
}
|
|
17096
|
-
|
|
17097
|
-
// src/identityAccounts.ts
|
|
17098
|
-
function readIdentityAccount(fs14, identitiesDir, identity) {
|
|
17099
|
-
try {
|
|
17100
|
-
const account = readAccountMetadata(fs14, identitiesDir, identity);
|
|
17101
|
-
return account === void 0 ? void 0 : { account };
|
|
17102
|
-
} catch (error) {
|
|
17103
|
-
if (error instanceof AccountMetadataError) {
|
|
17104
|
-
return { problem: error.message };
|
|
17105
|
-
}
|
|
17106
|
-
throw error;
|
|
17107
|
-
}
|
|
17108
|
-
}
|
|
17109
|
-
function summariseIdentityAccount(account) {
|
|
17110
|
-
const summary = {
|
|
17111
|
-
...account.emailAddress === void 0 ? {} : { emailAddress: account.emailAddress },
|
|
17112
|
-
...account.organizationName === void 0 ? {} : { organizationName: account.organizationName },
|
|
17113
|
-
...account.organizationType === void 0 ? {} : { organizationType: account.organizationType },
|
|
17114
|
-
...account.organizationRole === void 0 ? {} : { organizationRole: account.organizationRole },
|
|
17115
|
-
...account.billingType === void 0 ? {} : { billingType: account.billingType },
|
|
17116
|
-
...account.seatTier === void 0 ? {} : { seatTier: account.seatTier }
|
|
17117
|
-
};
|
|
17118
|
-
return Object.keys(summary).length === 0 ? void 0 : summary;
|
|
17119
|
-
}
|
|
17120
|
-
function loginKeyOf(account) {
|
|
17121
|
-
return account.accountUuid === void 0 ? void 0 : JSON.stringify([account.accountUuid, account.organizationUuid ?? null]);
|
|
17122
|
-
}
|
|
17123
|
-
function collectByLogin(items, loginOf) {
|
|
17124
|
-
const groups = /* @__PURE__ */ new Map();
|
|
17125
|
-
for (const item of items) {
|
|
17126
|
-
const key = loginOf(item) ?? /* @__PURE__ */ Symbol("no login");
|
|
17127
|
-
const group = groups.get(key);
|
|
17128
|
-
if (group === void 0) {
|
|
17129
|
-
groups.set(key, [item]);
|
|
17130
|
-
} else {
|
|
17131
|
-
group.push(item);
|
|
17132
|
-
}
|
|
17133
|
-
}
|
|
17134
|
-
return [...groups.values()];
|
|
17135
|
-
}
|
|
17136
|
-
function groupSharedLogins(items, loginOf) {
|
|
17137
|
-
return collectByLogin(items, loginOf).filter((group) => group.length > 1);
|
|
17138
|
-
}
|
|
17139
|
-
function describeAccountHolder(summary) {
|
|
17140
|
-
const organisation = describeAccountOrganisation(summary);
|
|
17141
|
-
if (summary.emailAddress === void 0) {
|
|
17142
|
-
return organisation;
|
|
17143
|
-
}
|
|
17144
|
-
return organisation === void 0 ? summary.emailAddress : `${summary.emailAddress} (${organisation})`;
|
|
17145
|
-
}
|
|
17188
|
+
init_identityAccounts();
|
|
17146
17189
|
|
|
17147
17190
|
// src/codex/siwcStore.ts
|
|
17148
17191
|
var import_zod26 = require("zod");
|
|
@@ -17496,6 +17539,27 @@ init_providerAliases();
|
|
|
17496
17539
|
init_providersStore();
|
|
17497
17540
|
init_guard();
|
|
17498
17541
|
init_identity();
|
|
17542
|
+
|
|
17543
|
+
// src/poolSharedLogins.ts
|
|
17544
|
+
init_identityAccounts();
|
|
17545
|
+
init_identity();
|
|
17546
|
+
function sharedLoginMembers(members, accountOf) {
|
|
17547
|
+
const known = members.flatMap((identity) => {
|
|
17548
|
+
const account = poolNameOf(identity) === void 0 ? accountOf(identity) : void 0;
|
|
17549
|
+
return account === void 0 ? [] : [{ identity, account }];
|
|
17550
|
+
});
|
|
17551
|
+
return groupSharedLogins(known, (entry) => loginKeyOf(entry.account)).flatMap((group) => {
|
|
17552
|
+
const first = group[0];
|
|
17553
|
+
return first === void 0 ? [] : [{ members: group.map((entry) => entry.identity), account: first.account }];
|
|
17554
|
+
});
|
|
17555
|
+
}
|
|
17556
|
+
function describeSharedLoginMembers(poolName, shared) {
|
|
17557
|
+
const summary = summariseIdentityAccount(shared.account);
|
|
17558
|
+
const holder = summary === void 0 ? void 0 : describeAccountHolder(summary);
|
|
17559
|
+
return `Pool "${poolName}" lists ${joinNames(shared.members)}, which hold the same login${holder === void 0 ? "" : ` (${holder})`}, so they share one quota window. A launch ranks them as one candidate and never fails over from one to another; keep one of them in the pool.`;
|
|
17560
|
+
}
|
|
17561
|
+
|
|
17562
|
+
// src/doctorReport.ts
|
|
17499
17563
|
init_extends();
|
|
17500
17564
|
var DOCTOR_SEVERITIES = ["pass", "warn", "fail"];
|
|
17501
17565
|
var DOCTOR_SECTIONS = [
|
|
@@ -17518,10 +17582,6 @@ var DOCTOR_SECTIONS = [
|
|
|
17518
17582
|
"frontdoor",
|
|
17519
17583
|
"models"
|
|
17520
17584
|
];
|
|
17521
|
-
function joinNames(names) {
|
|
17522
|
-
const last = names.at(-1);
|
|
17523
|
-
return names.length < 2 || last === void 0 ? names.join("") : `${names.slice(0, -1).join(", ")} and ${last}`;
|
|
17524
|
-
}
|
|
17525
17585
|
function refinePathShadow(status, ownExecutablePath, realpath) {
|
|
17526
17586
|
if (status.status !== "shadowed") {
|
|
17527
17587
|
return status;
|
|
@@ -17834,6 +17894,7 @@ function runDoctor(params) {
|
|
|
17834
17894
|
}
|
|
17835
17895
|
const validatedGlobalConfig = params.globalConfig.raw === void 0 ? void 0 : validateJson(GlobalConfigSchema, params.globalConfig);
|
|
17836
17896
|
const pools = validatedGlobalConfig?.ok === true ? validatedGlobalConfig.data.pools ?? {} : {};
|
|
17897
|
+
const accountByIdentity = new Map(params.identities.flatMap((entry) => validIdentityNames.has(entry.name) && entry.account !== void 0 ? [[entry.name, entry.account]] : []));
|
|
17837
17898
|
for (const [poolName, pool] of Object.entries(pools)) {
|
|
17838
17899
|
const missing = pool.identities.filter((member) => poolNameOf(poolMemberIdentity(member)) === void 0 && !validIdentityNames.has(poolMemberIdentity(member)));
|
|
17839
17900
|
const undefinedPools = pool.identities.flatMap((member) => {
|
|
@@ -17849,6 +17910,9 @@ function runDoctor(params) {
|
|
|
17849
17910
|
];
|
|
17850
17911
|
push("pool", "fail", `Pool "${poolName}" names ${problems.join(" and ")}.`, poolName);
|
|
17851
17912
|
}
|
|
17913
|
+
for (const shared of sharedLoginMembers(pool.identities.map(poolMemberIdentity), (identityName) => accountByIdentity.get(identityName))) {
|
|
17914
|
+
push("pool", "warn", describeSharedLoginMembers(poolName, shared), poolName);
|
|
17915
|
+
}
|
|
17852
17916
|
}
|
|
17853
17917
|
const reportedCycles = /* @__PURE__ */ new Set();
|
|
17854
17918
|
for (const poolName of Object.keys(pools).sort()) {
|
package/dist/index.mjs
CHANGED
|
@@ -4740,7 +4740,7 @@ var init_package = __esm({
|
|
|
4740
4740
|
"package.json"() {
|
|
4741
4741
|
package_default = {
|
|
4742
4742
|
name: "agent-shim",
|
|
4743
|
-
version: "11.
|
|
4743
|
+
version: "11.80.0",
|
|
4744
4744
|
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.",
|
|
4745
4745
|
license: "MIT",
|
|
4746
4746
|
author: "Joseph Mearman <joseph@mearman.co.uk>",
|
|
@@ -7012,6 +7012,78 @@ var init_account = __esm({
|
|
|
7012
7012
|
}
|
|
7013
7013
|
});
|
|
7014
7014
|
|
|
7015
|
+
// src/usage/accountDescription.ts
|
|
7016
|
+
function describeAccountOrganisation(account) {
|
|
7017
|
+
const parts = [account.organizationName, account.organizationType].filter((part) => part !== void 0);
|
|
7018
|
+
return parts.length === 0 ? void 0 : parts.join(", ");
|
|
7019
|
+
}
|
|
7020
|
+
var init_accountDescription = __esm({
|
|
7021
|
+
"src/usage/accountDescription.ts"() {
|
|
7022
|
+
"use strict";
|
|
7023
|
+
}
|
|
7024
|
+
});
|
|
7025
|
+
|
|
7026
|
+
// src/identityAccounts.ts
|
|
7027
|
+
function readIdentityAccount(fs14, identitiesDir, identity) {
|
|
7028
|
+
try {
|
|
7029
|
+
const account = readAccountMetadata(fs14, identitiesDir, identity);
|
|
7030
|
+
return account === void 0 ? void 0 : { account };
|
|
7031
|
+
} catch (error) {
|
|
7032
|
+
if (error instanceof AccountMetadataError) {
|
|
7033
|
+
return { problem: error.message };
|
|
7034
|
+
}
|
|
7035
|
+
throw error;
|
|
7036
|
+
}
|
|
7037
|
+
}
|
|
7038
|
+
function summariseIdentityAccount(account) {
|
|
7039
|
+
const summary = {
|
|
7040
|
+
...account.emailAddress === void 0 ? {} : { emailAddress: account.emailAddress },
|
|
7041
|
+
...account.organizationName === void 0 ? {} : { organizationName: account.organizationName },
|
|
7042
|
+
...account.organizationType === void 0 ? {} : { organizationType: account.organizationType },
|
|
7043
|
+
...account.organizationRole === void 0 ? {} : { organizationRole: account.organizationRole },
|
|
7044
|
+
...account.billingType === void 0 ? {} : { billingType: account.billingType },
|
|
7045
|
+
...account.seatTier === void 0 ? {} : { seatTier: account.seatTier }
|
|
7046
|
+
};
|
|
7047
|
+
return Object.keys(summary).length === 0 ? void 0 : summary;
|
|
7048
|
+
}
|
|
7049
|
+
function loginKeyOf(account) {
|
|
7050
|
+
return account.accountUuid === void 0 ? void 0 : JSON.stringify([account.accountUuid, account.organizationUuid ?? null]);
|
|
7051
|
+
}
|
|
7052
|
+
function collectByLogin(items, loginOf) {
|
|
7053
|
+
const groups = /* @__PURE__ */ new Map();
|
|
7054
|
+
for (const item of items) {
|
|
7055
|
+
const key = loginOf(item) ?? /* @__PURE__ */ Symbol("no login");
|
|
7056
|
+
const group = groups.get(key);
|
|
7057
|
+
if (group === void 0) {
|
|
7058
|
+
groups.set(key, [item]);
|
|
7059
|
+
} else {
|
|
7060
|
+
group.push(item);
|
|
7061
|
+
}
|
|
7062
|
+
}
|
|
7063
|
+
return [...groups.values()];
|
|
7064
|
+
}
|
|
7065
|
+
function groupSharedLogins(items, loginOf) {
|
|
7066
|
+
return collectByLogin(items, loginOf).filter((group) => group.length > 1);
|
|
7067
|
+
}
|
|
7068
|
+
function joinNames(names) {
|
|
7069
|
+
const last = names.at(-1);
|
|
7070
|
+
return names.length < 2 || last === void 0 ? names.join("") : `${names.slice(0, -1).join(", ")} and ${last}`;
|
|
7071
|
+
}
|
|
7072
|
+
function describeAccountHolder(summary) {
|
|
7073
|
+
const organisation = describeAccountOrganisation(summary);
|
|
7074
|
+
if (summary.emailAddress === void 0) {
|
|
7075
|
+
return organisation;
|
|
7076
|
+
}
|
|
7077
|
+
return organisation === void 0 ? summary.emailAddress : `${summary.emailAddress} (${organisation})`;
|
|
7078
|
+
}
|
|
7079
|
+
var init_identityAccounts = __esm({
|
|
7080
|
+
"src/identityAccounts.ts"() {
|
|
7081
|
+
"use strict";
|
|
7082
|
+
init_account();
|
|
7083
|
+
init_accountDescription();
|
|
7084
|
+
}
|
|
7085
|
+
});
|
|
7086
|
+
|
|
7015
7087
|
// src/usage/rateLimit.ts
|
|
7016
7088
|
function epochSecondsToIso(value) {
|
|
7017
7089
|
if (value === void 0) {
|
|
@@ -7379,6 +7451,9 @@ function assessRefusedNested(member, nested, nowMs) {
|
|
|
7379
7451
|
};
|
|
7380
7452
|
}
|
|
7381
7453
|
function assess(member, nowMs) {
|
|
7454
|
+
if (member.sameLoginAs !== void 0) {
|
|
7455
|
+
return { candidate: { identity: member.identity, class: "ineligible", plan: planOf(member.account), reasons: [`same login as ${member.sameLoginAs}`] } };
|
|
7456
|
+
}
|
|
7382
7457
|
const nested = member.nested;
|
|
7383
7458
|
if (nested === void 0) {
|
|
7384
7459
|
return assessIdentity(member, nowMs);
|
|
@@ -7853,6 +7928,29 @@ function loadPoolMembers(fs14, paths, identities, nowMs) {
|
|
|
7853
7928
|
}
|
|
7854
7929
|
});
|
|
7855
7930
|
}
|
|
7931
|
+
function snapshotAgeKey(member) {
|
|
7932
|
+
return member.snapshot === void 0 ? Number.NEGATIVE_INFINITY : Date.parse(member.snapshot.updatedAt);
|
|
7933
|
+
}
|
|
7934
|
+
function collapseSharedLogins(members) {
|
|
7935
|
+
const groups = groupSharedLogins(members, (member) => member.nested === void 0 && member.account !== void 0 ? loginKeyOf(member.account) : void 0);
|
|
7936
|
+
const representativeOf = /* @__PURE__ */ new Map();
|
|
7937
|
+
for (const group of groups) {
|
|
7938
|
+
const representative = group.reduce((freshest, member) => snapshotAgeKey(member) > snapshotAgeKey(freshest) ? member : freshest);
|
|
7939
|
+
for (const member of group) {
|
|
7940
|
+
if (member !== representative) {
|
|
7941
|
+
representativeOf.set(member, representative.identity);
|
|
7942
|
+
}
|
|
7943
|
+
}
|
|
7944
|
+
}
|
|
7945
|
+
return members.map((member) => {
|
|
7946
|
+
const representative = representativeOf.get(member);
|
|
7947
|
+
return representative === void 0 ? member : { ...member, sameLoginAs: representative };
|
|
7948
|
+
});
|
|
7949
|
+
}
|
|
7950
|
+
function stickyOnRepresentative(sticky, members) {
|
|
7951
|
+
const twin = sticky === void 0 ? void 0 : members.find((member) => member.identity === sticky.identity && member.sameLoginAs !== void 0);
|
|
7952
|
+
return sticky === void 0 || twin?.sameLoginAs === void 0 ? sticky : { ...sticky, identity: twin.sameLoginAs };
|
|
7953
|
+
}
|
|
7856
7954
|
function rankPoolGraph(input) {
|
|
7857
7955
|
return rankNamedPool(input, input.poolName, [], input.sticky);
|
|
7858
7956
|
}
|
|
@@ -7880,13 +7978,15 @@ function rankNamedPool(input, poolName, stack, sticky) {
|
|
|
7880
7978
|
members.push(typeof entry === "string" ? nested.member : { ...nested.member, policy: entry.when });
|
|
7881
7979
|
missing.push(...nested.missing);
|
|
7882
7980
|
}
|
|
7981
|
+
const collapsed = collapseSharedLogins(members);
|
|
7982
|
+
const stickyPick = stickyOnRepresentative(sticky, collapsed);
|
|
7883
7983
|
const ranking = rankPool({
|
|
7884
|
-
members,
|
|
7984
|
+
members: collapsed,
|
|
7885
7985
|
nowMs: input.nowMs,
|
|
7886
7986
|
resuming: input.resuming,
|
|
7887
7987
|
...input.resumeContextTokens === void 0 ? {} : { resumeContextTokens: input.resumeContextTokens },
|
|
7888
7988
|
...input.committedContextTokens === void 0 ? {} : { committedContextTokens: input.committedContextTokens },
|
|
7889
|
-
...
|
|
7989
|
+
...stickyPick === void 0 ? {} : { sticky: stickyPick },
|
|
7890
7990
|
...pool.preference === void 0 ? {} : { preference: pool.preference }
|
|
7891
7991
|
});
|
|
7892
7992
|
return { ranking, missing };
|
|
@@ -7972,6 +8072,7 @@ var init_poolPick = __esm({
|
|
|
7972
8072
|
init_cliError();
|
|
7973
8073
|
init_identity();
|
|
7974
8074
|
init_schema();
|
|
8075
|
+
init_identityAccounts();
|
|
7975
8076
|
init_account();
|
|
7976
8077
|
init_pick();
|
|
7977
8078
|
init_read();
|
|
@@ -16669,65 +16770,7 @@ init_realPorts();
|
|
|
16669
16770
|
import fs11 from "node:fs";
|
|
16670
16771
|
import path29 from "node:path";
|
|
16671
16772
|
init_signIn();
|
|
16672
|
-
|
|
16673
|
-
// src/identityAccounts.ts
|
|
16674
|
-
init_account();
|
|
16675
|
-
|
|
16676
|
-
// src/usage/accountDescription.ts
|
|
16677
|
-
function describeAccountOrganisation(account) {
|
|
16678
|
-
const parts = [account.organizationName, account.organizationType].filter((part) => part !== void 0);
|
|
16679
|
-
return parts.length === 0 ? void 0 : parts.join(", ");
|
|
16680
|
-
}
|
|
16681
|
-
|
|
16682
|
-
// src/identityAccounts.ts
|
|
16683
|
-
function readIdentityAccount(fs14, identitiesDir, identity) {
|
|
16684
|
-
try {
|
|
16685
|
-
const account = readAccountMetadata(fs14, identitiesDir, identity);
|
|
16686
|
-
return account === void 0 ? void 0 : { account };
|
|
16687
|
-
} catch (error) {
|
|
16688
|
-
if (error instanceof AccountMetadataError) {
|
|
16689
|
-
return { problem: error.message };
|
|
16690
|
-
}
|
|
16691
|
-
throw error;
|
|
16692
|
-
}
|
|
16693
|
-
}
|
|
16694
|
-
function summariseIdentityAccount(account) {
|
|
16695
|
-
const summary = {
|
|
16696
|
-
...account.emailAddress === void 0 ? {} : { emailAddress: account.emailAddress },
|
|
16697
|
-
...account.organizationName === void 0 ? {} : { organizationName: account.organizationName },
|
|
16698
|
-
...account.organizationType === void 0 ? {} : { organizationType: account.organizationType },
|
|
16699
|
-
...account.organizationRole === void 0 ? {} : { organizationRole: account.organizationRole },
|
|
16700
|
-
...account.billingType === void 0 ? {} : { billingType: account.billingType },
|
|
16701
|
-
...account.seatTier === void 0 ? {} : { seatTier: account.seatTier }
|
|
16702
|
-
};
|
|
16703
|
-
return Object.keys(summary).length === 0 ? void 0 : summary;
|
|
16704
|
-
}
|
|
16705
|
-
function loginKeyOf(account) {
|
|
16706
|
-
return account.accountUuid === void 0 ? void 0 : JSON.stringify([account.accountUuid, account.organizationUuid ?? null]);
|
|
16707
|
-
}
|
|
16708
|
-
function collectByLogin(items, loginOf) {
|
|
16709
|
-
const groups = /* @__PURE__ */ new Map();
|
|
16710
|
-
for (const item of items) {
|
|
16711
|
-
const key = loginOf(item) ?? /* @__PURE__ */ Symbol("no login");
|
|
16712
|
-
const group = groups.get(key);
|
|
16713
|
-
if (group === void 0) {
|
|
16714
|
-
groups.set(key, [item]);
|
|
16715
|
-
} else {
|
|
16716
|
-
group.push(item);
|
|
16717
|
-
}
|
|
16718
|
-
}
|
|
16719
|
-
return [...groups.values()];
|
|
16720
|
-
}
|
|
16721
|
-
function groupSharedLogins(items, loginOf) {
|
|
16722
|
-
return collectByLogin(items, loginOf).filter((group) => group.length > 1);
|
|
16723
|
-
}
|
|
16724
|
-
function describeAccountHolder(summary) {
|
|
16725
|
-
const organisation = describeAccountOrganisation(summary);
|
|
16726
|
-
if (summary.emailAddress === void 0) {
|
|
16727
|
-
return organisation;
|
|
16728
|
-
}
|
|
16729
|
-
return organisation === void 0 ? summary.emailAddress : `${summary.emailAddress} (${organisation})`;
|
|
16730
|
-
}
|
|
16773
|
+
init_identityAccounts();
|
|
16731
16774
|
|
|
16732
16775
|
// src/codex/siwcStore.ts
|
|
16733
16776
|
import { z as z26 } from "zod";
|
|
@@ -17081,6 +17124,27 @@ init_providerAliases();
|
|
|
17081
17124
|
init_providersStore();
|
|
17082
17125
|
init_guard();
|
|
17083
17126
|
init_identity();
|
|
17127
|
+
|
|
17128
|
+
// src/poolSharedLogins.ts
|
|
17129
|
+
init_identityAccounts();
|
|
17130
|
+
init_identity();
|
|
17131
|
+
function sharedLoginMembers(members, accountOf) {
|
|
17132
|
+
const known = members.flatMap((identity) => {
|
|
17133
|
+
const account = poolNameOf(identity) === void 0 ? accountOf(identity) : void 0;
|
|
17134
|
+
return account === void 0 ? [] : [{ identity, account }];
|
|
17135
|
+
});
|
|
17136
|
+
return groupSharedLogins(known, (entry) => loginKeyOf(entry.account)).flatMap((group) => {
|
|
17137
|
+
const first = group[0];
|
|
17138
|
+
return first === void 0 ? [] : [{ members: group.map((entry) => entry.identity), account: first.account }];
|
|
17139
|
+
});
|
|
17140
|
+
}
|
|
17141
|
+
function describeSharedLoginMembers(poolName, shared) {
|
|
17142
|
+
const summary = summariseIdentityAccount(shared.account);
|
|
17143
|
+
const holder = summary === void 0 ? void 0 : describeAccountHolder(summary);
|
|
17144
|
+
return `Pool "${poolName}" lists ${joinNames(shared.members)}, which hold the same login${holder === void 0 ? "" : ` (${holder})`}, so they share one quota window. A launch ranks them as one candidate and never fails over from one to another; keep one of them in the pool.`;
|
|
17145
|
+
}
|
|
17146
|
+
|
|
17147
|
+
// src/doctorReport.ts
|
|
17084
17148
|
init_extends();
|
|
17085
17149
|
var DOCTOR_SEVERITIES = ["pass", "warn", "fail"];
|
|
17086
17150
|
var DOCTOR_SECTIONS = [
|
|
@@ -17103,10 +17167,6 @@ var DOCTOR_SECTIONS = [
|
|
|
17103
17167
|
"frontdoor",
|
|
17104
17168
|
"models"
|
|
17105
17169
|
];
|
|
17106
|
-
function joinNames(names) {
|
|
17107
|
-
const last = names.at(-1);
|
|
17108
|
-
return names.length < 2 || last === void 0 ? names.join("") : `${names.slice(0, -1).join(", ")} and ${last}`;
|
|
17109
|
-
}
|
|
17110
17170
|
function refinePathShadow(status, ownExecutablePath, realpath) {
|
|
17111
17171
|
if (status.status !== "shadowed") {
|
|
17112
17172
|
return status;
|
|
@@ -17419,6 +17479,7 @@ function runDoctor(params) {
|
|
|
17419
17479
|
}
|
|
17420
17480
|
const validatedGlobalConfig = params.globalConfig.raw === void 0 ? void 0 : validateJson(GlobalConfigSchema, params.globalConfig);
|
|
17421
17481
|
const pools = validatedGlobalConfig?.ok === true ? validatedGlobalConfig.data.pools ?? {} : {};
|
|
17482
|
+
const accountByIdentity = new Map(params.identities.flatMap((entry) => validIdentityNames.has(entry.name) && entry.account !== void 0 ? [[entry.name, entry.account]] : []));
|
|
17422
17483
|
for (const [poolName, pool] of Object.entries(pools)) {
|
|
17423
17484
|
const missing = pool.identities.filter((member) => poolNameOf(poolMemberIdentity(member)) === void 0 && !validIdentityNames.has(poolMemberIdentity(member)));
|
|
17424
17485
|
const undefinedPools = pool.identities.flatMap((member) => {
|
|
@@ -17434,6 +17495,9 @@ function runDoctor(params) {
|
|
|
17434
17495
|
];
|
|
17435
17496
|
push("pool", "fail", `Pool "${poolName}" names ${problems.join(" and ")}.`, poolName);
|
|
17436
17497
|
}
|
|
17498
|
+
for (const shared of sharedLoginMembers(pool.identities.map(poolMemberIdentity), (identityName) => accountByIdentity.get(identityName))) {
|
|
17499
|
+
push("pool", "warn", describeSharedLoginMembers(poolName, shared), poolName);
|
|
17500
|
+
}
|
|
17437
17501
|
}
|
|
17438
17502
|
const reportedCycles = /* @__PURE__ */ new Set();
|
|
17439
17503
|
for (const poolName of Object.keys(pools).sort()) {
|
package/dist/types/index.d.ts
CHANGED
|
@@ -26336,6 +26336,8 @@ interface PoolMember {
|
|
|
26336
26336
|
readonly records: readonly UsageRecord[];
|
|
26337
26337
|
/** Present when this member stands for a nested `pool:<name>` entry rather than a direct identity. */
|
|
26338
26338
|
readonly nested?: NestedContribution;
|
|
26339
|
+
/** The member that represents this member's login in the ranking, when both hold the same login and so draw on one quota window. This member is then ineligible as a candidate of its own, since ranking it beside its representative would count one window twice and could fail over to a login that is limited too. */
|
|
26340
|
+
readonly sameLoginAs?: string;
|
|
26339
26341
|
/** The member entry's policy condition, from the object form of a pool member: definite false skips the member as ineligible by policy, indeterminate demotes it to last within its class, naming the missing fact either way. */
|
|
26340
26342
|
readonly policy?: WhenCondition;
|
|
26341
26343
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agent-shim",
|
|
3
|
-
"version": "11.
|
|
3
|
+
"version": "11.80.0",
|
|
4
4
|
"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.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Joseph Mearman <joseph@mearman.co.uk>",
|