agent-shim 8.22.0 → 8.23.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/cli.cjs +117 -6
- package/dist/index.cjs +200 -2
- package/dist/index.mjs +200 -2
- package/dist/types/index.d.ts +45 -9
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -145,7 +145,7 @@ agent-shim frontdoor rc watch [<cse_id>] [--json]
|
|
|
145
145
|
agent-shim frontdoor rc selfhost mint <identity> [--force] [--json]
|
|
146
146
|
agent-shim usage [--identity <name>] [--provider <name>] [--since <duration>] [--refresh] [--json]
|
|
147
147
|
agent-shim account show [<identity>] [--refresh] [--json]
|
|
148
|
-
agent-shim update [--check] [--json]
|
|
148
|
+
agent-shim update [--check] [--mode <off|notify|auto>] [--json]
|
|
149
149
|
agent-shim completion <bash|zsh|fish>
|
|
150
150
|
agent-shim shim enable [--dir <path>] [--force]
|
|
151
151
|
agent-shim shim disable [--dir <path>] [--force]
|
package/dist/cli.cjs
CHANGED
|
@@ -55361,6 +55361,11 @@ var FrontDoorGlobalConfigSchema = external_exports.strictObject({
|
|
|
55361
55361
|
/** How long the front door may sit with no registered sessions before it closes and exits. Defaults to FRONTDOOR_DEFAULT_IDLE_SHUTDOWN_MINUTES. */
|
|
55362
55362
|
idleShutdownMinutes: external_exports.number().int().positive().optional()
|
|
55363
55363
|
});
|
|
55364
|
+
var UPDATE_MODES = ["off", "notify", "auto"];
|
|
55365
|
+
var UpdateGlobalConfigSchema = external_exports.strictObject({
|
|
55366
|
+
/** What a launch does about a newer release of agent-shim itself; see `UPDATE_MODES`. Absent means `off`. */
|
|
55367
|
+
mode: external_exports.enum(UPDATE_MODES).optional()
|
|
55368
|
+
});
|
|
55364
55369
|
var GlobalConfigSchema = external_exports.strictObject({
|
|
55365
55370
|
$schema: external_exports.string().optional(),
|
|
55366
55371
|
defaultConfigProfile: external_exports.string().min(1).optional(),
|
|
@@ -55370,6 +55375,7 @@ var GlobalConfigSchema = external_exports.strictObject({
|
|
|
55370
55375
|
launch: LaunchSchema.optional(),
|
|
55371
55376
|
headroom: HeadroomGlobalConfigSchema.optional(),
|
|
55372
55377
|
frontdoor: FrontDoorGlobalConfigSchema.optional(),
|
|
55378
|
+
update: UpdateGlobalConfigSchema.optional(),
|
|
55373
55379
|
pools: external_exports.record(PoolNameSchema, PoolSchema).optional()
|
|
55374
55380
|
});
|
|
55375
55381
|
var IdentitySchema = external_exports.strictObject({
|
|
@@ -61790,7 +61796,7 @@ function registerIdentityCommand(program2, deps) {
|
|
|
61790
61796
|
// package.json
|
|
61791
61797
|
var package_default = {
|
|
61792
61798
|
name: "agent-shim",
|
|
61793
|
-
version: "8.
|
|
61799
|
+
version: "8.23.0",
|
|
61794
61800
|
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.",
|
|
61795
61801
|
license: "MIT",
|
|
61796
61802
|
author: "Joseph Mearman <joseph@mearman.co.uk>",
|
|
@@ -77539,6 +77545,7 @@ function registerRunCommand(program2, handler) {
|
|
|
77539
77545
|
}
|
|
77540
77546
|
|
|
77541
77547
|
// src/update/commands.ts
|
|
77548
|
+
var import_node_child_process7 = require("node:child_process");
|
|
77542
77549
|
var import_node_fs17 = __toESM(require("node:fs"), 1);
|
|
77543
77550
|
var import_node_os7 = __toESM(require("node:os"), 1);
|
|
77544
77551
|
var import_node_path41 = __toESM(require("node:path"), 1);
|
|
@@ -77874,11 +77881,41 @@ function formatUpdateReport(report) {
|
|
|
77874
77881
|
return report.action;
|
|
77875
77882
|
}
|
|
77876
77883
|
}
|
|
77884
|
+
function setUpdateMode(paths, mode) {
|
|
77885
|
+
const existing = readGlobalConfig(paths);
|
|
77886
|
+
applyPatch(paths.globalConfigFile, GlobalConfigSchema, { update: { ...existing?.update, mode } }, { defaults: {} });
|
|
77887
|
+
}
|
|
77888
|
+
function realLaunchUpdatePort(paths) {
|
|
77889
|
+
return {
|
|
77890
|
+
effectiveUrl: realUpdatePorts.http.effectiveUrl,
|
|
77891
|
+
readStamp: (filePath) => realUpdatePorts.fs.readFileUtf8(filePath),
|
|
77892
|
+
writeStamp: (filePath, contents) => {
|
|
77893
|
+
writeTextAtomic(filePath, contents);
|
|
77894
|
+
},
|
|
77895
|
+
now: () => Date.now(),
|
|
77896
|
+
spawnDetached: (args) => {
|
|
77897
|
+
const invocation = selfInvocation(args);
|
|
77898
|
+
const child = (0, import_node_child_process7.spawn)(invocation.command, invocation.args, { detached: true, stdio: "ignore", env: { ...process.env, AGENT_SHIM_HOME: paths.root } });
|
|
77899
|
+
child.unref();
|
|
77900
|
+
},
|
|
77901
|
+
writeErr: (line) => {
|
|
77902
|
+
console.error(line);
|
|
77903
|
+
}
|
|
77904
|
+
};
|
|
77905
|
+
}
|
|
77877
77906
|
function registerUpdateCommand(program2, deps, ports = realUpdatePorts) {
|
|
77878
77907
|
withExamples(
|
|
77879
77908
|
program2.command("update").description(
|
|
77880
|
-
"Download the newest release binary and install it over the running one. An installation that belongs to a package manager (Homebrew, npm, Scoop) names its channel and its upgrade command instead of updating in place."
|
|
77881
|
-
).option("--check", "Only report whether a newer release exists; download and change nothing.").option("--json", "Print the result as JSON.").action(async (options) => {
|
|
77909
|
+
"Download the newest release binary and install it over the running one. An installation that belongs to a package manager (Homebrew, npm, Scoop) names its channel and its upgrade command instead of updating in place. With --mode, set the launch-time update mode in the global config instead of updating now."
|
|
77910
|
+
).option("--check", "Only report whether a newer release exists; download and change nothing.").addOption(new Option("--mode <mode>", "Set what a launch does about a newer release (off: nothing; notify: print one line; auto: also apply it in the background) in the global config, then exit.").choices(UPDATE_MODES)).option("--json", "Print the result as JSON.").action(async (options) => {
|
|
77911
|
+
const mode = options.mode;
|
|
77912
|
+
if (mode !== void 0) {
|
|
77913
|
+
setUpdateMode(deps.paths, mode);
|
|
77914
|
+
reportMutation(options.json, { action: "updated", kind: "update", name: "mode", value: { mode } }, () => {
|
|
77915
|
+
console.log(`update mode set to ${mode}`);
|
|
77916
|
+
});
|
|
77917
|
+
return;
|
|
77918
|
+
}
|
|
77882
77919
|
const report = await runSelfUpdate(ports, {
|
|
77883
77920
|
currentVersion: package_default.version,
|
|
77884
77921
|
platform: process.platform,
|
|
@@ -77894,7 +77931,7 @@ function registerUpdateCommand(program2, deps, ports = realUpdatePorts) {
|
|
|
77894
77931
|
}
|
|
77895
77932
|
console.log(formatUpdateReport(report));
|
|
77896
77933
|
}),
|
|
77897
|
-
["agent-shim update", "agent-shim update --check", "agent-shim update --json"]
|
|
77934
|
+
["agent-shim update", "agent-shim update --check", "agent-shim update --mode auto", "agent-shim update --json"]
|
|
77898
77935
|
);
|
|
77899
77936
|
}
|
|
77900
77937
|
|
|
@@ -78479,6 +78516,68 @@ function spawnClaude(params) {
|
|
|
78479
78516
|
return params.proc.exit(exitCodeFor(result));
|
|
78480
78517
|
}
|
|
78481
78518
|
|
|
78519
|
+
// src/update/launchHook.ts
|
|
78520
|
+
var UPDATE_CHECK_COOLDOWN_MS = 864e5;
|
|
78521
|
+
function resolveUpdateMode(globalConfig2) {
|
|
78522
|
+
return globalConfig2?.update?.mode ?? "off";
|
|
78523
|
+
}
|
|
78524
|
+
function updateCheckDue(contents, nowMs, cooldownMs = UPDATE_CHECK_COOLDOWN_MS) {
|
|
78525
|
+
if (contents === void 0) {
|
|
78526
|
+
return true;
|
|
78527
|
+
}
|
|
78528
|
+
const checkedAt = Date.parse(contents.trim());
|
|
78529
|
+
if (Number.isNaN(checkedAt)) {
|
|
78530
|
+
return true;
|
|
78531
|
+
}
|
|
78532
|
+
const age = nowMs - checkedAt;
|
|
78533
|
+
return age < 0 || age >= cooldownMs;
|
|
78534
|
+
}
|
|
78535
|
+
var NOOP_HANDLE = { markChildStarted: () => void 0 };
|
|
78536
|
+
function updateNotifyLine(currentVersion, latest) {
|
|
78537
|
+
return `agent-shim: update available: ${currentVersion} -> ${latest} (run \`agent-shim update\` to install it)`;
|
|
78538
|
+
}
|
|
78539
|
+
function runLaunchUpdateCheck(params) {
|
|
78540
|
+
const { mode, checkPath, currentVersion, port } = params;
|
|
78541
|
+
if (mode === "off" || port === void 0) {
|
|
78542
|
+
return NOOP_HANDLE;
|
|
78543
|
+
}
|
|
78544
|
+
let childStarted = false;
|
|
78545
|
+
try {
|
|
78546
|
+
if (!updateCheckDue(port.readStamp(checkPath), port.now())) {
|
|
78547
|
+
return NOOP_HANDLE;
|
|
78548
|
+
}
|
|
78549
|
+
port.writeStamp(checkPath, new Date(port.now()).toISOString());
|
|
78550
|
+
} catch {
|
|
78551
|
+
return NOOP_HANDLE;
|
|
78552
|
+
}
|
|
78553
|
+
const answer = (url2) => {
|
|
78554
|
+
try {
|
|
78555
|
+
const latest = releaseTagFromUrl(url2);
|
|
78556
|
+
if (latest === void 0 || compareVersions3(latest, currentVersion) <= 0) {
|
|
78557
|
+
return;
|
|
78558
|
+
}
|
|
78559
|
+
if (mode === "auto") {
|
|
78560
|
+
port.spawnDetached(["update"]);
|
|
78561
|
+
}
|
|
78562
|
+
if (!childStarted) {
|
|
78563
|
+
port.writeErr(updateNotifyLine(currentVersion, latest));
|
|
78564
|
+
}
|
|
78565
|
+
} catch {
|
|
78566
|
+
}
|
|
78567
|
+
};
|
|
78568
|
+
port.effectiveUrl(LATEST_RELEASE_URL).then(
|
|
78569
|
+
(url2) => {
|
|
78570
|
+
answer(url2);
|
|
78571
|
+
},
|
|
78572
|
+
() => void 0
|
|
78573
|
+
);
|
|
78574
|
+
return {
|
|
78575
|
+
markChildStarted: () => {
|
|
78576
|
+
childStarted = true;
|
|
78577
|
+
}
|
|
78578
|
+
};
|
|
78579
|
+
}
|
|
78580
|
+
|
|
78482
78581
|
// src/launcher.ts
|
|
78483
78582
|
function resolveIdentityCredential(identity, credential, env, port) {
|
|
78484
78583
|
if (port === void 0) {
|
|
@@ -78644,6 +78743,12 @@ function prepareLaunch(params) {
|
|
|
78644
78743
|
log.info(
|
|
78645
78744
|
`agent-shim: identity ${identityDecision.name ?? "(none)"} (${identityDecision.source}${poolExplanation === void 0 ? "" : `, ${poolExplanation}`}), config profile ${configProfileDecision.name ?? "(none)"} (${configProfileDecision.source})` + (resolvedProvider === void 0 ? "" : `, provider ${resolvedProvider.name} (credential ${resolvedProvider.credential.target} from ${describeSource(resolvedProvider.credential.source)})`) + (identityCredential === void 0 ? "" : `, identity credential ${identityCredential.target} from ${describeSource(identityCredential.source)}`)
|
|
78646
78745
|
);
|
|
78746
|
+
const updateCheck = runLaunchUpdateCheck({
|
|
78747
|
+
mode: params.updateMode ?? "off",
|
|
78748
|
+
checkPath: import_node_path43.default.join(paths.root, "update.check"),
|
|
78749
|
+
currentVersion: package_default.version,
|
|
78750
|
+
port: params.update
|
|
78751
|
+
});
|
|
78647
78752
|
let cascadeLaunch;
|
|
78648
78753
|
if (farmContext !== void 0) {
|
|
78649
78754
|
const { farm: resyncFarmRuntime, identity: resyncIdentity, cascade } = farmContext;
|
|
@@ -78749,11 +78854,12 @@ function prepareLaunch(params) {
|
|
|
78749
78854
|
registered();
|
|
78750
78855
|
}
|
|
78751
78856
|
};
|
|
78752
|
-
return { bin: discovered.path, args: finalArgv, env: finalEnv, release };
|
|
78857
|
+
return { bin: discovered.path, args: finalArgv, env: finalEnv, release, markChildStarted: updateCheck.markChildStarted };
|
|
78753
78858
|
}
|
|
78754
78859
|
function runLauncher(params) {
|
|
78755
78860
|
const plan = prepareLaunch(params);
|
|
78756
78861
|
try {
|
|
78862
|
+
plan.markChildStarted();
|
|
78757
78863
|
spawnClaude({ bin: plan.bin, args: plan.args, env: plan.env, spawn: params.spawn, proc: params.proc, beforeExit: plan.release });
|
|
78758
78864
|
} finally {
|
|
78759
78865
|
plan.release();
|
|
@@ -78768,6 +78874,7 @@ function buildFarmRuntime(paths, cwd) {
|
|
|
78768
78874
|
const loaded = loadCascadeInput({ paths, home, cwd, read });
|
|
78769
78875
|
const selections = readDirectorySelections(loaded);
|
|
78770
78876
|
const git = resolveGitBranch(realRunPort, cwd);
|
|
78877
|
+
const updateMode = resolveUpdateMode(loaded.globalConfig);
|
|
78771
78878
|
return {
|
|
78772
78879
|
runtime: {
|
|
78773
78880
|
fs: realFarmFs,
|
|
@@ -78793,7 +78900,8 @@ function buildFarmRuntime(paths, cwd) {
|
|
|
78793
78900
|
...selections.identity === void 0 ? {} : { directoryIdentity: selections.identity },
|
|
78794
78901
|
...selections.configProfile === void 0 ? {} : { directoryConfigProfile: selections.configProfile },
|
|
78795
78902
|
...loaded.globalConfig?.defaultConfigProfile === void 0 ? {} : { globalDefaultConfigProfile: loaded.globalConfig.defaultConfigProfile },
|
|
78796
|
-
...loaded.globalConfig?.pools === void 0 ? {} : { pools: loaded.globalConfig.pools }
|
|
78903
|
+
...loaded.globalConfig?.pools === void 0 ? {} : { pools: loaded.globalConfig.pools },
|
|
78904
|
+
...updateMode === "off" ? {} : { updateMode }
|
|
78797
78905
|
};
|
|
78798
78906
|
}
|
|
78799
78907
|
function realClaudeBinaryResolver(paths) {
|
|
@@ -78815,6 +78923,7 @@ function realPrepareLaunchParams(paths, options) {
|
|
|
78815
78923
|
...farm.directoryConfigProfile === void 0 ? {} : { directoryRuleConfigProfile: farm.directoryConfigProfile },
|
|
78816
78924
|
...farm.globalDefaultConfigProfile === void 0 ? {} : { globalDefaultConfigProfile: farm.globalDefaultConfigProfile },
|
|
78817
78925
|
...farm.pools === void 0 ? {} : { pools: farm.pools },
|
|
78926
|
+
...farm.updateMode === void 0 ? {} : { updateMode: farm.updateMode },
|
|
78818
78927
|
...options.allowMissingConfigProfile === void 0 ? {} : { allowMissingConfigProfile: options.allowMissingConfigProfile }
|
|
78819
78928
|
};
|
|
78820
78929
|
}
|
|
@@ -78918,6 +79027,8 @@ async function runClaude(argvOverride) {
|
|
|
78918
79027
|
farm,
|
|
78919
79028
|
allowMissingConfigProfile
|
|
78920
79029
|
}),
|
|
79030
|
+
// 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.
|
|
79031
|
+
update: realLaunchUpdatePort(paths),
|
|
78921
79032
|
spawn: realSpawnPort
|
|
78922
79033
|
});
|
|
78923
79034
|
}
|
package/dist/index.cjs
CHANGED
|
@@ -640,6 +640,11 @@ var FrontDoorGlobalConfigSchema = import_zod.z.strictObject({
|
|
|
640
640
|
/** How long the front door may sit with no registered sessions before it closes and exits. Defaults to FRONTDOOR_DEFAULT_IDLE_SHUTDOWN_MINUTES. */
|
|
641
641
|
idleShutdownMinutes: import_zod.z.number().int().positive().optional()
|
|
642
642
|
});
|
|
643
|
+
var UPDATE_MODES = ["off", "notify", "auto"];
|
|
644
|
+
var UpdateGlobalConfigSchema = import_zod.z.strictObject({
|
|
645
|
+
/** What a launch does about a newer release of agent-shim itself; see `UPDATE_MODES`. Absent means `off`. */
|
|
646
|
+
mode: import_zod.z.enum(UPDATE_MODES).optional()
|
|
647
|
+
});
|
|
643
648
|
var GlobalConfigSchema = import_zod.z.strictObject({
|
|
644
649
|
$schema: import_zod.z.string().optional(),
|
|
645
650
|
defaultConfigProfile: import_zod.z.string().min(1).optional(),
|
|
@@ -649,6 +654,7 @@ var GlobalConfigSchema = import_zod.z.strictObject({
|
|
|
649
654
|
launch: LaunchSchema.optional(),
|
|
650
655
|
headroom: HeadroomGlobalConfigSchema.optional(),
|
|
651
656
|
frontdoor: FrontDoorGlobalConfigSchema.optional(),
|
|
657
|
+
update: UpdateGlobalConfigSchema.optional(),
|
|
652
658
|
pools: import_zod.z.record(PoolNameSchema, PoolSchema).optional()
|
|
653
659
|
});
|
|
654
660
|
var IdentitySchema = import_zod.z.strictObject({
|
|
@@ -11457,6 +11463,106 @@ function removeDirectoryRule(paths, rulePath) {
|
|
|
11457
11463
|
var import_node_crypto10 = require("node:crypto");
|
|
11458
11464
|
var import_node_path30 = __toESM(require("node:path"), 1);
|
|
11459
11465
|
|
|
11466
|
+
// package.json
|
|
11467
|
+
var package_default = {
|
|
11468
|
+
name: "agent-shim",
|
|
11469
|
+
version: "8.23.0",
|
|
11470
|
+
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.",
|
|
11471
|
+
license: "MIT",
|
|
11472
|
+
author: "Joseph Mearman <joseph@mearman.co.uk>",
|
|
11473
|
+
repository: {
|
|
11474
|
+
type: "git",
|
|
11475
|
+
url: "git+https://github.com/ExaDev/agent-shim.git"
|
|
11476
|
+
},
|
|
11477
|
+
homepage: "https://github.com/ExaDev/agent-shim#readme",
|
|
11478
|
+
bugs: "https://github.com/ExaDev/agent-shim/issues",
|
|
11479
|
+
keywords: [
|
|
11480
|
+
"claude-code",
|
|
11481
|
+
"claude",
|
|
11482
|
+
"cli"
|
|
11483
|
+
],
|
|
11484
|
+
packageManager: "pnpm@12.4.1+sha512.2e81e399d73fe8390dab25e06aa788ab7a5908248d2f5a370f82b481147a6a7a367bf8048f9a6fdb6460f21a66f0542dedb8b94ca2c8723596741920b1656d4c",
|
|
11485
|
+
type: "module",
|
|
11486
|
+
engines: {
|
|
11487
|
+
node: "^22.18 || >=24"
|
|
11488
|
+
},
|
|
11489
|
+
bin: {
|
|
11490
|
+
"agent-shim": "dist/cli.cjs",
|
|
11491
|
+
"claude-use": "dist/cli.cjs"
|
|
11492
|
+
},
|
|
11493
|
+
files: [
|
|
11494
|
+
"dist/cli.cjs",
|
|
11495
|
+
"dist/index.mjs",
|
|
11496
|
+
"dist/index.cjs",
|
|
11497
|
+
"dist/types"
|
|
11498
|
+
],
|
|
11499
|
+
scripts: {
|
|
11500
|
+
prepare: "husky && node scripts/build.mts --bundle-only",
|
|
11501
|
+
typecheck: "turbo run _typecheck",
|
|
11502
|
+
_typecheck: "tsc --noEmit",
|
|
11503
|
+
lint: "turbo run _lint",
|
|
11504
|
+
_lint: "eslint . --cache --cache-location .eslintcache --max-warnings 0",
|
|
11505
|
+
test: "turbo run _test",
|
|
11506
|
+
_test: "vitest run",
|
|
11507
|
+
"test:coverage": "turbo run _test:coverage",
|
|
11508
|
+
"_test:coverage": "vitest run --coverage",
|
|
11509
|
+
knip: "turbo run _knip",
|
|
11510
|
+
_knip: "knip --cache",
|
|
11511
|
+
build: "turbo run _build",
|
|
11512
|
+
_build: "node scripts/build.mts",
|
|
11513
|
+
"build:bundle": "node scripts/build.mts --bundle-only",
|
|
11514
|
+
prepublishOnly: "pnpm build:bundle",
|
|
11515
|
+
schema: "node scripts/gen-schema.mts"
|
|
11516
|
+
},
|
|
11517
|
+
dependencies: {
|
|
11518
|
+
"@clack/prompts": "^1.8.0",
|
|
11519
|
+
"@orpc/client": "1.15.4",
|
|
11520
|
+
"@orpc/server": "1.15.4",
|
|
11521
|
+
commander: "^15.0.0",
|
|
11522
|
+
cosmiconfig: "^10.0.1",
|
|
11523
|
+
picomatch: "^4.0.7",
|
|
11524
|
+
undici: "7.29.1",
|
|
11525
|
+
zod: "^4.6.1"
|
|
11526
|
+
},
|
|
11527
|
+
devDependencies: {
|
|
11528
|
+
"@commitlint/cli": "^21.2.2",
|
|
11529
|
+
"@commitlint/config-conventional": "^21.2.2",
|
|
11530
|
+
"@exadev/eslint-config": "2.12.1",
|
|
11531
|
+
"@semantic-release/changelog": "^7.0.0",
|
|
11532
|
+
"@semantic-release/git": "^11.0.1",
|
|
11533
|
+
"@semantic-release/npm": "^13.1.5",
|
|
11534
|
+
"@types/node": "^26.5.1",
|
|
11535
|
+
"@types/picomatch": "^4.0.3",
|
|
11536
|
+
"@vitest/coverage-v8": "^4.1.11",
|
|
11537
|
+
"conventional-changelog-conventionalcommits": "^10.4.0",
|
|
11538
|
+
esbuild: "^0.28.2",
|
|
11539
|
+
eslint: "^10.10.0",
|
|
11540
|
+
globals: "^17.12.0",
|
|
11541
|
+
husky: "^9.1.7",
|
|
11542
|
+
jiti: "^2.7.0",
|
|
11543
|
+
knip: "^6.35.1",
|
|
11544
|
+
"lint-staged": "^17.5.0",
|
|
11545
|
+
rollup: "4.64.0",
|
|
11546
|
+
"rollup-plugin-dts": "6.5.1",
|
|
11547
|
+
"semantic-release": "^25.0.9",
|
|
11548
|
+
turbo: "^2.11.5",
|
|
11549
|
+
typescript: "^6.0.3",
|
|
11550
|
+
"typescript-eslint": "^8.70.0",
|
|
11551
|
+
vitest: "^4.1.11"
|
|
11552
|
+
},
|
|
11553
|
+
main: "dist/index.cjs",
|
|
11554
|
+
module: "dist/index.mjs",
|
|
11555
|
+
types: "dist/types/index.d.ts",
|
|
11556
|
+
exports: {
|
|
11557
|
+
".": {
|
|
11558
|
+
types: "./dist/types/index.d.ts",
|
|
11559
|
+
import: "./dist/index.mjs",
|
|
11560
|
+
require: "./dist/index.cjs"
|
|
11561
|
+
},
|
|
11562
|
+
"./package.json": "./package.json"
|
|
11563
|
+
}
|
|
11564
|
+
};
|
|
11565
|
+
|
|
11460
11566
|
// src/launcher/argv.ts
|
|
11461
11567
|
var ConflictingIdentityError = class extends UsageError {
|
|
11462
11568
|
constructor(positional, flag) {
|
|
@@ -11929,6 +12035,88 @@ function spawnClaude(params) {
|
|
|
11929
12035
|
return params.proc.exit(exitCodeFor(result));
|
|
11930
12036
|
}
|
|
11931
12037
|
|
|
12038
|
+
// src/update/update.ts
|
|
12039
|
+
var LATEST_RELEASE_URL = "https://github.com/ExaDev/agent-shim/releases/latest";
|
|
12040
|
+
function compareVersions3(left, right) {
|
|
12041
|
+
const parse = (version) => {
|
|
12042
|
+
const match = /^(\d+)\.(\d+)\.(\d+)$/.exec(version);
|
|
12043
|
+
if (match === null) {
|
|
12044
|
+
throw new Error(`not a plain release version: ${version}`);
|
|
12045
|
+
}
|
|
12046
|
+
return [Number(match[1]), Number(match[2]), Number(match[3])];
|
|
12047
|
+
};
|
|
12048
|
+
const leftParts = parse(left);
|
|
12049
|
+
const rightParts = parse(right);
|
|
12050
|
+
return leftParts.map((part, index) => part - (rightParts[index] ?? 0)).find((difference) => difference !== 0) ?? 0;
|
|
12051
|
+
}
|
|
12052
|
+
function releaseTagFromUrl(url) {
|
|
12053
|
+
const segment = url.split("?")[0]?.split("/").at(-1);
|
|
12054
|
+
const candidate = segment?.startsWith("v") === true ? segment.slice(1) : void 0;
|
|
12055
|
+
return candidate !== void 0 && /^\d+\.\d+\.\d+$/.test(candidate) ? candidate : void 0;
|
|
12056
|
+
}
|
|
12057
|
+
|
|
12058
|
+
// src/update/launchHook.ts
|
|
12059
|
+
var UPDATE_CHECK_COOLDOWN_MS = 864e5;
|
|
12060
|
+
function resolveUpdateMode(globalConfig) {
|
|
12061
|
+
return globalConfig?.update?.mode ?? "off";
|
|
12062
|
+
}
|
|
12063
|
+
function updateCheckDue(contents, nowMs, cooldownMs = UPDATE_CHECK_COOLDOWN_MS) {
|
|
12064
|
+
if (contents === void 0) {
|
|
12065
|
+
return true;
|
|
12066
|
+
}
|
|
12067
|
+
const checkedAt = Date.parse(contents.trim());
|
|
12068
|
+
if (Number.isNaN(checkedAt)) {
|
|
12069
|
+
return true;
|
|
12070
|
+
}
|
|
12071
|
+
const age = nowMs - checkedAt;
|
|
12072
|
+
return age < 0 || age >= cooldownMs;
|
|
12073
|
+
}
|
|
12074
|
+
var NOOP_HANDLE = { markChildStarted: () => void 0 };
|
|
12075
|
+
function updateNotifyLine(currentVersion, latest) {
|
|
12076
|
+
return `agent-shim: update available: ${currentVersion} -> ${latest} (run \`agent-shim update\` to install it)`;
|
|
12077
|
+
}
|
|
12078
|
+
function runLaunchUpdateCheck(params) {
|
|
12079
|
+
const { mode, checkPath, currentVersion, port } = params;
|
|
12080
|
+
if (mode === "off" || port === void 0) {
|
|
12081
|
+
return NOOP_HANDLE;
|
|
12082
|
+
}
|
|
12083
|
+
let childStarted = false;
|
|
12084
|
+
try {
|
|
12085
|
+
if (!updateCheckDue(port.readStamp(checkPath), port.now())) {
|
|
12086
|
+
return NOOP_HANDLE;
|
|
12087
|
+
}
|
|
12088
|
+
port.writeStamp(checkPath, new Date(port.now()).toISOString());
|
|
12089
|
+
} catch {
|
|
12090
|
+
return NOOP_HANDLE;
|
|
12091
|
+
}
|
|
12092
|
+
const answer = (url) => {
|
|
12093
|
+
try {
|
|
12094
|
+
const latest = releaseTagFromUrl(url);
|
|
12095
|
+
if (latest === void 0 || compareVersions3(latest, currentVersion) <= 0) {
|
|
12096
|
+
return;
|
|
12097
|
+
}
|
|
12098
|
+
if (mode === "auto") {
|
|
12099
|
+
port.spawnDetached(["update"]);
|
|
12100
|
+
}
|
|
12101
|
+
if (!childStarted) {
|
|
12102
|
+
port.writeErr(updateNotifyLine(currentVersion, latest));
|
|
12103
|
+
}
|
|
12104
|
+
} catch {
|
|
12105
|
+
}
|
|
12106
|
+
};
|
|
12107
|
+
port.effectiveUrl(LATEST_RELEASE_URL).then(
|
|
12108
|
+
(url) => {
|
|
12109
|
+
answer(url);
|
|
12110
|
+
},
|
|
12111
|
+
() => void 0
|
|
12112
|
+
);
|
|
12113
|
+
return {
|
|
12114
|
+
markChildStarted: () => {
|
|
12115
|
+
childStarted = true;
|
|
12116
|
+
}
|
|
12117
|
+
};
|
|
12118
|
+
}
|
|
12119
|
+
|
|
11932
12120
|
// src/launcher.ts
|
|
11933
12121
|
function resolveIdentityCredential(identity, credential, env, port) {
|
|
11934
12122
|
if (port === void 0) {
|
|
@@ -12094,6 +12282,12 @@ function prepareLaunch(params) {
|
|
|
12094
12282
|
log.info(
|
|
12095
12283
|
`agent-shim: identity ${identityDecision.name ?? "(none)"} (${identityDecision.source}${poolExplanation === void 0 ? "" : `, ${poolExplanation}`}), config profile ${configProfileDecision.name ?? "(none)"} (${configProfileDecision.source})` + (resolvedProvider === void 0 ? "" : `, provider ${resolvedProvider.name} (credential ${resolvedProvider.credential.target} from ${describeSource(resolvedProvider.credential.source)})`) + (identityCredential === void 0 ? "" : `, identity credential ${identityCredential.target} from ${describeSource(identityCredential.source)}`)
|
|
12096
12284
|
);
|
|
12285
|
+
const updateCheck = runLaunchUpdateCheck({
|
|
12286
|
+
mode: params.updateMode ?? "off",
|
|
12287
|
+
checkPath: import_node_path30.default.join(paths.root, "update.check"),
|
|
12288
|
+
currentVersion: package_default.version,
|
|
12289
|
+
port: params.update
|
|
12290
|
+
});
|
|
12097
12291
|
let cascadeLaunch;
|
|
12098
12292
|
if (farmContext !== void 0) {
|
|
12099
12293
|
const { farm: resyncFarmRuntime, identity: resyncIdentity, cascade } = farmContext;
|
|
@@ -12199,11 +12393,12 @@ function prepareLaunch(params) {
|
|
|
12199
12393
|
registered();
|
|
12200
12394
|
}
|
|
12201
12395
|
};
|
|
12202
|
-
return { bin: discovered.path, args: finalArgv, env: finalEnv, release };
|
|
12396
|
+
return { bin: discovered.path, args: finalArgv, env: finalEnv, release, markChildStarted: updateCheck.markChildStarted };
|
|
12203
12397
|
}
|
|
12204
12398
|
function runLauncher(params) {
|
|
12205
12399
|
const plan = prepareLaunch(params);
|
|
12206
12400
|
try {
|
|
12401
|
+
plan.markChildStarted();
|
|
12207
12402
|
spawnClaude({ bin: plan.bin, args: plan.args, env: plan.env, spawn: params.spawn, proc: params.proc, beforeExit: plan.release });
|
|
12208
12403
|
} finally {
|
|
12209
12404
|
plan.release();
|
|
@@ -12366,6 +12561,7 @@ function buildFarmRuntime(paths, cwd) {
|
|
|
12366
12561
|
const loaded = loadCascadeInput({ paths, home, cwd, read });
|
|
12367
12562
|
const selections = readDirectorySelections(loaded);
|
|
12368
12563
|
const git = resolveGitBranch(realRunPort, cwd);
|
|
12564
|
+
const updateMode = resolveUpdateMode(loaded.globalConfig);
|
|
12369
12565
|
return {
|
|
12370
12566
|
runtime: {
|
|
12371
12567
|
fs: realFarmFs,
|
|
@@ -12391,7 +12587,8 @@ function buildFarmRuntime(paths, cwd) {
|
|
|
12391
12587
|
...selections.identity === void 0 ? {} : { directoryIdentity: selections.identity },
|
|
12392
12588
|
...selections.configProfile === void 0 ? {} : { directoryConfigProfile: selections.configProfile },
|
|
12393
12589
|
...loaded.globalConfig?.defaultConfigProfile === void 0 ? {} : { globalDefaultConfigProfile: loaded.globalConfig.defaultConfigProfile },
|
|
12394
|
-
...loaded.globalConfig?.pools === void 0 ? {} : { pools: loaded.globalConfig.pools }
|
|
12590
|
+
...loaded.globalConfig?.pools === void 0 ? {} : { pools: loaded.globalConfig.pools },
|
|
12591
|
+
...updateMode === "off" ? {} : { updateMode }
|
|
12395
12592
|
};
|
|
12396
12593
|
}
|
|
12397
12594
|
function realClaudeBinaryResolver(paths) {
|
|
@@ -12413,6 +12610,7 @@ function realPrepareLaunchParams(paths, options) {
|
|
|
12413
12610
|
...farm.directoryConfigProfile === void 0 ? {} : { directoryRuleConfigProfile: farm.directoryConfigProfile },
|
|
12414
12611
|
...farm.globalDefaultConfigProfile === void 0 ? {} : { globalDefaultConfigProfile: farm.globalDefaultConfigProfile },
|
|
12415
12612
|
...farm.pools === void 0 ? {} : { pools: farm.pools },
|
|
12613
|
+
...farm.updateMode === void 0 ? {} : { updateMode: farm.updateMode },
|
|
12416
12614
|
...options.allowMissingConfigProfile === void 0 ? {} : { allowMissingConfigProfile: options.allowMissingConfigProfile }
|
|
12417
12615
|
};
|
|
12418
12616
|
}
|
package/dist/index.mjs
CHANGED
|
@@ -368,6 +368,11 @@ var FrontDoorGlobalConfigSchema = z.strictObject({
|
|
|
368
368
|
/** How long the front door may sit with no registered sessions before it closes and exits. Defaults to FRONTDOOR_DEFAULT_IDLE_SHUTDOWN_MINUTES. */
|
|
369
369
|
idleShutdownMinutes: z.number().int().positive().optional()
|
|
370
370
|
});
|
|
371
|
+
var UPDATE_MODES = ["off", "notify", "auto"];
|
|
372
|
+
var UpdateGlobalConfigSchema = z.strictObject({
|
|
373
|
+
/** What a launch does about a newer release of agent-shim itself; see `UPDATE_MODES`. Absent means `off`. */
|
|
374
|
+
mode: z.enum(UPDATE_MODES).optional()
|
|
375
|
+
});
|
|
371
376
|
var GlobalConfigSchema = z.strictObject({
|
|
372
377
|
$schema: z.string().optional(),
|
|
373
378
|
defaultConfigProfile: z.string().min(1).optional(),
|
|
@@ -377,6 +382,7 @@ var GlobalConfigSchema = z.strictObject({
|
|
|
377
382
|
launch: LaunchSchema.optional(),
|
|
378
383
|
headroom: HeadroomGlobalConfigSchema.optional(),
|
|
379
384
|
frontdoor: FrontDoorGlobalConfigSchema.optional(),
|
|
385
|
+
update: UpdateGlobalConfigSchema.optional(),
|
|
380
386
|
pools: z.record(PoolNameSchema, PoolSchema).optional()
|
|
381
387
|
});
|
|
382
388
|
var IdentitySchema = z.strictObject({
|
|
@@ -11185,6 +11191,106 @@ function removeDirectoryRule(paths, rulePath) {
|
|
|
11185
11191
|
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
11186
11192
|
import path30 from "node:path";
|
|
11187
11193
|
|
|
11194
|
+
// package.json
|
|
11195
|
+
var package_default = {
|
|
11196
|
+
name: "agent-shim",
|
|
11197
|
+
version: "8.23.0",
|
|
11198
|
+
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.",
|
|
11199
|
+
license: "MIT",
|
|
11200
|
+
author: "Joseph Mearman <joseph@mearman.co.uk>",
|
|
11201
|
+
repository: {
|
|
11202
|
+
type: "git",
|
|
11203
|
+
url: "git+https://github.com/ExaDev/agent-shim.git"
|
|
11204
|
+
},
|
|
11205
|
+
homepage: "https://github.com/ExaDev/agent-shim#readme",
|
|
11206
|
+
bugs: "https://github.com/ExaDev/agent-shim/issues",
|
|
11207
|
+
keywords: [
|
|
11208
|
+
"claude-code",
|
|
11209
|
+
"claude",
|
|
11210
|
+
"cli"
|
|
11211
|
+
],
|
|
11212
|
+
packageManager: "pnpm@12.4.1+sha512.2e81e399d73fe8390dab25e06aa788ab7a5908248d2f5a370f82b481147a6a7a367bf8048f9a6fdb6460f21a66f0542dedb8b94ca2c8723596741920b1656d4c",
|
|
11213
|
+
type: "module",
|
|
11214
|
+
engines: {
|
|
11215
|
+
node: "^22.18 || >=24"
|
|
11216
|
+
},
|
|
11217
|
+
bin: {
|
|
11218
|
+
"agent-shim": "dist/cli.cjs",
|
|
11219
|
+
"claude-use": "dist/cli.cjs"
|
|
11220
|
+
},
|
|
11221
|
+
files: [
|
|
11222
|
+
"dist/cli.cjs",
|
|
11223
|
+
"dist/index.mjs",
|
|
11224
|
+
"dist/index.cjs",
|
|
11225
|
+
"dist/types"
|
|
11226
|
+
],
|
|
11227
|
+
scripts: {
|
|
11228
|
+
prepare: "husky && node scripts/build.mts --bundle-only",
|
|
11229
|
+
typecheck: "turbo run _typecheck",
|
|
11230
|
+
_typecheck: "tsc --noEmit",
|
|
11231
|
+
lint: "turbo run _lint",
|
|
11232
|
+
_lint: "eslint . --cache --cache-location .eslintcache --max-warnings 0",
|
|
11233
|
+
test: "turbo run _test",
|
|
11234
|
+
_test: "vitest run",
|
|
11235
|
+
"test:coverage": "turbo run _test:coverage",
|
|
11236
|
+
"_test:coverage": "vitest run --coverage",
|
|
11237
|
+
knip: "turbo run _knip",
|
|
11238
|
+
_knip: "knip --cache",
|
|
11239
|
+
build: "turbo run _build",
|
|
11240
|
+
_build: "node scripts/build.mts",
|
|
11241
|
+
"build:bundle": "node scripts/build.mts --bundle-only",
|
|
11242
|
+
prepublishOnly: "pnpm build:bundle",
|
|
11243
|
+
schema: "node scripts/gen-schema.mts"
|
|
11244
|
+
},
|
|
11245
|
+
dependencies: {
|
|
11246
|
+
"@clack/prompts": "^1.8.0",
|
|
11247
|
+
"@orpc/client": "1.15.4",
|
|
11248
|
+
"@orpc/server": "1.15.4",
|
|
11249
|
+
commander: "^15.0.0",
|
|
11250
|
+
cosmiconfig: "^10.0.1",
|
|
11251
|
+
picomatch: "^4.0.7",
|
|
11252
|
+
undici: "7.29.1",
|
|
11253
|
+
zod: "^4.6.1"
|
|
11254
|
+
},
|
|
11255
|
+
devDependencies: {
|
|
11256
|
+
"@commitlint/cli": "^21.2.2",
|
|
11257
|
+
"@commitlint/config-conventional": "^21.2.2",
|
|
11258
|
+
"@exadev/eslint-config": "2.12.1",
|
|
11259
|
+
"@semantic-release/changelog": "^7.0.0",
|
|
11260
|
+
"@semantic-release/git": "^11.0.1",
|
|
11261
|
+
"@semantic-release/npm": "^13.1.5",
|
|
11262
|
+
"@types/node": "^26.5.1",
|
|
11263
|
+
"@types/picomatch": "^4.0.3",
|
|
11264
|
+
"@vitest/coverage-v8": "^4.1.11",
|
|
11265
|
+
"conventional-changelog-conventionalcommits": "^10.4.0",
|
|
11266
|
+
esbuild: "^0.28.2",
|
|
11267
|
+
eslint: "^10.10.0",
|
|
11268
|
+
globals: "^17.12.0",
|
|
11269
|
+
husky: "^9.1.7",
|
|
11270
|
+
jiti: "^2.7.0",
|
|
11271
|
+
knip: "^6.35.1",
|
|
11272
|
+
"lint-staged": "^17.5.0",
|
|
11273
|
+
rollup: "4.64.0",
|
|
11274
|
+
"rollup-plugin-dts": "6.5.1",
|
|
11275
|
+
"semantic-release": "^25.0.9",
|
|
11276
|
+
turbo: "^2.11.5",
|
|
11277
|
+
typescript: "^6.0.3",
|
|
11278
|
+
"typescript-eslint": "^8.70.0",
|
|
11279
|
+
vitest: "^4.1.11"
|
|
11280
|
+
},
|
|
11281
|
+
main: "dist/index.cjs",
|
|
11282
|
+
module: "dist/index.mjs",
|
|
11283
|
+
types: "dist/types/index.d.ts",
|
|
11284
|
+
exports: {
|
|
11285
|
+
".": {
|
|
11286
|
+
types: "./dist/types/index.d.ts",
|
|
11287
|
+
import: "./dist/index.mjs",
|
|
11288
|
+
require: "./dist/index.cjs"
|
|
11289
|
+
},
|
|
11290
|
+
"./package.json": "./package.json"
|
|
11291
|
+
}
|
|
11292
|
+
};
|
|
11293
|
+
|
|
11188
11294
|
// src/launcher/argv.ts
|
|
11189
11295
|
var ConflictingIdentityError = class extends UsageError {
|
|
11190
11296
|
constructor(positional, flag) {
|
|
@@ -11657,6 +11763,88 @@ function spawnClaude(params) {
|
|
|
11657
11763
|
return params.proc.exit(exitCodeFor(result));
|
|
11658
11764
|
}
|
|
11659
11765
|
|
|
11766
|
+
// src/update/update.ts
|
|
11767
|
+
var LATEST_RELEASE_URL = "https://github.com/ExaDev/agent-shim/releases/latest";
|
|
11768
|
+
function compareVersions3(left, right) {
|
|
11769
|
+
const parse = (version) => {
|
|
11770
|
+
const match = /^(\d+)\.(\d+)\.(\d+)$/.exec(version);
|
|
11771
|
+
if (match === null) {
|
|
11772
|
+
throw new Error(`not a plain release version: ${version}`);
|
|
11773
|
+
}
|
|
11774
|
+
return [Number(match[1]), Number(match[2]), Number(match[3])];
|
|
11775
|
+
};
|
|
11776
|
+
const leftParts = parse(left);
|
|
11777
|
+
const rightParts = parse(right);
|
|
11778
|
+
return leftParts.map((part, index) => part - (rightParts[index] ?? 0)).find((difference) => difference !== 0) ?? 0;
|
|
11779
|
+
}
|
|
11780
|
+
function releaseTagFromUrl(url) {
|
|
11781
|
+
const segment = url.split("?")[0]?.split("/").at(-1);
|
|
11782
|
+
const candidate = segment?.startsWith("v") === true ? segment.slice(1) : void 0;
|
|
11783
|
+
return candidate !== void 0 && /^\d+\.\d+\.\d+$/.test(candidate) ? candidate : void 0;
|
|
11784
|
+
}
|
|
11785
|
+
|
|
11786
|
+
// src/update/launchHook.ts
|
|
11787
|
+
var UPDATE_CHECK_COOLDOWN_MS = 864e5;
|
|
11788
|
+
function resolveUpdateMode(globalConfig) {
|
|
11789
|
+
return globalConfig?.update?.mode ?? "off";
|
|
11790
|
+
}
|
|
11791
|
+
function updateCheckDue(contents, nowMs, cooldownMs = UPDATE_CHECK_COOLDOWN_MS) {
|
|
11792
|
+
if (contents === void 0) {
|
|
11793
|
+
return true;
|
|
11794
|
+
}
|
|
11795
|
+
const checkedAt = Date.parse(contents.trim());
|
|
11796
|
+
if (Number.isNaN(checkedAt)) {
|
|
11797
|
+
return true;
|
|
11798
|
+
}
|
|
11799
|
+
const age = nowMs - checkedAt;
|
|
11800
|
+
return age < 0 || age >= cooldownMs;
|
|
11801
|
+
}
|
|
11802
|
+
var NOOP_HANDLE = { markChildStarted: () => void 0 };
|
|
11803
|
+
function updateNotifyLine(currentVersion, latest) {
|
|
11804
|
+
return `agent-shim: update available: ${currentVersion} -> ${latest} (run \`agent-shim update\` to install it)`;
|
|
11805
|
+
}
|
|
11806
|
+
function runLaunchUpdateCheck(params) {
|
|
11807
|
+
const { mode, checkPath, currentVersion, port } = params;
|
|
11808
|
+
if (mode === "off" || port === void 0) {
|
|
11809
|
+
return NOOP_HANDLE;
|
|
11810
|
+
}
|
|
11811
|
+
let childStarted = false;
|
|
11812
|
+
try {
|
|
11813
|
+
if (!updateCheckDue(port.readStamp(checkPath), port.now())) {
|
|
11814
|
+
return NOOP_HANDLE;
|
|
11815
|
+
}
|
|
11816
|
+
port.writeStamp(checkPath, new Date(port.now()).toISOString());
|
|
11817
|
+
} catch {
|
|
11818
|
+
return NOOP_HANDLE;
|
|
11819
|
+
}
|
|
11820
|
+
const answer = (url) => {
|
|
11821
|
+
try {
|
|
11822
|
+
const latest = releaseTagFromUrl(url);
|
|
11823
|
+
if (latest === void 0 || compareVersions3(latest, currentVersion) <= 0) {
|
|
11824
|
+
return;
|
|
11825
|
+
}
|
|
11826
|
+
if (mode === "auto") {
|
|
11827
|
+
port.spawnDetached(["update"]);
|
|
11828
|
+
}
|
|
11829
|
+
if (!childStarted) {
|
|
11830
|
+
port.writeErr(updateNotifyLine(currentVersion, latest));
|
|
11831
|
+
}
|
|
11832
|
+
} catch {
|
|
11833
|
+
}
|
|
11834
|
+
};
|
|
11835
|
+
port.effectiveUrl(LATEST_RELEASE_URL).then(
|
|
11836
|
+
(url) => {
|
|
11837
|
+
answer(url);
|
|
11838
|
+
},
|
|
11839
|
+
() => void 0
|
|
11840
|
+
);
|
|
11841
|
+
return {
|
|
11842
|
+
markChildStarted: () => {
|
|
11843
|
+
childStarted = true;
|
|
11844
|
+
}
|
|
11845
|
+
};
|
|
11846
|
+
}
|
|
11847
|
+
|
|
11660
11848
|
// src/launcher.ts
|
|
11661
11849
|
function resolveIdentityCredential(identity, credential, env, port) {
|
|
11662
11850
|
if (port === void 0) {
|
|
@@ -11822,6 +12010,12 @@ function prepareLaunch(params) {
|
|
|
11822
12010
|
log.info(
|
|
11823
12011
|
`agent-shim: identity ${identityDecision.name ?? "(none)"} (${identityDecision.source}${poolExplanation === void 0 ? "" : `, ${poolExplanation}`}), config profile ${configProfileDecision.name ?? "(none)"} (${configProfileDecision.source})` + (resolvedProvider === void 0 ? "" : `, provider ${resolvedProvider.name} (credential ${resolvedProvider.credential.target} from ${describeSource(resolvedProvider.credential.source)})`) + (identityCredential === void 0 ? "" : `, identity credential ${identityCredential.target} from ${describeSource(identityCredential.source)}`)
|
|
11824
12012
|
);
|
|
12013
|
+
const updateCheck = runLaunchUpdateCheck({
|
|
12014
|
+
mode: params.updateMode ?? "off",
|
|
12015
|
+
checkPath: path30.join(paths.root, "update.check"),
|
|
12016
|
+
currentVersion: package_default.version,
|
|
12017
|
+
port: params.update
|
|
12018
|
+
});
|
|
11825
12019
|
let cascadeLaunch;
|
|
11826
12020
|
if (farmContext !== void 0) {
|
|
11827
12021
|
const { farm: resyncFarmRuntime, identity: resyncIdentity, cascade } = farmContext;
|
|
@@ -11927,11 +12121,12 @@ function prepareLaunch(params) {
|
|
|
11927
12121
|
registered();
|
|
11928
12122
|
}
|
|
11929
12123
|
};
|
|
11930
|
-
return { bin: discovered.path, args: finalArgv, env: finalEnv, release };
|
|
12124
|
+
return { bin: discovered.path, args: finalArgv, env: finalEnv, release, markChildStarted: updateCheck.markChildStarted };
|
|
11931
12125
|
}
|
|
11932
12126
|
function runLauncher(params) {
|
|
11933
12127
|
const plan = prepareLaunch(params);
|
|
11934
12128
|
try {
|
|
12129
|
+
plan.markChildStarted();
|
|
11935
12130
|
spawnClaude({ bin: plan.bin, args: plan.args, env: plan.env, spawn: params.spawn, proc: params.proc, beforeExit: plan.release });
|
|
11936
12131
|
} finally {
|
|
11937
12132
|
plan.release();
|
|
@@ -12094,6 +12289,7 @@ function buildFarmRuntime(paths, cwd) {
|
|
|
12094
12289
|
const loaded = loadCascadeInput({ paths, home, cwd, read });
|
|
12095
12290
|
const selections = readDirectorySelections(loaded);
|
|
12096
12291
|
const git = resolveGitBranch(realRunPort, cwd);
|
|
12292
|
+
const updateMode = resolveUpdateMode(loaded.globalConfig);
|
|
12097
12293
|
return {
|
|
12098
12294
|
runtime: {
|
|
12099
12295
|
fs: realFarmFs,
|
|
@@ -12119,7 +12315,8 @@ function buildFarmRuntime(paths, cwd) {
|
|
|
12119
12315
|
...selections.identity === void 0 ? {} : { directoryIdentity: selections.identity },
|
|
12120
12316
|
...selections.configProfile === void 0 ? {} : { directoryConfigProfile: selections.configProfile },
|
|
12121
12317
|
...loaded.globalConfig?.defaultConfigProfile === void 0 ? {} : { globalDefaultConfigProfile: loaded.globalConfig.defaultConfigProfile },
|
|
12122
|
-
...loaded.globalConfig?.pools === void 0 ? {} : { pools: loaded.globalConfig.pools }
|
|
12318
|
+
...loaded.globalConfig?.pools === void 0 ? {} : { pools: loaded.globalConfig.pools },
|
|
12319
|
+
...updateMode === "off" ? {} : { updateMode }
|
|
12123
12320
|
};
|
|
12124
12321
|
}
|
|
12125
12322
|
function realClaudeBinaryResolver(paths) {
|
|
@@ -12141,6 +12338,7 @@ function realPrepareLaunchParams(paths, options) {
|
|
|
12141
12338
|
...farm.directoryConfigProfile === void 0 ? {} : { directoryRuleConfigProfile: farm.directoryConfigProfile },
|
|
12142
12339
|
...farm.globalDefaultConfigProfile === void 0 ? {} : { globalDefaultConfigProfile: farm.globalDefaultConfigProfile },
|
|
12143
12340
|
...farm.pools === void 0 ? {} : { pools: farm.pools },
|
|
12341
|
+
...farm.updateMode === void 0 ? {} : { updateMode: farm.updateMode },
|
|
12144
12342
|
...options.allowMissingConfigProfile === void 0 ? {} : { allowMissingConfigProfile: options.allowMissingConfigProfile }
|
|
12145
12343
|
};
|
|
12146
12344
|
}
|
package/dist/types/index.d.ts
CHANGED
|
@@ -542,6 +542,11 @@ declare const HeadroomGlobalConfigSchema: z.ZodObject<{
|
|
|
542
542
|
readMaturation: z.ZodOptional<z.ZodBoolean>;
|
|
543
543
|
}, z.core.$strict>;
|
|
544
544
|
type HeadroomGlobalConfig = z.infer<typeof HeadroomGlobalConfigSchema>;
|
|
545
|
+
/**
|
|
546
|
+
* The launch-time update modes. `off` never touches the network at launch; `notify` checks for a newer release on a cooldown and prints one line naming it and the command to apply it; `auto` additionally applies the update in the background.
|
|
547
|
+
*/
|
|
548
|
+
declare const UPDATE_MODES: readonly ["off", "notify", "auto"];
|
|
549
|
+
type UpdateMode = (typeof UPDATE_MODES)[number];
|
|
545
550
|
/** The user-global `~/.agent-shim/config.json`. */
|
|
546
551
|
declare const GlobalConfigSchema: z.ZodObject<{
|
|
547
552
|
$schema: z.ZodOptional<z.ZodString>;
|
|
@@ -602,6 +607,13 @@ declare const GlobalConfigSchema: z.ZodObject<{
|
|
|
602
607
|
frontdoor: z.ZodOptional<z.ZodObject<{
|
|
603
608
|
idleShutdownMinutes: z.ZodOptional<z.ZodNumber>;
|
|
604
609
|
}, z.core.$strict>>;
|
|
610
|
+
update: z.ZodOptional<z.ZodObject<{
|
|
611
|
+
mode: z.ZodOptional<z.ZodEnum<{
|
|
612
|
+
auto: "auto";
|
|
613
|
+
off: "off";
|
|
614
|
+
notify: "notify";
|
|
615
|
+
}>>;
|
|
616
|
+
}, z.core.$strict>>;
|
|
605
617
|
pools: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
606
618
|
identities: z.ZodArray<z.ZodString>;
|
|
607
619
|
preference: z.ZodOptional<z.ZodEnum<{
|
|
@@ -3998,13 +4010,13 @@ declare function createControlApiRouter(deps: ControlApiDeps): {
|
|
|
3998
4010
|
"config-profile": "config-profile";
|
|
3999
4011
|
identity: "identity";
|
|
4000
4012
|
provider: "provider";
|
|
4013
|
+
pool: "pool";
|
|
4014
|
+
keychain: "keychain";
|
|
4001
4015
|
"ambient-credential": "ambient-credential";
|
|
4002
4016
|
"binary-discovery": "binary-discovery";
|
|
4003
4017
|
"claude-shim": "claude-shim";
|
|
4004
4018
|
"path-resolution": "path-resolution";
|
|
4005
4019
|
"legacy-name": "legacy-name";
|
|
4006
|
-
pool: "pool";
|
|
4007
|
-
keychain: "keychain";
|
|
4008
4020
|
"directory-rules": "directory-rules";
|
|
4009
4021
|
"categories-local": "categories-local";
|
|
4010
4022
|
"active-identity": "active-identity";
|
|
@@ -4475,13 +4487,13 @@ declare function createDoorApiRouter(deps: DoorApiDeps): {
|
|
|
4475
4487
|
"config-profile": "config-profile";
|
|
4476
4488
|
identity: "identity";
|
|
4477
4489
|
provider: "provider";
|
|
4490
|
+
pool: "pool";
|
|
4491
|
+
keychain: "keychain";
|
|
4478
4492
|
"ambient-credential": "ambient-credential";
|
|
4479
4493
|
"binary-discovery": "binary-discovery";
|
|
4480
4494
|
"claude-shim": "claude-shim";
|
|
4481
4495
|
"path-resolution": "path-resolution";
|
|
4482
4496
|
"legacy-name": "legacy-name";
|
|
4483
|
-
pool: "pool";
|
|
4484
|
-
keychain: "keychain";
|
|
4485
4497
|
"directory-rules": "directory-rules";
|
|
4486
4498
|
"categories-local": "categories-local";
|
|
4487
4499
|
"active-identity": "active-identity";
|
|
@@ -4769,13 +4781,13 @@ declare const DoctorFindingSchema: z.ZodObject<{
|
|
|
4769
4781
|
"config-profile": "config-profile";
|
|
4770
4782
|
identity: "identity";
|
|
4771
4783
|
provider: "provider";
|
|
4784
|
+
pool: "pool";
|
|
4785
|
+
keychain: "keychain";
|
|
4772
4786
|
"ambient-credential": "ambient-credential";
|
|
4773
4787
|
"binary-discovery": "binary-discovery";
|
|
4774
4788
|
"claude-shim": "claude-shim";
|
|
4775
4789
|
"path-resolution": "path-resolution";
|
|
4776
4790
|
"legacy-name": "legacy-name";
|
|
4777
|
-
pool: "pool";
|
|
4778
|
-
keychain: "keychain";
|
|
4779
4791
|
"directory-rules": "directory-rules";
|
|
4780
4792
|
"categories-local": "categories-local";
|
|
4781
4793
|
"active-identity": "active-identity";
|
|
@@ -4798,13 +4810,13 @@ declare const DoctorRunOutputSchema: z.ZodObject<{
|
|
|
4798
4810
|
"config-profile": "config-profile";
|
|
4799
4811
|
identity: "identity";
|
|
4800
4812
|
provider: "provider";
|
|
4813
|
+
pool: "pool";
|
|
4814
|
+
keychain: "keychain";
|
|
4801
4815
|
"ambient-credential": "ambient-credential";
|
|
4802
4816
|
"binary-discovery": "binary-discovery";
|
|
4803
4817
|
"claude-shim": "claude-shim";
|
|
4804
4818
|
"path-resolution": "path-resolution";
|
|
4805
4819
|
"legacy-name": "legacy-name";
|
|
4806
|
-
pool: "pool";
|
|
4807
|
-
keychain: "keychain";
|
|
4808
4820
|
"directory-rules": "directory-rules";
|
|
4809
4821
|
"categories-local": "categories-local";
|
|
4810
4822
|
"active-identity": "active-identity";
|
|
@@ -5672,6 +5684,24 @@ interface CliOverride {
|
|
|
5672
5684
|
};
|
|
5673
5685
|
}
|
|
5674
5686
|
|
|
5687
|
+
/**
|
|
5688
|
+
* Everything the launch-time update check needs from its host, injected so tests run it against scripted answers and no launch ever reaches GitHub by accident. Deliberately narrower than `UpdatePorts`: the launch path never downloads anything (the detached `agent-shim update` does), so only the release check, the cooldown stamp, the clock, the background spawn and the terminal are wired.
|
|
5689
|
+
*/
|
|
5690
|
+
interface UpdateLaunchPort {
|
|
5691
|
+
/** Resolves the URL the `releases/latest` redirect lands on, exactly as `agent-shim update` resolves the newest version. */
|
|
5692
|
+
readonly effectiveUrl: (url: string) => Promise<string>;
|
|
5693
|
+
/** Reads the cooldown stamp, or undefined when it does not exist. */
|
|
5694
|
+
readonly readStamp: (filePath: string) => string | undefined;
|
|
5695
|
+
/** Writes the cooldown stamp atomically: a reader either sees the previous whole stamp or the new one, never a partial write. */
|
|
5696
|
+
readonly writeStamp: (filePath: string, contents: string) => void;
|
|
5697
|
+
/** The clock the cooldown reads, in epoch milliseconds. */
|
|
5698
|
+
readonly now: () => number;
|
|
5699
|
+
/** Re-invokes this very binary with `args` as a detached child whose stdio is ignored and which is unref'd, so it outlives the launch and never holds the terminal. */
|
|
5700
|
+
readonly spawnDetached: (args: readonly string[]) => void;
|
|
5701
|
+
/** Writes one line to the launching terminal's stderr. */
|
|
5702
|
+
readonly writeErr: (line: string) => void;
|
|
5703
|
+
}
|
|
5704
|
+
|
|
5675
5705
|
/**
|
|
5676
5706
|
* Everything the farm resync needs that the launcher itself has no way to produce: a real filesystem, a real clock, the working directory, and a way to load the cascade for it.
|
|
5677
5707
|
*
|
|
@@ -5732,6 +5762,10 @@ interface PrepareLaunchParams {
|
|
|
5732
5762
|
readonly credentials?: CredentialPort;
|
|
5733
5763
|
/** True when the user was asked on a terminal whether to create the selected configuration profile and chose to launch without it. Without that explicit choice, a selected profile with no file is refused rather than silently skipped. */
|
|
5734
5764
|
readonly allowMissingConfigProfile?: boolean;
|
|
5765
|
+
/** The user-global `update.mode`, resolved from the same global config the launcher already loads. Absent means `off`, and `off` runs no launch-time update check at all. */
|
|
5766
|
+
readonly updateMode?: UpdateMode;
|
|
5767
|
+
/** Wires the launch-time update check behind `update.mode`. Omitted by a caller that cannot resolve releases, re-invoke this binary, or write to the terminal; a mode of `notify` or `auto` with no port wired simply checks nothing. */
|
|
5768
|
+
readonly update?: UpdateLaunchPort;
|
|
5735
5769
|
}
|
|
5736
5770
|
/** Inputs to `runLauncher`: a launch's inputs plus the port that spawns the child. */
|
|
5737
5771
|
interface RunLauncherParams extends PrepareLaunchParams {
|
|
@@ -5746,11 +5780,13 @@ interface LaunchPlan {
|
|
|
5746
5780
|
readonly env: Readonly<Record<string, string | undefined>>;
|
|
5747
5781
|
/** Releases the daemon session registrations this launch holds. Call it when the child has exited; it is safe to call more than once. */
|
|
5748
5782
|
readonly release: () => void;
|
|
5783
|
+
/** Marks the moment this plan's child is spawned: the launch-time update check suppresses its notify line from then on, since a line printed after the child took over the terminal would land mid-session. Call it immediately before spawning; it is safe to call more than once. */
|
|
5784
|
+
readonly markChildStarted: () => void;
|
|
5749
5785
|
}
|
|
5750
5786
|
/**
|
|
5751
5787
|
* Prepares one `claude` launch, in order:
|
|
5752
5788
|
*
|
|
5753
|
-
* `CLAUDE_CONFIG_DIR` escape-hatch check, then the identity/config-profile decision, the provider decision, the identity's own credential, the ambient-credential guard, farm resync, version discovery, flag resolution (and, when headroom resolved on, daemon bring-up), the extra-flags split, and the final argument list and environment, returned as a `LaunchPlan` for the caller to spawn. It refuses through `params.proc.exit`, so a caller that is not a command line process passes a `proc` whose `exit` throws.
|
|
5789
|
+
* `CLAUDE_CONFIG_DIR` escape-hatch check, then the identity/config-profile decision, the provider decision, the identity's own credential, the ambient-credential guard, the config-gated launch-time update check (fired after the decision line and never awaited; see `runLaunchUpdateCheck`), farm resync, version discovery, flag resolution (and, when headroom resolved on, daemon bring-up), the extra-flags split, and the final argument list and environment, returned as a `LaunchPlan` for the caller to spawn. It refuses through `params.proc.exit`, so a caller that is not a command line process passes a `proc` whose `exit` throws.
|
|
5754
5790
|
*
|
|
5755
5791
|
* A launch that resolves an identity with no `identity.json`, or a configuration profile with no file, is refused with exit 1 naming the missing name and how it was selected: silently proceeding would create a brand-new login for a mistyped `@name`, or launch with a whole cascade layer missing. On a terminal, `src/runClaude.ts` offers to create either before this runs.
|
|
5756
5792
|
*
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agent-shim",
|
|
3
|
-
"version": "8.
|
|
3
|
+
"version": "8.23.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>",
|