claude-use 9.7.2 → 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 +418 -367
- package/dist/index.cjs +111 -74
- package/dist/index.mjs +107 -70
- 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
|
);
|
|
@@ -7025,7 +7025,7 @@ function decideLaunch(params, readOnly) {
|
|
|
7025
7025
|
extraFlags: splitExtraFlags(env.CLAUDE_EXTRA_FLAGS),
|
|
7026
7026
|
passthrough: parsedArgv.rest
|
|
7027
7027
|
});
|
|
7028
|
-
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);
|
|
7029
7029
|
const decision = {
|
|
7030
7030
|
identitySource: identityDecision.source,
|
|
7031
7031
|
configDirEscapeHatch: identityDecision.configDirEscapeHatch,
|
|
@@ -7066,7 +7066,7 @@ function prepareLaunch(params) {
|
|
|
7066
7066
|
);
|
|
7067
7067
|
const updateCheck = runLaunchUpdateCheck({
|
|
7068
7068
|
mode: params.updateMode ?? "off",
|
|
7069
|
-
checkPath:
|
|
7069
|
+
checkPath: path34.join(paths.root, "update.check"),
|
|
7070
7070
|
currentVersion: package_default.version,
|
|
7071
7071
|
port: params.update
|
|
7072
7072
|
});
|
|
@@ -7226,12 +7226,12 @@ var init_launcher = __esm({
|
|
|
7226
7226
|
});
|
|
7227
7227
|
|
|
7228
7228
|
// src/ownCli.ts
|
|
7229
|
-
import
|
|
7229
|
+
import path35 from "node:path";
|
|
7230
7230
|
function agentShimCliPath(distDir = typeof __AGENT_SHIM_DIST_DIR__ === "string" ? __AGENT_SHIM_DIST_DIR__ : void 0) {
|
|
7231
7231
|
if (distDir === void 0) {
|
|
7232
7232
|
throw new OwnCliPathUnknownError();
|
|
7233
7233
|
}
|
|
7234
|
-
return
|
|
7234
|
+
return path35.join(distDir, OWN_CLI_FILE_NAME);
|
|
7235
7235
|
}
|
|
7236
7236
|
var OWN_CLI_FILE_NAME, OwnCliPathUnknownError;
|
|
7237
7237
|
var init_ownCli = __esm({
|
|
@@ -7320,10 +7320,10 @@ request.on("error", (error) => finish(failed, (error.code ? error.code + ": " :
|
|
|
7320
7320
|
|
|
7321
7321
|
// src/frontdoor/trust.ts
|
|
7322
7322
|
import { createHash as createHash6 } from "node:crypto";
|
|
7323
|
-
import
|
|
7323
|
+
import path36 from "node:path";
|
|
7324
7324
|
function resolveTrustBundle(params) {
|
|
7325
7325
|
const { caCertFile, bundlesDir, variable, inherited, fs: fs12 } = params;
|
|
7326
|
-
if (inherited === void 0 || inherited === "" ||
|
|
7326
|
+
if (inherited === void 0 || inherited === "" || path36.resolve(inherited) === path36.resolve(caCertFile)) {
|
|
7327
7327
|
return { path: caCertFile };
|
|
7328
7328
|
}
|
|
7329
7329
|
const caPem = fs12.readFileUtf8(caCertFile);
|
|
@@ -7341,7 +7341,7 @@ function resolveTrustBundle(params) {
|
|
|
7341
7341
|
}
|
|
7342
7342
|
const combined = `${inheritedPem.trimEnd()}
|
|
7343
7343
|
${caPem}`;
|
|
7344
|
-
const bundle =
|
|
7344
|
+
const bundle = path36.join(bundlesDir, `${createHash6("sha256").update(combined).digest("hex").slice(0, BUNDLE_NAME_HEX_DIGITS)}.pem`);
|
|
7345
7345
|
if (!fs12.exists(bundle)) {
|
|
7346
7346
|
fs12.mkdirp(bundlesDir);
|
|
7347
7347
|
fs12.writeFileAtomic(bundle, combined);
|
|
@@ -8351,8 +8351,8 @@ function parseConnectTarget(authority) {
|
|
|
8351
8351
|
function isInterceptedHost(host, interceptHosts) {
|
|
8352
8352
|
return interceptHosts.includes(host);
|
|
8353
8353
|
}
|
|
8354
|
-
function servedByPipeline(
|
|
8355
|
-
return
|
|
8354
|
+
function servedByPipeline(path37) {
|
|
8355
|
+
return path37?.startsWith(ROUTED_PATH_PREFIX) === true;
|
|
8356
8356
|
}
|
|
8357
8357
|
var HOP_BY_HOP_HEADERS = /* @__PURE__ */ new Set([
|
|
8358
8358
|
"connection",
|
|
@@ -8887,11 +8887,11 @@ function createRcSessionTracker(deps) {
|
|
|
8887
8887
|
};
|
|
8888
8888
|
const observeExchange = (request4) => {
|
|
8889
8889
|
const method = (request4.method ?? "").toUpperCase();
|
|
8890
|
-
const
|
|
8891
|
-
if (!
|
|
8890
|
+
const path37 = new URL(request4.url ?? "/", "http://127.0.0.1").pathname;
|
|
8891
|
+
if (!path37.startsWith(RC_SESSIONS_PATH_PREFIX)) {
|
|
8892
8892
|
return void 0;
|
|
8893
8893
|
}
|
|
8894
|
-
const tail =
|
|
8894
|
+
const tail = path37.slice(RC_SESSIONS_PATH_PREFIX.length);
|
|
8895
8895
|
const facts = {
|
|
8896
8896
|
oauthAuthorization: oauthAuthorizationOf(request4.headers),
|
|
8897
8897
|
anthropicVersion: singleHeader(request4.headers, "anthropic-version"),
|
|
@@ -9273,8 +9273,8 @@ var RC_READ_FILE_ENCODINGS = ["utf-8", "base64"];
|
|
|
9273
9273
|
function isRcReadFileEncoding(value) {
|
|
9274
9274
|
return RC_READ_FILE_ENCODINGS.some((encoding) => encoding === value);
|
|
9275
9275
|
}
|
|
9276
|
-
function buildRcReadFilePayload(requestId,
|
|
9277
|
-
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 } });
|
|
9278
9278
|
}
|
|
9279
9279
|
function buildRcFileSuggestionsPayload(requestId, query) {
|
|
9280
9280
|
return buildRcControlRequestPayload(requestId, { subtype: "file_suggestions", query });
|
|
@@ -9376,15 +9376,15 @@ async function getRcSessionContextUsage(deps, sessionId, detail) {
|
|
|
9376
9376
|
const result = await deliverRcClientPayload(deps, sessionId, buildRcGetContextUsagePayload(requestId, detail), `request the context usage of session ${sessionId}`);
|
|
9377
9377
|
return result.ok ? { ...result, requestId } : result;
|
|
9378
9378
|
}
|
|
9379
|
-
async function readRcSessionFile(deps, sessionId,
|
|
9380
|
-
if (
|
|
9379
|
+
async function readRcSessionFile(deps, sessionId, path37, options) {
|
|
9380
|
+
if (path37 === "") {
|
|
9381
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" };
|
|
9382
9382
|
}
|
|
9383
9383
|
if (options?.maxBytes !== void 0 && (!Number.isInteger(options.maxBytes) || options.maxBytes <= 0)) {
|
|
9384
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" };
|
|
9385
9385
|
}
|
|
9386
9386
|
const requestId = deps.newUuid();
|
|
9387
|
-
const result = await deliverRcClientPayload(deps, sessionId, buildRcReadFilePayload(requestId,
|
|
9387
|
+
const result = await deliverRcClientPayload(deps, sessionId, buildRcReadFilePayload(requestId, path37, options), `read ${path37} from session ${sessionId}`);
|
|
9388
9388
|
return result.ok ? { ...result, requestId } : result;
|
|
9389
9389
|
}
|
|
9390
9390
|
async function suggestRcSessionFiles(deps, sessionId, query) {
|
|
@@ -9553,11 +9553,11 @@ function createRcControlHandler(deps) {
|
|
|
9553
9553
|
path: "read-file",
|
|
9554
9554
|
read: (body) => {
|
|
9555
9555
|
const session = bodyString(body, "session");
|
|
9556
|
-
const
|
|
9556
|
+
const path37 = bodyString(body, "path");
|
|
9557
9557
|
const maxBytes = "maxBytes" in body ? bodyPositiveInteger(body, "maxBytes") : void 0;
|
|
9558
9558
|
const encoding = "encoding" in body && isRcReadFileEncoding(body.encoding) ? body.encoding : void 0;
|
|
9559
|
-
const refused2 = session === 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,
|
|
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 } }) };
|
|
9561
9561
|
}
|
|
9562
9562
|
},
|
|
9563
9563
|
{
|
|
@@ -9867,9 +9867,9 @@ function requestIdOfBody(body) {
|
|
|
9867
9867
|
}
|
|
9868
9868
|
function frontDoorRcControl(transport, token) {
|
|
9869
9869
|
const headers = { authorization: `Bearer ${token}` };
|
|
9870
|
-
const listAnswerOf = async (
|
|
9870
|
+
const listAnswerOf = async (path37, what) => {
|
|
9871
9871
|
try {
|
|
9872
|
-
return await transport.request({ method: "GET", path:
|
|
9872
|
+
return await transport.request({ method: "GET", path: path37, headers });
|
|
9873
9873
|
} catch (error) {
|
|
9874
9874
|
throw new Error(`${what}: could not reach the front door's control listener: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
|
|
9875
9875
|
}
|
|
@@ -9941,10 +9941,10 @@ function frontDoorRcControl(transport, token) {
|
|
|
9941
9941
|
}
|
|
9942
9942
|
return pending;
|
|
9943
9943
|
};
|
|
9944
|
-
const writeOf = async (
|
|
9944
|
+
const writeOf = async (path37, body, describeFailure) => {
|
|
9945
9945
|
let answer;
|
|
9946
9946
|
try {
|
|
9947
|
-
answer = await transport.request({ method: "POST", path:
|
|
9947
|
+
answer = await transport.request({ method: "POST", path: path37, headers: { ...headers, "content-type": "application/json" }, body });
|
|
9948
9948
|
} catch (error) {
|
|
9949
9949
|
return { ok: false, message: `could not reach the front door's control listener: ${error instanceof Error ? error.message : String(error)}` };
|
|
9950
9950
|
}
|
|
@@ -9975,10 +9975,10 @@ function frontDoorRcControl(transport, token) {
|
|
|
9975
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}`),
|
|
9976
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}`),
|
|
9977
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}`),
|
|
9978
|
-
readFile: async (sessionId,
|
|
9978
|
+
readFile: async (sessionId, path37, options) => await writeOf(
|
|
9979
9979
|
`${CONTROL_PATH_PREFIX}/read-file`,
|
|
9980
|
-
JSON.stringify({ session: sessionId, path:
|
|
9981
|
-
(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}`
|
|
9982
9982
|
),
|
|
9983
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}`),
|
|
9984
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}`),
|
|
@@ -10137,12 +10137,12 @@ function tlsFacts(options) {
|
|
|
10137
10137
|
}
|
|
10138
10138
|
function realRcEventDial(target = { host: CONNECT_INTERCEPT_HOST, port: HTTPS_PORT }) {
|
|
10139
10139
|
const agent = new ExemptTlsAgent();
|
|
10140
|
-
const post = async (
|
|
10140
|
+
const post = async (path37, headers, body) => await new Promise((resolve, reject) => {
|
|
10141
10141
|
const options = {
|
|
10142
10142
|
host: target.host,
|
|
10143
10143
|
port: target.port,
|
|
10144
10144
|
method: "POST",
|
|
10145
|
-
path:
|
|
10145
|
+
path: path37,
|
|
10146
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.
|
|
10147
10147
|
headers: { ...headers, host: target.servername ?? target.host, "content-length": String(Buffer.byteLength(body, "utf8")) },
|
|
10148
10148
|
agent
|
|
@@ -10207,12 +10207,12 @@ function lateRcStreamDial(resolve) {
|
|
|
10207
10207
|
}
|
|
10208
10208
|
function realRcStreamDial(target = { host: CONNECT_INTERCEPT_HOST, port: HTTPS_PORT }) {
|
|
10209
10209
|
const agent = new ExemptTlsAgent();
|
|
10210
|
-
const request4 = async (method,
|
|
10210
|
+
const request4 = async (method, path37, headers, body, signal) => await new Promise((resolve, reject) => {
|
|
10211
10211
|
const options = {
|
|
10212
10212
|
host: target.host,
|
|
10213
10213
|
port: target.port,
|
|
10214
10214
|
method,
|
|
10215
|
-
path:
|
|
10215
|
+
path: path37,
|
|
10216
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.
|
|
10217
10217
|
headers: { ...headers, host: target.servername ?? target.host, ...body === void 0 ? {} : { "content-length": String(Buffer.byteLength(body, "utf8")) } },
|
|
10218
10218
|
agent,
|
|
@@ -10254,9 +10254,9 @@ function realRcStreamDial(target = { host: CONNECT_INTERCEPT_HOST, port: HTTPS_P
|
|
|
10254
10254
|
return { status, body: await readAll(response) };
|
|
10255
10255
|
},
|
|
10256
10256
|
openStream: async (sessionId, headers, resume, signal) => {
|
|
10257
|
-
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)}`;
|
|
10258
10258
|
const streamHeaders = resume === void 0 ? headers : { ...headers, "last-event-id": String(resume.fromSequenceNum) };
|
|
10259
|
-
const { status, response } = await request4("GET",
|
|
10259
|
+
const { status, response } = await request4("GET", path37, streamHeaders, void 0, signal);
|
|
10260
10260
|
if (!isSuccessful2(status)) {
|
|
10261
10261
|
await readAll(response);
|
|
10262
10262
|
return { status, chunks: NO_CHUNKS };
|
|
@@ -11171,19 +11171,19 @@ function writePools(paths, pools) {
|
|
|
11171
11171
|
applyPatch(paths.globalConfigFile, GlobalConfigSchema, { pools }, { defaults: {} });
|
|
11172
11172
|
}
|
|
11173
11173
|
function poolCycleOf(pools, name) {
|
|
11174
|
-
const walk = (current,
|
|
11174
|
+
const walk = (current, path37) => {
|
|
11175
11175
|
for (const entry of pools[current]?.identities ?? []) {
|
|
11176
11176
|
const nested = poolNameOf(poolMemberIdentity(entry));
|
|
11177
11177
|
if (nested === void 0) {
|
|
11178
11178
|
continue;
|
|
11179
11179
|
}
|
|
11180
11180
|
if (nested === name) {
|
|
11181
|
-
return [...
|
|
11181
|
+
return [...path37, nested];
|
|
11182
11182
|
}
|
|
11183
|
-
if (
|
|
11183
|
+
if (path37.includes(nested)) {
|
|
11184
11184
|
continue;
|
|
11185
11185
|
}
|
|
11186
|
-
const found = walk(nested, [...
|
|
11186
|
+
const found = walk(nested, [...path37, nested]);
|
|
11187
11187
|
if (found !== void 0) {
|
|
11188
11188
|
return found;
|
|
11189
11189
|
}
|
|
@@ -11856,7 +11856,7 @@ init_middleware();
|
|
|
11856
11856
|
init_preflight();
|
|
11857
11857
|
|
|
11858
11858
|
// src/frontdoor/controlSchemas.ts
|
|
11859
|
-
import
|
|
11859
|
+
import path30 from "node:path";
|
|
11860
11860
|
import { z as z19 } from "zod";
|
|
11861
11861
|
|
|
11862
11862
|
// src/doctorReport.ts
|
|
@@ -12027,7 +12027,29 @@ function removeIdentity(paths, name) {
|
|
|
12027
12027
|
// src/doctorReport.ts
|
|
12028
12028
|
init_realPorts();
|
|
12029
12029
|
import fs10 from "node:fs";
|
|
12030
|
+
import path29 from "node:path";
|
|
12031
|
+
|
|
12032
|
+
// src/usage/signIn.ts
|
|
12030
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
|
+
}
|
|
12031
12053
|
|
|
12032
12054
|
// src/codex/siwcStore.ts
|
|
12033
12055
|
import { z as z18 } from "zod";
|
|
@@ -12128,6 +12150,7 @@ var DOCTOR_SECTIONS = [
|
|
|
12128
12150
|
"legacy-name",
|
|
12129
12151
|
"config-profile",
|
|
12130
12152
|
"identity",
|
|
12153
|
+
"sign-in",
|
|
12131
12154
|
"pool",
|
|
12132
12155
|
"provider",
|
|
12133
12156
|
"keychain",
|
|
@@ -12170,7 +12193,7 @@ function tcpPortEraRecord(raw) {
|
|
|
12170
12193
|
return (has("port") || has("lastPort")) && !has("socketPath");
|
|
12171
12194
|
}
|
|
12172
12195
|
function pushPathResolution(push, resolution) {
|
|
12173
|
-
const ownDir =
|
|
12196
|
+
const ownDir = path29.dirname(resolution.ownExecutablePath);
|
|
12174
12197
|
switch (resolution.agentShim.status) {
|
|
12175
12198
|
case "ok":
|
|
12176
12199
|
push("path-resolution", "pass", `\`agent-shim\` on PATH resolves to this running executable, ${resolution.ownExecutablePath}.`, "agent-shim");
|
|
@@ -12269,14 +12292,14 @@ function pushProvider(push, entry, cacheEnv, signIn) {
|
|
|
12269
12292
|
}
|
|
12270
12293
|
function pushLegacyName(push, params) {
|
|
12271
12294
|
const legacyVariables = Object.keys(params.env).filter((name) => name.startsWith(LEGACY_ENV_PREFIX) && params.env[name] !== void 0).sort();
|
|
12272
|
-
if (legacyVariables.length === 0 &&
|
|
12295
|
+
if (legacyVariables.length === 0 && path29.basename(params.rootPath) !== LEGACY_HOME_DIRNAME) {
|
|
12273
12296
|
push("legacy-name", "pass", "Nothing here still uses the former `claude-use` name.");
|
|
12274
12297
|
return;
|
|
12275
12298
|
}
|
|
12276
12299
|
for (const name of legacyVariables) {
|
|
12277
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);
|
|
12278
12301
|
}
|
|
12279
|
-
if (
|
|
12302
|
+
if (path29.basename(params.rootPath) === LEGACY_HOME_DIRNAME) {
|
|
12280
12303
|
push(
|
|
12281
12304
|
"legacy-name",
|
|
12282
12305
|
"warn",
|
|
@@ -12373,6 +12396,18 @@ function runDoctor(params) {
|
|
|
12373
12396
|
`${entry.name} is valid and authenticates with ${credential === void 0 ? "its stored login" : `credential ${describeCredential(credential)}`}${cache.text}.`,
|
|
12374
12397
|
entry.name
|
|
12375
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
|
+
);
|
|
12376
12411
|
}
|
|
12377
12412
|
}
|
|
12378
12413
|
const validatedGlobalConfig = params.globalConfig.raw === void 0 ? void 0 : validateJson(GlobalConfigSchema, params.globalConfig);
|
|
@@ -12418,7 +12453,7 @@ function runDoctor(params) {
|
|
|
12418
12453
|
} else {
|
|
12419
12454
|
for (const entry of params.identities) {
|
|
12420
12455
|
const result = lookupKeychainService(params.run, entry.farmRoot);
|
|
12421
|
-
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);
|
|
12422
12457
|
}
|
|
12423
12458
|
}
|
|
12424
12459
|
if (params.directoryRules.raw === void 0) {
|
|
@@ -12553,6 +12588,7 @@ var SECTION_TITLES = {
|
|
|
12553
12588
|
"legacy-name": "Former `claude-use` name",
|
|
12554
12589
|
"config-profile": "Configuration profiles",
|
|
12555
12590
|
identity: "Identities",
|
|
12591
|
+
"sign-in": "Sign-in",
|
|
12556
12592
|
pool: "Pools",
|
|
12557
12593
|
provider: "Providers",
|
|
12558
12594
|
keychain: "macOS Keychain",
|
|
@@ -12569,6 +12605,7 @@ var SECTION_ORDER = [
|
|
|
12569
12605
|
"path-resolution",
|
|
12570
12606
|
"config-profile",
|
|
12571
12607
|
"identity",
|
|
12608
|
+
"sign-in",
|
|
12572
12609
|
"pool",
|
|
12573
12610
|
"provider",
|
|
12574
12611
|
"keychain",
|
|
@@ -12618,18 +12655,18 @@ function collectDoctorReport(params) {
|
|
|
12618
12655
|
const { paths } = params;
|
|
12619
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() : [];
|
|
12620
12657
|
const identities = identityNames.map((name) => {
|
|
12621
|
-
const farmRoot =
|
|
12622
|
-
const identityPath =
|
|
12623
|
-
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)) };
|
|
12624
12661
|
});
|
|
12625
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() : [];
|
|
12626
12663
|
const configProfiles = profileNames.map((name) => {
|
|
12627
|
-
const profilePath =
|
|
12664
|
+
const profilePath = path29.join(paths.configProfilesDir, `${name}.json`);
|
|
12628
12665
|
return { name, path: profilePath, raw: realFsPort.readFileUtf8(profilePath) };
|
|
12629
12666
|
});
|
|
12630
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() : [];
|
|
12631
12668
|
const providers = providerNames.map((name) => {
|
|
12632
|
-
const providerPath =
|
|
12669
|
+
const providerPath = path29.join(paths.providersDir, `${name}.json`);
|
|
12633
12670
|
return { name, path: providerPath, raw: realFsPort.readFileUtf8(providerPath) };
|
|
12634
12671
|
});
|
|
12635
12672
|
const ownExecutablePath = realOwnExecutablePath();
|
|
@@ -12641,12 +12678,12 @@ function collectDoctorReport(params) {
|
|
|
12641
12678
|
binaryDiscovery = { ok: false, message: error instanceof Error ? error.message : String(error) };
|
|
12642
12679
|
}
|
|
12643
12680
|
const shimState = readJson(paths.claudeShimFile, ClaudeShimStateSchema);
|
|
12644
|
-
const pathDirs = (params.env.PATH ?? "").split(
|
|
12681
|
+
const pathDirs = (params.env.PATH ?? "").split(path29.delimiter).filter((dir) => dir !== "");
|
|
12645
12682
|
const claudeShimShadow = shimState === void 0 ? void 0 : refinePathShadow(
|
|
12646
12683
|
findPathShadow({
|
|
12647
12684
|
pathDirs,
|
|
12648
|
-
targetDir:
|
|
12649
|
-
targetFilename:
|
|
12685
|
+
targetDir: path29.dirname(shimState.targetPath),
|
|
12686
|
+
targetFilename: path29.basename(shimState.targetPath),
|
|
12650
12687
|
findExecutableInDir
|
|
12651
12688
|
}),
|
|
12652
12689
|
shimState.targetPath,
|
|
@@ -12672,7 +12709,7 @@ function collectDoctorReport(params) {
|
|
|
12672
12709
|
agentShim: refinePathShadow(
|
|
12673
12710
|
findPathShadow({
|
|
12674
12711
|
pathDirs,
|
|
12675
|
-
targetDir:
|
|
12712
|
+
targetDir: path29.dirname(ownExecutablePath),
|
|
12676
12713
|
targetFilename: commandFilename(ownExecutablePath, "agent-shim"),
|
|
12677
12714
|
findExecutableInDir
|
|
12678
12715
|
}),
|
|
@@ -12746,11 +12783,11 @@ var FrontDoorSessionsOutputSchema = z19.strictObject({ sessions: z19.readonly(z1
|
|
|
12746
12783
|
var CheckRunInputSchema = z19.strictObject({
|
|
12747
12784
|
path: z19.string().min(1),
|
|
12748
12785
|
identity: z19.string().min(1).optional()
|
|
12749
|
-
}).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" });
|
|
12750
12787
|
var PoolPickInputSchema = z19.strictObject({
|
|
12751
12788
|
pool: z19.string().min(1),
|
|
12752
12789
|
path: z19.string().min(1)
|
|
12753
|
-
}).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" });
|
|
12754
12791
|
var DoctorFindingSchema = z19.strictObject({
|
|
12755
12792
|
section: z19.enum(DOCTOR_SECTIONS),
|
|
12756
12793
|
subject: z19.string().optional(),
|
|
@@ -13126,7 +13163,7 @@ function profileValue(name, paths) {
|
|
|
13126
13163
|
function createConfigApiRouter(deps) {
|
|
13127
13164
|
const authed = doorApiAuth(deps.expectedToken);
|
|
13128
13165
|
const { paths } = deps;
|
|
13129
|
-
const route = (
|
|
13166
|
+
const route = (path37, summary) => authed.meta(openapi3({ method: "POST", path: path37, summary, tags: [CONFIG_API_TAG] }));
|
|
13130
13167
|
return {
|
|
13131
13168
|
config: {
|
|
13132
13169
|
identity: {
|
|
@@ -13485,7 +13522,7 @@ import { ORPCError as ORPCError5 } from "@orpc/client";
|
|
|
13485
13522
|
import { openapi as openapi6 } from "@orpc/openapi";
|
|
13486
13523
|
|
|
13487
13524
|
// src/frontdoor/launchSchemas.ts
|
|
13488
|
-
import
|
|
13525
|
+
import path31 from "node:path";
|
|
13489
13526
|
import { z as z22 } from "zod";
|
|
13490
13527
|
init_claudeVersion();
|
|
13491
13528
|
init_identity();
|
|
@@ -13495,7 +13532,7 @@ var LaunchResolveInputSchema = z22.strictObject({
|
|
|
13495
13532
|
argv: z22.readonly(z22.array(z22.string())).optional(),
|
|
13496
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. */
|
|
13497
13534
|
env: z22.record(z22.string(), z22.string()).optional()
|
|
13498
|
-
}).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" });
|
|
13499
13536
|
var LaunchPoolDecisionSchema = z22.strictObject({
|
|
13500
13537
|
name: z22.string(),
|
|
13501
13538
|
reasons: z22.readonly(z22.array(z22.string())),
|
|
@@ -15591,8 +15628,8 @@ data: ${JSON.stringify(envelope)}
|
|
|
15591
15628
|
|
|
15592
15629
|
// src/frontdoor/rcSelfHostMint.ts
|
|
15593
15630
|
init_account();
|
|
15594
|
-
import
|
|
15595
|
-
var
|
|
15631
|
+
import path32 from "node:path";
|
|
15632
|
+
var CREDENTIALS_FILE2 = ".credentials.json";
|
|
15596
15633
|
var CLAUDE_JSON2 = ".claude.json";
|
|
15597
15634
|
var RC_SELF_HOST_RECORD_DIR = "rc-selfhost";
|
|
15598
15635
|
var RC_SELF_HOST_RECORD_FILE = "credential.json";
|
|
@@ -15615,7 +15652,7 @@ function readJsonObject(fs12, file) {
|
|
|
15615
15652
|
return isRecord11(parsed) ? parsed : void 0;
|
|
15616
15653
|
}
|
|
15617
15654
|
function readRcSelfHostRecord(fs12, frontdoorDir) {
|
|
15618
|
-
const parsed = readJsonObject(fs12,
|
|
15655
|
+
const parsed = readJsonObject(fs12, path32.join(frontdoorDir, RC_SELF_HOST_RECORD_DIR, RC_SELF_HOST_RECORD_FILE));
|
|
15619
15656
|
if (parsed === void 0) {
|
|
15620
15657
|
return void 0;
|
|
15621
15658
|
}
|
|
@@ -15629,11 +15666,11 @@ function mintRcSelfHostCredential(deps) {
|
|
|
15629
15666
|
if (!isIdentityName(deps.identity)) {
|
|
15630
15667
|
throw new Error(`"${deps.identity}" is not a valid identity name.`);
|
|
15631
15668
|
}
|
|
15632
|
-
const identityDir =
|
|
15633
|
-
const credentialsFile =
|
|
15634
|
-
const claudeJsonFile =
|
|
15635
|
-
const recordDir =
|
|
15636
|
-
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);
|
|
15637
15674
|
const previousRecord = readRcSelfHostRecord(deps.fs, deps.frontdoorDir);
|
|
15638
15675
|
const existingCredentials = readJsonObject(deps.fs, credentialsFile);
|
|
15639
15676
|
const existingOauth = isRecord11(existingCredentials?.claudeAiOauth) ? existingCredentials.claudeAiOauth : void 0;
|
|
@@ -15649,7 +15686,7 @@ function mintRcSelfHostCredential(deps) {
|
|
|
15649
15686
|
const organizationUuid = deps.newUuid();
|
|
15650
15687
|
const accountUuid = deps.newUuid();
|
|
15651
15688
|
const mintedAt = new Date(deps.now()).toISOString();
|
|
15652
|
-
deps.fs.mkdirPrivate(
|
|
15689
|
+
deps.fs.mkdirPrivate(path32.dirname(credentialsFile));
|
|
15653
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)}
|
|
15654
15691
|
`);
|
|
15655
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>",
|