claude-use 2.7.0 → 2.9.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 +4 -1
- package/dist/cli.cjs +85 -17
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -77,13 +77,16 @@ claude-use profile set <name> --category <cat>=<bool>[,<cat>=<bool>,...]
|
|
|
77
77
|
claude-use profile set <name> --entry "<path>"=<bool>[,"<path>"=<bool>,...]
|
|
78
78
|
claude-use profile set <name> [--skip-permissions] [--remote-control] [--headroom]
|
|
79
79
|
|
|
80
|
-
claude-use provider add <name> --display-name <name> --base-url <url> --token-env <VAR> [--env KEY=VALUE]
|
|
80
|
+
claude-use provider add <name> --display-name <name> --base-url <url> (--token-env <VAR> | --token-command <argv...>) [--auth-scheme <bearer|apiKey>] [--env KEY=VALUE]
|
|
81
81
|
claude-use provider list
|
|
82
82
|
claude-use provider show <name>
|
|
83
83
|
claude-use provider remove <name>
|
|
84
84
|
|
|
85
85
|
claude-use headroom status
|
|
86
86
|
|
|
87
|
+
claude @<identity> --headroom # one launch routed through headroom
|
|
88
|
+
claude --no-headroom # one launch routed direct, overriding every layer
|
|
89
|
+
|
|
87
90
|
claude-use rules add <path> [--profile <name>] [--identity <name>]
|
|
88
91
|
claude-use rules list
|
|
89
92
|
claude-use rules remove <path>
|
package/dist/cli.cjs
CHANGED
|
@@ -239649,7 +239649,7 @@ var program = new Command();
|
|
|
239649
239649
|
// package.json
|
|
239650
239650
|
var package_default = {
|
|
239651
239651
|
name: "claude-use",
|
|
239652
|
-
version: "2.
|
|
239652
|
+
version: "2.9.0",
|
|
239653
239653
|
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.",
|
|
239654
239654
|
license: "Apache-2.0",
|
|
239655
239655
|
author: "Joseph Mearman <joseph@mearman.co.uk>",
|
|
@@ -259498,14 +259498,34 @@ var LaunchSchema = external_exports.strictObject({
|
|
|
259498
259498
|
provider: external_exports.string().min(1).optional(),
|
|
259499
259499
|
headroom: external_exports.boolean().optional()
|
|
259500
259500
|
});
|
|
259501
|
+
var AUTH_SCHEMES = ["bearer", "apiKey"];
|
|
259501
259502
|
var ProviderSchema = external_exports.strictObject({
|
|
259502
259503
|
$schema: external_exports.string().optional(),
|
|
259503
259504
|
displayName: external_exports.string().min(1),
|
|
259504
259505
|
baseUrl: external_exports.url(),
|
|
259505
259506
|
tokenEnv: external_exports.string().min(1).optional(),
|
|
259507
|
+
tokenCommand: external_exports.tuple([external_exports.string().min(1)], external_exports.string()).optional(),
|
|
259508
|
+
authScheme: external_exports.enum(AUTH_SCHEMES).optional(),
|
|
259506
259509
|
env: external_exports.record(external_exports.string().min(1), external_exports.string()).optional()
|
|
259507
|
-
}).
|
|
259508
|
-
|
|
259510
|
+
}).superRefine((provider, ctx) => {
|
|
259511
|
+
const sources = [
|
|
259512
|
+
provider.tokenEnv !== void 0 ? "tokenEnv" : void 0,
|
|
259513
|
+
provider.tokenCommand !== void 0 ? "tokenCommand" : void 0,
|
|
259514
|
+
(provider.env?.ANTHROPIC_AUTH_TOKEN ?? "") !== "" ? "env.ANTHROPIC_AUTH_TOKEN" : void 0
|
|
259515
|
+
].filter((source) => source !== void 0);
|
|
259516
|
+
if (sources.length !== 1) {
|
|
259517
|
+
ctx.addIssue({
|
|
259518
|
+
code: "custom",
|
|
259519
|
+
message: sources.length === 0 ? "a provider needs exactly one token source: tokenEnv (the name of the environment variable holding its token), tokenCommand (an argv whose stdout is the token), or a non-empty env.ANTHROPIC_AUTH_TOKEN" : `a provider takes exactly one token source, but this one has ${sources.join(", ")}`
|
|
259520
|
+
});
|
|
259521
|
+
}
|
|
259522
|
+
if (provider.authScheme === "apiKey" && (provider.env?.ANTHROPIC_API_KEY ?? "") !== "") {
|
|
259523
|
+
ctx.addIssue({
|
|
259524
|
+
code: "custom",
|
|
259525
|
+
path: ["env", "ANTHROPIC_API_KEY"],
|
|
259526
|
+
message: 'authScheme "apiKey" exports the token as ANTHROPIC_API_KEY, so env.ANTHROPIC_API_KEY must not be set to a value'
|
|
259527
|
+
});
|
|
259528
|
+
}
|
|
259509
259529
|
});
|
|
259510
259530
|
var ConfigProfileSchema = external_exports.strictObject({
|
|
259511
259531
|
$schema: external_exports.string().optional(),
|
|
@@ -266045,6 +266065,13 @@ var READY_FETCH_TIMEOUT_MS = 2e3;
|
|
|
266045
266065
|
function headroomPidRunning(pid) {
|
|
266046
266066
|
return !exitedHeadroom.has(pid) && realIsProcessRunning(pid);
|
|
266047
266067
|
}
|
|
266068
|
+
function headroomSpawnEnv(parentEnv, allowlist) {
|
|
266069
|
+
return {
|
|
266070
|
+
...parentEnv,
|
|
266071
|
+
HEADROOM_ALLOWED_BASE_URLS: allowlist.join(","),
|
|
266072
|
+
HEADROOM_HTTP2: parentEnv.HEADROOM_HTTP2 ?? "0"
|
|
266073
|
+
};
|
|
266074
|
+
}
|
|
266048
266075
|
function realSupervisorPorts(paths) {
|
|
266049
266076
|
return {
|
|
266050
266077
|
fs: realFarmFs,
|
|
@@ -266067,7 +266094,7 @@ function realSupervisorPorts(paths) {
|
|
|
266067
266094
|
const child = (0, import_node_child_process3.spawn)("headroom", ["proxy", "--host", "127.0.0.1", "--port", String(port)], {
|
|
266068
266095
|
detached: true,
|
|
266069
266096
|
stdio: ["ignore", logFd, logFd],
|
|
266070
|
-
env:
|
|
266097
|
+
env: headroomSpawnEnv(process.env, allowlist)
|
|
266071
266098
|
});
|
|
266072
266099
|
if (child.pid === void 0) {
|
|
266073
266100
|
throw new Error("spawning headroom returned no pid");
|
|
@@ -266270,6 +266297,8 @@ function addProvider(paths, name, input2) {
|
|
|
266270
266297
|
displayName: input2.displayName,
|
|
266271
266298
|
baseUrl: input2.baseUrl,
|
|
266272
266299
|
...input2.tokenEnv === void 0 ? {} : { tokenEnv: input2.tokenEnv },
|
|
266300
|
+
...input2.tokenCommand === void 0 ? {} : { tokenCommand: input2.tokenCommand },
|
|
266301
|
+
...input2.authScheme === void 0 ? {} : { authScheme: input2.authScheme },
|
|
266273
266302
|
...input2.env === void 0 || Object.keys(input2.env).length === 0 ? {} : { env: input2.env }
|
|
266274
266303
|
});
|
|
266275
266304
|
if (!parsed.success) {
|
|
@@ -266285,6 +266314,30 @@ function removeProvider(paths, name) {
|
|
|
266285
266314
|
import_node_fs10.default.rmSync(providerJsonPath(paths, name));
|
|
266286
266315
|
}
|
|
266287
266316
|
var PROVIDER_MISSING_TOKEN_EXIT = 64;
|
|
266317
|
+
function obtainToken(name, definition, params) {
|
|
266318
|
+
const unusable = (message) => ({ ok: false, status: PROVIDER_MISSING_TOKEN_EXIT, message });
|
|
266319
|
+
if (definition.tokenCommand !== void 0) {
|
|
266320
|
+
const [command, ...args] = definition.tokenCommand;
|
|
266321
|
+
if (params.run === void 0) {
|
|
266322
|
+
return { ok: false, status: 1, message: `claude-use: provider ${name} needs its token command run, but this launcher has no command runner wired` };
|
|
266323
|
+
}
|
|
266324
|
+
const result = params.run.run(command, args);
|
|
266325
|
+
if (result.status !== 0) {
|
|
266326
|
+
const stderr = result.stderr.trim();
|
|
266327
|
+
const outcome = result.status === null ? "could not be run or was killed by a signal" : `exited with status ${String(result.status)}`;
|
|
266328
|
+
return unusable(`claude-use: provider ${name}: token command ${command} ${outcome}${stderr === "" ? "" : `: ${stderr}`}`);
|
|
266329
|
+
}
|
|
266330
|
+
const token2 = result.stdout.trim();
|
|
266331
|
+
return token2 === "" ? unusable(`claude-use: provider ${name}: token command ${command} printed no token`) : { ok: true, token: token2 };
|
|
266332
|
+
}
|
|
266333
|
+
const token = definition.tokenEnv !== void 0 ? params.env[definition.tokenEnv] : definition.env?.ANTHROPIC_AUTH_TOKEN;
|
|
266334
|
+
if (token === void 0 || token === "") {
|
|
266335
|
+
return unusable(
|
|
266336
|
+
definition.tokenEnv !== void 0 ? `claude-use: provider ${name} needs ${definition.tokenEnv} set in your environment` : `claude-use: provider ${name} has no usable credential: its env.ANTHROPIC_AUTH_TOKEN is empty`
|
|
266337
|
+
);
|
|
266338
|
+
}
|
|
266339
|
+
return { ok: true, token };
|
|
266340
|
+
}
|
|
266288
266341
|
function resolveProvider(params) {
|
|
266289
266342
|
const cliName = params.cliProvider !== void 0 && params.cliProvider !== "" ? params.cliProvider : void 0;
|
|
266290
266343
|
let cascadeName;
|
|
@@ -266308,14 +266361,11 @@ function resolveProvider(params) {
|
|
|
266308
266361
|
message: `claude-use: no provider named "${name}". ` + (known.length > 0 ? `Known providers: ${known.join(", ")}.` : "No providers are defined yet; run `claude-use provider add`.")
|
|
266309
266362
|
};
|
|
266310
266363
|
}
|
|
266311
|
-
const
|
|
266312
|
-
if (
|
|
266313
|
-
return
|
|
266314
|
-
ok: false,
|
|
266315
|
-
status: PROVIDER_MISSING_TOKEN_EXIT,
|
|
266316
|
-
message: definition.tokenEnv !== void 0 ? `claude-use: provider ${name} needs ${definition.tokenEnv} set in your environment` : `claude-use: provider ${name} has no usable credential: its env.ANTHROPIC_AUTH_TOKEN is empty`
|
|
266317
|
-
};
|
|
266364
|
+
const credential = obtainToken(name, definition, params);
|
|
266365
|
+
if (!credential.ok) {
|
|
266366
|
+
return credential;
|
|
266318
266367
|
}
|
|
266368
|
+
const token = credential.token;
|
|
266319
266369
|
return { ok: true, provider: { name, definition, token } };
|
|
266320
266370
|
}
|
|
266321
266371
|
function collectEnvPairs(value, previous = {}) {
|
|
@@ -266332,16 +266382,17 @@ function collectEnvPairs(value, previous = {}) {
|
|
|
266332
266382
|
}
|
|
266333
266383
|
function registerProviderCommand(program2, paths) {
|
|
266334
266384
|
const provider = program2.command("provider").description("Manage API providers the launcher can route a session through.");
|
|
266335
|
-
provider.command("add <name>").description("Create a new API provider definition.").requiredOption("--display-name <name>", "Human-readable name, exported to the child as CLAUDE_USE_PROVIDER.").requiredOption("--base-url <url>", "Anthropic-compatible base URL the child's requests are sent to.").option("--token-env <var>", "NAME of the environment variable holding the provider's token (never the token itself).
|
|
266385
|
+
provider.command("add <name>").description("Create a new API provider definition.").requiredOption("--display-name <name>", "Human-readable name, exported to the child as CLAUDE_USE_PROVIDER.").requiredOption("--base-url <url>", "Anthropic-compatible base URL the child's requests are sent to.").option("--token-env <var>", "NAME of the environment variable holding the provider's token (never the token itself). Exactly one of --token-env, --token-command or --env ANTHROPIC_AUTH_TOKEN=<fixed dummy token for a local proxy> is required.").option("--token-command <argv...>", "Command (program and arguments) run at launch whose trimmed stdout is the token, e.g. --token-command op read op://vault/item/field. Give it last on the command line, since it consumes every following word.").addOption(new Option("--auth-scheme <scheme>", "How the token reaches Claude Code: bearer sets ANTHROPIC_AUTH_TOKEN (default), apiKey sets ANTHROPIC_API_KEY.").choices(AUTH_SCHEMES)).option("--env <pair>", "Extra KEY=VALUE environment entry for the child (repeatable).", collectEnvPairs).action((name, options) => {
|
|
266336
266386
|
addProvider(paths, name, {
|
|
266337
266387
|
displayName: options.displayName,
|
|
266338
266388
|
baseUrl: options.baseUrl,
|
|
266339
266389
|
...options.tokenEnv === void 0 ? {} : { tokenEnv: options.tokenEnv },
|
|
266390
|
+
...options.tokenCommand === void 0 ? {} : { tokenCommand: options.tokenCommand },
|
|
266391
|
+
...options.authScheme === void 0 ? {} : { authScheme: options.authScheme },
|
|
266340
266392
|
...options.env === void 0 ? {} : { env: options.env }
|
|
266341
266393
|
});
|
|
266342
|
-
|
|
266343
|
-
|
|
266344
|
-
);
|
|
266394
|
+
const source = options.tokenEnv !== void 0 ? `token from ${options.tokenEnv}` : options.tokenCommand !== void 0 ? `token from ${options.tokenCommand[0]}` : "fixed env credential";
|
|
266395
|
+
console.log(`Created provider "${name}" (${options.baseUrl}, ${source}).`);
|
|
266345
266396
|
});
|
|
266346
266397
|
provider.command("list").description("List every API provider.").action(() => {
|
|
266347
266398
|
const entries = listProviders(paths);
|
|
@@ -266394,6 +266445,7 @@ function parseLauncherArgv(argv) {
|
|
|
266394
266445
|
const remaining = hasIdentity ? argv.slice(1) : argv;
|
|
266395
266446
|
let configProfile;
|
|
266396
266447
|
let provider;
|
|
266448
|
+
let headroom;
|
|
266397
266449
|
const categoryFlags = [];
|
|
266398
266450
|
const shareFlags = [];
|
|
266399
266451
|
const hideFlags = [];
|
|
@@ -266403,6 +266455,10 @@ function parseLauncherArgv(argv) {
|
|
|
266403
266455
|
if (token === void 0) {
|
|
266404
266456
|
continue;
|
|
266405
266457
|
}
|
|
266458
|
+
if (token === "--headroom" || token === "--no-headroom") {
|
|
266459
|
+
headroom = token === "--headroom";
|
|
266460
|
+
continue;
|
|
266461
|
+
}
|
|
266406
266462
|
const matched = matchValuedFlag(token);
|
|
266407
266463
|
if (matched === void 0) {
|
|
266408
266464
|
rest.push(token);
|
|
@@ -266436,6 +266492,7 @@ function parseLauncherArgv(argv) {
|
|
|
266436
266492
|
...hasIdentity ? { identity: first.slice(1) } : {},
|
|
266437
266493
|
...configProfile === void 0 ? {} : { configProfile },
|
|
266438
266494
|
...provider === void 0 ? {} : { provider },
|
|
266495
|
+
...headroom === void 0 ? {} : { headroom },
|
|
266439
266496
|
categoryFlags,
|
|
266440
266497
|
shareFlags,
|
|
266441
266498
|
hideFlags,
|
|
@@ -266557,7 +266614,8 @@ function resolveLaunchFlags(params) {
|
|
|
266557
266614
|
return {
|
|
266558
266615
|
skipPermissions: params.cascade?.skipPermissions === true || isEnvFlagSet(params.env.CLAUDE_USE_SKIP_PERMISSIONS),
|
|
266559
266616
|
remoteControl: params.cascade?.remoteControl === true || isEnvFlagSet(params.env.CLAUDE_USE_REMOTE_CONTROL),
|
|
266560
|
-
|
|
266617
|
+
// Precedence: an explicit --headroom/--no-headroom flag decides outright, then the CLAUDE_USE_HEADROOM escape hatch, then the cascade. The flag outranks the environment variable because it is the more deliberate of the two one-off forms (typed on this very command line, not inherited from a shell profile).
|
|
266618
|
+
headroom: params.headroomFlag ?? (isEnvFlagSet(params.env.CLAUDE_USE_HEADROOM) || params.cascade?.headroom === true)
|
|
266561
266619
|
};
|
|
266562
266620
|
}
|
|
266563
266621
|
function buildFlagArgs(flags) {
|
|
@@ -266590,6 +266648,10 @@ function buildEnv(params) {
|
|
|
266590
266648
|
for (const [key, value] of Object.entries(providerEnv)) {
|
|
266591
266649
|
env[key] = value;
|
|
266592
266650
|
}
|
|
266651
|
+
if (params.provider.definition.authScheme === "apiKey") {
|
|
266652
|
+
env.ANTHROPIC_API_KEY = params.provider.token;
|
|
266653
|
+
env.ANTHROPIC_AUTH_TOKEN = "";
|
|
266654
|
+
}
|
|
266593
266655
|
}
|
|
266594
266656
|
if (params.headroom !== void 0) {
|
|
266595
266657
|
env.HEADROOM_PROXY_URL = `http://127.0.0.1:${String(params.headroom.port)}`;
|
|
@@ -266718,6 +266780,7 @@ function runLauncher(params) {
|
|
|
266718
266780
|
paths,
|
|
266719
266781
|
port: fs12,
|
|
266720
266782
|
env,
|
|
266783
|
+
...params.run === void 0 ? {} : { run: params.run },
|
|
266721
266784
|
...parsedArgv.provider === void 0 ? {} : { cliProvider: parsedArgv.provider },
|
|
266722
266785
|
...farmContext === void 0 ? {} : { cascade: farmContext.cascade }
|
|
266723
266786
|
});
|
|
@@ -266784,7 +266847,11 @@ function runLauncher(params) {
|
|
|
266784
266847
|
cascadeLaunch = flattenLayers(assembleCascade(params.farm.loadCascade(configProfileDecision.name, cliOverride)).layers, { home: params.farm.home }).launch;
|
|
266785
266848
|
}
|
|
266786
266849
|
const discovered = params.resolveClaudeBinary();
|
|
266787
|
-
const resolvedFlags = resolveLaunchFlags({
|
|
266850
|
+
const resolvedFlags = resolveLaunchFlags({
|
|
266851
|
+
env,
|
|
266852
|
+
...cascadeLaunch === void 0 ? {} : { cascade: cascadeLaunch },
|
|
266853
|
+
...parsedArgv.headroom === void 0 ? {} : { headroomFlag: parsedArgv.headroom }
|
|
266854
|
+
});
|
|
266788
266855
|
let headroom;
|
|
266789
266856
|
const headroomPort = params.headroom;
|
|
266790
266857
|
if (resolvedFlags.headroom && headroomPort !== void 0) {
|
|
@@ -266926,6 +266993,7 @@ async function runClaude(argvOverride) {
|
|
|
266926
266993
|
resolveClaudeBinary: realResolveClaudeBinary(resolveOwnInstallDirs(paths, realOwnExecutablePath())),
|
|
266927
266994
|
farm: farm.runtime,
|
|
266928
266995
|
headroom: realHeadroomPort(paths),
|
|
266996
|
+
run: realRunPort,
|
|
266929
266997
|
...farm.directoryIdentity === void 0 ? {} : { directoryPinnedIdentity: farm.directoryIdentity },
|
|
266930
266998
|
...farm.directoryConfigProfile === void 0 ? {} : { directoryRuleConfigProfile: farm.directoryConfigProfile },
|
|
266931
266999
|
...farm.globalDefaultConfigProfile === void 0 ? {} : { globalDefaultConfigProfile: farm.globalDefaultConfigProfile }
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-use",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.9.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": "Apache-2.0",
|
|
6
6
|
"author": "Joseph Mearman <joseph@mearman.co.uk>",
|