claude-use 9.7.1 → 9.8.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/dist/cli.cjs +427 -370
- package/dist/index.cjs +120 -77
- package/dist/index.mjs +116 -73
- package/dist/types/index.d.ts +7 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -2639,7 +2639,7 @@ var init_package = __esm({
|
|
|
2639
2639
|
"package.json"() {
|
|
2640
2640
|
package_default = {
|
|
2641
2641
|
name: "claude-use",
|
|
2642
|
-
version: "9.
|
|
2642
|
+
version: "9.8.0",
|
|
2643
2643
|
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.",
|
|
2644
2644
|
license: "MIT",
|
|
2645
2645
|
author: "Joseph Mearman <joseph@mearman.co.uk>",
|
|
@@ -6510,7 +6510,7 @@ var init_headers = __esm({
|
|
|
6510
6510
|
});
|
|
6511
6511
|
|
|
6512
6512
|
// src/launcher/flags.ts
|
|
6513
|
-
import
|
|
6513
|
+
import path33 from "node:path";
|
|
6514
6514
|
function resolveLaunchFlags(params) {
|
|
6515
6515
|
return {
|
|
6516
6516
|
skipPermissions: params.flags?.skipPermissions ?? parseEnvBool("AGENT_SHIM_SKIP_PERMISSIONS", params.env.AGENT_SHIM_SKIP_PERMISSIONS) ?? params.cascade?.skipPermissions ?? false,
|
|
@@ -6541,7 +6541,7 @@ function buildEnv(params) {
|
|
|
6541
6541
|
const parentCustomHeaders = params.baseEnv.ANTHROPIC_CUSTOM_HEADERS;
|
|
6542
6542
|
let providerCustomHeaders;
|
|
6543
6543
|
if (!params.configDirEscapeHatch && params.resolvedIdentityName !== void 0) {
|
|
6544
|
-
env.CLAUDE_CONFIG_DIR =
|
|
6544
|
+
env.CLAUDE_CONFIG_DIR = path33.join(params.identitiesDir, params.resolvedIdentityName);
|
|
6545
6545
|
}
|
|
6546
6546
|
if (params.provider !== void 0) {
|
|
6547
6547
|
const providerEnv = params.provider.definition.env ?? {};
|
|
@@ -6803,7 +6803,7 @@ var init_launchHook = __esm({
|
|
|
6803
6803
|
|
|
6804
6804
|
// src/launcher.ts
|
|
6805
6805
|
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
6806
|
-
import
|
|
6806
|
+
import path34 from "node:path";
|
|
6807
6807
|
function resolveIdentityCredential(identity, credential, env, port) {
|
|
6808
6808
|
if (port === void 0) {
|
|
6809
6809
|
return { ok: false, status: 1, message: `agent-shim: identity ${identity} needs its credential resolved, but this launcher has no credential port wired` };
|
|
@@ -6913,7 +6913,7 @@ function decideLaunch(params, readOnly) {
|
|
|
6913
6913
|
identityDefaultConfigProfile: loadedIdentity?.config.defaultConfigProfile,
|
|
6914
6914
|
globalDefaultConfigProfile: params.globalDefaultConfigProfile
|
|
6915
6915
|
});
|
|
6916
|
-
if (configProfileDecision.name !== void 0 && params.allowMissingConfigProfile !== true && fs12.readConfigFile(
|
|
6916
|
+
if (configProfileDecision.name !== void 0 && params.allowMissingConfigProfile !== true && fs12.readConfigFile(path34.join(paths.configProfilesDir, `${configProfileDecision.name}.json`)) === void 0) {
|
|
6917
6917
|
log.error(
|
|
6918
6918
|
`agent-shim: no configuration profile named "${configProfileDecision.name}" (selected via ${configProfileDecision.source}). Run \`agent-shim profile add ${configProfileDecision.name}\` first.`
|
|
6919
6919
|
);
|
|
@@ -6992,10 +6992,16 @@ function decideLaunch(params, readOnly) {
|
|
|
6992
6992
|
const assembled = assembleCascade(launchCascade);
|
|
6993
6993
|
const flattened = flattenLayers(assembled.layers, { home: params.farm.home });
|
|
6994
6994
|
cascadeLaunch = flattened.launch;
|
|
6995
|
-
if (readOnly) {
|
|
6995
|
+
if (readOnly || farmContext === void 0) {
|
|
6996
6996
|
for (const diagnostic of [...assembled.diagnostics, ...flattened.diagnostics]) {
|
|
6997
|
-
if (diagnostic.severity
|
|
6998
|
-
|
|
6997
|
+
if (diagnostic.severity === "info") {
|
|
6998
|
+
continue;
|
|
6999
|
+
}
|
|
7000
|
+
const message = `agent-shim: ${diagnostic.code}: ${diagnostic.message}`;
|
|
7001
|
+
if (diagnostic.severity === "error" && !readOnly) {
|
|
7002
|
+
log.error(message);
|
|
7003
|
+
} else {
|
|
7004
|
+
log.warn(message);
|
|
6999
7005
|
}
|
|
7000
7006
|
}
|
|
7001
7007
|
}
|
|
@@ -7019,7 +7025,7 @@ function decideLaunch(params, readOnly) {
|
|
|
7019
7025
|
extraFlags: splitExtraFlags(env.CLAUDE_EXTRA_FLAGS),
|
|
7020
7026
|
passthrough: parsedArgv.rest
|
|
7021
7027
|
});
|
|
7022
|
-
const configDir = configDirEscapeHatchApplies || identityDecision.name === void 0 ? env.CLAUDE_CONFIG_DIR :
|
|
7028
|
+
const configDir = configDirEscapeHatchApplies || identityDecision.name === void 0 ? env.CLAUDE_CONFIG_DIR : path34.join(paths.identitiesDir, identityDecision.name);
|
|
7023
7029
|
const decision = {
|
|
7024
7030
|
identitySource: identityDecision.source,
|
|
7025
7031
|
configDirEscapeHatch: identityDecision.configDirEscapeHatch,
|
|
@@ -7060,7 +7066,7 @@ function prepareLaunch(params) {
|
|
|
7060
7066
|
);
|
|
7061
7067
|
const updateCheck = runLaunchUpdateCheck({
|
|
7062
7068
|
mode: params.updateMode ?? "off",
|
|
7063
|
-
checkPath:
|
|
7069
|
+
checkPath: path34.join(paths.root, "update.check"),
|
|
7064
7070
|
currentVersion: package_default.version,
|
|
7065
7071
|
port: params.update
|
|
7066
7072
|
});
|
|
@@ -7220,12 +7226,12 @@ var init_launcher = __esm({
|
|
|
7220
7226
|
});
|
|
7221
7227
|
|
|
7222
7228
|
// src/ownCli.ts
|
|
7223
|
-
import
|
|
7229
|
+
import path35 from "node:path";
|
|
7224
7230
|
function agentShimCliPath(distDir = typeof __AGENT_SHIM_DIST_DIR__ === "string" ? __AGENT_SHIM_DIST_DIR__ : void 0) {
|
|
7225
7231
|
if (distDir === void 0) {
|
|
7226
7232
|
throw new OwnCliPathUnknownError();
|
|
7227
7233
|
}
|
|
7228
|
-
return
|
|
7234
|
+
return path35.join(distDir, OWN_CLI_FILE_NAME);
|
|
7229
7235
|
}
|
|
7230
7236
|
var OWN_CLI_FILE_NAME, OwnCliPathUnknownError;
|
|
7231
7237
|
var init_ownCli = __esm({
|
|
@@ -7314,10 +7320,10 @@ request.on("error", (error) => finish(failed, (error.code ? error.code + ": " :
|
|
|
7314
7320
|
|
|
7315
7321
|
// src/frontdoor/trust.ts
|
|
7316
7322
|
import { createHash as createHash6 } from "node:crypto";
|
|
7317
|
-
import
|
|
7323
|
+
import path36 from "node:path";
|
|
7318
7324
|
function resolveTrustBundle(params) {
|
|
7319
7325
|
const { caCertFile, bundlesDir, variable, inherited, fs: fs12 } = params;
|
|
7320
|
-
if (inherited === void 0 || inherited === "" ||
|
|
7326
|
+
if (inherited === void 0 || inherited === "" || path36.resolve(inherited) === path36.resolve(caCertFile)) {
|
|
7321
7327
|
return { path: caCertFile };
|
|
7322
7328
|
}
|
|
7323
7329
|
const caPem = fs12.readFileUtf8(caCertFile);
|
|
@@ -7335,7 +7341,7 @@ function resolveTrustBundle(params) {
|
|
|
7335
7341
|
}
|
|
7336
7342
|
const combined = `${inheritedPem.trimEnd()}
|
|
7337
7343
|
${caPem}`;
|
|
7338
|
-
const bundle =
|
|
7344
|
+
const bundle = path36.join(bundlesDir, `${createHash6("sha256").update(combined).digest("hex").slice(0, BUNDLE_NAME_HEX_DIGITS)}.pem`);
|
|
7339
7345
|
if (!fs12.exists(bundle)) {
|
|
7340
7346
|
fs12.mkdirp(bundlesDir);
|
|
7341
7347
|
fs12.writeFileAtomic(bundle, combined);
|
|
@@ -8345,8 +8351,8 @@ function parseConnectTarget(authority) {
|
|
|
8345
8351
|
function isInterceptedHost(host, interceptHosts) {
|
|
8346
8352
|
return interceptHosts.includes(host);
|
|
8347
8353
|
}
|
|
8348
|
-
function servedByPipeline(
|
|
8349
|
-
return
|
|
8354
|
+
function servedByPipeline(path37) {
|
|
8355
|
+
return path37?.startsWith(ROUTED_PATH_PREFIX) === true;
|
|
8350
8356
|
}
|
|
8351
8357
|
var HOP_BY_HOP_HEADERS = /* @__PURE__ */ new Set([
|
|
8352
8358
|
"connection",
|
|
@@ -8881,11 +8887,11 @@ function createRcSessionTracker(deps) {
|
|
|
8881
8887
|
};
|
|
8882
8888
|
const observeExchange = (request4) => {
|
|
8883
8889
|
const method = (request4.method ?? "").toUpperCase();
|
|
8884
|
-
const
|
|
8885
|
-
if (!
|
|
8890
|
+
const path37 = new URL(request4.url ?? "/", "http://127.0.0.1").pathname;
|
|
8891
|
+
if (!path37.startsWith(RC_SESSIONS_PATH_PREFIX)) {
|
|
8886
8892
|
return void 0;
|
|
8887
8893
|
}
|
|
8888
|
-
const tail =
|
|
8894
|
+
const tail = path37.slice(RC_SESSIONS_PATH_PREFIX.length);
|
|
8889
8895
|
const facts = {
|
|
8890
8896
|
oauthAuthorization: oauthAuthorizationOf(request4.headers),
|
|
8891
8897
|
anthropicVersion: singleHeader(request4.headers, "anthropic-version"),
|
|
@@ -9267,8 +9273,8 @@ var RC_READ_FILE_ENCODINGS = ["utf-8", "base64"];
|
|
|
9267
9273
|
function isRcReadFileEncoding(value) {
|
|
9268
9274
|
return RC_READ_FILE_ENCODINGS.some((encoding) => encoding === value);
|
|
9269
9275
|
}
|
|
9270
|
-
function buildRcReadFilePayload(requestId,
|
|
9271
|
-
return buildRcControlRequestPayload(requestId, { subtype: "read_file", path:
|
|
9276
|
+
function buildRcReadFilePayload(requestId, path37, options) {
|
|
9277
|
+
return buildRcControlRequestPayload(requestId, { subtype: "read_file", path: path37, ...options?.maxBytes === void 0 ? {} : { max_bytes: options.maxBytes }, ...options?.encoding === void 0 ? {} : { encoding: options.encoding } });
|
|
9272
9278
|
}
|
|
9273
9279
|
function buildRcFileSuggestionsPayload(requestId, query) {
|
|
9274
9280
|
return buildRcControlRequestPayload(requestId, { subtype: "file_suggestions", query });
|
|
@@ -9370,15 +9376,15 @@ async function getRcSessionContextUsage(deps, sessionId, detail) {
|
|
|
9370
9376
|
const result = await deliverRcClientPayload(deps, sessionId, buildRcGetContextUsagePayload(requestId, detail), `request the context usage of session ${sessionId}`);
|
|
9371
9377
|
return result.ok ? { ...result, requestId } : result;
|
|
9372
9378
|
}
|
|
9373
|
-
async function readRcSessionFile(deps, sessionId,
|
|
9374
|
-
if (
|
|
9379
|
+
async function readRcSessionFile(deps, sessionId, path37, options) {
|
|
9380
|
+
if (path37 === "") {
|
|
9375
9381
|
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" };
|
|
9376
9382
|
}
|
|
9377
9383
|
if (options?.maxBytes !== void 0 && (!Number.isInteger(options.maxBytes) || options.maxBytes <= 0)) {
|
|
9378
9384
|
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" };
|
|
9379
9385
|
}
|
|
9380
9386
|
const requestId = deps.newUuid();
|
|
9381
|
-
const result = await deliverRcClientPayload(deps, sessionId, buildRcReadFilePayload(requestId,
|
|
9387
|
+
const result = await deliverRcClientPayload(deps, sessionId, buildRcReadFilePayload(requestId, path37, options), `read ${path37} from session ${sessionId}`);
|
|
9382
9388
|
return result.ok ? { ...result, requestId } : result;
|
|
9383
9389
|
}
|
|
9384
9390
|
async function suggestRcSessionFiles(deps, sessionId, query) {
|
|
@@ -9547,11 +9553,11 @@ function createRcControlHandler(deps) {
|
|
|
9547
9553
|
path: "read-file",
|
|
9548
9554
|
read: (body) => {
|
|
9549
9555
|
const session = bodyString(body, "session");
|
|
9550
|
-
const
|
|
9556
|
+
const path37 = bodyString(body, "path");
|
|
9551
9557
|
const maxBytes = "maxBytes" in body ? bodyPositiveInteger(body, "maxBytes") : void 0;
|
|
9552
9558
|
const encoding = "encoding" in body && isRcReadFileEncoding(body.encoding) ? body.encoding : void 0;
|
|
9553
|
-
const refused2 = session === void 0 ||
|
|
9554
|
-
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,
|
|
9559
|
+
const refused2 = session === void 0 || path37 === void 0 || "maxBytes" in body && maxBytes === void 0 || "encoding" in body && encoding === void 0;
|
|
9560
|
+
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, path37, { ...maxBytes === void 0 ? {} : { maxBytes }, ...encoding === void 0 ? {} : { encoding } }) };
|
|
9555
9561
|
}
|
|
9556
9562
|
},
|
|
9557
9563
|
{
|
|
@@ -9861,9 +9867,9 @@ function requestIdOfBody(body) {
|
|
|
9861
9867
|
}
|
|
9862
9868
|
function frontDoorRcControl(transport, token) {
|
|
9863
9869
|
const headers = { authorization: `Bearer ${token}` };
|
|
9864
|
-
const listAnswerOf = async (
|
|
9870
|
+
const listAnswerOf = async (path37, what) => {
|
|
9865
9871
|
try {
|
|
9866
|
-
return await transport.request({ method: "GET", path:
|
|
9872
|
+
return await transport.request({ method: "GET", path: path37, headers });
|
|
9867
9873
|
} catch (error) {
|
|
9868
9874
|
throw new Error(`${what}: could not reach the front door's control listener: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
|
|
9869
9875
|
}
|
|
@@ -9935,10 +9941,10 @@ function frontDoorRcControl(transport, token) {
|
|
|
9935
9941
|
}
|
|
9936
9942
|
return pending;
|
|
9937
9943
|
};
|
|
9938
|
-
const writeOf = async (
|
|
9944
|
+
const writeOf = async (path37, body, describeFailure) => {
|
|
9939
9945
|
let answer;
|
|
9940
9946
|
try {
|
|
9941
|
-
answer = await transport.request({ method: "POST", path:
|
|
9947
|
+
answer = await transport.request({ method: "POST", path: path37, headers: { ...headers, "content-type": "application/json" }, body });
|
|
9942
9948
|
} catch (error) {
|
|
9943
9949
|
return { ok: false, message: `could not reach the front door's control listener: ${error instanceof Error ? error.message : String(error)}` };
|
|
9944
9950
|
}
|
|
@@ -9969,10 +9975,10 @@ function frontDoorRcControl(transport, token) {
|
|
|
9969
9975
|
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}`),
|
|
9970
9976
|
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}`),
|
|
9971
9977
|
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}`),
|
|
9972
|
-
readFile: async (sessionId,
|
|
9978
|
+
readFile: async (sessionId, path37, options) => await writeOf(
|
|
9973
9979
|
`${CONTROL_PATH_PREFIX}/read-file`,
|
|
9974
|
-
JSON.stringify({ session: sessionId, path:
|
|
9975
|
-
(status, message) => `reading ${
|
|
9980
|
+
JSON.stringify({ session: sessionId, path: path37, ...options?.maxBytes === void 0 ? {} : { maxBytes: options.maxBytes }, ...options?.encoding === void 0 ? {} : { encoding: options.encoding } }),
|
|
9981
|
+
(status, message) => `reading ${path37} from ${sessionId} failed (HTTP ${String(status)}): ${message}`
|
|
9976
9982
|
),
|
|
9977
9983
|
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}`),
|
|
9978
9984
|
keepAlive: async (sessionId) => await writeOf(`${CONTROL_PATH_PREFIX}/keep-alive`, JSON.stringify({ session: sessionId }), (status, message) => `keeping ${sessionId} alive failed (HTTP ${String(status)}): ${message}`),
|
|
@@ -10131,12 +10137,12 @@ function tlsFacts(options) {
|
|
|
10131
10137
|
}
|
|
10132
10138
|
function realRcEventDial(target = { host: CONNECT_INTERCEPT_HOST, port: HTTPS_PORT }) {
|
|
10133
10139
|
const agent = new ExemptTlsAgent();
|
|
10134
|
-
const post = async (
|
|
10140
|
+
const post = async (path37, headers, body) => await new Promise((resolve, reject) => {
|
|
10135
10141
|
const options = {
|
|
10136
10142
|
host: target.host,
|
|
10137
10143
|
port: target.port,
|
|
10138
10144
|
method: "POST",
|
|
10139
|
-
path:
|
|
10145
|
+
path: path37,
|
|
10140
10146
|
// 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.
|
|
10141
10147
|
headers: { ...headers, host: target.servername ?? target.host, "content-length": String(Buffer.byteLength(body, "utf8")) },
|
|
10142
10148
|
agent
|
|
@@ -10201,12 +10207,12 @@ function lateRcStreamDial(resolve) {
|
|
|
10201
10207
|
}
|
|
10202
10208
|
function realRcStreamDial(target = { host: CONNECT_INTERCEPT_HOST, port: HTTPS_PORT }) {
|
|
10203
10209
|
const agent = new ExemptTlsAgent();
|
|
10204
|
-
const request4 = async (method,
|
|
10210
|
+
const request4 = async (method, path37, headers, body, signal) => await new Promise((resolve, reject) => {
|
|
10205
10211
|
const options = {
|
|
10206
10212
|
host: target.host,
|
|
10207
10213
|
port: target.port,
|
|
10208
10214
|
method,
|
|
10209
|
-
path:
|
|
10215
|
+
path: path37,
|
|
10210
10216
|
// 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.
|
|
10211
10217
|
headers: { ...headers, host: target.servername ?? target.host, ...body === void 0 ? {} : { "content-length": String(Buffer.byteLength(body, "utf8")) } },
|
|
10212
10218
|
agent,
|
|
@@ -10248,9 +10254,9 @@ function realRcStreamDial(target = { host: CONNECT_INTERCEPT_HOST, port: HTTPS_P
|
|
|
10248
10254
|
return { status, body: await readAll(response) };
|
|
10249
10255
|
},
|
|
10250
10256
|
openStream: async (sessionId, headers, resume, signal) => {
|
|
10251
|
-
const
|
|
10257
|
+
const path37 = resume === void 0 ? `/v1/code/sessions/${encodeURIComponent(sessionId)}/events/stream` : `/v1/code/sessions/${encodeURIComponent(sessionId)}/events/stream?from_sequence_num=${String(resume.fromSequenceNum)}`;
|
|
10252
10258
|
const streamHeaders = resume === void 0 ? headers : { ...headers, "last-event-id": String(resume.fromSequenceNum) };
|
|
10253
|
-
const { status, response } = await request4("GET",
|
|
10259
|
+
const { status, response } = await request4("GET", path37, streamHeaders, void 0, signal);
|
|
10254
10260
|
if (!isSuccessful2(status)) {
|
|
10255
10261
|
await readAll(response);
|
|
10256
10262
|
return { status, chunks: NO_CHUNKS };
|
|
@@ -11165,19 +11171,19 @@ function writePools(paths, pools) {
|
|
|
11165
11171
|
applyPatch(paths.globalConfigFile, GlobalConfigSchema, { pools }, { defaults: {} });
|
|
11166
11172
|
}
|
|
11167
11173
|
function poolCycleOf(pools, name) {
|
|
11168
|
-
const walk = (current,
|
|
11174
|
+
const walk = (current, path37) => {
|
|
11169
11175
|
for (const entry of pools[current]?.identities ?? []) {
|
|
11170
11176
|
const nested = poolNameOf(poolMemberIdentity(entry));
|
|
11171
11177
|
if (nested === void 0) {
|
|
11172
11178
|
continue;
|
|
11173
11179
|
}
|
|
11174
11180
|
if (nested === name) {
|
|
11175
|
-
return [...
|
|
11181
|
+
return [...path37, nested];
|
|
11176
11182
|
}
|
|
11177
|
-
if (
|
|
11183
|
+
if (path37.includes(nested)) {
|
|
11178
11184
|
continue;
|
|
11179
11185
|
}
|
|
11180
|
-
const found = walk(nested, [...
|
|
11186
|
+
const found = walk(nested, [...path37, nested]);
|
|
11181
11187
|
if (found !== void 0) {
|
|
11182
11188
|
return found;
|
|
11183
11189
|
}
|
|
@@ -11850,7 +11856,7 @@ init_middleware();
|
|
|
11850
11856
|
init_preflight();
|
|
11851
11857
|
|
|
11852
11858
|
// src/frontdoor/controlSchemas.ts
|
|
11853
|
-
import
|
|
11859
|
+
import path30 from "node:path";
|
|
11854
11860
|
import { z as z19 } from "zod";
|
|
11855
11861
|
|
|
11856
11862
|
// src/doctorReport.ts
|
|
@@ -12021,7 +12027,29 @@ function removeIdentity(paths, name) {
|
|
|
12021
12027
|
// src/doctorReport.ts
|
|
12022
12028
|
init_realPorts();
|
|
12023
12029
|
import fs10 from "node:fs";
|
|
12030
|
+
import path29 from "node:path";
|
|
12031
|
+
|
|
12032
|
+
// src/usage/signIn.ts
|
|
12024
12033
|
import path28 from "node:path";
|
|
12034
|
+
var CREDENTIALS_FILE = ".credentials.json";
|
|
12035
|
+
function keychainHasItem(run, account) {
|
|
12036
|
+
return run.run("security", ["find-generic-password", "-a", account]).status === 0;
|
|
12037
|
+
}
|
|
12038
|
+
function decideSignIn(facts) {
|
|
12039
|
+
if (facts.hasCredentialBlock) {
|
|
12040
|
+
return { state: "token", detail: "supplies its own credential through a credential block, so a stored login is not what a launch uses" };
|
|
12041
|
+
}
|
|
12042
|
+
if (facts.keychainItem === true) {
|
|
12043
|
+
return { state: "signed-in", detail: "a login is stored in the macOS Keychain" };
|
|
12044
|
+
}
|
|
12045
|
+
if (facts.credentialsFile) {
|
|
12046
|
+
return { state: "signed-in", detail: `a login is stored in ${CREDENTIALS_FILE}` };
|
|
12047
|
+
}
|
|
12048
|
+
return { state: "signed-out", detail: facts.platform === "darwin" ? `no Keychain item and no ${CREDENTIALS_FILE}` : `no ${CREDENTIALS_FILE}` };
|
|
12049
|
+
}
|
|
12050
|
+
function credentialsFilePath(farmRoot) {
|
|
12051
|
+
return path28.join(farmRoot, CREDENTIALS_FILE);
|
|
12052
|
+
}
|
|
12025
12053
|
|
|
12026
12054
|
// src/codex/siwcStore.ts
|
|
12027
12055
|
import { z as z18 } from "zod";
|
|
@@ -12122,6 +12150,7 @@ var DOCTOR_SECTIONS = [
|
|
|
12122
12150
|
"legacy-name",
|
|
12123
12151
|
"config-profile",
|
|
12124
12152
|
"identity",
|
|
12153
|
+
"sign-in",
|
|
12125
12154
|
"pool",
|
|
12126
12155
|
"provider",
|
|
12127
12156
|
"keychain",
|
|
@@ -12164,7 +12193,7 @@ function tcpPortEraRecord(raw) {
|
|
|
12164
12193
|
return (has("port") || has("lastPort")) && !has("socketPath");
|
|
12165
12194
|
}
|
|
12166
12195
|
function pushPathResolution(push, resolution) {
|
|
12167
|
-
const ownDir =
|
|
12196
|
+
const ownDir = path29.dirname(resolution.ownExecutablePath);
|
|
12168
12197
|
switch (resolution.agentShim.status) {
|
|
12169
12198
|
case "ok":
|
|
12170
12199
|
push("path-resolution", "pass", `\`agent-shim\` on PATH resolves to this running executable, ${resolution.ownExecutablePath}.`, "agent-shim");
|
|
@@ -12263,14 +12292,14 @@ function pushProvider(push, entry, cacheEnv, signIn) {
|
|
|
12263
12292
|
}
|
|
12264
12293
|
function pushLegacyName(push, params) {
|
|
12265
12294
|
const legacyVariables = Object.keys(params.env).filter((name) => name.startsWith(LEGACY_ENV_PREFIX) && params.env[name] !== void 0).sort();
|
|
12266
|
-
if (legacyVariables.length === 0 &&
|
|
12295
|
+
if (legacyVariables.length === 0 && path29.basename(params.rootPath) !== LEGACY_HOME_DIRNAME) {
|
|
12267
12296
|
push("legacy-name", "pass", "Nothing here still uses the former `claude-use` name.");
|
|
12268
12297
|
return;
|
|
12269
12298
|
}
|
|
12270
12299
|
for (const name of legacyVariables) {
|
|
12271
12300
|
push("legacy-name", "warn", `${name} is the former name of ${name.replace(LEGACY_ENV_PREFIX, ENV_PREFIX)}. Rename it; the old name still works but is only a fallback.`, name);
|
|
12272
12301
|
}
|
|
12273
|
-
if (
|
|
12302
|
+
if (path29.basename(params.rootPath) === LEGACY_HOME_DIRNAME) {
|
|
12274
12303
|
push(
|
|
12275
12304
|
"legacy-name",
|
|
12276
12305
|
"warn",
|
|
@@ -12367,6 +12396,18 @@ function runDoctor(params) {
|
|
|
12367
12396
|
`${entry.name} is valid and authenticates with ${credential === void 0 ? "its stored login" : `credential ${describeCredential(credential)}`}${cache.text}.`,
|
|
12368
12397
|
entry.name
|
|
12369
12398
|
);
|
|
12399
|
+
const signIn = decideSignIn({
|
|
12400
|
+
hasCredentialBlock: credential !== void 0,
|
|
12401
|
+
keychainItem: params.platform === "darwin" && params.run !== void 0 ? keychainHasItem(params.run, entry.farmRoot) : void 0,
|
|
12402
|
+
credentialsFile: entry.credentialsFilePresent,
|
|
12403
|
+
platform: params.platform
|
|
12404
|
+
});
|
|
12405
|
+
push(
|
|
12406
|
+
"sign-in",
|
|
12407
|
+
signIn.state === "signed-out" ? "warn" : "pass",
|
|
12408
|
+
signIn.state === "signed-out" ? `${entry.name} is signed out (${signIn.detail}). Run \`agent-shim run @${entry.name}\` and sign in.` : `${entry.name} ${signIn.state === "token" ? "uses a credential block" : "is signed in"} (${signIn.detail}).`,
|
|
12409
|
+
entry.name
|
|
12410
|
+
);
|
|
12370
12411
|
}
|
|
12371
12412
|
}
|
|
12372
12413
|
const validatedGlobalConfig = params.globalConfig.raw === void 0 ? void 0 : validateJson(GlobalConfigSchema, params.globalConfig);
|
|
@@ -12412,7 +12453,7 @@ function runDoctor(params) {
|
|
|
12412
12453
|
} else {
|
|
12413
12454
|
for (const entry of params.identities) {
|
|
12414
12455
|
const result = lookupKeychainService(params.run, entry.farmRoot);
|
|
12415
|
-
push("keychain", result.found ?
|
|
12456
|
+
push("keychain", "pass", result.found ? result.note : `${result.note} The sign-in section reports whether a login is stored elsewhere.`, entry.name);
|
|
12416
12457
|
}
|
|
12417
12458
|
}
|
|
12418
12459
|
if (params.directoryRules.raw === void 0) {
|
|
@@ -12547,6 +12588,7 @@ var SECTION_TITLES = {
|
|
|
12547
12588
|
"legacy-name": "Former `claude-use` name",
|
|
12548
12589
|
"config-profile": "Configuration profiles",
|
|
12549
12590
|
identity: "Identities",
|
|
12591
|
+
"sign-in": "Sign-in",
|
|
12550
12592
|
pool: "Pools",
|
|
12551
12593
|
provider: "Providers",
|
|
12552
12594
|
keychain: "macOS Keychain",
|
|
@@ -12563,6 +12605,7 @@ var SECTION_ORDER = [
|
|
|
12563
12605
|
"path-resolution",
|
|
12564
12606
|
"config-profile",
|
|
12565
12607
|
"identity",
|
|
12608
|
+
"sign-in",
|
|
12566
12609
|
"pool",
|
|
12567
12610
|
"provider",
|
|
12568
12611
|
"keychain",
|
|
@@ -12612,18 +12655,18 @@ function collectDoctorReport(params) {
|
|
|
12612
12655
|
const { paths } = params;
|
|
12613
12656
|
const identityNames = fs10.existsSync(paths.identitiesDir) ? fs10.readdirSync(paths.identitiesDir, { withFileTypes: true }).filter((entry) => entry.isDirectory() && isIdentityDirectoryName(entry.name)).map((entry) => entry.name).sort() : [];
|
|
12614
12657
|
const identities = identityNames.map((name) => {
|
|
12615
|
-
const farmRoot =
|
|
12616
|
-
const identityPath =
|
|
12617
|
-
return { name, path: identityPath, raw: realFsPort.readFileUtf8(identityPath), farmRoot };
|
|
12658
|
+
const farmRoot = path29.join(paths.identitiesDir, name);
|
|
12659
|
+
const identityPath = path29.join(farmRoot, "identity.json");
|
|
12660
|
+
return { name, path: identityPath, raw: realFsPort.readFileUtf8(identityPath), farmRoot, credentialsFilePresent: fs10.existsSync(credentialsFilePath(farmRoot)) };
|
|
12618
12661
|
});
|
|
12619
12662
|
const profileNames = fs10.existsSync(paths.configProfilesDir) ? fs10.readdirSync(paths.configProfilesDir, { withFileTypes: true }).filter((entry) => entry.isFile() && entry.name.endsWith(".json")).map((entry) => entry.name.slice(0, -".json".length)).sort() : [];
|
|
12620
12663
|
const configProfiles = profileNames.map((name) => {
|
|
12621
|
-
const profilePath =
|
|
12664
|
+
const profilePath = path29.join(paths.configProfilesDir, `${name}.json`);
|
|
12622
12665
|
return { name, path: profilePath, raw: realFsPort.readFileUtf8(profilePath) };
|
|
12623
12666
|
});
|
|
12624
12667
|
const providerNames = fs10.existsSync(paths.providersDir) ? fs10.readdirSync(paths.providersDir, { withFileTypes: true }).filter((entry) => entry.isFile() && entry.name.endsWith(".json")).map((entry) => entry.name.slice(0, -".json".length)).sort() : [];
|
|
12625
12668
|
const providers = providerNames.map((name) => {
|
|
12626
|
-
const providerPath =
|
|
12669
|
+
const providerPath = path29.join(paths.providersDir, `${name}.json`);
|
|
12627
12670
|
return { name, path: providerPath, raw: realFsPort.readFileUtf8(providerPath) };
|
|
12628
12671
|
});
|
|
12629
12672
|
const ownExecutablePath = realOwnExecutablePath();
|
|
@@ -12635,12 +12678,12 @@ function collectDoctorReport(params) {
|
|
|
12635
12678
|
binaryDiscovery = { ok: false, message: error instanceof Error ? error.message : String(error) };
|
|
12636
12679
|
}
|
|
12637
12680
|
const shimState = readJson(paths.claudeShimFile, ClaudeShimStateSchema);
|
|
12638
|
-
const pathDirs = (params.env.PATH ?? "").split(
|
|
12681
|
+
const pathDirs = (params.env.PATH ?? "").split(path29.delimiter).filter((dir) => dir !== "");
|
|
12639
12682
|
const claudeShimShadow = shimState === void 0 ? void 0 : refinePathShadow(
|
|
12640
12683
|
findPathShadow({
|
|
12641
12684
|
pathDirs,
|
|
12642
|
-
targetDir:
|
|
12643
|
-
targetFilename:
|
|
12685
|
+
targetDir: path29.dirname(shimState.targetPath),
|
|
12686
|
+
targetFilename: path29.basename(shimState.targetPath),
|
|
12644
12687
|
findExecutableInDir
|
|
12645
12688
|
}),
|
|
12646
12689
|
shimState.targetPath,
|
|
@@ -12666,7 +12709,7 @@ function collectDoctorReport(params) {
|
|
|
12666
12709
|
agentShim: refinePathShadow(
|
|
12667
12710
|
findPathShadow({
|
|
12668
12711
|
pathDirs,
|
|
12669
|
-
targetDir:
|
|
12712
|
+
targetDir: path29.dirname(ownExecutablePath),
|
|
12670
12713
|
targetFilename: commandFilename(ownExecutablePath, "agent-shim"),
|
|
12671
12714
|
findExecutableInDir
|
|
12672
12715
|
}),
|
|
@@ -12740,11 +12783,11 @@ var FrontDoorSessionsOutputSchema = z19.strictObject({ sessions: z19.readonly(z1
|
|
|
12740
12783
|
var CheckRunInputSchema = z19.strictObject({
|
|
12741
12784
|
path: z19.string().min(1),
|
|
12742
12785
|
identity: z19.string().min(1).optional()
|
|
12743
|
-
}).refine((input) =>
|
|
12786
|
+
}).refine((input) => path30.isAbsolute(input.path), { message: "path must be absolute: the door cannot resolve a relative path against the caller's working directory" });
|
|
12744
12787
|
var PoolPickInputSchema = z19.strictObject({
|
|
12745
12788
|
pool: z19.string().min(1),
|
|
12746
12789
|
path: z19.string().min(1)
|
|
12747
|
-
}).refine((input) =>
|
|
12790
|
+
}).refine((input) => path30.isAbsolute(input.path), { message: "path must be absolute: the door cannot resolve a relative path against the caller's working directory" });
|
|
12748
12791
|
var DoctorFindingSchema = z19.strictObject({
|
|
12749
12792
|
section: z19.enum(DOCTOR_SECTIONS),
|
|
12750
12793
|
subject: z19.string().optional(),
|
|
@@ -13120,7 +13163,7 @@ function profileValue(name, paths) {
|
|
|
13120
13163
|
function createConfigApiRouter(deps) {
|
|
13121
13164
|
const authed = doorApiAuth(deps.expectedToken);
|
|
13122
13165
|
const { paths } = deps;
|
|
13123
|
-
const route = (
|
|
13166
|
+
const route = (path37, summary) => authed.meta(openapi3({ method: "POST", path: path37, summary, tags: [CONFIG_API_TAG] }));
|
|
13124
13167
|
return {
|
|
13125
13168
|
config: {
|
|
13126
13169
|
identity: {
|
|
@@ -13479,7 +13522,7 @@ import { ORPCError as ORPCError5 } from "@orpc/client";
|
|
|
13479
13522
|
import { openapi as openapi6 } from "@orpc/openapi";
|
|
13480
13523
|
|
|
13481
13524
|
// src/frontdoor/launchSchemas.ts
|
|
13482
|
-
import
|
|
13525
|
+
import path31 from "node:path";
|
|
13483
13526
|
import { z as z22 } from "zod";
|
|
13484
13527
|
init_claudeVersion();
|
|
13485
13528
|
init_identity();
|
|
@@ -13489,7 +13532,7 @@ var LaunchResolveInputSchema = z22.strictObject({
|
|
|
13489
13532
|
argv: z22.readonly(z22.array(z22.string())).optional(),
|
|
13490
13533
|
/** The launch's inherited environment. Absent means an empty one: the door's own environment is never a substitute for the caller's, so a caller that wants `AGENT_SHIM_*` switches or a `CLAUDE_CONFIG_DIR` considered names them here. Values are read, never reported. */
|
|
13491
13534
|
env: z22.record(z22.string(), z22.string()).optional()
|
|
13492
|
-
}).refine((input) =>
|
|
13535
|
+
}).refine((input) => path31.isAbsolute(input.path), { message: "path must be absolute: the door cannot resolve a relative path against the caller's working directory" });
|
|
13493
13536
|
var LaunchPoolDecisionSchema = z22.strictObject({
|
|
13494
13537
|
name: z22.string(),
|
|
13495
13538
|
reasons: z22.readonly(z22.array(z22.string())),
|
|
@@ -15585,8 +15628,8 @@ data: ${JSON.stringify(envelope)}
|
|
|
15585
15628
|
|
|
15586
15629
|
// src/frontdoor/rcSelfHostMint.ts
|
|
15587
15630
|
init_account();
|
|
15588
|
-
import
|
|
15589
|
-
var
|
|
15631
|
+
import path32 from "node:path";
|
|
15632
|
+
var CREDENTIALS_FILE2 = ".credentials.json";
|
|
15590
15633
|
var CLAUDE_JSON2 = ".claude.json";
|
|
15591
15634
|
var RC_SELF_HOST_RECORD_DIR = "rc-selfhost";
|
|
15592
15635
|
var RC_SELF_HOST_RECORD_FILE = "credential.json";
|
|
@@ -15609,7 +15652,7 @@ function readJsonObject(fs12, file) {
|
|
|
15609
15652
|
return isRecord11(parsed) ? parsed : void 0;
|
|
15610
15653
|
}
|
|
15611
15654
|
function readRcSelfHostRecord(fs12, frontdoorDir) {
|
|
15612
|
-
const parsed = readJsonObject(fs12,
|
|
15655
|
+
const parsed = readJsonObject(fs12, path32.join(frontdoorDir, RC_SELF_HOST_RECORD_DIR, RC_SELF_HOST_RECORD_FILE));
|
|
15613
15656
|
if (parsed === void 0) {
|
|
15614
15657
|
return void 0;
|
|
15615
15658
|
}
|
|
@@ -15623,11 +15666,11 @@ function mintRcSelfHostCredential(deps) {
|
|
|
15623
15666
|
if (!isIdentityName(deps.identity)) {
|
|
15624
15667
|
throw new Error(`"${deps.identity}" is not a valid identity name.`);
|
|
15625
15668
|
}
|
|
15626
|
-
const identityDir =
|
|
15627
|
-
const credentialsFile =
|
|
15628
|
-
const claudeJsonFile =
|
|
15629
|
-
const recordDir =
|
|
15630
|
-
const recordFile =
|
|
15669
|
+
const identityDir = path32.join(deps.identitiesDir, deps.identity);
|
|
15670
|
+
const credentialsFile = path32.join(identityDir, CREDENTIALS_FILE2);
|
|
15671
|
+
const claudeJsonFile = path32.join(identityDir, CLAUDE_JSON2);
|
|
15672
|
+
const recordDir = path32.join(deps.frontdoorDir, RC_SELF_HOST_RECORD_DIR);
|
|
15673
|
+
const recordFile = path32.join(recordDir, RC_SELF_HOST_RECORD_FILE);
|
|
15631
15674
|
const previousRecord = readRcSelfHostRecord(deps.fs, deps.frontdoorDir);
|
|
15632
15675
|
const existingCredentials = readJsonObject(deps.fs, credentialsFile);
|
|
15633
15676
|
const existingOauth = isRecord11(existingCredentials?.claudeAiOauth) ? existingCredentials.claudeAiOauth : void 0;
|
|
@@ -15643,7 +15686,7 @@ function mintRcSelfHostCredential(deps) {
|
|
|
15643
15686
|
const organizationUuid = deps.newUuid();
|
|
15644
15687
|
const accountUuid = deps.newUuid();
|
|
15645
15688
|
const mintedAt = new Date(deps.now()).toISOString();
|
|
15646
|
-
deps.fs.mkdirPrivate(
|
|
15689
|
+
deps.fs.mkdirPrivate(path32.dirname(credentialsFile));
|
|
15647
15690
|
deps.fs.writeFilePrivate(credentialsFile, `${JSON.stringify({ ...existingCredentials, claudeAiOauth: { accessToken, refreshToken, expiresAt: null, scopes: [...RC_SELF_HOST_SCOPE_LIST], subscriptionType: SELF_HOST_SUBSCRIPTION_TYPE, rateLimitTier: null } }, null, 2)}
|
|
15648
15691
|
`);
|
|
15649
15692
|
const claudeJson = readJsonObject(deps.fs, claudeJsonFile) ?? {};
|
package/dist/types/index.d.ts
CHANGED
|
@@ -4467,7 +4467,7 @@ type ClaudeBinaryResolver = (request?: Readonly<ClaudeBinaryRequest>) => Discove
|
|
|
4467
4467
|
|
|
4468
4468
|
declare const DOCTOR_SEVERITIES: readonly ["pass", "warn", "fail"];
|
|
4469
4469
|
type DoctorSeverity = (typeof DOCTOR_SEVERITIES)[number];
|
|
4470
|
-
declare const DOCTOR_SECTIONS: readonly ["ambient-credential", "binary-discovery", "claude-shim", "path-resolution", "legacy-name", "config-profile", "identity", "pool", "provider", "keychain", "directory-rules", "global-config", "categories-local", "active-identity", "headroom"];
|
|
4470
|
+
declare const DOCTOR_SECTIONS: readonly ["ambient-credential", "binary-discovery", "claude-shim", "path-resolution", "legacy-name", "config-profile", "identity", "sign-in", "pool", "provider", "keychain", "directory-rules", "global-config", "categories-local", "active-identity", "headroom"];
|
|
4471
4471
|
type DoctorSection = (typeof DOCTOR_SECTIONS)[number];
|
|
4472
4472
|
/** One line of `agent-shim doctor`'s report. `subject` names the identity/profile/rule the finding is about, when the section has more than one of those. */
|
|
4473
4473
|
interface DoctorFinding {
|
|
@@ -4488,6 +4488,8 @@ interface DoctorIdentityInput {
|
|
|
4488
4488
|
readonly raw: string | undefined;
|
|
4489
4489
|
/** The identity's own farm root (`identitiesDir/<name>`) — the account name the Keychain lookup uses. */
|
|
4490
4490
|
readonly farmRoot: string;
|
|
4491
|
+
/** Whether the identity's `.credentials.json` exists, pre-resolved by the wiring layer since it is a file-existence check. */
|
|
4492
|
+
readonly credentialsFilePresent: boolean;
|
|
4491
4493
|
}
|
|
4492
4494
|
/** One configuration profile's raw `<name>.json`, unparsed. */
|
|
4493
4495
|
interface DoctorConfigProfileInput {
|
|
@@ -7243,6 +7245,7 @@ declare function createControlApiRouter(deps: ControlApiDeps): {
|
|
|
7243
7245
|
"claude-shim": "claude-shim";
|
|
7244
7246
|
"path-resolution": "path-resolution";
|
|
7245
7247
|
"legacy-name": "legacy-name";
|
|
7248
|
+
"sign-in": "sign-in";
|
|
7246
7249
|
"directory-rules": "directory-rules";
|
|
7247
7250
|
"categories-local": "categories-local";
|
|
7248
7251
|
"active-identity": "active-identity";
|
|
@@ -9212,6 +9215,7 @@ declare function createDoorApiRouter(deps: DoorApiDeps): {
|
|
|
9212
9215
|
"claude-shim": "claude-shim";
|
|
9213
9216
|
"path-resolution": "path-resolution";
|
|
9214
9217
|
"legacy-name": "legacy-name";
|
|
9218
|
+
"sign-in": "sign-in";
|
|
9215
9219
|
"directory-rules": "directory-rules";
|
|
9216
9220
|
"categories-local": "categories-local";
|
|
9217
9221
|
"active-identity": "active-identity";
|
|
@@ -11017,6 +11021,7 @@ declare const DoctorFindingSchema: z.ZodObject<{
|
|
|
11017
11021
|
"claude-shim": "claude-shim";
|
|
11018
11022
|
"path-resolution": "path-resolution";
|
|
11019
11023
|
"legacy-name": "legacy-name";
|
|
11024
|
+
"sign-in": "sign-in";
|
|
11020
11025
|
"directory-rules": "directory-rules";
|
|
11021
11026
|
"categories-local": "categories-local";
|
|
11022
11027
|
"active-identity": "active-identity";
|
|
@@ -11046,6 +11051,7 @@ declare const DoctorRunOutputSchema: z.ZodObject<{
|
|
|
11046
11051
|
"claude-shim": "claude-shim";
|
|
11047
11052
|
"path-resolution": "path-resolution";
|
|
11048
11053
|
"legacy-name": "legacy-name";
|
|
11054
|
+
"sign-in": "sign-in";
|
|
11049
11055
|
"directory-rules": "directory-rules";
|
|
11050
11056
|
"categories-local": "categories-local";
|
|
11051
11057
|
"active-identity": "active-identity";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-use",
|
|
3
|
-
"version": "9.
|
|
3
|
+
"version": "9.8.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>",
|