claude-use 11.2.0 → 11.3.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 -0
- package/dist/cli.cjs +966 -707
- package/dist/index.cjs +169 -46
- package/dist/index.mjs +165 -43
- package/dist/types/index.d.ts +4 -0
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -2734,7 +2734,7 @@ var init_package = __esm({
|
|
|
2734
2734
|
"package.json"() {
|
|
2735
2735
|
package_default = {
|
|
2736
2736
|
name: "claude-use",
|
|
2737
|
-
version: "11.
|
|
2737
|
+
version: "11.3.0",
|
|
2738
2738
|
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.",
|
|
2739
2739
|
license: "MIT",
|
|
2740
2740
|
author: "Joseph Mearman <joseph@mearman.co.uk>",
|
|
@@ -4010,7 +4010,7 @@ function realHeadroomPort(paths, options) {
|
|
|
4010
4010
|
ensure: ({ routesProvider }) => {
|
|
4011
4011
|
const up = ensureHeadroom({
|
|
4012
4012
|
paths,
|
|
4013
|
-
launcherPid: process.pid,
|
|
4013
|
+
launcherPid: options.registerAs ?? process.pid,
|
|
4014
4014
|
...routesProvider ? { requiredUpstreams: () => launchRequiredUpstreams(realFarmFs, paths) } : {},
|
|
4015
4015
|
ports: {
|
|
4016
4016
|
fs: realFarmFs,
|
|
@@ -4028,7 +4028,7 @@ function realHeadroomPort(paths, options) {
|
|
|
4028
4028
|
};
|
|
4029
4029
|
},
|
|
4030
4030
|
release: () => {
|
|
4031
|
-
removeSession(realFarmFs, paths.headroomSessionsDir, process.pid);
|
|
4031
|
+
removeSession(realFarmFs, paths.headroomSessionsDir, options.registerAs ?? process.pid);
|
|
4032
4032
|
}
|
|
4033
4033
|
};
|
|
4034
4034
|
}
|
|
@@ -5106,6 +5106,28 @@ function windowBurn(records, which) {
|
|
|
5106
5106
|
}
|
|
5107
5107
|
return (last.utilization - first.utilization) / (last.atMs - first.atMs);
|
|
5108
5108
|
}
|
|
5109
|
+
function billedTokensOf(record) {
|
|
5110
|
+
const usage = record.usage;
|
|
5111
|
+
return (usage?.inputTokens ?? 0) + (usage?.cacheCreationInputTokens ?? 0) + (usage?.outputTokens ?? 0);
|
|
5112
|
+
}
|
|
5113
|
+
function utilisationPerBilledToken(records) {
|
|
5114
|
+
const points = [];
|
|
5115
|
+
for (const record of records) {
|
|
5116
|
+
const window = record.rateLimitHeaders === void 0 ? void 0 : parseUnifiedRateLimit(record.rateLimitHeaders)?.fiveHour;
|
|
5117
|
+
if (window?.utilization !== void 0 && window.resetsAt !== void 0) {
|
|
5118
|
+
points.push({ resetsAt: window.resetsAt, utilization: window.utilization, billed: billedTokensOf(record) });
|
|
5119
|
+
}
|
|
5120
|
+
}
|
|
5121
|
+
const latest = points.at(-1)?.resetsAt;
|
|
5122
|
+
const current = points.filter((point) => point.resetsAt === latest);
|
|
5123
|
+
const first = current.at(0);
|
|
5124
|
+
const last = current.at(-1);
|
|
5125
|
+
if (first === void 0 || last === void 0 || last.utilization <= first.utilization) {
|
|
5126
|
+
return void 0;
|
|
5127
|
+
}
|
|
5128
|
+
const billed = current.slice(1).reduce((sum, point) => sum + point.billed, 0);
|
|
5129
|
+
return billed > 0 ? (last.utilization - first.utilization) / billed : void 0;
|
|
5130
|
+
}
|
|
5109
5131
|
function windowRatio(records) {
|
|
5110
5132
|
const points = [];
|
|
5111
5133
|
for (const record of records) {
|
|
@@ -5282,6 +5304,16 @@ function rankPool(input) {
|
|
|
5282
5304
|
drySpots.push(`7d window would run dry in ${formatAge(runsDryInMs)}, before it resets in ${formatAge(sevenDay.untilResetMs)}`);
|
|
5283
5305
|
}
|
|
5284
5306
|
}
|
|
5307
|
+
const { sticky: sticky2 } = input;
|
|
5308
|
+
const warmHere = sticky2?.identity === candidate.identity && nowMs - Date.parse(sticky2.at) <= PROMPT_CACHE_TTL_MS;
|
|
5309
|
+
if (input.resuming && input.resumeContextTokens !== void 0 && fiveHour !== void 0 && !warmHere) {
|
|
5310
|
+
const perToken = utilisationPerBilledToken(assessment.member.records);
|
|
5311
|
+
const cost = perToken === void 0 ? void 0 : input.resumeContextTokens * perToken;
|
|
5312
|
+
if (cost !== void 0 && cost > fiveHour.remaining) {
|
|
5313
|
+
dryAfterMs.push(0);
|
|
5314
|
+
drySpots.push(`resuming a ${String(input.resumeContextTokens)}-token conversation here would cost about ${percent(cost)} of the 5h window, which has ${percent(fiveHour.remaining)} left`);
|
|
5315
|
+
}
|
|
5316
|
+
}
|
|
5285
5317
|
if (drySpots.length === 0) {
|
|
5286
5318
|
return { ...candidate, feasible: true };
|
|
5287
5319
|
}
|
|
@@ -5631,6 +5663,7 @@ function rankNamedPool(input, poolName, stack, sticky) {
|
|
|
5631
5663
|
members,
|
|
5632
5664
|
nowMs: input.nowMs,
|
|
5633
5665
|
resuming: input.resuming,
|
|
5666
|
+
...input.resumeContextTokens === void 0 ? {} : { resumeContextTokens: input.resumeContextTokens },
|
|
5634
5667
|
...sticky === void 0 ? {} : { sticky },
|
|
5635
5668
|
...pool.preference === void 0 ? {} : { preference: pool.preference }
|
|
5636
5669
|
});
|
|
@@ -5773,6 +5806,7 @@ function buildLayoutPaths(root) {
|
|
|
5773
5806
|
claudeShimFile: path23.join(root, "claude-shim.json"),
|
|
5774
5807
|
headroomDir: path23.join(root, "headroom"),
|
|
5775
5808
|
headroomStateFile: path23.join(root, "headroom", "state.json"),
|
|
5809
|
+
headroomRoutingFile: path23.join(root, "headroom", "routing.json"),
|
|
5776
5810
|
headroomLegacyStateFile: path23.join(root, "headroom", "state.v2.json"),
|
|
5777
5811
|
headroomAllowlistFile: path23.join(root, "headroom", "run", "allowlist.txt"),
|
|
5778
5812
|
headroomSocketDir: path23.join(root, "headroom", "run"),
|
|
@@ -7246,6 +7280,7 @@ function resolvePoolLaunch(params) {
|
|
|
7246
7280
|
poolName,
|
|
7247
7281
|
nowMs,
|
|
7248
7282
|
resuming,
|
|
7283
|
+
...params.resumeContextTokens === void 0 ? {} : { resumeContextTokens: params.resumeContextTokens },
|
|
7249
7284
|
identityExists: (name) => loadIdentity(params.paths.identitiesDir, name, params.fs) !== void 0,
|
|
7250
7285
|
...stickyRead.sticky === void 0 ? {} : { sticky: stickyRead.sticky }
|
|
7251
7286
|
});
|
|
@@ -7316,6 +7351,90 @@ var init_pool = __esm({
|
|
|
7316
7351
|
}
|
|
7317
7352
|
});
|
|
7318
7353
|
|
|
7354
|
+
// src/usage/resumeContext.ts
|
|
7355
|
+
import path37 from "node:path";
|
|
7356
|
+
function projectDirNameOf(cwd) {
|
|
7357
|
+
return cwd.replace(/[^A-Za-z0-9]/g, "-");
|
|
7358
|
+
}
|
|
7359
|
+
function resumeTargetOf(passthrough) {
|
|
7360
|
+
const end = passthrough.indexOf("--");
|
|
7361
|
+
const tokens = end === -1 ? passthrough : passthrough.slice(0, end);
|
|
7362
|
+
for (const [index, token] of tokens.entries()) {
|
|
7363
|
+
if (token === "--continue" || token === "-c") {
|
|
7364
|
+
return { kind: "latest" };
|
|
7365
|
+
}
|
|
7366
|
+
if (token === "--resume" || token === "-r") {
|
|
7367
|
+
const next = tokens[index + 1];
|
|
7368
|
+
return next === void 0 || next.startsWith("-") ? void 0 : { kind: "id", id: next };
|
|
7369
|
+
}
|
|
7370
|
+
if (token.startsWith("--resume=")) {
|
|
7371
|
+
const id = token.slice("--resume=".length);
|
|
7372
|
+
return id === "" ? void 0 : { kind: "id", id };
|
|
7373
|
+
}
|
|
7374
|
+
}
|
|
7375
|
+
return void 0;
|
|
7376
|
+
}
|
|
7377
|
+
function countOf(usage, key) {
|
|
7378
|
+
const value = key in usage ? Reflect.get(usage, key) : void 0;
|
|
7379
|
+
return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : 0;
|
|
7380
|
+
}
|
|
7381
|
+
function contextTokensOfTranscript(text) {
|
|
7382
|
+
const lines = text.split("\n");
|
|
7383
|
+
for (let index = lines.length - 1; index >= 0; index -= 1) {
|
|
7384
|
+
const line = lines[index];
|
|
7385
|
+
if (line === void 0 || line === "") {
|
|
7386
|
+
continue;
|
|
7387
|
+
}
|
|
7388
|
+
let parsed;
|
|
7389
|
+
try {
|
|
7390
|
+
parsed = JSON.parse(line);
|
|
7391
|
+
} catch {
|
|
7392
|
+
continue;
|
|
7393
|
+
}
|
|
7394
|
+
if (typeof parsed !== "object" || parsed === null || !("type" in parsed) || parsed.type !== "assistant" || !("message" in parsed)) {
|
|
7395
|
+
continue;
|
|
7396
|
+
}
|
|
7397
|
+
const { message } = parsed;
|
|
7398
|
+
if (typeof message !== "object" || message === null || !("usage" in message) || typeof message.usage !== "object" || message.usage === null) {
|
|
7399
|
+
continue;
|
|
7400
|
+
}
|
|
7401
|
+
const { usage } = message;
|
|
7402
|
+
return countOf(usage, "input_tokens") + countOf(usage, "cache_read_input_tokens") + countOf(usage, "cache_creation_input_tokens");
|
|
7403
|
+
}
|
|
7404
|
+
return void 0;
|
|
7405
|
+
}
|
|
7406
|
+
function resumedContextTokens(fs12, params) {
|
|
7407
|
+
const target = resumeTargetOf(params.passthrough);
|
|
7408
|
+
if (target === void 0) {
|
|
7409
|
+
return void 0;
|
|
7410
|
+
}
|
|
7411
|
+
const projectDir = path37.join(params.claudeHome, "projects", projectDirNameOf(params.cwd));
|
|
7412
|
+
let file;
|
|
7413
|
+
if (target.kind === "id") {
|
|
7414
|
+
file = path37.join(projectDir, `${target.id}.jsonl`);
|
|
7415
|
+
} else {
|
|
7416
|
+
let newestMs = -Infinity;
|
|
7417
|
+
for (const name of fs12.readdir(projectDir)) {
|
|
7418
|
+
if (!name.endsWith(".jsonl")) {
|
|
7419
|
+
continue;
|
|
7420
|
+
}
|
|
7421
|
+
const candidate = path37.join(projectDir, name);
|
|
7422
|
+
const stat = fs12.lstat(candidate);
|
|
7423
|
+
if (stat?.kind === "file" && stat.mtimeMs > newestMs) {
|
|
7424
|
+
newestMs = stat.mtimeMs;
|
|
7425
|
+
file = candidate;
|
|
7426
|
+
}
|
|
7427
|
+
}
|
|
7428
|
+
}
|
|
7429
|
+
const text = file === void 0 ? void 0 : fs12.readFileUtf8(file);
|
|
7430
|
+
return text === void 0 ? void 0 : contextTokensOfTranscript(text);
|
|
7431
|
+
}
|
|
7432
|
+
var init_resumeContext = __esm({
|
|
7433
|
+
"src/usage/resumeContext.ts"() {
|
|
7434
|
+
"use strict";
|
|
7435
|
+
}
|
|
7436
|
+
});
|
|
7437
|
+
|
|
7319
7438
|
// src/launcher/spawn.ts
|
|
7320
7439
|
import os7 from "node:os";
|
|
7321
7440
|
function childExitCode(result) {
|
|
@@ -7416,7 +7535,7 @@ var init_launchHook = __esm({
|
|
|
7416
7535
|
|
|
7417
7536
|
// src/launcher.ts
|
|
7418
7537
|
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
7419
|
-
import
|
|
7538
|
+
import path38 from "node:path";
|
|
7420
7539
|
function resolveIdentityCredential(identity, credential, env, port) {
|
|
7421
7540
|
if (port === void 0) {
|
|
7422
7541
|
return { ok: false, status: 1, message: `agent-shim: identity ${identity} needs its credential resolved, but this launcher has no credential port wired` };
|
|
@@ -7434,6 +7553,7 @@ function pickFromPool(decided, params, parsedArgv, readOnly) {
|
|
|
7434
7553
|
log.error(`agent-shim: pool "${decided.pool}" was selected, but this launcher has no farm wired to read usage and pick a member with.`);
|
|
7435
7554
|
return proc.exit(1);
|
|
7436
7555
|
}
|
|
7556
|
+
const resumeContextTokens = resumedContextTokens(farmRuntime.fs, { claudeHome: farmRuntime.claudeHome, cwd: farmRuntime.cwd, passthrough: parsedArgv.rest });
|
|
7437
7557
|
const resolution = resolvePoolLaunch({
|
|
7438
7558
|
poolName: decided.pool,
|
|
7439
7559
|
selectedVia: decided.source,
|
|
@@ -7445,6 +7565,7 @@ function pickFromPool(decided, params, parsedArgv, readOnly) {
|
|
|
7445
7565
|
now: farmRuntime.now,
|
|
7446
7566
|
sleep: farmRuntime.lock.sleep,
|
|
7447
7567
|
passthrough: parsedArgv.rest,
|
|
7568
|
+
...resumeContextTokens === void 0 ? {} : { resumeContextTokens },
|
|
7448
7569
|
// A read-only decision never sleeps for a refused pool and never records its pick, so asking what a launch would pick leaves the next real launch's keep-warm preference as it was.
|
|
7449
7570
|
wait: !readOnly && parsedArgv.wait === true,
|
|
7450
7571
|
recordPick: !readOnly,
|
|
@@ -7526,7 +7647,7 @@ function decideLaunch(params, readOnly) {
|
|
|
7526
7647
|
identityDefaultConfigProfile: loadedIdentity?.config.defaultConfigProfile,
|
|
7527
7648
|
globalDefaultConfigProfile: params.globalDefaultConfigProfile
|
|
7528
7649
|
});
|
|
7529
|
-
if (configProfileDecision.name !== void 0 && params.allowMissingConfigProfile !== true && fs12.readConfigFile(
|
|
7650
|
+
if (configProfileDecision.name !== void 0 && params.allowMissingConfigProfile !== true && fs12.readConfigFile(path38.join(paths.configProfilesDir, `${configProfileDecision.name}.json`)) === void 0) {
|
|
7530
7651
|
log.error(
|
|
7531
7652
|
`agent-shim: no configuration profile named "${configProfileDecision.name}" (selected via ${configProfileDecision.source}). Run \`agent-shim profile add ${configProfileDecision.name}\` first.`
|
|
7532
7653
|
);
|
|
@@ -7636,7 +7757,7 @@ function decideLaunch(params, readOnly) {
|
|
|
7636
7757
|
extraFlags: splitExtraFlags(env.CLAUDE_EXTRA_FLAGS),
|
|
7637
7758
|
passthrough: parsedArgv.rest
|
|
7638
7759
|
});
|
|
7639
|
-
const configDir = configDirEscapeHatchApplies || identityDecision.name === void 0 ? env.CLAUDE_CONFIG_DIR :
|
|
7760
|
+
const configDir = configDirEscapeHatchApplies || identityDecision.name === void 0 ? env.CLAUDE_CONFIG_DIR : path38.join(paths.identitiesDir, identityDecision.name);
|
|
7640
7761
|
const decision = {
|
|
7641
7762
|
identitySource: identityDecision.source,
|
|
7642
7763
|
configDirEscapeHatch: identityDecision.configDirEscapeHatch,
|
|
@@ -7677,7 +7798,7 @@ function prepareLaunch(params) {
|
|
|
7677
7798
|
);
|
|
7678
7799
|
const updateCheck = runLaunchUpdateCheck({
|
|
7679
7800
|
mode: params.updateMode ?? "off",
|
|
7680
|
-
checkPath:
|
|
7801
|
+
checkPath: path38.join(paths.root, "update.check"),
|
|
7681
7802
|
currentVersion: package_default.version,
|
|
7682
7803
|
port: params.update
|
|
7683
7804
|
});
|
|
@@ -7821,6 +7942,7 @@ var init_launcher = __esm({
|
|
|
7821
7942
|
init_flags();
|
|
7822
7943
|
init_extraFlags();
|
|
7823
7944
|
init_pool();
|
|
7945
|
+
init_resumeContext();
|
|
7824
7946
|
init_lock();
|
|
7825
7947
|
init_spawn();
|
|
7826
7948
|
init_providersStore();
|
|
@@ -7837,12 +7959,12 @@ var init_launcher = __esm({
|
|
|
7837
7959
|
});
|
|
7838
7960
|
|
|
7839
7961
|
// src/ownCli.ts
|
|
7840
|
-
import
|
|
7962
|
+
import path39 from "node:path";
|
|
7841
7963
|
function agentShimCliPath(distDir = typeof __AGENT_SHIM_DIST_DIR__ === "string" ? __AGENT_SHIM_DIST_DIR__ : void 0) {
|
|
7842
7964
|
if (distDir === void 0) {
|
|
7843
7965
|
throw new OwnCliPathUnknownError();
|
|
7844
7966
|
}
|
|
7845
|
-
return
|
|
7967
|
+
return path39.join(distDir, OWN_CLI_FILE_NAME);
|
|
7846
7968
|
}
|
|
7847
7969
|
var OWN_CLI_FILE_NAME, OwnCliPathUnknownError;
|
|
7848
7970
|
var init_ownCli = __esm({
|
|
@@ -7931,10 +8053,10 @@ request.on("error", (error) => finish(failed, (error.code ? error.code + ": " :
|
|
|
7931
8053
|
|
|
7932
8054
|
// src/frontdoor/trust.ts
|
|
7933
8055
|
import { createHash as createHash6 } from "node:crypto";
|
|
7934
|
-
import
|
|
8056
|
+
import path40 from "node:path";
|
|
7935
8057
|
function resolveTrustBundle(params) {
|
|
7936
8058
|
const { caCertFile, bundlesDir, variable, inherited, fs: fs12 } = params;
|
|
7937
|
-
if (inherited === void 0 || inherited === "" ||
|
|
8059
|
+
if (inherited === void 0 || inherited === "" || path40.resolve(inherited) === path40.resolve(caCertFile)) {
|
|
7938
8060
|
return { path: caCertFile };
|
|
7939
8061
|
}
|
|
7940
8062
|
const caPem = fs12.readFileUtf8(caCertFile);
|
|
@@ -7952,7 +8074,7 @@ function resolveTrustBundle(params) {
|
|
|
7952
8074
|
}
|
|
7953
8075
|
const combined = `${inheritedPem.trimEnd()}
|
|
7954
8076
|
${caPem}`;
|
|
7955
|
-
const bundle =
|
|
8077
|
+
const bundle = path40.join(bundlesDir, `${createHash6("sha256").update(combined).digest("hex").slice(0, BUNDLE_NAME_HEX_DIGITS)}.pem`);
|
|
7956
8078
|
if (!fs12.exists(bundle)) {
|
|
7957
8079
|
fs12.mkdirp(bundlesDir);
|
|
7958
8080
|
fs12.writeFileAtomic(bundle, combined);
|
|
@@ -9013,8 +9135,8 @@ function parseConnectTarget(authority) {
|
|
|
9013
9135
|
function isInterceptedHost(host, interceptHosts) {
|
|
9014
9136
|
return interceptHosts.includes(host);
|
|
9015
9137
|
}
|
|
9016
|
-
function servedByPipeline(
|
|
9017
|
-
return
|
|
9138
|
+
function servedByPipeline(path41) {
|
|
9139
|
+
return path41?.startsWith(ROUTED_PATH_PREFIX) === true;
|
|
9018
9140
|
}
|
|
9019
9141
|
var HOP_BY_HOP_HEADERS = /* @__PURE__ */ new Set([
|
|
9020
9142
|
"connection",
|
|
@@ -9808,11 +9930,11 @@ function createRcSessionTracker(deps) {
|
|
|
9808
9930
|
};
|
|
9809
9931
|
const observeExchange = (request4) => {
|
|
9810
9932
|
const method = (request4.method ?? "").toUpperCase();
|
|
9811
|
-
const
|
|
9812
|
-
if (!
|
|
9933
|
+
const path41 = new URL(request4.url ?? "/", "http://127.0.0.1").pathname;
|
|
9934
|
+
if (!path41.startsWith(RC_SESSIONS_PATH_PREFIX)) {
|
|
9813
9935
|
return void 0;
|
|
9814
9936
|
}
|
|
9815
|
-
const tail =
|
|
9937
|
+
const tail = path41.slice(RC_SESSIONS_PATH_PREFIX.length);
|
|
9816
9938
|
const facts = {
|
|
9817
9939
|
oauthAuthorization: oauthAuthorizationOf(request4.headers),
|
|
9818
9940
|
anthropicVersion: singleHeader(request4.headers, "anthropic-version"),
|
|
@@ -10202,8 +10324,8 @@ var RC_READ_FILE_ENCODINGS = ["utf-8", "base64"];
|
|
|
10202
10324
|
function isRcReadFileEncoding(value) {
|
|
10203
10325
|
return RC_READ_FILE_ENCODINGS.some((encoding) => encoding === value);
|
|
10204
10326
|
}
|
|
10205
|
-
function buildRcReadFilePayload(requestId,
|
|
10206
|
-
return buildRcControlRequestPayload(requestId, { subtype: "read_file", path:
|
|
10327
|
+
function buildRcReadFilePayload(requestId, path41, options) {
|
|
10328
|
+
return buildRcControlRequestPayload(requestId, { subtype: "read_file", path: path41, ...options?.maxBytes === void 0 ? {} : { max_bytes: options.maxBytes }, ...options?.encoding === void 0 ? {} : { encoding: options.encoding } });
|
|
10207
10329
|
}
|
|
10208
10330
|
function buildRcFileSuggestionsPayload(requestId, query) {
|
|
10209
10331
|
return buildRcControlRequestPayload(requestId, { subtype: "file_suggestions", query });
|
|
@@ -10305,15 +10427,15 @@ async function getRcSessionContextUsage(deps, sessionId, detail) {
|
|
|
10305
10427
|
const result = await deliverRcClientPayload(deps, sessionId, buildRcGetContextUsagePayload(requestId, detail), `request the context usage of session ${sessionId}`);
|
|
10306
10428
|
return result.ok ? { ...result, requestId } : result;
|
|
10307
10429
|
}
|
|
10308
|
-
async function readRcSessionFile(deps, sessionId,
|
|
10309
|
-
if (
|
|
10430
|
+
async function readRcSessionFile(deps, sessionId, path41, options) {
|
|
10431
|
+
if (path41 === "") {
|
|
10310
10432
|
return { ok: false, message: "a read-file write needs a non-empty path: the SDK's own field names the file the worker resolves against the session's cwd, and an empty string names none" };
|
|
10311
10433
|
}
|
|
10312
10434
|
if (options?.maxBytes !== void 0 && (!Number.isInteger(options.maxBytes) || options.maxBytes <= 0)) {
|
|
10313
10435
|
return { ok: false, message: "a read-file write's max-bytes is a positive whole number of bytes: the SDK's own field caps the read, and a zero or negative cap reads nothing" };
|
|
10314
10436
|
}
|
|
10315
10437
|
const requestId = deps.newUuid();
|
|
10316
|
-
const result = await deliverRcClientPayload(deps, sessionId, buildRcReadFilePayload(requestId,
|
|
10438
|
+
const result = await deliverRcClientPayload(deps, sessionId, buildRcReadFilePayload(requestId, path41, options), `read ${path41} from session ${sessionId}`);
|
|
10317
10439
|
return result.ok ? { ...result, requestId } : result;
|
|
10318
10440
|
}
|
|
10319
10441
|
async function suggestRcSessionFiles(deps, sessionId, query) {
|
|
@@ -10482,11 +10604,11 @@ function createRcControlHandler(deps) {
|
|
|
10482
10604
|
path: "read-file",
|
|
10483
10605
|
read: (body) => {
|
|
10484
10606
|
const session = bodyString(body, "session");
|
|
10485
|
-
const
|
|
10607
|
+
const path41 = bodyString(body, "path");
|
|
10486
10608
|
const maxBytes = "maxBytes" in body ? bodyPositiveInteger(body, "maxBytes") : void 0;
|
|
10487
10609
|
const encoding = "encoding" in body && isRcReadFileEncoding(body.encoding) ? body.encoding : void 0;
|
|
10488
|
-
const refused2 = session === void 0 ||
|
|
10489
|
-
return refused2 ? { error: `the read-file body must be JSON naming a non-empty session id and path, maxBytes only as a positive whole number or absent, and an encoding the SDK's own type permits (${RC_READ_FILE_ENCODINGS.join(", ")}) or none` } : { session, run: async () => await deps.readFile(session,
|
|
10610
|
+
const refused2 = session === void 0 || path41 === void 0 || "maxBytes" in body && maxBytes === void 0 || "encoding" in body && encoding === void 0;
|
|
10611
|
+
return refused2 ? { error: `the read-file body must be JSON naming a non-empty session id and path, maxBytes only as a positive whole number or absent, and an encoding the SDK's own type permits (${RC_READ_FILE_ENCODINGS.join(", ")}) or none` } : { session, run: async () => await deps.readFile(session, path41, { ...maxBytes === void 0 ? {} : { maxBytes }, ...encoding === void 0 ? {} : { encoding } }) };
|
|
10490
10612
|
}
|
|
10491
10613
|
},
|
|
10492
10614
|
{
|
|
@@ -10796,9 +10918,9 @@ function requestIdOfBody(body) {
|
|
|
10796
10918
|
}
|
|
10797
10919
|
function frontDoorRcControl(transport, token) {
|
|
10798
10920
|
const headers = { authorization: `Bearer ${token}` };
|
|
10799
|
-
const listAnswerOf = async (
|
|
10921
|
+
const listAnswerOf = async (path41, what) => {
|
|
10800
10922
|
try {
|
|
10801
|
-
return await transport.request({ method: "GET", path:
|
|
10923
|
+
return await transport.request({ method: "GET", path: path41, headers });
|
|
10802
10924
|
} catch (error) {
|
|
10803
10925
|
throw new Error(`${what}: could not reach the front door's control listener: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
|
|
10804
10926
|
}
|
|
@@ -10870,10 +10992,10 @@ function frontDoorRcControl(transport, token) {
|
|
|
10870
10992
|
}
|
|
10871
10993
|
return pending;
|
|
10872
10994
|
};
|
|
10873
|
-
const writeOf = async (
|
|
10995
|
+
const writeOf = async (path41, body, describeFailure2) => {
|
|
10874
10996
|
let answer;
|
|
10875
10997
|
try {
|
|
10876
|
-
answer = await transport.request({ method: "POST", path:
|
|
10998
|
+
answer = await transport.request({ method: "POST", path: path41, headers: { ...headers, "content-type": "application/json" }, body });
|
|
10877
10999
|
} catch (error) {
|
|
10878
11000
|
return { ok: false, message: `could not reach the front door's control listener: ${error instanceof Error ? error.message : String(error)}` };
|
|
10879
11001
|
}
|
|
@@ -10904,10 +11026,10 @@ function frontDoorRcControl(transport, token) {
|
|
|
10904
11026
|
endSession: async (sessionId, reason) => await writeOf(`${CONTROL_PATH_PREFIX}/end-session`, JSON.stringify({ session: sessionId, ...reason === void 0 ? {} : { reason } }), (status, message) => `ending ${sessionId} failed (HTTP ${String(status)}): ${message}`),
|
|
10905
11027
|
getUsage: async (sessionId, skipBehaviors) => await writeOf(`${CONTROL_PATH_PREFIX}/get-usage`, JSON.stringify({ session: sessionId, ...skipBehaviors === void 0 ? {} : { skipBehaviors } }), (status, message) => `requesting the usage of ${sessionId} failed (HTTP ${String(status)}): ${message}`),
|
|
10906
11028
|
getContextUsage: async (sessionId, detail) => await writeOf(`${CONTROL_PATH_PREFIX}/get-context-usage`, JSON.stringify({ session: sessionId, ...detail === void 0 ? {} : { detail } }), (status, message) => `requesting the context usage of ${sessionId} failed (HTTP ${String(status)}): ${message}`),
|
|
10907
|
-
readFile: async (sessionId,
|
|
11029
|
+
readFile: async (sessionId, path41, options) => await writeOf(
|
|
10908
11030
|
`${CONTROL_PATH_PREFIX}/read-file`,
|
|
10909
|
-
JSON.stringify({ session: sessionId, path:
|
|
10910
|
-
(status, message) => `reading ${
|
|
11031
|
+
JSON.stringify({ session: sessionId, path: path41, ...options?.maxBytes === void 0 ? {} : { maxBytes: options.maxBytes }, ...options?.encoding === void 0 ? {} : { encoding: options.encoding } }),
|
|
11032
|
+
(status, message) => `reading ${path41} from ${sessionId} failed (HTTP ${String(status)}): ${message}`
|
|
10911
11033
|
),
|
|
10912
11034
|
fileSuggestions: async (sessionId, query) => await writeOf(`${CONTROL_PATH_PREFIX}/file-suggestions`, JSON.stringify({ session: sessionId, query }), (status, message) => `requesting file suggestions from ${sessionId} failed (HTTP ${String(status)}): ${message}`),
|
|
10913
11035
|
keepAlive: async (sessionId) => await writeOf(`${CONTROL_PATH_PREFIX}/keep-alive`, JSON.stringify({ session: sessionId }), (status, message) => `keeping ${sessionId} alive failed (HTTP ${String(status)}): ${message}`),
|
|
@@ -11066,12 +11188,12 @@ function tlsFacts(options) {
|
|
|
11066
11188
|
}
|
|
11067
11189
|
function realRcEventDial(target = { host: CONNECT_INTERCEPT_HOST, port: HTTPS_PORT }) {
|
|
11068
11190
|
const agent = new ExemptTlsAgent();
|
|
11069
|
-
const post = async (
|
|
11191
|
+
const post = async (path41, headers, body) => await new Promise((resolve, reject) => {
|
|
11070
11192
|
const options = {
|
|
11071
11193
|
host: target.host,
|
|
11072
11194
|
port: target.port,
|
|
11073
11195
|
method: "POST",
|
|
11074
|
-
path:
|
|
11196
|
+
path: path41,
|
|
11075
11197
|
// The Host header names the host whose API this is, not the address dialled: a redirected test dials a loopback stand-in while still speaking to the API host by name, exactly as the forwarded paths present their SNI.
|
|
11076
11198
|
headers: { ...headers, host: target.servername ?? target.host, "content-length": String(Buffer.byteLength(body, "utf8")) },
|
|
11077
11199
|
agent
|
|
@@ -11136,12 +11258,12 @@ function lateRcStreamDial(resolve) {
|
|
|
11136
11258
|
}
|
|
11137
11259
|
function realRcStreamDial(target = { host: CONNECT_INTERCEPT_HOST, port: HTTPS_PORT }) {
|
|
11138
11260
|
const agent = new ExemptTlsAgent();
|
|
11139
|
-
const request4 = async (method,
|
|
11261
|
+
const request4 = async (method, path41, headers, body, signal) => await new Promise((resolve, reject) => {
|
|
11140
11262
|
const options = {
|
|
11141
11263
|
host: target.host,
|
|
11142
11264
|
port: target.port,
|
|
11143
11265
|
method,
|
|
11144
|
-
path:
|
|
11266
|
+
path: path41,
|
|
11145
11267
|
// The Host header names the host whose API this is, not the address dialled: a redirected test dials a loopback stand-in while still speaking to the API host by name, exactly as the forwarded paths present their SNI.
|
|
11146
11268
|
headers: { ...headers, host: target.servername ?? target.host, ...body === void 0 ? {} : { "content-length": String(Buffer.byteLength(body, "utf8")) } },
|
|
11147
11269
|
agent,
|
|
@@ -11183,9 +11305,9 @@ function realRcStreamDial(target = { host: CONNECT_INTERCEPT_HOST, port: HTTPS_P
|
|
|
11183
11305
|
return { status, body: await readAll(response) };
|
|
11184
11306
|
},
|
|
11185
11307
|
openStream: async (sessionId, headers, resume, signal) => {
|
|
11186
|
-
const
|
|
11308
|
+
const path41 = resume === void 0 ? `/v1/code/sessions/${encodeURIComponent(sessionId)}/events/stream` : `/v1/code/sessions/${encodeURIComponent(sessionId)}/events/stream?from_sequence_num=${String(resume.fromSequenceNum)}`;
|
|
11187
11309
|
const streamHeaders = resume === void 0 ? headers : { ...headers, "last-event-id": String(resume.fromSequenceNum) };
|
|
11188
|
-
const { status, response } = await request4("GET",
|
|
11310
|
+
const { status, response } = await request4("GET", path41, streamHeaders, void 0, signal);
|
|
11189
11311
|
if (!isSuccessful2(status)) {
|
|
11190
11312
|
await readAll(response);
|
|
11191
11313
|
return { status, chunks: NO_CHUNKS };
|
|
@@ -12337,19 +12459,19 @@ function writePools(paths, pools) {
|
|
|
12337
12459
|
applyPatch(paths.globalConfigFile, GlobalConfigSchema, { pools }, { defaults: {} });
|
|
12338
12460
|
}
|
|
12339
12461
|
function poolCycleOf(pools, name) {
|
|
12340
|
-
const walk = (current,
|
|
12462
|
+
const walk = (current, path41) => {
|
|
12341
12463
|
for (const entry of pools[current]?.identities ?? []) {
|
|
12342
12464
|
const nested = poolNameOf(poolMemberIdentity(entry));
|
|
12343
12465
|
if (nested === void 0) {
|
|
12344
12466
|
continue;
|
|
12345
12467
|
}
|
|
12346
12468
|
if (nested === name) {
|
|
12347
|
-
return [...
|
|
12469
|
+
return [...path41, nested];
|
|
12348
12470
|
}
|
|
12349
|
-
if (
|
|
12471
|
+
if (path41.includes(nested)) {
|
|
12350
12472
|
continue;
|
|
12351
12473
|
}
|
|
12352
|
-
const found = walk(nested, [...
|
|
12474
|
+
const found = walk(nested, [...path41, nested]);
|
|
12353
12475
|
if (found !== void 0) {
|
|
12354
12476
|
return found;
|
|
12355
12477
|
}
|
|
@@ -14560,7 +14682,7 @@ function profileValue(name, paths) {
|
|
|
14560
14682
|
function createConfigApiRouter(deps) {
|
|
14561
14683
|
const authed = doorApiAuth(deps.expectedToken);
|
|
14562
14684
|
const { paths } = deps;
|
|
14563
|
-
const route = (
|
|
14685
|
+
const route = (path41, summary) => authed.meta(openapi3({ method: "POST", path: path41, summary, tags: [CONFIG_API_TAG] }));
|
|
14564
14686
|
return {
|
|
14565
14687
|
config: {
|
|
14566
14688
|
identity: {
|
package/dist/types/index.d.ts
CHANGED
|
@@ -1707,6 +1707,8 @@ interface LayoutPaths {
|
|
|
1707
1707
|
readonly headroomDir: string;
|
|
1708
1708
|
/** Path to the headroom supervisor's state file: pids, socket path, version, the hash of the allowlist the daemon serves, last error. One unversioned name every release shares, arbitrated by the ownership rules in `headroom/state.ts` rather than by a version in the file name. */
|
|
1709
1709
|
readonly headroomStateFile: string;
|
|
1710
|
+
/** The live routing setting `agent-shim headroom enable|disable` writes and the front door re-reads per request: which sessions go through headroom, whatever their launch asked for. */
|
|
1711
|
+
readonly headroomRoutingFile: string;
|
|
1710
1712
|
/** The previous release's versioned name for the state file, read only while a supervisor from that release is still alive and removed once its generation has drained (see `migrateHeadroomState`). */
|
|
1711
1713
|
readonly headroomLegacyStateFile: string;
|
|
1712
1714
|
/** Path to the file the headroom daemon reads its upstream allowlist from (`--allowed-base-urls-file`): the direct origin of every live front door, one per line. It lives in the owner-only socket directory because headroom refuses an allowlist file whose directory another user could write to, and that directory is the one this tool already creates mode 0700 (narrowing it if it existed wider) and checks before every daemon start. The supervisor replaces the file owner-only and atomically whenever a door's origin changes, and the daemon re-reads it on its next request, so a moved or retired front door never needs a restart. */
|
|
@@ -12753,6 +12755,8 @@ interface RankPoolInput {
|
|
|
12753
12755
|
readonly sticky?: StickyPick;
|
|
12754
12756
|
/** True when the launch continues or resumes a conversation, which belongs on the account it started on whatever the cache lifetime. */
|
|
12755
12757
|
readonly resuming: boolean;
|
|
12758
|
+
/** The size in tokens of the context a resumed conversation continues with. A member that is not the warm account of that conversation must pay to write this context again, so one whose five-hour window cannot cover it is not feasible. */
|
|
12759
|
+
readonly resumeContextTokens?: number;
|
|
12756
12760
|
/** How members are ordered: "score" (the default when absent) by the use-it-or-lose-it ranking, "listed" strictly in `members` order. */
|
|
12757
12761
|
readonly preference?: "score" | "listed";
|
|
12758
12762
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-use",
|
|
3
|
-
"version": "11.
|
|
3
|
+
"version": "11.3.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>",
|