agent-shim 11.55.0 → 11.56.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.cjs +253 -51
- package/dist/index.cjs +72 -39
- package/dist/index.mjs +73 -40
- package/package.json +1 -1
package/dist/cli.cjs
CHANGED
|
@@ -29545,11 +29545,59 @@ function hasDesktopSession() {
|
|
|
29545
29545
|
const result = (0, import_node_child_process2.spawnSync)("launchctl", ["managername"], { encoding: "utf8" });
|
|
29546
29546
|
return result.status === 0 && result.stdout.trim() === MACOS_GUI_SESSION_MANAGER;
|
|
29547
29547
|
}
|
|
29548
|
+
return hasDisplayServer();
|
|
29549
|
+
}
|
|
29550
|
+
function hasDisplayServer() {
|
|
29548
29551
|
if (process.platform === "win32") {
|
|
29549
29552
|
return false;
|
|
29550
29553
|
}
|
|
29551
29554
|
return (process.env.DISPLAY ?? "") !== "" || (process.env.WAYLAND_DISPLAY ?? "") !== "";
|
|
29552
29555
|
}
|
|
29556
|
+
async function hasDesktopSessionAsync() {
|
|
29557
|
+
if (process.platform !== "darwin") {
|
|
29558
|
+
return hasDisplayServer();
|
|
29559
|
+
}
|
|
29560
|
+
return await new Promise((resolve2) => {
|
|
29561
|
+
(0, import_node_child_process2.execFile)("launchctl", ["managername"], { encoding: "utf8" }, (error63, stdout2) => {
|
|
29562
|
+
resolve2(error63 === null && stdout2.trim() === MACOS_GUI_SESSION_MANAGER);
|
|
29563
|
+
});
|
|
29564
|
+
});
|
|
29565
|
+
}
|
|
29566
|
+
async function runCredentialCommand(argv, options) {
|
|
29567
|
+
const [command, ...args] = argv;
|
|
29568
|
+
return await new Promise((resolve2) => {
|
|
29569
|
+
const child = (0, import_node_child_process2.spawn)(command, args, { stdio: options.interactive ? ["inherit", "pipe", "inherit"] : ["ignore", "pipe", "pipe"] });
|
|
29570
|
+
let stdout2 = "";
|
|
29571
|
+
let stderr = "";
|
|
29572
|
+
let timedOut = false;
|
|
29573
|
+
const timer = setTimeout(() => {
|
|
29574
|
+
timedOut = true;
|
|
29575
|
+
child.kill();
|
|
29576
|
+
}, options.timeoutMs);
|
|
29577
|
+
let settled = false;
|
|
29578
|
+
const settle2 = (result) => {
|
|
29579
|
+
if (!settled) {
|
|
29580
|
+
settled = true;
|
|
29581
|
+
clearTimeout(timer);
|
|
29582
|
+
resolve2(result);
|
|
29583
|
+
}
|
|
29584
|
+
};
|
|
29585
|
+
child.stdout?.setEncoding("utf8");
|
|
29586
|
+
child.stdout?.on("data", (chunk2) => {
|
|
29587
|
+
stdout2 += chunk2;
|
|
29588
|
+
});
|
|
29589
|
+
child.stderr?.setEncoding("utf8");
|
|
29590
|
+
child.stderr?.on("data", (chunk2) => {
|
|
29591
|
+
stderr += chunk2;
|
|
29592
|
+
});
|
|
29593
|
+
child.once("error", (error63) => {
|
|
29594
|
+
settle2({ status: null, stdout: "", stderr: error63.message, timedOut: false });
|
|
29595
|
+
});
|
|
29596
|
+
child.once("close", (status) => {
|
|
29597
|
+
settle2(timedOut ? { status: null, stdout: "", stderr: "", timedOut: true } : { status, stdout: stdout2, stderr: options.interactive ? "" : stderr, timedOut: false });
|
|
29598
|
+
});
|
|
29599
|
+
});
|
|
29600
|
+
}
|
|
29553
29601
|
function resolveGitBranch(run, cwd) {
|
|
29554
29602
|
const result = run.run("git", ["-C", cwd, "rev-parse", "--abbrev-ref", "HEAD"]);
|
|
29555
29603
|
if (result.status !== 0) {
|
|
@@ -29746,7 +29794,7 @@ function realResolveClaudeBinary(isOwnBinary) {
|
|
|
29746
29794
|
function realInstalledClaudeVersions() {
|
|
29747
29795
|
return installedVersions(listVersionsDir(defaultVersionsDir()));
|
|
29748
29796
|
}
|
|
29749
|
-
var import_node_child_process2, import_node_crypto4, import_node_fs3, import_node_os2, import_node_path9, import_node_sea, realFsPort, OWNER_ONLY_DIR_MODE, OWNER_ONLY_FILE_MODE, PERMISSION_BITS, realFarmFs, INT32_BYTE_LENGTH, KEY_POLL_MS, CTRL_C_BYTE, realHoldPort, LINE_FEED, UTF8_CONTINUATION_MASK, UTF8_CONTINUATION_BITS, PS_TIMEOUT_MS, realRunPort, MACOS_GUI_SESSION_MANAGER, realCredentialPort, SOCKET_PERMISSION_BITS, realHeadroomSocketTrust, realSpawnPort, realProcPort, realLogPort, EXECUTE_BITS_MASK, WINDOWS_DEFAULT_PATHEXT;
|
|
29797
|
+
var import_node_child_process2, import_node_crypto4, import_node_fs3, import_node_os2, import_node_path9, import_node_sea, realFsPort, OWNER_ONLY_DIR_MODE, OWNER_ONLY_FILE_MODE, PERMISSION_BITS, realFarmFs, INT32_BYTE_LENGTH, KEY_POLL_MS, CTRL_C_BYTE, realHoldPort, LINE_FEED, UTF8_CONTINUATION_MASK, UTF8_CONTINUATION_BITS, PS_TIMEOUT_MS, realRunPort, MACOS_GUI_SESSION_MANAGER, realCredentialPort, realAsyncCredentialPort, SOCKET_PERMISSION_BITS, realHeadroomSocketTrust, realSpawnPort, realProcPort, realLogPort, EXECUTE_BITS_MASK, WINDOWS_DEFAULT_PATHEXT;
|
|
29750
29798
|
var init_realPorts = __esm({
|
|
29751
29799
|
"src/realPorts.ts"() {
|
|
29752
29800
|
"use strict";
|
|
@@ -29962,6 +30010,11 @@ var init_realPorts = __esm({
|
|
|
29962
30010
|
},
|
|
29963
30011
|
personPresent: () => process.stdin.isTTY || hasDesktopSession()
|
|
29964
30012
|
};
|
|
30013
|
+
realAsyncCredentialPort = {
|
|
30014
|
+
readSecretFile: (filePath) => realCredentialPort.readSecretFile(filePath),
|
|
30015
|
+
runCommand: runCredentialCommand,
|
|
30016
|
+
personPresent: async () => process.stdin.isTTY || await hasDesktopSessionAsync()
|
|
30017
|
+
};
|
|
29965
30018
|
SOCKET_PERMISSION_BITS = 4095;
|
|
29966
30019
|
realHeadroomSocketTrust = {
|
|
29967
30020
|
platform: process.platform,
|
|
@@ -35365,51 +35418,87 @@ function unpackKeyringToken(raw) {
|
|
|
35365
35418
|
}
|
|
35366
35419
|
return trimmed;
|
|
35367
35420
|
}
|
|
35368
|
-
function
|
|
35369
|
-
|
|
35421
|
+
function declined(reason, warn = false) {
|
|
35422
|
+
return { ok: false, reason, warn };
|
|
35423
|
+
}
|
|
35424
|
+
function isCommandBacked(source) {
|
|
35425
|
+
return "command" in source || "op" in source || "keychain" in source;
|
|
35426
|
+
}
|
|
35427
|
+
function immediateOutcome(source, params) {
|
|
35370
35428
|
if ("env" in source) {
|
|
35371
35429
|
const value2 = params.env[source.env];
|
|
35372
|
-
return value2 === void 0 || value2 === "" ?
|
|
35430
|
+
return value2 === void 0 || value2 === "" ? declined("is unset or empty") : { ok: true, token: unpackKeyringToken(value2) };
|
|
35373
35431
|
}
|
|
35374
35432
|
if ("literal" in source) {
|
|
35375
35433
|
return { ok: true, token: source.literal };
|
|
35376
35434
|
}
|
|
35377
|
-
|
|
35378
|
-
|
|
35379
|
-
|
|
35380
|
-
return none("does not exist");
|
|
35381
|
-
}
|
|
35382
|
-
if (read.mode !== void 0 && (read.mode & GROUP_OTHER_PERMISSION_BITS) !== 0) {
|
|
35383
|
-
return none(
|
|
35384
|
-
`is readable or writable by group or others (mode ${(read.mode & PERMISSION_BITS2).toString(OCTAL_RADIX2)}); run \`chmod 600 ${source.file}\``,
|
|
35385
|
-
true
|
|
35386
|
-
);
|
|
35387
|
-
}
|
|
35388
|
-
const token2 = unpackKeyringToken(read.content.trim());
|
|
35389
|
-
return token2 === "" ? none("is empty") : { ok: true, token: token2 };
|
|
35435
|
+
const read = params.port.readSecretFile(source.file);
|
|
35436
|
+
if (!read.found) {
|
|
35437
|
+
return declined("does not exist");
|
|
35390
35438
|
}
|
|
35391
|
-
|
|
35392
|
-
|
|
35393
|
-
|
|
35394
|
-
|
|
35439
|
+
if (read.mode !== void 0 && (read.mode & GROUP_OTHER_PERMISSION_BITS) !== 0) {
|
|
35440
|
+
return declined(
|
|
35441
|
+
`is readable or writable by group or others (mode ${(read.mode & PERMISSION_BITS2).toString(OCTAL_RADIX2)}); run \`chmod 600 ${source.file}\``,
|
|
35442
|
+
true
|
|
35443
|
+
);
|
|
35395
35444
|
}
|
|
35396
|
-
const
|
|
35397
|
-
|
|
35445
|
+
const token = unpackKeyringToken(read.content.trim());
|
|
35446
|
+
return token === "" ? declined("is empty") : { ok: true, token };
|
|
35447
|
+
}
|
|
35448
|
+
function commandRunOf(source, env) {
|
|
35449
|
+
const interactive = isInteractiveSource(source, env);
|
|
35450
|
+
return { argv: commandArgv(source), interactive, timeoutMs: source.timeoutMs ?? (interactive ? CREDENTIAL_INTERACTIVE_TIMEOUT_MS : CREDENTIAL_COMMAND_TIMEOUT_MS) };
|
|
35451
|
+
}
|
|
35452
|
+
function commandOutcome(result, timeoutMs) {
|
|
35398
35453
|
if (result.timedOut) {
|
|
35399
|
-
return
|
|
35454
|
+
return declined(`timed out after ${String(timeoutMs)}ms`);
|
|
35400
35455
|
}
|
|
35401
35456
|
if (result.status !== 0) {
|
|
35402
35457
|
const stderr = result.stderr.trim();
|
|
35403
35458
|
const outcome = result.status === null ? "could not be run or was killed by a signal" : `exited with status ${String(result.status)}`;
|
|
35404
|
-
return
|
|
35459
|
+
return declined(`${outcome}${stderr === "" ? "" : `: ${stderr}`}`);
|
|
35405
35460
|
}
|
|
35406
35461
|
const token = unpackKeyringToken(result.stdout.trim());
|
|
35407
|
-
return token === "" ?
|
|
35462
|
+
return token === "" ? declined("printed no token") : { ok: true, token };
|
|
35463
|
+
}
|
|
35464
|
+
function trySource(source, params) {
|
|
35465
|
+
if (!isCommandBacked(source)) {
|
|
35466
|
+
return immediateOutcome(source, params);
|
|
35467
|
+
}
|
|
35468
|
+
const run = commandRunOf(source, params.env);
|
|
35469
|
+
if (run.interactive && !params.port.personPresent()) {
|
|
35470
|
+
return declined(NO_PERSON_REASON);
|
|
35471
|
+
}
|
|
35472
|
+
return commandOutcome(params.port.runCommand(run.argv, { timeoutMs: run.timeoutMs, interactive: run.interactive }), run.timeoutMs);
|
|
35473
|
+
}
|
|
35474
|
+
async function trySourceAsync(source, params) {
|
|
35475
|
+
if (!isCommandBacked(source)) {
|
|
35476
|
+
return immediateOutcome(source, params);
|
|
35477
|
+
}
|
|
35478
|
+
const run = commandRunOf(source, params.env);
|
|
35479
|
+
if (run.interactive && !await params.port.personPresent()) {
|
|
35480
|
+
return declined(NO_PERSON_REASON);
|
|
35481
|
+
}
|
|
35482
|
+
return commandOutcome(await params.port.runCommand(run.argv, { timeoutMs: run.timeoutMs, interactive: run.interactive }), run.timeoutMs);
|
|
35408
35483
|
}
|
|
35409
35484
|
function warmCommandFor(subject) {
|
|
35410
35485
|
const [kind, name] = subject.split(" ");
|
|
35411
35486
|
return kind === "provider" ? `agent-shim credential warm --provider ${name ?? ""}` : `agent-shim credential warm ${name ?? ""}`;
|
|
35412
35487
|
}
|
|
35488
|
+
function cachedResolution(target, entry) {
|
|
35489
|
+
return { ok: true, credential: { target, token: entry.token, source: entry.source, warnings: [], cachedAt: entry.fetchedAt } };
|
|
35490
|
+
}
|
|
35491
|
+
function liveResolution(target, token, source, warnings) {
|
|
35492
|
+
return { ok: true, credential: { target, token, source, warnings } };
|
|
35493
|
+
}
|
|
35494
|
+
function unresolved(subject, cacheBlock, attempts) {
|
|
35495
|
+
const hint = cacheBlock === void 0 ? "" : `; fill the cache from a terminal with \`${warmCommandFor(subject)}\``;
|
|
35496
|
+
return { ok: false, message: `agent-shim: ${subject} has no usable credential: ${attempts.join("; ")}${hint}` };
|
|
35497
|
+
}
|
|
35498
|
+
function declinedLine(source, outcome, subject) {
|
|
35499
|
+
const attempt = `${describeSource(source)} ${outcome.reason}`;
|
|
35500
|
+
return { attempt, warning: outcome.warn ? `agent-shim: ${subject}: skipped ${attempt}` : void 0 };
|
|
35501
|
+
}
|
|
35413
35502
|
function resolveCredential(params) {
|
|
35414
35503
|
const target = params.credential.target ?? "bearer";
|
|
35415
35504
|
const cacheBlock = params.credential.cache;
|
|
@@ -35418,7 +35507,7 @@ function resolveCredential(params) {
|
|
|
35418
35507
|
if (cacheBlock !== void 0 && cache !== void 0 && store !== void 0 && params.refresh !== true) {
|
|
35419
35508
|
const entry = cache.port.read(store, params.subject);
|
|
35420
35509
|
if (entry !== void 0 && isFresh(entry, cacheBlock, cache.now())) {
|
|
35421
|
-
return
|
|
35510
|
+
return cachedResolution(target, entry);
|
|
35422
35511
|
}
|
|
35423
35512
|
}
|
|
35424
35513
|
const attempts = [];
|
|
@@ -35429,16 +35518,59 @@ function resolveCredential(params) {
|
|
|
35429
35518
|
if (cache !== void 0 && store !== void 0) {
|
|
35430
35519
|
cache.port.write(store, params.subject, { token: outcome.token, fetchedAt: cache.now(), source });
|
|
35431
35520
|
}
|
|
35432
|
-
return
|
|
35521
|
+
return liveResolution(target, outcome.token, source, warnings);
|
|
35522
|
+
}
|
|
35523
|
+
const line = declinedLine(source, outcome, params.subject);
|
|
35524
|
+
attempts.push(line.attempt);
|
|
35525
|
+
if (line.warning !== void 0) {
|
|
35526
|
+
warnings.push(line.warning);
|
|
35527
|
+
}
|
|
35528
|
+
}
|
|
35529
|
+
return unresolved(params.subject, cacheBlock, attempts);
|
|
35530
|
+
}
|
|
35531
|
+
async function resolveCredentialAsync(params) {
|
|
35532
|
+
const target = params.credential.target ?? "bearer";
|
|
35533
|
+
const cacheBlock = params.credential.cache;
|
|
35534
|
+
const cache = cacheBlock === void 0 ? void 0 : params.port.cache;
|
|
35535
|
+
const store = cacheBlock === void 0 || cache === void 0 ? void 0 : effectiveStore(cacheBlock, cache.platform);
|
|
35536
|
+
if (cacheBlock !== void 0 && cache !== void 0 && store !== void 0 && params.refresh !== true) {
|
|
35537
|
+
const entry = await cache.port.read(store, params.subject);
|
|
35538
|
+
if (entry !== void 0 && isFresh(entry, cacheBlock, cache.now())) {
|
|
35539
|
+
return cachedResolution(target, entry);
|
|
35540
|
+
}
|
|
35541
|
+
}
|
|
35542
|
+
const attempts = [];
|
|
35543
|
+
const warnings = [];
|
|
35544
|
+
for (const source of params.credential.sources) {
|
|
35545
|
+
const outcome = await trySourceAsync(source, params);
|
|
35546
|
+
if (outcome.ok) {
|
|
35547
|
+
if (cache !== void 0 && store !== void 0) {
|
|
35548
|
+
await cache.port.write(store, params.subject, { token: outcome.token, fetchedAt: cache.now(), source });
|
|
35549
|
+
}
|
|
35550
|
+
return liveResolution(target, outcome.token, source, warnings);
|
|
35433
35551
|
}
|
|
35434
|
-
const line =
|
|
35435
|
-
attempts.push(line);
|
|
35436
|
-
if (
|
|
35437
|
-
warnings.push(
|
|
35552
|
+
const line = declinedLine(source, outcome, params.subject);
|
|
35553
|
+
attempts.push(line.attempt);
|
|
35554
|
+
if (line.warning !== void 0) {
|
|
35555
|
+
warnings.push(line.warning);
|
|
35438
35556
|
}
|
|
35439
35557
|
}
|
|
35440
|
-
|
|
35441
|
-
|
|
35558
|
+
return unresolved(params.subject, cacheBlock, attempts);
|
|
35559
|
+
}
|
|
35560
|
+
function shareInFlightResolutions(resolve2) {
|
|
35561
|
+
const inFlight = /* @__PURE__ */ new Map();
|
|
35562
|
+
return async (params) => {
|
|
35563
|
+
const key = JSON.stringify([params.subject, params.credential, params.refresh === true]);
|
|
35564
|
+
const running = inFlight.get(key);
|
|
35565
|
+
if (running !== void 0) {
|
|
35566
|
+
return await running;
|
|
35567
|
+
}
|
|
35568
|
+
const started = resolve2(params).finally(() => {
|
|
35569
|
+
inFlight.delete(key);
|
|
35570
|
+
});
|
|
35571
|
+
inFlight.set(key, started);
|
|
35572
|
+
return await started;
|
|
35573
|
+
};
|
|
35442
35574
|
}
|
|
35443
35575
|
function credentialVariables(target, token) {
|
|
35444
35576
|
return {
|
|
@@ -35447,7 +35579,7 @@ function credentialVariables(target, token) {
|
|
|
35447
35579
|
CLAUDE_CODE_OAUTH_TOKEN: target === "oauthToken" ? token : void 0
|
|
35448
35580
|
};
|
|
35449
35581
|
}
|
|
35450
|
-
var CREDENTIAL_UNAVAILABLE_EXIT, CREDENTIAL_COMMAND_TIMEOUT_MS, CREDENTIAL_INTERACTIVE_TIMEOUT_MS, GROUP_OTHER_PERMISSION_BITS, PERMISSION_BITS2, OCTAL_RADIX2, GO_KEYRING_BASE64_PREFIX;
|
|
35582
|
+
var CREDENTIAL_UNAVAILABLE_EXIT, CREDENTIAL_COMMAND_TIMEOUT_MS, CREDENTIAL_INTERACTIVE_TIMEOUT_MS, GROUP_OTHER_PERMISSION_BITS, PERMISSION_BITS2, OCTAL_RADIX2, GO_KEYRING_BASE64_PREFIX, NO_PERSON_REASON;
|
|
35451
35583
|
var init_credential = __esm({
|
|
35452
35584
|
"src/credential.ts"() {
|
|
35453
35585
|
"use strict";
|
|
@@ -35459,6 +35591,7 @@ var init_credential = __esm({
|
|
|
35459
35591
|
PERMISSION_BITS2 = 511;
|
|
35460
35592
|
OCTAL_RADIX2 = 8;
|
|
35461
35593
|
GO_KEYRING_BASE64_PREFIX = "go-keyring-base64:";
|
|
35594
|
+
NO_PERSON_REASON = "needs a person to approve it, but there is no terminal or desktop session";
|
|
35462
35595
|
}
|
|
35463
35596
|
});
|
|
35464
35597
|
|
|
@@ -36633,7 +36766,7 @@ var init_package = __esm({
|
|
|
36633
36766
|
"package.json"() {
|
|
36634
36767
|
package_default = {
|
|
36635
36768
|
name: "agent-shim",
|
|
36636
|
-
version: "11.
|
|
36769
|
+
version: "11.56.1",
|
|
36637
36770
|
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.",
|
|
36638
36771
|
license: "MIT",
|
|
36639
36772
|
author: "Joseph Mearman <joseph@mearman.co.uk>",
|
|
@@ -38070,6 +38203,30 @@ function security(args, stdin2) {
|
|
|
38070
38203
|
const result = (0, import_node_child_process3.spawnSync)("security", args, { encoding: "utf8", ...stdin2 === void 0 ? {} : { input: stdin2 }, stdio: ["pipe", "pipe", "ignore"] });
|
|
38071
38204
|
return { status: result.status, stdout: result.stdout };
|
|
38072
38205
|
}
|
|
38206
|
+
async function securityAsync(args, stdin2) {
|
|
38207
|
+
return await new Promise((resolve2) => {
|
|
38208
|
+
const child = (0, import_node_child_process3.spawn)("security", args, { stdio: ["pipe", "pipe", "ignore"] });
|
|
38209
|
+
let stdout2 = "";
|
|
38210
|
+
let settled = false;
|
|
38211
|
+
const settle2 = (status) => {
|
|
38212
|
+
if (!settled) {
|
|
38213
|
+
settled = true;
|
|
38214
|
+
resolve2({ status, stdout: stdout2 });
|
|
38215
|
+
}
|
|
38216
|
+
};
|
|
38217
|
+
child.stdout.setEncoding("utf8");
|
|
38218
|
+
child.stdout.on("data", (chunk2) => {
|
|
38219
|
+
stdout2 += chunk2;
|
|
38220
|
+
});
|
|
38221
|
+
child.stdin.on("error", () => {
|
|
38222
|
+
});
|
|
38223
|
+
child.stdin.end(stdin2);
|
|
38224
|
+
child.once("error", () => {
|
|
38225
|
+
settle2(null);
|
|
38226
|
+
});
|
|
38227
|
+
child.once("close", settle2);
|
|
38228
|
+
});
|
|
38229
|
+
}
|
|
38073
38230
|
function createRealCredentialCache(root) {
|
|
38074
38231
|
const dir = import_node_path29.default.join(root, "credential-cache");
|
|
38075
38232
|
const filePath = (owner) => import_node_path29.default.join(dir, cacheFileNameFor(owner));
|
|
@@ -38118,6 +38275,46 @@ function createRealCredentialCache(root) {
|
|
|
38118
38275
|
function realCredentialCacheEnv(paths) {
|
|
38119
38276
|
return { port: createRealCredentialCache(paths.root), platform: process.platform, now: () => Date.now() };
|
|
38120
38277
|
}
|
|
38278
|
+
function createAsyncRealCredentialCache(root) {
|
|
38279
|
+
const dir = import_node_path29.default.join(root, "credential-cache");
|
|
38280
|
+
const filePath = (owner) => import_node_path29.default.join(dir, cacheFileNameFor(owner));
|
|
38281
|
+
return {
|
|
38282
|
+
async read(store, owner) {
|
|
38283
|
+
if (store === "file") {
|
|
38284
|
+
try {
|
|
38285
|
+
return parseEntry(await import_node_fs9.default.promises.readFile(filePath(owner), "utf8"));
|
|
38286
|
+
} catch {
|
|
38287
|
+
return void 0;
|
|
38288
|
+
}
|
|
38289
|
+
}
|
|
38290
|
+
requireKeychain();
|
|
38291
|
+
const result = await securityAsync(["find-generic-password", "-s", KEYCHAIN_CACHE_SERVICE, "-a", owner, "-w"]);
|
|
38292
|
+
return result.status === 0 ? parseEntry(Buffer.from(result.stdout.trim(), "base64").toString("utf8")) : void 0;
|
|
38293
|
+
},
|
|
38294
|
+
async write(store, owner, entry) {
|
|
38295
|
+
const serialised = JSON.stringify(entry);
|
|
38296
|
+
if (store === "file") {
|
|
38297
|
+
await import_node_fs9.default.promises.mkdir(dir, { recursive: true, mode: CACHE_DIR_MODE });
|
|
38298
|
+
await import_node_fs9.default.promises.chmod(dir, CACHE_DIR_MODE);
|
|
38299
|
+
const target = filePath(owner);
|
|
38300
|
+
const temp = `${target}.${String(process.pid)}.tmp`;
|
|
38301
|
+
await import_node_fs9.default.promises.writeFile(temp, serialised, { mode: CACHE_FILE_MODE });
|
|
38302
|
+
await import_node_fs9.default.promises.rename(temp, target);
|
|
38303
|
+
return;
|
|
38304
|
+
}
|
|
38305
|
+
requireKeychain();
|
|
38306
|
+
const encoded = Buffer.from(serialised, "utf8").toString("base64");
|
|
38307
|
+
const result = await securityAsync(["-i"], `add-generic-password -U -s ${KEYCHAIN_CACHE_SERVICE} -a ${JSON.stringify(owner)} -w ${encoded}
|
|
38308
|
+
`);
|
|
38309
|
+
if (result.status !== 0) {
|
|
38310
|
+
throw new Error(`could not write the keychain credential cache for ${owner}`);
|
|
38311
|
+
}
|
|
38312
|
+
}
|
|
38313
|
+
};
|
|
38314
|
+
}
|
|
38315
|
+
function realAsyncCredentialCacheEnv(paths) {
|
|
38316
|
+
return { port: createAsyncRealCredentialCache(paths.root), platform: process.platform, now: () => Date.now() };
|
|
38317
|
+
}
|
|
38121
38318
|
var import_node_child_process3, import_node_fs9, import_node_path29, KEYCHAIN_CACHE_SERVICE, CACHE_DIR_MODE, CACHE_FILE_MODE;
|
|
38122
38319
|
var init_realCredentialCache = __esm({
|
|
38123
38320
|
"src/realCredentialCache.ts"() {
|
|
@@ -65190,8 +65387,11 @@ setTimeout(() => { socket.destroy(); finish(failed, "no connection accepted with
|
|
|
65190
65387
|
function declareThisProcessTheFrontDoor() {
|
|
65191
65388
|
declaredPid = process.pid;
|
|
65192
65389
|
}
|
|
65390
|
+
function isDeclaredFrontDoor(pid) {
|
|
65391
|
+
return declaredPid !== void 0 && pid === declaredPid && pid === process.pid;
|
|
65392
|
+
}
|
|
65193
65393
|
function isFrontDoorSupervisorPid(pid, identify) {
|
|
65194
|
-
return
|
|
65394
|
+
return isDeclaredFrontDoor(pid) || identify(pid);
|
|
65195
65395
|
}
|
|
65196
65396
|
var declaredPid;
|
|
65197
65397
|
var init_selfIdentity = __esm({
|
|
@@ -65242,7 +65442,8 @@ var init_trust = __esm({
|
|
|
65242
65442
|
function realEnsurePorts(paths, spawnDaemon) {
|
|
65243
65443
|
return {
|
|
65244
65444
|
fs: realFarmFs,
|
|
65245
|
-
|
|
65445
|
+
// The door plans launches of its own (the usage probe, the window opener, jobs), and asked whether the supervisor the state file names is running, the answer for itself is known: a synchronous `ps` here would hold the loop that answers every session.
|
|
65446
|
+
isRunning: (pid) => isDeclaredFrontDoor(pid) || realIsProcessRunning(pid),
|
|
65246
65447
|
now: () => Date.now(),
|
|
65247
65448
|
sleep: realSleepSync,
|
|
65248
65449
|
spawnSupervisor: (layout) => spawnDaemon(layout, "__frontdoor-supervisor", layout.frontdoorLogPath),
|
|
@@ -68677,13 +68878,13 @@ function resolveLaunch(params) {
|
|
|
68677
68878
|
environment
|
|
68678
68879
|
};
|
|
68679
68880
|
}
|
|
68680
|
-
function runLaunchPlan(plan,
|
|
68881
|
+
function runLaunchPlan(plan, spawn9) {
|
|
68681
68882
|
try {
|
|
68682
68883
|
if (plan.hold() === "cancelled") {
|
|
68683
68884
|
return LAUNCH_CANCELLED_EXIT;
|
|
68684
68885
|
}
|
|
68685
68886
|
plan.markChildStarted();
|
|
68686
|
-
const result =
|
|
68887
|
+
const result = spawn9.spawnSync(plan.bin, plan.args, { stdio: "inherit", env: plan.env });
|
|
68687
68888
|
if (result.error !== void 0) {
|
|
68688
68889
|
throw result.error;
|
|
68689
68890
|
}
|
|
@@ -69171,7 +69372,7 @@ function createQuotaRefresher(deps) {
|
|
|
69171
69372
|
const fetchNow = async (identity, provider, lookup, adapter) => {
|
|
69172
69373
|
const key = `${identity}\0${provider}`;
|
|
69173
69374
|
try {
|
|
69174
|
-
const apiKey = lookup.apiKey();
|
|
69375
|
+
const apiKey = await lookup.apiKey();
|
|
69175
69376
|
const quota = await adapter.fetch(apiKey, deps.http, AbortSignal.timeout(QUOTA_REQUEST_TIMEOUT_MS), deps.now());
|
|
69176
69377
|
if (!deps.record(identity, provider, quota)) {
|
|
69177
69378
|
return { status: "no-usage" };
|
|
@@ -69241,8 +69442,8 @@ function createProviderLookup(ports) {
|
|
|
69241
69442
|
}
|
|
69242
69443
|
return {
|
|
69243
69444
|
baseUrl,
|
|
69244
|
-
apiKey: () => {
|
|
69245
|
-
const resolution =
|
|
69445
|
+
apiKey: async () => {
|
|
69446
|
+
const resolution = await resolveCredentialAsync({ credential: isRouterProvider(definition) ? { sources: [] } : definition.credential, env: ports.env, port: ports.credentials, subject: `provider ${name}` });
|
|
69246
69447
|
if (!resolution.ok) {
|
|
69247
69448
|
throw new Error(resolution.message);
|
|
69248
69449
|
}
|
|
@@ -132748,7 +132949,7 @@ function createAntigravityRoute(ports) {
|
|
|
132748
132949
|
body: JSON.stringify({ type: "error", error: { type: "not_found_error", message: "no provider specified in path" } })
|
|
132749
132950
|
};
|
|
132750
132951
|
}
|
|
132751
|
-
const lookup = ports.loadProvider(providerName);
|
|
132952
|
+
const lookup = await ports.loadProvider(providerName);
|
|
132752
132953
|
if (!lookup.ok) {
|
|
132753
132954
|
return {
|
|
132754
132955
|
status: lookup.status,
|
|
@@ -133262,6 +133463,7 @@ function resolveAccountTarget(model, models) {
|
|
|
133262
133463
|
}
|
|
133263
133464
|
function createProviderRouteResolver(deps) {
|
|
133264
133465
|
const oauthRoute = createPassthroughRoute("anthropic", { baseUrl: `https://${CONNECT_INTERCEPT_HOST}:${String(HTTPS_PORT)}`, stripPrefix: void 0, headroomUpstream: void 0 });
|
|
133466
|
+
const resolveCredential2 = shareInFlightResolutions(resolveCredentialAsync);
|
|
133265
133467
|
const antigravityQuotaSources = /* @__PURE__ */ new Map();
|
|
133266
133468
|
const antigravityRoutingMemory = /* @__PURE__ */ new Map();
|
|
133267
133469
|
const definesProvider = (name) => {
|
|
@@ -133290,7 +133492,7 @@ function createProviderRouteResolver(deps) {
|
|
|
133290
133492
|
const source = createCachedAntigravityQuotaSource({
|
|
133291
133493
|
now: () => Date.now(),
|
|
133292
133494
|
fetchSummary: async (nowMs) => {
|
|
133293
|
-
const res =
|
|
133495
|
+
const res = await resolveCredential2({ credential: definition.credential, env: deps.env, port: deps.credentials, subject: `provider ${provider}` });
|
|
133294
133496
|
if (!res.ok) {
|
|
133295
133497
|
return void 0;
|
|
133296
133498
|
}
|
|
@@ -133356,8 +133558,8 @@ function createProviderRouteResolver(deps) {
|
|
|
133356
133558
|
ok: true,
|
|
133357
133559
|
route: createAntigravityRouteMount(
|
|
133358
133560
|
{
|
|
133359
|
-
loadProvider: () => {
|
|
133360
|
-
const res =
|
|
133561
|
+
loadProvider: async () => {
|
|
133562
|
+
const res = await resolveCredential2({
|
|
133361
133563
|
credential: antigravityProvider.credential,
|
|
133362
133564
|
env: deps.env,
|
|
133363
133565
|
port: deps.credentials,
|
|
@@ -133393,7 +133595,7 @@ function createProviderRouteResolver(deps) {
|
|
|
133393
133595
|
stripPrefix: `${PROVIDER_PATH_PREFIX}${encodeURIComponent(provider)}`,
|
|
133394
133596
|
headroomUpstream: directOrigin2(deps.directPort())
|
|
133395
133597
|
}),
|
|
133396
|
-
{ provider, credential: httpProvider.credential, env: deps.env, port: deps.credentials }
|
|
133598
|
+
{ provider, credential: httpProvider.credential, env: deps.env, port: deps.credentials, resolve: resolveCredential2 }
|
|
133397
133599
|
)
|
|
133398
133600
|
};
|
|
133399
133601
|
};
|
|
@@ -133539,7 +133741,7 @@ function attachingProviderCredential(route, deps) {
|
|
|
133539
133741
|
headroomEligible: route.headroomEligible,
|
|
133540
133742
|
headroomUpstream: route.headroomUpstream,
|
|
133541
133743
|
serve: async (request7, response) => {
|
|
133542
|
-
const resolution =
|
|
133744
|
+
const resolution = await deps.resolve({ credential: deps.credential, env: deps.env, port: deps.port, subject: `provider ${deps.provider}` });
|
|
133543
133745
|
if (!resolution.ok) {
|
|
133544
133746
|
response.start(HTTP_STATUS.badGateway, { "Content-Type": "application/json" });
|
|
133545
133747
|
await response.write(
|
|
@@ -136581,7 +136783,7 @@ init_read();
|
|
|
136581
136783
|
function createRealQuotaRefresher(params) {
|
|
136582
136784
|
const { paths, store, log } = params;
|
|
136583
136785
|
return createQuotaRefresher({
|
|
136584
|
-
lookup: createProviderLookup({ fs: realFsPort, providersDir: paths.providersDir, env: process.env, credentials:
|
|
136786
|
+
lookup: createProviderLookup({ fs: realFsPort, providersDir: paths.providersDir, env: process.env, credentials: realAsyncCredentialPort }),
|
|
136585
136787
|
http: realQuotaHttpGet,
|
|
136586
136788
|
readQuota: (identity, provider) => {
|
|
136587
136789
|
try {
|
|
@@ -136699,7 +136901,7 @@ function realFrontDoorSupervisorPorts(paths, respawnGeneration, retire, trackTun
|
|
|
136699
136901
|
directPort: () => directPort,
|
|
136700
136902
|
// The same port (cache included) the launcher resolves a launch's provider with, so the credential the door attaches at the route and the one the launcher handed the child are the same resolution of the same block.
|
|
136701
136903
|
env: process.env,
|
|
136702
|
-
credentials: { ...
|
|
136904
|
+
credentials: { ...realAsyncCredentialPort, cache: realAsyncCredentialCacheEnv(paths) },
|
|
136703
136905
|
usageSnapshotOf: (identity) => identity === void 0 ? void 0 : routingSnapshots.get(identity) ?? readUsageSnapshot(realFarmFs, paths.usageSnapshotsDir, identity),
|
|
136704
136906
|
// An `acct:` model member is served by relaunch: the door leaves a move request for the session's supervisor (found across every pool's registry, since the door does not know which pool launched the session) and answers the request with what is happening. A session nothing supervises gets the message naming the command to run instead.
|
|
136705
136907
|
observations: (target) => observations.observation(target),
|
package/dist/index.cjs
CHANGED
|
@@ -4450,7 +4450,7 @@ var init_package = __esm({
|
|
|
4450
4450
|
"package.json"() {
|
|
4451
4451
|
package_default = {
|
|
4452
4452
|
name: "agent-shim",
|
|
4453
|
-
version: "11.
|
|
4453
|
+
version: "11.56.1",
|
|
4454
4454
|
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.",
|
|
4455
4455
|
license: "MIT",
|
|
4456
4456
|
author: "Joseph Mearman <joseph@mearman.co.uk>",
|
|
@@ -5737,6 +5737,9 @@ function hasDesktopSession() {
|
|
|
5737
5737
|
const result = (0, import_node_child_process2.spawnSync)("launchctl", ["managername"], { encoding: "utf8" });
|
|
5738
5738
|
return result.status === 0 && result.stdout.trim() === MACOS_GUI_SESSION_MANAGER;
|
|
5739
5739
|
}
|
|
5740
|
+
return hasDisplayServer();
|
|
5741
|
+
}
|
|
5742
|
+
function hasDisplayServer() {
|
|
5740
5743
|
if (process.platform === "win32") {
|
|
5741
5744
|
return false;
|
|
5742
5745
|
}
|
|
@@ -8308,51 +8311,77 @@ function unpackKeyringToken(raw) {
|
|
|
8308
8311
|
}
|
|
8309
8312
|
return trimmed;
|
|
8310
8313
|
}
|
|
8311
|
-
function
|
|
8312
|
-
|
|
8314
|
+
function declined(reason, warn = false) {
|
|
8315
|
+
return { ok: false, reason, warn };
|
|
8316
|
+
}
|
|
8317
|
+
function isCommandBacked(source) {
|
|
8318
|
+
return "command" in source || "op" in source || "keychain" in source;
|
|
8319
|
+
}
|
|
8320
|
+
function immediateOutcome(source, params) {
|
|
8313
8321
|
if ("env" in source) {
|
|
8314
8322
|
const value = params.env[source.env];
|
|
8315
|
-
return value === void 0 || value === "" ?
|
|
8323
|
+
return value === void 0 || value === "" ? declined("is unset or empty") : { ok: true, token: unpackKeyringToken(value) };
|
|
8316
8324
|
}
|
|
8317
8325
|
if ("literal" in source) {
|
|
8318
8326
|
return { ok: true, token: source.literal };
|
|
8319
8327
|
}
|
|
8320
|
-
|
|
8321
|
-
|
|
8322
|
-
|
|
8323
|
-
return none("does not exist");
|
|
8324
|
-
}
|
|
8325
|
-
if (read.mode !== void 0 && (read.mode & GROUP_OTHER_PERMISSION_BITS) !== 0) {
|
|
8326
|
-
return none(
|
|
8327
|
-
`is readable or writable by group or others (mode ${(read.mode & PERMISSION_BITS2).toString(OCTAL_RADIX2)}); run \`chmod 600 ${source.file}\``,
|
|
8328
|
-
true
|
|
8329
|
-
);
|
|
8330
|
-
}
|
|
8331
|
-
const token2 = unpackKeyringToken(read.content.trim());
|
|
8332
|
-
return token2 === "" ? none("is empty") : { ok: true, token: token2 };
|
|
8328
|
+
const read = params.port.readSecretFile(source.file);
|
|
8329
|
+
if (!read.found) {
|
|
8330
|
+
return declined("does not exist");
|
|
8333
8331
|
}
|
|
8334
|
-
|
|
8335
|
-
|
|
8336
|
-
|
|
8337
|
-
|
|
8332
|
+
if (read.mode !== void 0 && (read.mode & GROUP_OTHER_PERMISSION_BITS) !== 0) {
|
|
8333
|
+
return declined(
|
|
8334
|
+
`is readable or writable by group or others (mode ${(read.mode & PERMISSION_BITS2).toString(OCTAL_RADIX2)}); run \`chmod 600 ${source.file}\``,
|
|
8335
|
+
true
|
|
8336
|
+
);
|
|
8338
8337
|
}
|
|
8339
|
-
const
|
|
8340
|
-
|
|
8338
|
+
const token = unpackKeyringToken(read.content.trim());
|
|
8339
|
+
return token === "" ? declined("is empty") : { ok: true, token };
|
|
8340
|
+
}
|
|
8341
|
+
function commandRunOf(source, env) {
|
|
8342
|
+
const interactive = isInteractiveSource(source, env);
|
|
8343
|
+
return { argv: commandArgv(source), interactive, timeoutMs: source.timeoutMs ?? (interactive ? CREDENTIAL_INTERACTIVE_TIMEOUT_MS : CREDENTIAL_COMMAND_TIMEOUT_MS) };
|
|
8344
|
+
}
|
|
8345
|
+
function commandOutcome(result, timeoutMs) {
|
|
8341
8346
|
if (result.timedOut) {
|
|
8342
|
-
return
|
|
8347
|
+
return declined(`timed out after ${String(timeoutMs)}ms`);
|
|
8343
8348
|
}
|
|
8344
8349
|
if (result.status !== 0) {
|
|
8345
8350
|
const stderr = result.stderr.trim();
|
|
8346
8351
|
const outcome = result.status === null ? "could not be run or was killed by a signal" : `exited with status ${String(result.status)}`;
|
|
8347
|
-
return
|
|
8352
|
+
return declined(`${outcome}${stderr === "" ? "" : `: ${stderr}`}`);
|
|
8348
8353
|
}
|
|
8349
8354
|
const token = unpackKeyringToken(result.stdout.trim());
|
|
8350
|
-
return token === "" ?
|
|
8355
|
+
return token === "" ? declined("printed no token") : { ok: true, token };
|
|
8356
|
+
}
|
|
8357
|
+
function trySource(source, params) {
|
|
8358
|
+
if (!isCommandBacked(source)) {
|
|
8359
|
+
return immediateOutcome(source, params);
|
|
8360
|
+
}
|
|
8361
|
+
const run = commandRunOf(source, params.env);
|
|
8362
|
+
if (run.interactive && !params.port.personPresent()) {
|
|
8363
|
+
return declined(NO_PERSON_REASON);
|
|
8364
|
+
}
|
|
8365
|
+
return commandOutcome(params.port.runCommand(run.argv, { timeoutMs: run.timeoutMs, interactive: run.interactive }), run.timeoutMs);
|
|
8351
8366
|
}
|
|
8352
8367
|
function warmCommandFor(subject) {
|
|
8353
8368
|
const [kind, name] = subject.split(" ");
|
|
8354
8369
|
return kind === "provider" ? `agent-shim credential warm --provider ${name ?? ""}` : `agent-shim credential warm ${name ?? ""}`;
|
|
8355
8370
|
}
|
|
8371
|
+
function cachedResolution(target, entry) {
|
|
8372
|
+
return { ok: true, credential: { target, token: entry.token, source: entry.source, warnings: [], cachedAt: entry.fetchedAt } };
|
|
8373
|
+
}
|
|
8374
|
+
function liveResolution(target, token, source, warnings) {
|
|
8375
|
+
return { ok: true, credential: { target, token, source, warnings } };
|
|
8376
|
+
}
|
|
8377
|
+
function unresolved(subject, cacheBlock, attempts) {
|
|
8378
|
+
const hint = cacheBlock === void 0 ? "" : `; fill the cache from a terminal with \`${warmCommandFor(subject)}\``;
|
|
8379
|
+
return { ok: false, message: `agent-shim: ${subject} has no usable credential: ${attempts.join("; ")}${hint}` };
|
|
8380
|
+
}
|
|
8381
|
+
function declinedLine(source, outcome, subject) {
|
|
8382
|
+
const attempt = `${describeSource(source)} ${outcome.reason}`;
|
|
8383
|
+
return { attempt, warning: outcome.warn ? `agent-shim: ${subject}: skipped ${attempt}` : void 0 };
|
|
8384
|
+
}
|
|
8356
8385
|
function resolveCredential(params) {
|
|
8357
8386
|
const target = params.credential.target ?? "bearer";
|
|
8358
8387
|
const cacheBlock = params.credential.cache;
|
|
@@ -8361,7 +8390,7 @@ function resolveCredential(params) {
|
|
|
8361
8390
|
if (cacheBlock !== void 0 && cache !== void 0 && store !== void 0 && params.refresh !== true) {
|
|
8362
8391
|
const entry = cache.port.read(store, params.subject);
|
|
8363
8392
|
if (entry !== void 0 && isFresh(entry, cacheBlock, cache.now())) {
|
|
8364
|
-
return
|
|
8393
|
+
return cachedResolution(target, entry);
|
|
8365
8394
|
}
|
|
8366
8395
|
}
|
|
8367
8396
|
const attempts = [];
|
|
@@ -8372,16 +8401,15 @@ function resolveCredential(params) {
|
|
|
8372
8401
|
if (cache !== void 0 && store !== void 0) {
|
|
8373
8402
|
cache.port.write(store, params.subject, { token: outcome.token, fetchedAt: cache.now(), source });
|
|
8374
8403
|
}
|
|
8375
|
-
return
|
|
8404
|
+
return liveResolution(target, outcome.token, source, warnings);
|
|
8376
8405
|
}
|
|
8377
|
-
const line =
|
|
8378
|
-
attempts.push(line);
|
|
8379
|
-
if (
|
|
8380
|
-
warnings.push(
|
|
8406
|
+
const line = declinedLine(source, outcome, params.subject);
|
|
8407
|
+
attempts.push(line.attempt);
|
|
8408
|
+
if (line.warning !== void 0) {
|
|
8409
|
+
warnings.push(line.warning);
|
|
8381
8410
|
}
|
|
8382
8411
|
}
|
|
8383
|
-
|
|
8384
|
-
return { ok: false, message: `agent-shim: ${params.subject} has no usable credential: ${attempts.join("; ")}${hint}` };
|
|
8412
|
+
return unresolved(params.subject, cacheBlock, attempts);
|
|
8385
8413
|
}
|
|
8386
8414
|
function credentialVariables(target, token) {
|
|
8387
8415
|
return {
|
|
@@ -8390,7 +8418,7 @@ function credentialVariables(target, token) {
|
|
|
8390
8418
|
CLAUDE_CODE_OAUTH_TOKEN: target === "oauthToken" ? token : void 0
|
|
8391
8419
|
};
|
|
8392
8420
|
}
|
|
8393
|
-
var CREDENTIAL_UNAVAILABLE_EXIT, CREDENTIAL_COMMAND_TIMEOUT_MS, CREDENTIAL_INTERACTIVE_TIMEOUT_MS, GROUP_OTHER_PERMISSION_BITS, PERMISSION_BITS2, OCTAL_RADIX2, GO_KEYRING_BASE64_PREFIX;
|
|
8421
|
+
var CREDENTIAL_UNAVAILABLE_EXIT, CREDENTIAL_COMMAND_TIMEOUT_MS, CREDENTIAL_INTERACTIVE_TIMEOUT_MS, GROUP_OTHER_PERMISSION_BITS, PERMISSION_BITS2, OCTAL_RADIX2, GO_KEYRING_BASE64_PREFIX, NO_PERSON_REASON;
|
|
8394
8422
|
var init_credential = __esm({
|
|
8395
8423
|
"src/credential.ts"() {
|
|
8396
8424
|
"use strict";
|
|
@@ -8402,6 +8430,7 @@ var init_credential = __esm({
|
|
|
8402
8430
|
PERMISSION_BITS2 = 511;
|
|
8403
8431
|
OCTAL_RADIX2 = 8;
|
|
8404
8432
|
GO_KEYRING_BASE64_PREFIX = "go-keyring-base64:";
|
|
8433
|
+
NO_PERSON_REASON = "needs a person to approve it, but there is no terminal or desktop session";
|
|
8405
8434
|
}
|
|
8406
8435
|
});
|
|
8407
8436
|
|
|
@@ -11498,13 +11527,13 @@ function resolveLaunch(params) {
|
|
|
11498
11527
|
environment
|
|
11499
11528
|
};
|
|
11500
11529
|
}
|
|
11501
|
-
function runLaunchPlan(plan,
|
|
11530
|
+
function runLaunchPlan(plan, spawn4) {
|
|
11502
11531
|
try {
|
|
11503
11532
|
if (plan.hold() === "cancelled") {
|
|
11504
11533
|
return LAUNCH_CANCELLED_EXIT;
|
|
11505
11534
|
}
|
|
11506
11535
|
plan.markChildStarted();
|
|
11507
|
-
const result =
|
|
11536
|
+
const result = spawn4.spawnSync(plan.bin, plan.args, { stdio: "inherit", env: plan.env });
|
|
11508
11537
|
if (result.error !== void 0) {
|
|
11509
11538
|
throw result.error;
|
|
11510
11539
|
}
|
|
@@ -11597,8 +11626,11 @@ var init_doorLog = __esm({
|
|
|
11597
11626
|
});
|
|
11598
11627
|
|
|
11599
11628
|
// src/frontdoor/selfIdentity.ts
|
|
11629
|
+
function isDeclaredFrontDoor(pid) {
|
|
11630
|
+
return declaredPid !== void 0 && pid === declaredPid && pid === process.pid;
|
|
11631
|
+
}
|
|
11600
11632
|
function isFrontDoorSupervisorPid(pid, identify) {
|
|
11601
|
-
return
|
|
11633
|
+
return isDeclaredFrontDoor(pid) || identify(pid);
|
|
11602
11634
|
}
|
|
11603
11635
|
var declaredPid;
|
|
11604
11636
|
var init_selfIdentity = __esm({
|
|
@@ -11649,7 +11681,8 @@ var init_trust = __esm({
|
|
|
11649
11681
|
function realEnsurePorts(paths, spawnDaemon) {
|
|
11650
11682
|
return {
|
|
11651
11683
|
fs: realFarmFs,
|
|
11652
|
-
|
|
11684
|
+
// The door plans launches of its own (the usage probe, the window opener, jobs), and asked whether the supervisor the state file names is running, the answer for itself is known: a synchronous `ps` here would hold the loop that answers every session.
|
|
11685
|
+
isRunning: (pid) => isDeclaredFrontDoor(pid) || realIsProcessRunning(pid),
|
|
11653
11686
|
now: () => Date.now(),
|
|
11654
11687
|
sleep: realSleepSync,
|
|
11655
11688
|
spawnSupervisor: (layout) => spawnDaemon(layout, "__frontdoor-supervisor", layout.frontdoorLogPath),
|
package/dist/index.mjs
CHANGED
|
@@ -4426,7 +4426,7 @@ var init_package = __esm({
|
|
|
4426
4426
|
"package.json"() {
|
|
4427
4427
|
package_default = {
|
|
4428
4428
|
name: "agent-shim",
|
|
4429
|
-
version: "11.
|
|
4429
|
+
version: "11.56.1",
|
|
4430
4430
|
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.",
|
|
4431
4431
|
license: "MIT",
|
|
4432
4432
|
author: "Joseph Mearman <joseph@mearman.co.uk>",
|
|
@@ -5718,6 +5718,9 @@ function hasDesktopSession() {
|
|
|
5718
5718
|
const result = spawnSync("launchctl", ["managername"], { encoding: "utf8" });
|
|
5719
5719
|
return result.status === 0 && result.stdout.trim() === MACOS_GUI_SESSION_MANAGER;
|
|
5720
5720
|
}
|
|
5721
|
+
return hasDisplayServer();
|
|
5722
|
+
}
|
|
5723
|
+
function hasDisplayServer() {
|
|
5721
5724
|
if (process.platform === "win32") {
|
|
5722
5725
|
return false;
|
|
5723
5726
|
}
|
|
@@ -8053,7 +8056,7 @@ var init_credentialCache = __esm({
|
|
|
8053
8056
|
});
|
|
8054
8057
|
|
|
8055
8058
|
// src/realCredentialCache.ts
|
|
8056
|
-
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
8059
|
+
import { spawn as spawn3, spawnSync as spawnSync2 } from "node:child_process";
|
|
8057
8060
|
import fs6 from "node:fs";
|
|
8058
8061
|
import path24 from "node:path";
|
|
8059
8062
|
function cacheFileNameFor(owner) {
|
|
@@ -8280,51 +8283,77 @@ function unpackKeyringToken(raw) {
|
|
|
8280
8283
|
}
|
|
8281
8284
|
return trimmed;
|
|
8282
8285
|
}
|
|
8283
|
-
function
|
|
8284
|
-
|
|
8286
|
+
function declined(reason, warn = false) {
|
|
8287
|
+
return { ok: false, reason, warn };
|
|
8288
|
+
}
|
|
8289
|
+
function isCommandBacked(source) {
|
|
8290
|
+
return "command" in source || "op" in source || "keychain" in source;
|
|
8291
|
+
}
|
|
8292
|
+
function immediateOutcome(source, params) {
|
|
8285
8293
|
if ("env" in source) {
|
|
8286
8294
|
const value = params.env[source.env];
|
|
8287
|
-
return value === void 0 || value === "" ?
|
|
8295
|
+
return value === void 0 || value === "" ? declined("is unset or empty") : { ok: true, token: unpackKeyringToken(value) };
|
|
8288
8296
|
}
|
|
8289
8297
|
if ("literal" in source) {
|
|
8290
8298
|
return { ok: true, token: source.literal };
|
|
8291
8299
|
}
|
|
8292
|
-
|
|
8293
|
-
|
|
8294
|
-
|
|
8295
|
-
return none("does not exist");
|
|
8296
|
-
}
|
|
8297
|
-
if (read.mode !== void 0 && (read.mode & GROUP_OTHER_PERMISSION_BITS) !== 0) {
|
|
8298
|
-
return none(
|
|
8299
|
-
`is readable or writable by group or others (mode ${(read.mode & PERMISSION_BITS2).toString(OCTAL_RADIX2)}); run \`chmod 600 ${source.file}\``,
|
|
8300
|
-
true
|
|
8301
|
-
);
|
|
8302
|
-
}
|
|
8303
|
-
const token2 = unpackKeyringToken(read.content.trim());
|
|
8304
|
-
return token2 === "" ? none("is empty") : { ok: true, token: token2 };
|
|
8300
|
+
const read = params.port.readSecretFile(source.file);
|
|
8301
|
+
if (!read.found) {
|
|
8302
|
+
return declined("does not exist");
|
|
8305
8303
|
}
|
|
8306
|
-
|
|
8307
|
-
|
|
8308
|
-
|
|
8309
|
-
|
|
8304
|
+
if (read.mode !== void 0 && (read.mode & GROUP_OTHER_PERMISSION_BITS) !== 0) {
|
|
8305
|
+
return declined(
|
|
8306
|
+
`is readable or writable by group or others (mode ${(read.mode & PERMISSION_BITS2).toString(OCTAL_RADIX2)}); run \`chmod 600 ${source.file}\``,
|
|
8307
|
+
true
|
|
8308
|
+
);
|
|
8310
8309
|
}
|
|
8311
|
-
const
|
|
8312
|
-
|
|
8310
|
+
const token = unpackKeyringToken(read.content.trim());
|
|
8311
|
+
return token === "" ? declined("is empty") : { ok: true, token };
|
|
8312
|
+
}
|
|
8313
|
+
function commandRunOf(source, env) {
|
|
8314
|
+
const interactive = isInteractiveSource(source, env);
|
|
8315
|
+
return { argv: commandArgv(source), interactive, timeoutMs: source.timeoutMs ?? (interactive ? CREDENTIAL_INTERACTIVE_TIMEOUT_MS : CREDENTIAL_COMMAND_TIMEOUT_MS) };
|
|
8316
|
+
}
|
|
8317
|
+
function commandOutcome(result, timeoutMs) {
|
|
8313
8318
|
if (result.timedOut) {
|
|
8314
|
-
return
|
|
8319
|
+
return declined(`timed out after ${String(timeoutMs)}ms`);
|
|
8315
8320
|
}
|
|
8316
8321
|
if (result.status !== 0) {
|
|
8317
8322
|
const stderr = result.stderr.trim();
|
|
8318
8323
|
const outcome = result.status === null ? "could not be run or was killed by a signal" : `exited with status ${String(result.status)}`;
|
|
8319
|
-
return
|
|
8324
|
+
return declined(`${outcome}${stderr === "" ? "" : `: ${stderr}`}`);
|
|
8320
8325
|
}
|
|
8321
8326
|
const token = unpackKeyringToken(result.stdout.trim());
|
|
8322
|
-
return token === "" ?
|
|
8327
|
+
return token === "" ? declined("printed no token") : { ok: true, token };
|
|
8328
|
+
}
|
|
8329
|
+
function trySource(source, params) {
|
|
8330
|
+
if (!isCommandBacked(source)) {
|
|
8331
|
+
return immediateOutcome(source, params);
|
|
8332
|
+
}
|
|
8333
|
+
const run = commandRunOf(source, params.env);
|
|
8334
|
+
if (run.interactive && !params.port.personPresent()) {
|
|
8335
|
+
return declined(NO_PERSON_REASON);
|
|
8336
|
+
}
|
|
8337
|
+
return commandOutcome(params.port.runCommand(run.argv, { timeoutMs: run.timeoutMs, interactive: run.interactive }), run.timeoutMs);
|
|
8323
8338
|
}
|
|
8324
8339
|
function warmCommandFor(subject) {
|
|
8325
8340
|
const [kind, name] = subject.split(" ");
|
|
8326
8341
|
return kind === "provider" ? `agent-shim credential warm --provider ${name ?? ""}` : `agent-shim credential warm ${name ?? ""}`;
|
|
8327
8342
|
}
|
|
8343
|
+
function cachedResolution(target, entry) {
|
|
8344
|
+
return { ok: true, credential: { target, token: entry.token, source: entry.source, warnings: [], cachedAt: entry.fetchedAt } };
|
|
8345
|
+
}
|
|
8346
|
+
function liveResolution(target, token, source, warnings) {
|
|
8347
|
+
return { ok: true, credential: { target, token, source, warnings } };
|
|
8348
|
+
}
|
|
8349
|
+
function unresolved(subject, cacheBlock, attempts) {
|
|
8350
|
+
const hint = cacheBlock === void 0 ? "" : `; fill the cache from a terminal with \`${warmCommandFor(subject)}\``;
|
|
8351
|
+
return { ok: false, message: `agent-shim: ${subject} has no usable credential: ${attempts.join("; ")}${hint}` };
|
|
8352
|
+
}
|
|
8353
|
+
function declinedLine(source, outcome, subject) {
|
|
8354
|
+
const attempt = `${describeSource(source)} ${outcome.reason}`;
|
|
8355
|
+
return { attempt, warning: outcome.warn ? `agent-shim: ${subject}: skipped ${attempt}` : void 0 };
|
|
8356
|
+
}
|
|
8328
8357
|
function resolveCredential(params) {
|
|
8329
8358
|
const target = params.credential.target ?? "bearer";
|
|
8330
8359
|
const cacheBlock = params.credential.cache;
|
|
@@ -8333,7 +8362,7 @@ function resolveCredential(params) {
|
|
|
8333
8362
|
if (cacheBlock !== void 0 && cache !== void 0 && store !== void 0 && params.refresh !== true) {
|
|
8334
8363
|
const entry = cache.port.read(store, params.subject);
|
|
8335
8364
|
if (entry !== void 0 && isFresh(entry, cacheBlock, cache.now())) {
|
|
8336
|
-
return
|
|
8365
|
+
return cachedResolution(target, entry);
|
|
8337
8366
|
}
|
|
8338
8367
|
}
|
|
8339
8368
|
const attempts = [];
|
|
@@ -8344,16 +8373,15 @@ function resolveCredential(params) {
|
|
|
8344
8373
|
if (cache !== void 0 && store !== void 0) {
|
|
8345
8374
|
cache.port.write(store, params.subject, { token: outcome.token, fetchedAt: cache.now(), source });
|
|
8346
8375
|
}
|
|
8347
|
-
return
|
|
8376
|
+
return liveResolution(target, outcome.token, source, warnings);
|
|
8348
8377
|
}
|
|
8349
|
-
const line =
|
|
8350
|
-
attempts.push(line);
|
|
8351
|
-
if (
|
|
8352
|
-
warnings.push(
|
|
8378
|
+
const line = declinedLine(source, outcome, params.subject);
|
|
8379
|
+
attempts.push(line.attempt);
|
|
8380
|
+
if (line.warning !== void 0) {
|
|
8381
|
+
warnings.push(line.warning);
|
|
8353
8382
|
}
|
|
8354
8383
|
}
|
|
8355
|
-
|
|
8356
|
-
return { ok: false, message: `agent-shim: ${params.subject} has no usable credential: ${attempts.join("; ")}${hint}` };
|
|
8384
|
+
return unresolved(params.subject, cacheBlock, attempts);
|
|
8357
8385
|
}
|
|
8358
8386
|
function credentialVariables(target, token) {
|
|
8359
8387
|
return {
|
|
@@ -8362,7 +8390,7 @@ function credentialVariables(target, token) {
|
|
|
8362
8390
|
CLAUDE_CODE_OAUTH_TOKEN: target === "oauthToken" ? token : void 0
|
|
8363
8391
|
};
|
|
8364
8392
|
}
|
|
8365
|
-
var CREDENTIAL_UNAVAILABLE_EXIT, CREDENTIAL_COMMAND_TIMEOUT_MS, CREDENTIAL_INTERACTIVE_TIMEOUT_MS, GROUP_OTHER_PERMISSION_BITS, PERMISSION_BITS2, OCTAL_RADIX2, GO_KEYRING_BASE64_PREFIX;
|
|
8393
|
+
var CREDENTIAL_UNAVAILABLE_EXIT, CREDENTIAL_COMMAND_TIMEOUT_MS, CREDENTIAL_INTERACTIVE_TIMEOUT_MS, GROUP_OTHER_PERMISSION_BITS, PERMISSION_BITS2, OCTAL_RADIX2, GO_KEYRING_BASE64_PREFIX, NO_PERSON_REASON;
|
|
8366
8394
|
var init_credential = __esm({
|
|
8367
8395
|
"src/credential.ts"() {
|
|
8368
8396
|
"use strict";
|
|
@@ -8374,6 +8402,7 @@ var init_credential = __esm({
|
|
|
8374
8402
|
PERMISSION_BITS2 = 511;
|
|
8375
8403
|
OCTAL_RADIX2 = 8;
|
|
8376
8404
|
GO_KEYRING_BASE64_PREFIX = "go-keyring-base64:";
|
|
8405
|
+
NO_PERSON_REASON = "needs a person to approve it, but there is no terminal or desktop session";
|
|
8377
8406
|
}
|
|
8378
8407
|
});
|
|
8379
8408
|
|
|
@@ -11472,13 +11501,13 @@ function resolveLaunch(params) {
|
|
|
11472
11501
|
environment
|
|
11473
11502
|
};
|
|
11474
11503
|
}
|
|
11475
|
-
function runLaunchPlan(plan,
|
|
11504
|
+
function runLaunchPlan(plan, spawn4) {
|
|
11476
11505
|
try {
|
|
11477
11506
|
if (plan.hold() === "cancelled") {
|
|
11478
11507
|
return LAUNCH_CANCELLED_EXIT;
|
|
11479
11508
|
}
|
|
11480
11509
|
plan.markChildStarted();
|
|
11481
|
-
const result =
|
|
11510
|
+
const result = spawn4.spawnSync(plan.bin, plan.args, { stdio: "inherit", env: plan.env });
|
|
11482
11511
|
if (result.error !== void 0) {
|
|
11483
11512
|
throw result.error;
|
|
11484
11513
|
}
|
|
@@ -11566,8 +11595,11 @@ var init_doorLog = __esm({
|
|
|
11566
11595
|
});
|
|
11567
11596
|
|
|
11568
11597
|
// src/frontdoor/selfIdentity.ts
|
|
11598
|
+
function isDeclaredFrontDoor(pid) {
|
|
11599
|
+
return declaredPid !== void 0 && pid === declaredPid && pid === process.pid;
|
|
11600
|
+
}
|
|
11569
11601
|
function isFrontDoorSupervisorPid(pid, identify) {
|
|
11570
|
-
return
|
|
11602
|
+
return isDeclaredFrontDoor(pid) || identify(pid);
|
|
11571
11603
|
}
|
|
11572
11604
|
var declaredPid;
|
|
11573
11605
|
var init_selfIdentity = __esm({
|
|
@@ -11619,7 +11651,8 @@ import fs13 from "node:fs";
|
|
|
11619
11651
|
function realEnsurePorts(paths, spawnDaemon) {
|
|
11620
11652
|
return {
|
|
11621
11653
|
fs: realFarmFs,
|
|
11622
|
-
|
|
11654
|
+
// The door plans launches of its own (the usage probe, the window opener, jobs), and asked whether the supervisor the state file names is running, the answer for itself is known: a synchronous `ps` here would hold the loop that answers every session.
|
|
11655
|
+
isRunning: (pid) => isDeclaredFrontDoor(pid) || realIsProcessRunning(pid),
|
|
11623
11656
|
now: () => Date.now(),
|
|
11624
11657
|
sleep: realSleepSync,
|
|
11625
11658
|
spawnSupervisor: (layout) => spawnDaemon(layout, "__frontdoor-supervisor", layout.frontdoorLogPath),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agent-shim",
|
|
3
|
-
"version": "11.
|
|
3
|
+
"version": "11.56.1",
|
|
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>",
|