agent-shim 11.77.0 → 11.79.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 +281 -14
- package/dist/index.cjs +81 -4
- package/dist/index.mjs +81 -4
- package/dist/types/index.d.ts +178 -174
- 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).
|
|
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).
|
|
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
|
|
|
@@ -200,6 +200,7 @@ agent-shim run [@<identity>] [launch flags] [claude arguments]
|
|
|
200
200
|
# --claude-version <version> run exactly this installed Claude Code version
|
|
201
201
|
# --delay <duration> wait this long after the launcher's own output before starting claude; --[no-]pause waits for a key press instead
|
|
202
202
|
# --[no-]explain with @pool:<name>, list every member the pick ranked and why, not only the one picked
|
|
203
|
+
# --[no-]pick on a terminal, ask which identity to run as, even when one resolved (--no-pick never asks); a launch also asks by itself when no identity resolves, a pool pick would change account or organisation, or the identity is refused right now
|
|
203
204
|
# --native run the real claude with nothing from agent-shim applied; cannot be combined with the flags above
|
|
204
205
|
claude @<identity> ... # the same, once `agent-shim shim enable` has run
|
|
205
206
|
```
|
package/dist/cli.cjs
CHANGED
|
@@ -38198,7 +38198,7 @@ var init_package = __esm({
|
|
|
38198
38198
|
"package.json"() {
|
|
38199
38199
|
package_default = {
|
|
38200
38200
|
name: "agent-shim",
|
|
38201
|
-
version: "11.
|
|
38201
|
+
version: "11.79.0",
|
|
38202
38202
|
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
38203
|
license: "MIT",
|
|
38204
38204
|
author: "Joseph Mearman <joseph@mearman.co.uk>",
|
|
@@ -67175,7 +67175,8 @@ var init_argv = __esm({
|
|
|
67175
67175
|
{ flag: "--remote-control", key: "remoteControl" },
|
|
67176
67176
|
{ flag: "--wait", key: "wait" },
|
|
67177
67177
|
{ flag: "--pause", key: "pause" },
|
|
67178
|
-
{ flag: "--explain", key: "explain" }
|
|
67178
|
+
{ flag: "--explain", key: "explain" },
|
|
67179
|
+
{ flag: "--pick", key: "pick" }
|
|
67179
67180
|
];
|
|
67180
67181
|
LAUNCHER_FLAG_NAMES = [
|
|
67181
67182
|
...VALUED_FLAGS,
|
|
@@ -69956,7 +69957,7 @@ function decideLaunch(params, readOnly) {
|
|
|
69956
69957
|
const configDirEscapeHatchApplies = env.CLAUDE_CONFIG_DIR !== void 0 && env.CLAUDE_CONFIG_DIR !== "";
|
|
69957
69958
|
const decidedIdentity = decideIdentity({
|
|
69958
69959
|
env,
|
|
69959
|
-
argv0Identity: parsedArgv.identity,
|
|
69960
|
+
argv0Identity: params.pickedIdentity ?? parsedArgv.identity,
|
|
69960
69961
|
directoryPinnedIdentity: params.directoryPinnedIdentity,
|
|
69961
69962
|
readActiveIdentityFile: () => {
|
|
69962
69963
|
const raw = fs31.readFileUtf8(paths.activeIdentityFile);
|
|
@@ -117743,7 +117744,7 @@ function summariseIdentityAccount(account) {
|
|
|
117743
117744
|
function loginKeyOf(account) {
|
|
117744
117745
|
return account.accountUuid === void 0 ? void 0 : JSON.stringify([account.accountUuid, account.organizationUuid ?? null]);
|
|
117745
117746
|
}
|
|
117746
|
-
function
|
|
117747
|
+
function collectByLogin(items, loginOf) {
|
|
117747
117748
|
const groups = /* @__PURE__ */ new Map();
|
|
117748
117749
|
for (const item of items) {
|
|
117749
117750
|
const key = loginOf(item) ?? /* @__PURE__ */ Symbol("no login");
|
|
@@ -117754,7 +117755,13 @@ function groupByLogin(items, loginOf) {
|
|
|
117754
117755
|
group.push(item);
|
|
117755
117756
|
}
|
|
117756
117757
|
}
|
|
117757
|
-
return [...groups.values()]
|
|
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);
|
|
117758
117765
|
}
|
|
117759
117766
|
function describeAccountHolder(summary) {
|
|
117760
117767
|
const organisation = describeAccountOrganisation(summary);
|
|
@@ -123523,6 +123530,10 @@ var DOCTOR_SECTIONS = [
|
|
|
123523
123530
|
"frontdoor",
|
|
123524
123531
|
"models"
|
|
123525
123532
|
];
|
|
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
|
+
}
|
|
123526
123537
|
function refinePathShadow(status, ownExecutablePath, realpath) {
|
|
123527
123538
|
if (status.status !== "shadowed") {
|
|
123528
123539
|
return status;
|
|
@@ -123770,6 +123781,7 @@ function runDoctor(params) {
|
|
|
123770
123781
|
const validProfileNames = new Set(profileSources.keys());
|
|
123771
123782
|
const validProviderNames = /* @__PURE__ */ new Set([...params.providers.map((entry) => entry.name), ...Object.keys(params.providerAliases ?? {})]);
|
|
123772
123783
|
const validIdentityNames = /* @__PURE__ */ new Set();
|
|
123784
|
+
const signedInAccounts = [];
|
|
123773
123785
|
for (const entry of params.identities) {
|
|
123774
123786
|
const validated2 = validate3(IdentitySchema, entry, "identity", entry.name);
|
|
123775
123787
|
if (!validated2.ok) {
|
|
@@ -123819,6 +123831,18 @@ function runDoctor(params) {
|
|
|
123819
123831
|
signIn.state === "signed-out" ? `${entry.name} is signed out (${signIn.detail}). Run \`agent-shim run @${entry.name}\` and sign in.` : `${entry.name} ${standing} (${signIn.detail}).`,
|
|
123820
123832
|
entry.name
|
|
123821
123833
|
);
|
|
123834
|
+
if (signIn.state === "signed-in" && entry.account !== void 0) {
|
|
123835
|
+
signedInAccounts.push({ name: entry.name, account: entry.account });
|
|
123836
|
+
}
|
|
123837
|
+
}
|
|
123838
|
+
for (const group of groupSharedLogins(signedInAccounts, (entry) => loginKeyOf(entry.account))) {
|
|
123839
|
+
const names = group.map((entry) => entry.name);
|
|
123840
|
+
const holder = group.map((entry) => summariseIdentityAccount(entry.account)).map((summary) => summary === void 0 ? void 0 : describeAccountHolder(summary)).find((described) => described !== void 0);
|
|
123841
|
+
push(
|
|
123842
|
+
"sign-in",
|
|
123843
|
+
"warn",
|
|
123844
|
+
`Identities ${joinNames(names)} hold the same login${holder === void 0 ? "" : ` (${holder})`}, so they share one quota window and all but one are redundant. Remove the redundant ones with \`agent-shim identity remove <name>\`.`
|
|
123845
|
+
);
|
|
123822
123846
|
}
|
|
123823
123847
|
const validatedGlobalConfig = params.globalConfig.raw === void 0 ? void 0 : validateJson(GlobalConfigSchema, params.globalConfig);
|
|
123824
123848
|
const pools = validatedGlobalConfig?.ok === true ? validatedGlobalConfig.data.pools ?? {} : {};
|
|
@@ -124107,7 +124131,7 @@ function collectDoctorReport(params) {
|
|
|
124107
124131
|
const identities = identityNames.map((name) => {
|
|
124108
124132
|
const farmRoot = import_node_path47.default.join(paths.identitiesDir, name);
|
|
124109
124133
|
const identityPath = import_node_path47.default.join(farmRoot, "identity.json");
|
|
124110
|
-
return { name, path: identityPath, raw: realFsPort.readFileUtf8(identityPath), farmRoot, credentialsFilePresent: import_node_fs20.default.existsSync(credentialsFilePath(farmRoot)) };
|
|
124134
|
+
return { name, path: identityPath, raw: realFsPort.readFileUtf8(identityPath), farmRoot, credentialsFilePresent: import_node_fs20.default.existsSync(credentialsFilePath(farmRoot)), account: readIdentityAccount(realFsPort, paths.identitiesDir, name)?.account };
|
|
124111
124135
|
});
|
|
124112
124136
|
const profileNames = import_node_fs20.default.existsSync(paths.configProfilesDir) ? import_node_fs20.default.readdirSync(paths.configProfilesDir, { withFileTypes: true }).filter((entry) => entry.isFile() && entry.name.endsWith(".json")).map((entry) => entry.name.slice(0, -".json".length)).sort() : [];
|
|
124113
124137
|
const configProfiles = profileNames.map((name) => {
|
|
@@ -157797,6 +157821,241 @@ function buildProgram(deps) {
|
|
|
157797
157821
|
// src/runClaude.ts
|
|
157798
157822
|
init_cliError();
|
|
157799
157823
|
init_configProfilesStore();
|
|
157824
|
+
|
|
157825
|
+
// src/launcher/pickerPrompt.ts
|
|
157826
|
+
function promptsIdentityPicker(prompts) {
|
|
157827
|
+
return {
|
|
157828
|
+
pick: async (request7) => {
|
|
157829
|
+
const answer = await prompts.select({
|
|
157830
|
+
message: request7.message,
|
|
157831
|
+
options: request7.entries.map((entry) => ({ value: entry.value, label: entry.label })),
|
|
157832
|
+
...request7.initial === void 0 ? {} : { initialValue: request7.initial }
|
|
157833
|
+
});
|
|
157834
|
+
return prompts.isCancel(answer) ? { kind: "cancelled" } : { kind: "picked", value: answer };
|
|
157835
|
+
}
|
|
157836
|
+
};
|
|
157837
|
+
}
|
|
157838
|
+
|
|
157839
|
+
// src/launcher/runPicker.ts
|
|
157840
|
+
init_cliError();
|
|
157841
|
+
init_schema();
|
|
157842
|
+
init_account();
|
|
157843
|
+
init_candidateText();
|
|
157844
|
+
init_pick();
|
|
157845
|
+
init_poolPick();
|
|
157846
|
+
init_identity();
|
|
157847
|
+
init_launchReport();
|
|
157848
|
+
init_hold();
|
|
157849
|
+
|
|
157850
|
+
// src/launcher/pickerEntries.ts
|
|
157851
|
+
var PART_SEPARATOR = " | ";
|
|
157852
|
+
function pickerLabel(facts) {
|
|
157853
|
+
const name = [facts.rank === void 0 ? void 0 : `${String(facts.rank)}.`, facts.identity, facts.heading, facts.picked === true ? "(picked)" : void 0].filter((part) => part !== void 0).join(" ");
|
|
157854
|
+
return [name, facts.detail, facts.account, facts.quota].filter((part) => part !== void 0).join(PART_SEPARATOR);
|
|
157855
|
+
}
|
|
157856
|
+
|
|
157857
|
+
// src/launcher/pickerDecision.ts
|
|
157858
|
+
init_claudeSubcommand();
|
|
157859
|
+
function decidePicker(facts) {
|
|
157860
|
+
if (!facts.interactive || facts.configDirEscapeHatch || facts.pick === false) {
|
|
157861
|
+
return void 0;
|
|
157862
|
+
}
|
|
157863
|
+
if (facts.pick === true) {
|
|
157864
|
+
return "requested";
|
|
157865
|
+
}
|
|
157866
|
+
if (facts.unattended) {
|
|
157867
|
+
return void 0;
|
|
157868
|
+
}
|
|
157869
|
+
const { selection } = facts;
|
|
157870
|
+
switch (selection.kind) {
|
|
157871
|
+
case "none":
|
|
157872
|
+
return "no-identity";
|
|
157873
|
+
case "identity":
|
|
157874
|
+
return selection.limited ? "no-eligible-identity" : void 0;
|
|
157875
|
+
case "pool":
|
|
157876
|
+
if (selection.outcome === "none-eligible") {
|
|
157877
|
+
return facts.waiting ? void 0 : "no-eligible-identity";
|
|
157878
|
+
}
|
|
157879
|
+
return selection.outcome === "changes-account" ? "account-change" : void 0;
|
|
157880
|
+
default:
|
|
157881
|
+
return selection;
|
|
157882
|
+
}
|
|
157883
|
+
}
|
|
157884
|
+
var TERMINATOR4 = "--";
|
|
157885
|
+
var UNATTENDED_FLAGS = /* @__PURE__ */ new Set(["-p", "--print", "--bg"]);
|
|
157886
|
+
function isUnattendedLaunch(passthrough) {
|
|
157887
|
+
const end = passthrough.indexOf(TERMINATOR4);
|
|
157888
|
+
const head = end === -1 ? passthrough : passthrough.slice(0, end);
|
|
157889
|
+
return head.some((token) => UNATTENDED_FLAGS.has(token)) || isClaudeSubcommand(passthrough);
|
|
157890
|
+
}
|
|
157891
|
+
|
|
157892
|
+
// src/launcher/runPicker.ts
|
|
157893
|
+
init_pool();
|
|
157894
|
+
var IdentityPickerCancelledError = class extends CliError {
|
|
157895
|
+
exitCode = LAUNCH_CANCELLED_EXIT;
|
|
157896
|
+
constructor() {
|
|
157897
|
+
super("launch cancelled at the identity picker: no identity was chosen.");
|
|
157898
|
+
this.name = "IdentityPickerCancelledError";
|
|
157899
|
+
}
|
|
157900
|
+
};
|
|
157901
|
+
function memberTexts(member, nowMs) {
|
|
157902
|
+
if (member === void 0) {
|
|
157903
|
+
return {};
|
|
157904
|
+
}
|
|
157905
|
+
const billing = { login: member.account, snapshot: member.snapshot, provider: void 0, nowMs };
|
|
157906
|
+
const account = accountRows(billing)[0]?.value;
|
|
157907
|
+
const quotaRow2 = quotaRows(billing)[0];
|
|
157908
|
+
return {
|
|
157909
|
+
...account === void 0 ? {} : { account },
|
|
157910
|
+
...quotaRow2 === void 0 ? {} : { quota: quotaRow2.detail === void 0 ? quotaRow2.value : `${quotaRow2.value} (${quotaRow2.detail})` }
|
|
157911
|
+
};
|
|
157912
|
+
}
|
|
157913
|
+
function refusalOf(candidate) {
|
|
157914
|
+
return candidate.class === "ineligible" ? candidate.reasons[0] : void 0;
|
|
157915
|
+
}
|
|
157916
|
+
function accountsDiffer(members2, left, right) {
|
|
157917
|
+
const keyOf3 = (identity) => {
|
|
157918
|
+
const account = members2.find((member) => member.identity === identity)?.account;
|
|
157919
|
+
return account === void 0 ? void 0 : loginKeyOf(account);
|
|
157920
|
+
};
|
|
157921
|
+
const leftKey = keyOf3(left);
|
|
157922
|
+
const rightKey = keyOf3(right);
|
|
157923
|
+
return leftKey !== void 0 && rightKey !== void 0 && leftKey !== rightKey;
|
|
157924
|
+
}
|
|
157925
|
+
function poolContext(params, poolName, resuming, nowMs) {
|
|
157926
|
+
const { paths, usageFs } = params;
|
|
157927
|
+
const { sticky } = readStickyPick(usageFs, paths.usagePicksFile, params.cwd);
|
|
157928
|
+
const { ranking } = rankPoolGraph({
|
|
157929
|
+
fs: usageFs,
|
|
157930
|
+
paths,
|
|
157931
|
+
pools: params.pools ?? {},
|
|
157932
|
+
poolName,
|
|
157933
|
+
nowMs,
|
|
157934
|
+
resuming,
|
|
157935
|
+
identityExists: (name) => loadIdentity(paths.identitiesDir, name, params.fs) !== void 0,
|
|
157936
|
+
...sticky === void 0 ? {} : { sticky }
|
|
157937
|
+
});
|
|
157938
|
+
const pick2 = ranking.pick?.identity;
|
|
157939
|
+
const named = [.../* @__PURE__ */ new Set([...ranking.candidates.map((candidate) => candidate.identity), ...sticky === void 0 ? [] : [sticky.identity]])].filter(isIdentityName);
|
|
157940
|
+
const members2 = loadPoolMembers(usageFs, paths, named, nowMs);
|
|
157941
|
+
const changes = pick2 !== void 0 && sticky !== void 0 && sticky.identity !== pick2 && accountsDiffer(members2, sticky.identity, pick2);
|
|
157942
|
+
return {
|
|
157943
|
+
selection: { kind: "pool", outcome: pick2 === void 0 ? "none-eligible" : changes ? "changes-account" : "keeps-account" },
|
|
157944
|
+
entries: ranking.candidates.map((candidate, index) => ({
|
|
157945
|
+
value: candidate.identity,
|
|
157946
|
+
label: pickerLabel({
|
|
157947
|
+
identity: candidate.identity,
|
|
157948
|
+
rank: index + 1,
|
|
157949
|
+
heading: candidateHeading(candidate),
|
|
157950
|
+
picked: candidate.identity === pick2,
|
|
157951
|
+
detail: refusalOf(candidate),
|
|
157952
|
+
...memberTexts(members2.find((member) => member.identity === candidate.identity), nowMs)
|
|
157953
|
+
})
|
|
157954
|
+
})),
|
|
157955
|
+
initial: pick2,
|
|
157956
|
+
poolPick: pick2,
|
|
157957
|
+
message: (reason) => poolMessage(reason, poolName, pick2, sticky)
|
|
157958
|
+
};
|
|
157959
|
+
}
|
|
157960
|
+
function poolMessage(reason, poolName, pick2, sticky) {
|
|
157961
|
+
switch (reason) {
|
|
157962
|
+
case "account-change":
|
|
157963
|
+
return `Pool "${poolName}" would run this launch as ${pick2 ?? "(none)"}, a different account from ${sticky?.identity ?? "(none)"}, which this directory last ran as. Which identity should it run as?`;
|
|
157964
|
+
case "no-eligible-identity":
|
|
157965
|
+
return `Every member of pool "${poolName}" is refused right now. Which identity should this launch run as?`;
|
|
157966
|
+
case "requested":
|
|
157967
|
+
case "no-identity":
|
|
157968
|
+
return `Pool "${poolName}" is selected for this launch. Which identity should it run as?`;
|
|
157969
|
+
default:
|
|
157970
|
+
return reason;
|
|
157971
|
+
}
|
|
157972
|
+
}
|
|
157973
|
+
function identityContext(params, resuming, nowMs) {
|
|
157974
|
+
const { paths, usageFs } = params;
|
|
157975
|
+
const members2 = loadPoolMembers(usageFs, paths, params.identityNames(), nowMs);
|
|
157976
|
+
const { candidates } = rankPool({ members: members2, nowMs, resuming, preference: "listed" });
|
|
157977
|
+
const named = params.decision.name;
|
|
157978
|
+
const limited = named !== void 0 && candidates.some((candidate) => candidate.identity === named && candidate.class === "ineligible");
|
|
157979
|
+
const identityEntries = candidates.map((candidate) => ({
|
|
157980
|
+
value: candidate.identity,
|
|
157981
|
+
label: pickerLabel({ identity: candidate.identity, detail: refusalOf(candidate), ...memberTexts(members2.find((member) => member.identity === candidate.identity), nowMs) })
|
|
157982
|
+
}));
|
|
157983
|
+
const poolEntries = Object.entries(params.pools ?? {}).map(([name, pool]) => ({
|
|
157984
|
+
value: `pool:${name}`,
|
|
157985
|
+
label: pickerLabel({ identity: `pool:${name}`, detail: `members ${pool.identities.map(poolMemberIdentity).join(", ")}` })
|
|
157986
|
+
}));
|
|
157987
|
+
return {
|
|
157988
|
+
selection: named === void 0 ? { kind: "none" } : { kind: "identity", limited },
|
|
157989
|
+
entries: [...identityEntries, ...poolEntries],
|
|
157990
|
+
initial: named,
|
|
157991
|
+
poolPick: void 0,
|
|
157992
|
+
message: (reason) => {
|
|
157993
|
+
switch (reason) {
|
|
157994
|
+
case "no-identity":
|
|
157995
|
+
return "No identity is selected for this launch. Which identity should it run as?";
|
|
157996
|
+
case "no-eligible-identity":
|
|
157997
|
+
return `${named ?? "The selected identity"} is refused right now. Which identity should this launch run as?`;
|
|
157998
|
+
case "requested":
|
|
157999
|
+
case "account-change":
|
|
158000
|
+
return "Which identity should this launch run as?";
|
|
158001
|
+
default:
|
|
158002
|
+
return reason;
|
|
158003
|
+
}
|
|
158004
|
+
}
|
|
158005
|
+
};
|
|
158006
|
+
}
|
|
158007
|
+
async function runIdentityPicker(params) {
|
|
158008
|
+
if (!params.interactive) {
|
|
158009
|
+
return { kind: "unchanged" };
|
|
158010
|
+
}
|
|
158011
|
+
const nowMs = params.now();
|
|
158012
|
+
const resuming = isResuming(params.parsed.rest);
|
|
158013
|
+
const context = params.decision.pool === void 0 ? identityContext(params, resuming, nowMs) : poolContext(params, params.decision.pool, resuming, nowMs);
|
|
158014
|
+
const reason = decidePicker({
|
|
158015
|
+
interactive: params.interactive,
|
|
158016
|
+
unattended: isUnattendedLaunch(params.parsed.rest),
|
|
158017
|
+
pick: params.parsed.pick,
|
|
158018
|
+
configDirEscapeHatch: params.decision.configDirEscapeHatch,
|
|
158019
|
+
waiting: params.parsed.wait === true,
|
|
158020
|
+
selection: context.selection
|
|
158021
|
+
});
|
|
158022
|
+
if (reason === void 0) {
|
|
158023
|
+
return { kind: "unchanged" };
|
|
158024
|
+
}
|
|
158025
|
+
const request7 = { message: context.message(reason), entries: context.entries, ...context.initial === void 0 ? {} : { initial: context.initial } };
|
|
158026
|
+
const answer = await params.picker.pick(request7);
|
|
158027
|
+
if (answer.kind === "cancelled") {
|
|
158028
|
+
return { kind: "cancelled" };
|
|
158029
|
+
}
|
|
158030
|
+
const chosen = answer.value;
|
|
158031
|
+
if (chosen === (params.decision.pool === void 0 ? params.decision.name : context.poolPick)) {
|
|
158032
|
+
return { kind: "unchanged" };
|
|
158033
|
+
}
|
|
158034
|
+
if (params.decision.pool !== void 0 && poolNameOf(chosen) === void 0) {
|
|
158035
|
+
recordStickyPick(params.usageFs, params.paths.usagePicksFile, params.cwd, chosen, nowMs);
|
|
158036
|
+
}
|
|
158037
|
+
return { kind: "selected", selector: chosen };
|
|
158038
|
+
}
|
|
158039
|
+
|
|
158040
|
+
// src/launchPicker.ts
|
|
158041
|
+
init_realPorts();
|
|
158042
|
+
async function pickLaunchIdentity(params) {
|
|
158043
|
+
return await runIdentityPicker({
|
|
158044
|
+
parsed: params.parsed,
|
|
158045
|
+
decision: params.decision,
|
|
158046
|
+
interactive: process.stdin.isTTY && process.stdout.isTTY,
|
|
158047
|
+
paths: params.paths,
|
|
158048
|
+
fs: realFsPort,
|
|
158049
|
+
usageFs: params.farm.runtime.fs,
|
|
158050
|
+
pools: params.farm.pools,
|
|
158051
|
+
cwd: params.farm.runtime.cwd,
|
|
158052
|
+
now: params.farm.runtime.now,
|
|
158053
|
+
identityNames: () => listIdentities(params.paths).flatMap((listing) => "problem" in listing ? [] : [listing.name]),
|
|
158054
|
+
picker: promptsIdentityPicker(realPromptsPort)
|
|
158055
|
+
});
|
|
158056
|
+
}
|
|
158057
|
+
|
|
158058
|
+
// src/runClaude.ts
|
|
157800
158059
|
init_launchWiring();
|
|
157801
158060
|
init_paths();
|
|
157802
158061
|
|
|
@@ -158566,6 +158825,7 @@ function otherLaunchFlags(parsed) {
|
|
|
158566
158825
|
...parsed.skipPermissions === void 0 ? [] : ["--[no-]skip-permissions"],
|
|
158567
158826
|
...parsed.remoteControl === void 0 ? [] : ["--[no-]remote-control"],
|
|
158568
158827
|
...parsed.wait === void 0 ? [] : ["--[no-]wait"],
|
|
158828
|
+
...parsed.pick === void 0 ? [] : ["--[no-]pick"],
|
|
158569
158829
|
...parsed.categoryFlags.length === 0 ? [] : ["--category"],
|
|
158570
158830
|
...parsed.shareFlags.length === 0 ? [] : ["--share"],
|
|
158571
158831
|
...parsed.hideFlags.length === 0 ? [] : ["--hide"]
|
|
@@ -158631,13 +158891,19 @@ async function runClaude(argvOverride) {
|
|
|
158631
158891
|
}
|
|
158632
158892
|
}
|
|
158633
158893
|
}
|
|
158634
|
-
|
|
158635
|
-
paths,
|
|
158636
|
-
|
|
158637
|
-
|
|
158638
|
-
|
|
158639
|
-
|
|
158640
|
-
|
|
158894
|
+
const refreshUsage = async (poolName2) => {
|
|
158895
|
+
await refreshPools({ paths, cwd: process.cwd(), poolNames: poolName2 === void 0 ? [] : [poolName2], spawnDaemon: spawnDetachedSupervisor, log: realLogPort.warn });
|
|
158896
|
+
};
|
|
158897
|
+
await refreshUsage(identityDecision.pool);
|
|
158898
|
+
const picked = await pickLaunchIdentity({ paths, farm, parsed: nativeArgv, decision: identityDecision });
|
|
158899
|
+
if (picked.kind === "cancelled") {
|
|
158900
|
+
throw new IdentityPickerCancelledError();
|
|
158901
|
+
}
|
|
158902
|
+
const pickedIdentity = picked.kind === "selected" ? picked.selector : void 0;
|
|
158903
|
+
const launchDecision = pickedIdentity === void 0 ? identityDecision : decideIdentity({ env: procForDecision.env, argv0Identity: pickedIdentity, readActiveIdentityFile: () => void 0 });
|
|
158904
|
+
if (launchDecision.pool !== identityDecision.pool) {
|
|
158905
|
+
await refreshUsage(launchDecision.pool);
|
|
158906
|
+
}
|
|
158641
158907
|
const prepareParams = {
|
|
158642
158908
|
...realPrepareLaunchParams(paths, {
|
|
158643
158909
|
proc: argvOverride === void 0 ? realProcPort : { ...realProcPort, argv: argvOverride },
|
|
@@ -158646,10 +158912,11 @@ async function runClaude(argvOverride) {
|
|
|
158646
158912
|
farm,
|
|
158647
158913
|
allowMissingConfigProfile
|
|
158648
158914
|
}),
|
|
158915
|
+
...pickedIdentity === void 0 ? {} : { pickedIdentity },
|
|
158649
158916
|
// Wired here rather than in realPrepareLaunchParams because the port re-invokes this very binary: correct for the agent-shim command line, wrong for a library host whose own executable is not agent-shim.
|
|
158650
158917
|
update: realLaunchUpdatePort(paths)
|
|
158651
158918
|
};
|
|
158652
|
-
const poolName =
|
|
158919
|
+
const poolName = launchDecision.pool;
|
|
158653
158920
|
if (poolName !== void 0 && farm.pools !== void 0 && supervisesLaunch(farm.pools[poolName], nativeArgv.rest)) {
|
|
158654
158921
|
const code = await runSupervised({
|
|
158655
158922
|
paths,
|
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.79.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>",
|
|
@@ -10726,7 +10726,8 @@ var init_argv = __esm({
|
|
|
10726
10726
|
{ flag: "--remote-control", key: "remoteControl" },
|
|
10727
10727
|
{ flag: "--wait", key: "wait" },
|
|
10728
10728
|
{ flag: "--pause", key: "pause" },
|
|
10729
|
-
{ flag: "--explain", key: "explain" }
|
|
10729
|
+
{ flag: "--explain", key: "explain" },
|
|
10730
|
+
{ flag: "--pick", key: "pick" }
|
|
10730
10731
|
];
|
|
10731
10732
|
LAUNCHER_FLAG_NAMES = [
|
|
10732
10733
|
...VALUED_FLAGS,
|
|
@@ -11812,7 +11813,7 @@ function decideLaunch(params, readOnly) {
|
|
|
11812
11813
|
const configDirEscapeHatchApplies = env.CLAUDE_CONFIG_DIR !== void 0 && env.CLAUDE_CONFIG_DIR !== "";
|
|
11813
11814
|
const decidedIdentity = decideIdentity({
|
|
11814
11815
|
env,
|
|
11815
|
-
argv0Identity: parsedArgv.identity,
|
|
11816
|
+
argv0Identity: params.pickedIdentity ?? parsedArgv.identity,
|
|
11816
11817
|
directoryPinnedIdentity: params.directoryPinnedIdentity,
|
|
11817
11818
|
readActiveIdentityFile: () => {
|
|
11818
11819
|
const raw = fs14.readFileUtf8(paths.activeIdentityFile);
|
|
@@ -17084,6 +17085,65 @@ var import_node_fs10 = __toESM(require("node:fs"), 1);
|
|
|
17084
17085
|
var import_node_path29 = __toESM(require("node:path"), 1);
|
|
17085
17086
|
init_signIn();
|
|
17086
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
|
+
}
|
|
17146
|
+
|
|
17087
17147
|
// src/codex/siwcStore.ts
|
|
17088
17148
|
var import_zod26 = require("zod");
|
|
17089
17149
|
|
|
@@ -17458,6 +17518,10 @@ var DOCTOR_SECTIONS = [
|
|
|
17458
17518
|
"frontdoor",
|
|
17459
17519
|
"models"
|
|
17460
17520
|
];
|
|
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
|
+
}
|
|
17461
17525
|
function refinePathShadow(status, ownExecutablePath, realpath) {
|
|
17462
17526
|
if (status.status !== "shadowed") {
|
|
17463
17527
|
return status;
|
|
@@ -17705,6 +17769,7 @@ function runDoctor(params) {
|
|
|
17705
17769
|
const validProfileNames = new Set(profileSources.keys());
|
|
17706
17770
|
const validProviderNames = /* @__PURE__ */ new Set([...params.providers.map((entry) => entry.name), ...Object.keys(params.providerAliases ?? {})]);
|
|
17707
17771
|
const validIdentityNames = /* @__PURE__ */ new Set();
|
|
17772
|
+
const signedInAccounts = [];
|
|
17708
17773
|
for (const entry of params.identities) {
|
|
17709
17774
|
const validated3 = validate(IdentitySchema, entry, "identity", entry.name);
|
|
17710
17775
|
if (!validated3.ok) {
|
|
@@ -17754,6 +17819,18 @@ function runDoctor(params) {
|
|
|
17754
17819
|
signIn.state === "signed-out" ? `${entry.name} is signed out (${signIn.detail}). Run \`agent-shim run @${entry.name}\` and sign in.` : `${entry.name} ${standing} (${signIn.detail}).`,
|
|
17755
17820
|
entry.name
|
|
17756
17821
|
);
|
|
17822
|
+
if (signIn.state === "signed-in" && entry.account !== void 0) {
|
|
17823
|
+
signedInAccounts.push({ name: entry.name, account: entry.account });
|
|
17824
|
+
}
|
|
17825
|
+
}
|
|
17826
|
+
for (const group of groupSharedLogins(signedInAccounts, (entry) => loginKeyOf(entry.account))) {
|
|
17827
|
+
const names = group.map((entry) => entry.name);
|
|
17828
|
+
const holder = group.map((entry) => summariseIdentityAccount(entry.account)).map((summary) => summary === void 0 ? void 0 : describeAccountHolder(summary)).find((described) => described !== void 0);
|
|
17829
|
+
push(
|
|
17830
|
+
"sign-in",
|
|
17831
|
+
"warn",
|
|
17832
|
+
`Identities ${joinNames(names)} hold the same login${holder === void 0 ? "" : ` (${holder})`}, so they share one quota window and all but one are redundant. Remove the redundant ones with \`agent-shim identity remove <name>\`.`
|
|
17833
|
+
);
|
|
17757
17834
|
}
|
|
17758
17835
|
const validatedGlobalConfig = params.globalConfig.raw === void 0 ? void 0 : validateJson(GlobalConfigSchema, params.globalConfig);
|
|
17759
17836
|
const pools = validatedGlobalConfig?.ok === true ? validatedGlobalConfig.data.pools ?? {} : {};
|
|
@@ -18042,7 +18119,7 @@ function collectDoctorReport(params) {
|
|
|
18042
18119
|
const identities = identityNames.map((name) => {
|
|
18043
18120
|
const farmRoot = import_node_path29.default.join(paths.identitiesDir, name);
|
|
18044
18121
|
const identityPath = import_node_path29.default.join(farmRoot, "identity.json");
|
|
18045
|
-
return { name, path: identityPath, raw: realFsPort.readFileUtf8(identityPath), farmRoot, credentialsFilePresent: import_node_fs10.default.existsSync(credentialsFilePath(farmRoot)) };
|
|
18122
|
+
return { name, path: identityPath, raw: realFsPort.readFileUtf8(identityPath), farmRoot, credentialsFilePresent: import_node_fs10.default.existsSync(credentialsFilePath(farmRoot)), account: readIdentityAccount(realFsPort, paths.identitiesDir, name)?.account };
|
|
18046
18123
|
});
|
|
18047
18124
|
const profileNames = import_node_fs10.default.existsSync(paths.configProfilesDir) ? import_node_fs10.default.readdirSync(paths.configProfilesDir, { withFileTypes: true }).filter((entry) => entry.isFile() && entry.name.endsWith(".json")).map((entry) => entry.name.slice(0, -".json".length)).sort() : [];
|
|
18048
18125
|
const configProfiles = profileNames.map((name) => {
|
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.79.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>",
|
|
@@ -10699,7 +10699,8 @@ var init_argv = __esm({
|
|
|
10699
10699
|
{ flag: "--remote-control", key: "remoteControl" },
|
|
10700
10700
|
{ flag: "--wait", key: "wait" },
|
|
10701
10701
|
{ flag: "--pause", key: "pause" },
|
|
10702
|
-
{ flag: "--explain", key: "explain" }
|
|
10702
|
+
{ flag: "--explain", key: "explain" },
|
|
10703
|
+
{ flag: "--pick", key: "pick" }
|
|
10703
10704
|
];
|
|
10704
10705
|
LAUNCHER_FLAG_NAMES = [
|
|
10705
10706
|
...VALUED_FLAGS,
|
|
@@ -11787,7 +11788,7 @@ function decideLaunch(params, readOnly) {
|
|
|
11787
11788
|
const configDirEscapeHatchApplies = env.CLAUDE_CONFIG_DIR !== void 0 && env.CLAUDE_CONFIG_DIR !== "";
|
|
11788
11789
|
const decidedIdentity = decideIdentity({
|
|
11789
11790
|
env,
|
|
11790
|
-
argv0Identity: parsedArgv.identity,
|
|
11791
|
+
argv0Identity: params.pickedIdentity ?? parsedArgv.identity,
|
|
11791
11792
|
directoryPinnedIdentity: params.directoryPinnedIdentity,
|
|
11792
11793
|
readActiveIdentityFile: () => {
|
|
11793
11794
|
const raw = fs14.readFileUtf8(paths.activeIdentityFile);
|
|
@@ -16669,6 +16670,65 @@ import fs11 from "node:fs";
|
|
|
16669
16670
|
import path29 from "node:path";
|
|
16670
16671
|
init_signIn();
|
|
16671
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
|
+
}
|
|
16731
|
+
|
|
16672
16732
|
// src/codex/siwcStore.ts
|
|
16673
16733
|
import { z as z26 } from "zod";
|
|
16674
16734
|
|
|
@@ -17043,6 +17103,10 @@ var DOCTOR_SECTIONS = [
|
|
|
17043
17103
|
"frontdoor",
|
|
17044
17104
|
"models"
|
|
17045
17105
|
];
|
|
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
|
+
}
|
|
17046
17110
|
function refinePathShadow(status, ownExecutablePath, realpath) {
|
|
17047
17111
|
if (status.status !== "shadowed") {
|
|
17048
17112
|
return status;
|
|
@@ -17290,6 +17354,7 @@ function runDoctor(params) {
|
|
|
17290
17354
|
const validProfileNames = new Set(profileSources.keys());
|
|
17291
17355
|
const validProviderNames = /* @__PURE__ */ new Set([...params.providers.map((entry) => entry.name), ...Object.keys(params.providerAliases ?? {})]);
|
|
17292
17356
|
const validIdentityNames = /* @__PURE__ */ new Set();
|
|
17357
|
+
const signedInAccounts = [];
|
|
17293
17358
|
for (const entry of params.identities) {
|
|
17294
17359
|
const validated3 = validate(IdentitySchema, entry, "identity", entry.name);
|
|
17295
17360
|
if (!validated3.ok) {
|
|
@@ -17339,6 +17404,18 @@ function runDoctor(params) {
|
|
|
17339
17404
|
signIn.state === "signed-out" ? `${entry.name} is signed out (${signIn.detail}). Run \`agent-shim run @${entry.name}\` and sign in.` : `${entry.name} ${standing} (${signIn.detail}).`,
|
|
17340
17405
|
entry.name
|
|
17341
17406
|
);
|
|
17407
|
+
if (signIn.state === "signed-in" && entry.account !== void 0) {
|
|
17408
|
+
signedInAccounts.push({ name: entry.name, account: entry.account });
|
|
17409
|
+
}
|
|
17410
|
+
}
|
|
17411
|
+
for (const group of groupSharedLogins(signedInAccounts, (entry) => loginKeyOf(entry.account))) {
|
|
17412
|
+
const names = group.map((entry) => entry.name);
|
|
17413
|
+
const holder = group.map((entry) => summariseIdentityAccount(entry.account)).map((summary) => summary === void 0 ? void 0 : describeAccountHolder(summary)).find((described) => described !== void 0);
|
|
17414
|
+
push(
|
|
17415
|
+
"sign-in",
|
|
17416
|
+
"warn",
|
|
17417
|
+
`Identities ${joinNames(names)} hold the same login${holder === void 0 ? "" : ` (${holder})`}, so they share one quota window and all but one are redundant. Remove the redundant ones with \`agent-shim identity remove <name>\`.`
|
|
17418
|
+
);
|
|
17342
17419
|
}
|
|
17343
17420
|
const validatedGlobalConfig = params.globalConfig.raw === void 0 ? void 0 : validateJson(GlobalConfigSchema, params.globalConfig);
|
|
17344
17421
|
const pools = validatedGlobalConfig?.ok === true ? validatedGlobalConfig.data.pools ?? {} : {};
|
|
@@ -17627,7 +17704,7 @@ function collectDoctorReport(params) {
|
|
|
17627
17704
|
const identities = identityNames.map((name) => {
|
|
17628
17705
|
const farmRoot = path29.join(paths.identitiesDir, name);
|
|
17629
17706
|
const identityPath = path29.join(farmRoot, "identity.json");
|
|
17630
|
-
return { name, path: identityPath, raw: realFsPort.readFileUtf8(identityPath), farmRoot, credentialsFilePresent: fs11.existsSync(credentialsFilePath(farmRoot)) };
|
|
17707
|
+
return { name, path: identityPath, raw: realFsPort.readFileUtf8(identityPath), farmRoot, credentialsFilePresent: fs11.existsSync(credentialsFilePath(farmRoot)), account: readIdentityAccount(realFsPort, paths.identitiesDir, name)?.account };
|
|
17631
17708
|
});
|
|
17632
17709
|
const profileNames = fs11.existsSync(paths.configProfilesDir) ? fs11.readdirSync(paths.configProfilesDir, { withFileTypes: true }).filter((entry) => entry.isFile() && entry.name.endsWith(".json")).map((entry) => entry.name.slice(0, -".json".length)).sort() : [];
|
|
17633
17710
|
const configProfiles = profileNames.map((name) => {
|
package/dist/types/index.d.ts
CHANGED
|
@@ -8876,6 +8876,180 @@ type PathShadowStatus = {
|
|
|
8876
8876
|
readonly by: string;
|
|
8877
8877
|
};
|
|
8878
8878
|
|
|
8879
|
+
/** One routed request, appended to the usage log when its response has finished. */
|
|
8880
|
+
declare const UsageRecordSchema: z.ZodObject<{
|
|
8881
|
+
schemaVersion: z.ZodLiteral<1>;
|
|
8882
|
+
at: z.ZodISODateTime;
|
|
8883
|
+
identity: z.ZodOptional<z.ZodString>;
|
|
8884
|
+
provider: z.ZodString;
|
|
8885
|
+
sessionId: z.ZodOptional<z.ZodString>;
|
|
8886
|
+
clientSessionId: z.ZodOptional<z.ZodString>;
|
|
8887
|
+
project: z.ZodOptional<z.ZodString>;
|
|
8888
|
+
viaHeadroom: z.ZodOptional<z.ZodBoolean>;
|
|
8889
|
+
route: z.ZodString;
|
|
8890
|
+
method: z.ZodString;
|
|
8891
|
+
endpoint: z.ZodString;
|
|
8892
|
+
model: z.ZodOptional<z.ZodString>;
|
|
8893
|
+
requestedModel: z.ZodOptional<z.ZodString>;
|
|
8894
|
+
candidateProviders: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
8895
|
+
status: z.ZodNumber;
|
|
8896
|
+
latencyMs: z.ZodNumber;
|
|
8897
|
+
durationMs: z.ZodNumber;
|
|
8898
|
+
outcome: z.ZodEnum<{
|
|
8899
|
+
completed: "completed";
|
|
8900
|
+
aborted: "aborted";
|
|
8901
|
+
}>;
|
|
8902
|
+
usage: z.ZodOptional<z.ZodObject<{
|
|
8903
|
+
inputTokens: z.ZodOptional<z.ZodNumber>;
|
|
8904
|
+
outputTokens: z.ZodOptional<z.ZodNumber>;
|
|
8905
|
+
cacheCreationInputTokens: z.ZodOptional<z.ZodNumber>;
|
|
8906
|
+
cacheReadInputTokens: z.ZodOptional<z.ZodNumber>;
|
|
8907
|
+
}, z.core.$strict>>;
|
|
8908
|
+
rateLimitHeaders: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
8909
|
+
limit: z.ZodOptional<z.ZodObject<{
|
|
8910
|
+
kind: z.ZodEnum<{
|
|
8911
|
+
"rate-limited": "rate-limited";
|
|
8912
|
+
"quota-exhausted": "quota-exhausted";
|
|
8913
|
+
}>;
|
|
8914
|
+
retryAfterSeconds: z.ZodOptional<z.ZodNumber>;
|
|
8915
|
+
resetAt: z.ZodOptional<z.ZodISODateTime>;
|
|
8916
|
+
window: z.ZodOptional<z.ZodString>;
|
|
8917
|
+
evidence: z.ZodArray<z.ZodString>;
|
|
8918
|
+
}, z.core.$strict>>;
|
|
8919
|
+
requestId: z.ZodOptional<z.ZodString>;
|
|
8920
|
+
}, z.core.$strict>;
|
|
8921
|
+
type UsageRecord = z.infer<typeof UsageRecordSchema>;
|
|
8922
|
+
/** One quota window from Anthropic's unified rate-limit headers. */
|
|
8923
|
+
declare const QuotaWindowSchema: z.ZodObject<{
|
|
8924
|
+
utilization: z.ZodOptional<z.ZodNumber>;
|
|
8925
|
+
resetsAt: z.ZodOptional<z.ZodISODateTime>;
|
|
8926
|
+
status: z.ZodOptional<z.ZodString>;
|
|
8927
|
+
graceUtilization: z.ZodOptional<z.ZodNumber>;
|
|
8928
|
+
}, z.core.$strict>;
|
|
8929
|
+
type QuotaWindow = z.infer<typeof QuotaWindowSchema>;
|
|
8930
|
+
/**
|
|
8931
|
+
* The account fields copied from an identity's stored Claude login (`oauthAccount` in the identity's `.claude.json`): who the account is and which plan and tier it is on. Never the token, which Claude Code keeps elsewhere. Each field is present only when the stored login has it; a setup-token identity has no profile scope and so none of them (see issue #44).
|
|
8932
|
+
*/
|
|
8933
|
+
declare const AccountMetadataSchema: z.ZodObject<{
|
|
8934
|
+
accountUuid: z.ZodOptional<z.ZodString>;
|
|
8935
|
+
emailAddress: z.ZodOptional<z.ZodString>;
|
|
8936
|
+
displayName: z.ZodOptional<z.ZodString>;
|
|
8937
|
+
organizationUuid: z.ZodOptional<z.ZodString>;
|
|
8938
|
+
organizationName: z.ZodOptional<z.ZodString>;
|
|
8939
|
+
organizationType: z.ZodOptional<z.ZodString>;
|
|
8940
|
+
organizationRole: z.ZodOptional<z.ZodString>;
|
|
8941
|
+
workspaceRole: z.ZodOptional<z.ZodString>;
|
|
8942
|
+
billingType: z.ZodOptional<z.ZodString>;
|
|
8943
|
+
seatTier: z.ZodOptional<z.ZodString>;
|
|
8944
|
+
organizationRateLimitTier: z.ZodOptional<z.ZodString>;
|
|
8945
|
+
userRateLimitTier: z.ZodOptional<z.ZodString>;
|
|
8946
|
+
hasExtraUsageEnabled: z.ZodOptional<z.ZodBoolean>;
|
|
8947
|
+
subscriptionCreatedAt: z.ZodOptional<z.ZodString>;
|
|
8948
|
+
accountCreatedAt: z.ZodOptional<z.ZodString>;
|
|
8949
|
+
}, z.core.$strict>;
|
|
8950
|
+
type AccountMetadata = z.infer<typeof AccountMetadataSchema>;
|
|
8951
|
+
/**
|
|
8952
|
+
* The latest state for one identity, rewritten atomically after each recorded response: the snapshot file other tools read (`~/.agent-shim/usage/snapshots/<identity>.json`) without shelling out to `agent-shim`.
|
|
8953
|
+
*/
|
|
8954
|
+
declare const UsageSnapshotSchema: z.ZodObject<{
|
|
8955
|
+
schemaVersion: z.ZodLiteral<1>;
|
|
8956
|
+
identity: z.ZodString;
|
|
8957
|
+
updatedAt: z.ZodISODateTime;
|
|
8958
|
+
account: z.ZodOptional<z.ZodObject<{
|
|
8959
|
+
accountUuid: z.ZodOptional<z.ZodString>;
|
|
8960
|
+
emailAddress: z.ZodOptional<z.ZodString>;
|
|
8961
|
+
displayName: z.ZodOptional<z.ZodString>;
|
|
8962
|
+
organizationUuid: z.ZodOptional<z.ZodString>;
|
|
8963
|
+
organizationName: z.ZodOptional<z.ZodString>;
|
|
8964
|
+
organizationType: z.ZodOptional<z.ZodString>;
|
|
8965
|
+
organizationRole: z.ZodOptional<z.ZodString>;
|
|
8966
|
+
workspaceRole: z.ZodOptional<z.ZodString>;
|
|
8967
|
+
billingType: z.ZodOptional<z.ZodString>;
|
|
8968
|
+
seatTier: z.ZodOptional<z.ZodString>;
|
|
8969
|
+
organizationRateLimitTier: z.ZodOptional<z.ZodString>;
|
|
8970
|
+
userRateLimitTier: z.ZodOptional<z.ZodString>;
|
|
8971
|
+
hasExtraUsageEnabled: z.ZodOptional<z.ZodBoolean>;
|
|
8972
|
+
subscriptionCreatedAt: z.ZodOptional<z.ZodString>;
|
|
8973
|
+
accountCreatedAt: z.ZodOptional<z.ZodString>;
|
|
8974
|
+
}, z.core.$strict>>;
|
|
8975
|
+
providers: z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
8976
|
+
lastRequestAt: z.ZodOptional<z.ZodISODateTime>;
|
|
8977
|
+
lastStatus: z.ZodOptional<z.ZodNumber>;
|
|
8978
|
+
lastModel: z.ZodOptional<z.ZodString>;
|
|
8979
|
+
rateLimit: z.ZodOptional<z.ZodObject<{
|
|
8980
|
+
observedAt: z.ZodISODateTime;
|
|
8981
|
+
headers: z.ZodRecord<z.ZodString, z.ZodString>;
|
|
8982
|
+
unified: z.ZodOptional<z.ZodObject<{
|
|
8983
|
+
status: z.ZodOptional<z.ZodString>;
|
|
8984
|
+
fiveHour: z.ZodOptional<z.ZodObject<{
|
|
8985
|
+
utilization: z.ZodOptional<z.ZodNumber>;
|
|
8986
|
+
resetsAt: z.ZodOptional<z.ZodISODateTime>;
|
|
8987
|
+
status: z.ZodOptional<z.ZodString>;
|
|
8988
|
+
graceUtilization: z.ZodOptional<z.ZodNumber>;
|
|
8989
|
+
}, z.core.$strict>>;
|
|
8990
|
+
sevenDay: z.ZodOptional<z.ZodObject<{
|
|
8991
|
+
utilization: z.ZodOptional<z.ZodNumber>;
|
|
8992
|
+
resetsAt: z.ZodOptional<z.ZodISODateTime>;
|
|
8993
|
+
status: z.ZodOptional<z.ZodString>;
|
|
8994
|
+
graceUtilization: z.ZodOptional<z.ZodNumber>;
|
|
8995
|
+
}, z.core.$strict>>;
|
|
8996
|
+
sevenDayOverageIncluded: z.ZodOptional<z.ZodObject<{
|
|
8997
|
+
utilization: z.ZodOptional<z.ZodNumber>;
|
|
8998
|
+
resetsAt: z.ZodOptional<z.ZodISODateTime>;
|
|
8999
|
+
status: z.ZodOptional<z.ZodString>;
|
|
9000
|
+
graceUtilization: z.ZodOptional<z.ZodNumber>;
|
|
9001
|
+
}, z.core.$strict>>;
|
|
9002
|
+
representativeClaim: z.ZodOptional<z.ZodString>;
|
|
9003
|
+
resetAt: z.ZodOptional<z.ZodISODateTime>;
|
|
9004
|
+
overageStatus: z.ZodOptional<z.ZodString>;
|
|
9005
|
+
overageUtilization: z.ZodOptional<z.ZodNumber>;
|
|
9006
|
+
overageResetsAt: z.ZodOptional<z.ZodISODateTime>;
|
|
9007
|
+
overageDisabledReason: z.ZodOptional<z.ZodString>;
|
|
9008
|
+
overageInUse: z.ZodOptional<z.ZodBoolean>;
|
|
9009
|
+
extraUsageSpend: z.ZodOptional<z.ZodObject<{
|
|
9010
|
+
usedMinor: z.ZodNumber;
|
|
9011
|
+
limitMinor: z.ZodOptional<z.ZodNumber>;
|
|
9012
|
+
currency: z.ZodString;
|
|
9013
|
+
}, z.core.$strict>>;
|
|
9014
|
+
fallbackAvailable: z.ZodOptional<z.ZodBoolean>;
|
|
9015
|
+
}, z.core.$strict>>;
|
|
9016
|
+
planWindowsUnavailableAt: z.ZodOptional<z.ZodISODateTime>;
|
|
9017
|
+
}, z.core.$strict>>;
|
|
9018
|
+
lastLimit: z.ZodOptional<z.ZodObject<{
|
|
9019
|
+
kind: z.ZodEnum<{
|
|
9020
|
+
"rate-limited": "rate-limited";
|
|
9021
|
+
"quota-exhausted": "quota-exhausted";
|
|
9022
|
+
}>;
|
|
9023
|
+
retryAfterSeconds: z.ZodOptional<z.ZodNumber>;
|
|
9024
|
+
resetAt: z.ZodOptional<z.ZodISODateTime>;
|
|
9025
|
+
window: z.ZodOptional<z.ZodString>;
|
|
9026
|
+
evidence: z.ZodArray<z.ZodString>;
|
|
9027
|
+
observedAt: z.ZodISODateTime;
|
|
9028
|
+
status: z.ZodNumber;
|
|
9029
|
+
}, z.core.$strict>>;
|
|
9030
|
+
quota: z.ZodOptional<z.ZodObject<{
|
|
9031
|
+
observedAt: z.ZodISODateTime;
|
|
9032
|
+
source: z.ZodString;
|
|
9033
|
+
level: z.ZodOptional<z.ZodString>;
|
|
9034
|
+
account: z.ZodOptional<z.ZodObject<{
|
|
9035
|
+
email: z.ZodOptional<z.ZodString>;
|
|
9036
|
+
accountId: z.ZodOptional<z.ZodString>;
|
|
9037
|
+
}, z.core.$strict>>;
|
|
9038
|
+
windows: z.ZodArray<z.ZodObject<{
|
|
9039
|
+
measures: z.ZodString;
|
|
9040
|
+
periodMs: z.ZodOptional<z.ZodNumber>;
|
|
9041
|
+
period: z.ZodOptional<z.ZodString>;
|
|
9042
|
+
utilization: z.ZodNumber;
|
|
9043
|
+
resetsAt: z.ZodOptional<z.ZodISODateTime>;
|
|
9044
|
+
limit: z.ZodOptional<z.ZodNumber>;
|
|
9045
|
+
used: z.ZodOptional<z.ZodNumber>;
|
|
9046
|
+
remaining: z.ZodOptional<z.ZodNumber>;
|
|
9047
|
+
}, z.core.$strict>>;
|
|
9048
|
+
}, z.core.$strict>>;
|
|
9049
|
+
}, z.core.$strict>>;
|
|
9050
|
+
}, z.core.$strict>;
|
|
9051
|
+
type UsageSnapshot = z.infer<typeof UsageSnapshotSchema>;
|
|
9052
|
+
|
|
8879
9053
|
/**
|
|
8880
9054
|
* How the allowlist the headroom daemon serves lags the allowlist computed now. The daemon re-reads its allowlist file on every request that follows a change to it, and its supervisor rewrites the file and records the hash in the same tick, so a lag that lasts beyond one tick means the supervisor is not running or cannot write the file. A daemon started by an earlier release reads no file, and is reported as such instead.
|
|
8881
9055
|
*/
|
|
@@ -9085,6 +9259,8 @@ interface DoctorIdentityInput {
|
|
|
9085
9259
|
readonly farmRoot: string;
|
|
9086
9260
|
/** Whether the identity's `.credentials.json` exists, pre-resolved by the wiring layer since it is a file-existence check. */
|
|
9087
9261
|
readonly credentialsFilePresent: boolean;
|
|
9262
|
+
/** The account metadata of the identity's stored login, pre-resolved by the wiring layer since it is a read of the identity's `.claude.json`. Undefined when the identity has no stored login or its metadata cannot be read. */
|
|
9263
|
+
readonly account: AccountMetadata | undefined;
|
|
9088
9264
|
}
|
|
9089
9265
|
/** One configuration profile's raw `<name>.json`, unparsed. */
|
|
9090
9266
|
interface DoctorConfigProfileInput {
|
|
@@ -9192,180 +9368,6 @@ interface CollectDoctorReportParams {
|
|
|
9192
9368
|
*/
|
|
9193
9369
|
declare function collectDoctorReport(params: CollectDoctorReportParams): DoctorReport;
|
|
9194
9370
|
|
|
9195
|
-
/** One routed request, appended to the usage log when its response has finished. */
|
|
9196
|
-
declare const UsageRecordSchema: z.ZodObject<{
|
|
9197
|
-
schemaVersion: z.ZodLiteral<1>;
|
|
9198
|
-
at: z.ZodISODateTime;
|
|
9199
|
-
identity: z.ZodOptional<z.ZodString>;
|
|
9200
|
-
provider: z.ZodString;
|
|
9201
|
-
sessionId: z.ZodOptional<z.ZodString>;
|
|
9202
|
-
clientSessionId: z.ZodOptional<z.ZodString>;
|
|
9203
|
-
project: z.ZodOptional<z.ZodString>;
|
|
9204
|
-
viaHeadroom: z.ZodOptional<z.ZodBoolean>;
|
|
9205
|
-
route: z.ZodString;
|
|
9206
|
-
method: z.ZodString;
|
|
9207
|
-
endpoint: z.ZodString;
|
|
9208
|
-
model: z.ZodOptional<z.ZodString>;
|
|
9209
|
-
requestedModel: z.ZodOptional<z.ZodString>;
|
|
9210
|
-
candidateProviders: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
9211
|
-
status: z.ZodNumber;
|
|
9212
|
-
latencyMs: z.ZodNumber;
|
|
9213
|
-
durationMs: z.ZodNumber;
|
|
9214
|
-
outcome: z.ZodEnum<{
|
|
9215
|
-
completed: "completed";
|
|
9216
|
-
aborted: "aborted";
|
|
9217
|
-
}>;
|
|
9218
|
-
usage: z.ZodOptional<z.ZodObject<{
|
|
9219
|
-
inputTokens: z.ZodOptional<z.ZodNumber>;
|
|
9220
|
-
outputTokens: z.ZodOptional<z.ZodNumber>;
|
|
9221
|
-
cacheCreationInputTokens: z.ZodOptional<z.ZodNumber>;
|
|
9222
|
-
cacheReadInputTokens: z.ZodOptional<z.ZodNumber>;
|
|
9223
|
-
}, z.core.$strict>>;
|
|
9224
|
-
rateLimitHeaders: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
9225
|
-
limit: z.ZodOptional<z.ZodObject<{
|
|
9226
|
-
kind: z.ZodEnum<{
|
|
9227
|
-
"rate-limited": "rate-limited";
|
|
9228
|
-
"quota-exhausted": "quota-exhausted";
|
|
9229
|
-
}>;
|
|
9230
|
-
retryAfterSeconds: z.ZodOptional<z.ZodNumber>;
|
|
9231
|
-
resetAt: z.ZodOptional<z.ZodISODateTime>;
|
|
9232
|
-
window: z.ZodOptional<z.ZodString>;
|
|
9233
|
-
evidence: z.ZodArray<z.ZodString>;
|
|
9234
|
-
}, z.core.$strict>>;
|
|
9235
|
-
requestId: z.ZodOptional<z.ZodString>;
|
|
9236
|
-
}, z.core.$strict>;
|
|
9237
|
-
type UsageRecord = z.infer<typeof UsageRecordSchema>;
|
|
9238
|
-
/** One quota window from Anthropic's unified rate-limit headers. */
|
|
9239
|
-
declare const QuotaWindowSchema: z.ZodObject<{
|
|
9240
|
-
utilization: z.ZodOptional<z.ZodNumber>;
|
|
9241
|
-
resetsAt: z.ZodOptional<z.ZodISODateTime>;
|
|
9242
|
-
status: z.ZodOptional<z.ZodString>;
|
|
9243
|
-
graceUtilization: z.ZodOptional<z.ZodNumber>;
|
|
9244
|
-
}, z.core.$strict>;
|
|
9245
|
-
type QuotaWindow = z.infer<typeof QuotaWindowSchema>;
|
|
9246
|
-
/**
|
|
9247
|
-
* The account fields copied from an identity's stored Claude login (`oauthAccount` in the identity's `.claude.json`): who the account is and which plan and tier it is on. Never the token, which Claude Code keeps elsewhere. Each field is present only when the stored login has it; a setup-token identity has no profile scope and so none of them (see issue #44).
|
|
9248
|
-
*/
|
|
9249
|
-
declare const AccountMetadataSchema: z.ZodObject<{
|
|
9250
|
-
accountUuid: z.ZodOptional<z.ZodString>;
|
|
9251
|
-
emailAddress: z.ZodOptional<z.ZodString>;
|
|
9252
|
-
displayName: z.ZodOptional<z.ZodString>;
|
|
9253
|
-
organizationUuid: z.ZodOptional<z.ZodString>;
|
|
9254
|
-
organizationName: z.ZodOptional<z.ZodString>;
|
|
9255
|
-
organizationType: z.ZodOptional<z.ZodString>;
|
|
9256
|
-
organizationRole: z.ZodOptional<z.ZodString>;
|
|
9257
|
-
workspaceRole: z.ZodOptional<z.ZodString>;
|
|
9258
|
-
billingType: z.ZodOptional<z.ZodString>;
|
|
9259
|
-
seatTier: z.ZodOptional<z.ZodString>;
|
|
9260
|
-
organizationRateLimitTier: z.ZodOptional<z.ZodString>;
|
|
9261
|
-
userRateLimitTier: z.ZodOptional<z.ZodString>;
|
|
9262
|
-
hasExtraUsageEnabled: z.ZodOptional<z.ZodBoolean>;
|
|
9263
|
-
subscriptionCreatedAt: z.ZodOptional<z.ZodString>;
|
|
9264
|
-
accountCreatedAt: z.ZodOptional<z.ZodString>;
|
|
9265
|
-
}, z.core.$strict>;
|
|
9266
|
-
type AccountMetadata = z.infer<typeof AccountMetadataSchema>;
|
|
9267
|
-
/**
|
|
9268
|
-
* The latest state for one identity, rewritten atomically after each recorded response: the snapshot file other tools read (`~/.agent-shim/usage/snapshots/<identity>.json`) without shelling out to `agent-shim`.
|
|
9269
|
-
*/
|
|
9270
|
-
declare const UsageSnapshotSchema: z.ZodObject<{
|
|
9271
|
-
schemaVersion: z.ZodLiteral<1>;
|
|
9272
|
-
identity: z.ZodString;
|
|
9273
|
-
updatedAt: z.ZodISODateTime;
|
|
9274
|
-
account: z.ZodOptional<z.ZodObject<{
|
|
9275
|
-
accountUuid: z.ZodOptional<z.ZodString>;
|
|
9276
|
-
emailAddress: z.ZodOptional<z.ZodString>;
|
|
9277
|
-
displayName: z.ZodOptional<z.ZodString>;
|
|
9278
|
-
organizationUuid: z.ZodOptional<z.ZodString>;
|
|
9279
|
-
organizationName: z.ZodOptional<z.ZodString>;
|
|
9280
|
-
organizationType: z.ZodOptional<z.ZodString>;
|
|
9281
|
-
organizationRole: z.ZodOptional<z.ZodString>;
|
|
9282
|
-
workspaceRole: z.ZodOptional<z.ZodString>;
|
|
9283
|
-
billingType: z.ZodOptional<z.ZodString>;
|
|
9284
|
-
seatTier: z.ZodOptional<z.ZodString>;
|
|
9285
|
-
organizationRateLimitTier: z.ZodOptional<z.ZodString>;
|
|
9286
|
-
userRateLimitTier: z.ZodOptional<z.ZodString>;
|
|
9287
|
-
hasExtraUsageEnabled: z.ZodOptional<z.ZodBoolean>;
|
|
9288
|
-
subscriptionCreatedAt: z.ZodOptional<z.ZodString>;
|
|
9289
|
-
accountCreatedAt: z.ZodOptional<z.ZodString>;
|
|
9290
|
-
}, z.core.$strict>>;
|
|
9291
|
-
providers: z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
9292
|
-
lastRequestAt: z.ZodOptional<z.ZodISODateTime>;
|
|
9293
|
-
lastStatus: z.ZodOptional<z.ZodNumber>;
|
|
9294
|
-
lastModel: z.ZodOptional<z.ZodString>;
|
|
9295
|
-
rateLimit: z.ZodOptional<z.ZodObject<{
|
|
9296
|
-
observedAt: z.ZodISODateTime;
|
|
9297
|
-
headers: z.ZodRecord<z.ZodString, z.ZodString>;
|
|
9298
|
-
unified: z.ZodOptional<z.ZodObject<{
|
|
9299
|
-
status: z.ZodOptional<z.ZodString>;
|
|
9300
|
-
fiveHour: z.ZodOptional<z.ZodObject<{
|
|
9301
|
-
utilization: z.ZodOptional<z.ZodNumber>;
|
|
9302
|
-
resetsAt: z.ZodOptional<z.ZodISODateTime>;
|
|
9303
|
-
status: z.ZodOptional<z.ZodString>;
|
|
9304
|
-
graceUtilization: z.ZodOptional<z.ZodNumber>;
|
|
9305
|
-
}, z.core.$strict>>;
|
|
9306
|
-
sevenDay: z.ZodOptional<z.ZodObject<{
|
|
9307
|
-
utilization: z.ZodOptional<z.ZodNumber>;
|
|
9308
|
-
resetsAt: z.ZodOptional<z.ZodISODateTime>;
|
|
9309
|
-
status: z.ZodOptional<z.ZodString>;
|
|
9310
|
-
graceUtilization: z.ZodOptional<z.ZodNumber>;
|
|
9311
|
-
}, z.core.$strict>>;
|
|
9312
|
-
sevenDayOverageIncluded: z.ZodOptional<z.ZodObject<{
|
|
9313
|
-
utilization: z.ZodOptional<z.ZodNumber>;
|
|
9314
|
-
resetsAt: z.ZodOptional<z.ZodISODateTime>;
|
|
9315
|
-
status: z.ZodOptional<z.ZodString>;
|
|
9316
|
-
graceUtilization: z.ZodOptional<z.ZodNumber>;
|
|
9317
|
-
}, z.core.$strict>>;
|
|
9318
|
-
representativeClaim: z.ZodOptional<z.ZodString>;
|
|
9319
|
-
resetAt: z.ZodOptional<z.ZodISODateTime>;
|
|
9320
|
-
overageStatus: z.ZodOptional<z.ZodString>;
|
|
9321
|
-
overageUtilization: z.ZodOptional<z.ZodNumber>;
|
|
9322
|
-
overageResetsAt: z.ZodOptional<z.ZodISODateTime>;
|
|
9323
|
-
overageDisabledReason: z.ZodOptional<z.ZodString>;
|
|
9324
|
-
overageInUse: z.ZodOptional<z.ZodBoolean>;
|
|
9325
|
-
extraUsageSpend: z.ZodOptional<z.ZodObject<{
|
|
9326
|
-
usedMinor: z.ZodNumber;
|
|
9327
|
-
limitMinor: z.ZodOptional<z.ZodNumber>;
|
|
9328
|
-
currency: z.ZodString;
|
|
9329
|
-
}, z.core.$strict>>;
|
|
9330
|
-
fallbackAvailable: z.ZodOptional<z.ZodBoolean>;
|
|
9331
|
-
}, z.core.$strict>>;
|
|
9332
|
-
planWindowsUnavailableAt: z.ZodOptional<z.ZodISODateTime>;
|
|
9333
|
-
}, z.core.$strict>>;
|
|
9334
|
-
lastLimit: z.ZodOptional<z.ZodObject<{
|
|
9335
|
-
kind: z.ZodEnum<{
|
|
9336
|
-
"rate-limited": "rate-limited";
|
|
9337
|
-
"quota-exhausted": "quota-exhausted";
|
|
9338
|
-
}>;
|
|
9339
|
-
retryAfterSeconds: z.ZodOptional<z.ZodNumber>;
|
|
9340
|
-
resetAt: z.ZodOptional<z.ZodISODateTime>;
|
|
9341
|
-
window: z.ZodOptional<z.ZodString>;
|
|
9342
|
-
evidence: z.ZodArray<z.ZodString>;
|
|
9343
|
-
observedAt: z.ZodISODateTime;
|
|
9344
|
-
status: z.ZodNumber;
|
|
9345
|
-
}, z.core.$strict>>;
|
|
9346
|
-
quota: z.ZodOptional<z.ZodObject<{
|
|
9347
|
-
observedAt: z.ZodISODateTime;
|
|
9348
|
-
source: z.ZodString;
|
|
9349
|
-
level: z.ZodOptional<z.ZodString>;
|
|
9350
|
-
account: z.ZodOptional<z.ZodObject<{
|
|
9351
|
-
email: z.ZodOptional<z.ZodString>;
|
|
9352
|
-
accountId: z.ZodOptional<z.ZodString>;
|
|
9353
|
-
}, z.core.$strict>>;
|
|
9354
|
-
windows: z.ZodArray<z.ZodObject<{
|
|
9355
|
-
measures: z.ZodString;
|
|
9356
|
-
periodMs: z.ZodOptional<z.ZodNumber>;
|
|
9357
|
-
period: z.ZodOptional<z.ZodString>;
|
|
9358
|
-
utilization: z.ZodNumber;
|
|
9359
|
-
resetsAt: z.ZodOptional<z.ZodISODateTime>;
|
|
9360
|
-
limit: z.ZodOptional<z.ZodNumber>;
|
|
9361
|
-
used: z.ZodOptional<z.ZodNumber>;
|
|
9362
|
-
remaining: z.ZodOptional<z.ZodNumber>;
|
|
9363
|
-
}, z.core.$strict>>;
|
|
9364
|
-
}, z.core.$strict>>;
|
|
9365
|
-
}, z.core.$strict>>;
|
|
9366
|
-
}, z.core.$strict>;
|
|
9367
|
-
type UsageSnapshot = z.infer<typeof UsageSnapshotSchema>;
|
|
9368
|
-
|
|
9369
9371
|
/** How a sign-out went: whether OpenAI was told, so the person knows the grant is dead on its side too. */
|
|
9370
9372
|
interface SiwcLogoutResult {
|
|
9371
9373
|
readonly hadGrant: boolean;
|
|
@@ -14030,6 +14032,8 @@ interface PrepareLaunchParams {
|
|
|
14030
14032
|
readonly log: LogPort;
|
|
14031
14033
|
/** Discovers the real `claude` binary to spawn. Injected so `runLauncher` never depends on `src/versionDiscovery.ts`'s own filesystem/PATH inputs directly — the caller (`src/cli.ts`) wires the real discovery, tests wire a fake that returns a fixed path. */
|
|
14032
14034
|
readonly resolveClaudeBinary: ClaudeBinaryResolver;
|
|
14035
|
+
/** The identity (or `pool:<name>`) the person chose at the identity picker, which takes the place of whatever the arguments named: the question was asked because that choice was not settled. */
|
|
14036
|
+
readonly pickedIdentity?: string;
|
|
14033
14037
|
/** An identity pinned to `$PWD` by a directory rule. Accepted as an already-resolved value — the rules-loading code that produces it lands in Phase 4/5. */
|
|
14034
14038
|
readonly directoryPinnedIdentity?: string;
|
|
14035
14039
|
/** A directory rule's `configProfile` selection for `$PWD`. Accepted as an already-resolved value for the same reason. */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agent-shim",
|
|
3
|
-
"version": "11.
|
|
3
|
+
"version": "11.79.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>",
|