agent-shim 8.6.0 → 8.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 +277 -209
- package/dist/index.cjs +2021 -1904
- package/dist/index.mjs +2008 -1900
- package/dist/types/index.d.ts +263 -60
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -63,8 +63,11 @@ __export(index_exports, {
|
|
|
63
63
|
InvalidProviderNameError: () => InvalidProviderNameError,
|
|
64
64
|
LaunchRefusedError: () => LaunchRefusedError,
|
|
65
65
|
LegacyProviderFileError: () => LegacyProviderFileError,
|
|
66
|
+
PROMPT_CACHE_TTL_MS: () => PROMPT_CACHE_TTL_MS,
|
|
67
|
+
PlanClassSchema: () => PlanClassSchema,
|
|
66
68
|
PoolNameSchema: () => PoolNameSchema,
|
|
67
69
|
PoolNotFoundError: () => PoolNotFoundError,
|
|
70
|
+
PoolPickReportSchema: () => PoolPickReportSchema,
|
|
68
71
|
PoolSchema: () => PoolSchema,
|
|
69
72
|
PortableConfigSchema: () => PortableConfigSchema,
|
|
70
73
|
ProfileAlreadyExistsError: () => ProfileAlreadyExistsError,
|
|
@@ -101,16 +104,19 @@ __export(index_exports, {
|
|
|
101
104
|
checkReportToJson: () => checkReportToJson,
|
|
102
105
|
collectCheckReport: () => collectCheckReport,
|
|
103
106
|
collectDoctorReport: () => collectDoctorReport,
|
|
107
|
+
collectPoolPick: () => collectPoolPick,
|
|
104
108
|
createLeafCache: () => createLeafCache,
|
|
105
109
|
createProfile: () => createProfile,
|
|
106
110
|
createRcControlHandler: () => createRcControlHandler,
|
|
107
111
|
createRcSessionTracker: () => createRcSessionTracker,
|
|
108
112
|
describeProviderEndpoint: () => describeProviderEndpoint,
|
|
109
113
|
detectAmbientCredential: () => detectAmbientCredential,
|
|
114
|
+
effectiveWindow: () => effectiveWindow,
|
|
110
115
|
ensureCa: () => ensureCa,
|
|
111
116
|
ensureFrontDoor: () => ensureFrontDoor,
|
|
112
117
|
ensureHeadroom: () => ensureHeadroom,
|
|
113
118
|
evaluateAmbientCredentialGuard: () => evaluateAmbientCredentialGuard,
|
|
119
|
+
evaluateWhen: () => evaluateWhen,
|
|
114
120
|
formatAmbientCredentialGuardMessage: () => formatAmbientCredentialGuardMessage,
|
|
115
121
|
formatCheckReport: () => formatCheckReport,
|
|
116
122
|
formatDoctorReport: () => formatDoctorReport,
|
|
@@ -128,13 +134,16 @@ __export(index_exports, {
|
|
|
128
134
|
listProfiles: () => listProfiles,
|
|
129
135
|
listProviders: () => listProviders,
|
|
130
136
|
listUsageSnapshots: () => listUsageSnapshots,
|
|
137
|
+
matchBranch: () => matchBranch,
|
|
131
138
|
mintLeaf: () => mintLeaf,
|
|
132
139
|
observingRoutedRoute: () => observingRoutedRoute,
|
|
133
140
|
parseConnectTarget: () => parseConnectTarget,
|
|
141
|
+
planOf: () => planOf,
|
|
134
142
|
prepareClaudeLaunch: () => prepareClaudeLaunch,
|
|
135
143
|
prepareLaunch: () => prepareLaunch,
|
|
136
144
|
profileExists: () => profileExists,
|
|
137
145
|
providerExists: () => providerExists,
|
|
146
|
+
rankPool: () => rankPool,
|
|
138
147
|
rcEventWriteResultFromAnswer: () => rcEventWriteResultFromAnswer,
|
|
139
148
|
rcObserverAsPassthrough: () => rcObserverAsPassthrough,
|
|
140
149
|
readActiveIdentity: () => readActiveIdentity,
|
|
@@ -3515,25 +3524,19 @@ function realConnectEffects() {
|
|
|
3515
3524
|
}
|
|
3516
3525
|
};
|
|
3517
3526
|
},
|
|
3518
|
-
connectTlsUpstream: async (host, port, clientAlpn) =>
|
|
3519
|
-
const
|
|
3520
|
-
|
|
3521
|
-
|
|
3522
|
-
}
|
|
3523
|
-
|
|
3524
|
-
|
|
3525
|
-
|
|
3526
|
-
|
|
3527
|
-
candidate.once("error", (error) => {
|
|
3528
|
-
if ("code" in error && error.code === "EADDRINUSE") {
|
|
3529
|
-
settle(dial(upstreamLocalPort()));
|
|
3530
|
-
return;
|
|
3531
|
-
}
|
|
3532
|
-
reject(error);
|
|
3527
|
+
connectTlsUpstream: async (host, port, clientAlpn) => {
|
|
3528
|
+
const dialled = await reservedDial({ host, port });
|
|
3529
|
+
if (dialled.error !== null) {
|
|
3530
|
+
throw dialled.error;
|
|
3531
|
+
}
|
|
3532
|
+
return await new Promise((resolve, reject) => {
|
|
3533
|
+
const secure = tls.connect({ socket: dialled.socket, servername: host, ...clientAlpn === void 0 ? {} : { ALPNProtocols: [clientAlpn] } });
|
|
3534
|
+
secure.once("secureConnect", () => {
|
|
3535
|
+
resolve(secure);
|
|
3533
3536
|
});
|
|
3534
|
-
|
|
3535
|
-
|
|
3536
|
-
}
|
|
3537
|
+
secure.once("error", reject);
|
|
3538
|
+
});
|
|
3539
|
+
},
|
|
3537
3540
|
connectTcp: async (host, port) => await new Promise((resolve, reject) => {
|
|
3538
3541
|
const socket = net2.connect({ host, port });
|
|
3539
3542
|
socket.once("connect", () => {
|
|
@@ -5095,547 +5098,380 @@ function listUsageSnapshots(fs12, snapshotsDir) {
|
|
|
5095
5098
|
}).sort((left, right) => left.identity.localeCompare(right.identity));
|
|
5096
5099
|
}
|
|
5097
5100
|
|
|
5098
|
-
// src/
|
|
5099
|
-
var
|
|
5100
|
-
var
|
|
5101
|
-
var
|
|
5102
|
-
|
|
5103
|
-
|
|
5104
|
-
|
|
5105
|
-
|
|
5106
|
-
|
|
5107
|
-
|
|
5108
|
-
const { paths, ports } = params;
|
|
5109
|
-
const deadline = ports.now() + HEADROOM_START_TIMEOUT_MS;
|
|
5110
|
-
let spawnedSupervisor = false;
|
|
5111
|
-
let awaitingAllowlist = false;
|
|
5112
|
-
for (; ; ) {
|
|
5113
|
-
const state = readHeadroomState(ports.fs, paths.headroomStateFile);
|
|
5114
|
-
if (state?.supervisorPid !== void 0 && ports.isRunning(state.supervisorPid)) {
|
|
5115
|
-
const daemonUp = state.socketPath !== void 0 && state.headroomPid !== void 0 && ports.isRunning(state.headroomPid);
|
|
5116
|
-
if (daemonUp && state.socketPath !== void 0) {
|
|
5117
|
-
const required = params.requiredAllowlistHash?.();
|
|
5118
|
-
if (required === void 0 || state.allowlistHash === required) {
|
|
5119
|
-
writeSession(ports.fs, paths.headroomSessionsDir, { pid: params.launcherPid, startedAt: ports.now(), supervisorPid: state.supervisorPid });
|
|
5120
|
-
return { socketPath: state.socketPath };
|
|
5121
|
-
}
|
|
5122
|
-
const holders = sessionsForSupervisor(ports.fs, paths.headroomSessionsDir, state.supervisorPid).filter((session) => ports.isRunning(session.pid));
|
|
5123
|
-
if (holders.length > 0) {
|
|
5124
|
-
throw new HeadroomStartError(
|
|
5125
|
-
`the running headroom daemon was started before this launch's front door address and would refuse every request this launch sends through it. It restarts once the launches using it end (pid ${holders.map((session) => String(session.pid)).join(", ")}); end them and launch again, or launch with --no-headroom.`
|
|
5126
|
-
);
|
|
5127
|
-
}
|
|
5128
|
-
awaitingAllowlist = true;
|
|
5129
|
-
}
|
|
5130
|
-
if (state.lastError !== void 0) {
|
|
5131
|
-
throw new HeadroomStartError(
|
|
5132
|
-
`the headroom daemon reported a fatal error and is not serving: ${state.lastError} (daemon log: ${paths.headroomLogPath})`
|
|
5133
|
-
);
|
|
5134
|
-
}
|
|
5135
|
-
} else if (!spawnedSupervisor) {
|
|
5136
|
-
ports.fs.mkdirp(paths.headroomDir);
|
|
5137
|
-
const created = ports.fs.writeFileExclusive(
|
|
5138
|
-
paths.headroomLockFile,
|
|
5139
|
-
`${JSON.stringify({ pid: params.launcherPid, at: ports.now() })}
|
|
5140
|
-
`
|
|
5141
|
-
);
|
|
5142
|
-
if (created) {
|
|
5143
|
-
ports.spawnSupervisor(paths);
|
|
5144
|
-
spawnedSupervisor = true;
|
|
5145
|
-
} else {
|
|
5146
|
-
const lock = readStartLock(ports.fs, paths.headroomLockFile);
|
|
5147
|
-
if (lock === void 0 || !ports.isRunning(lock.pid)) {
|
|
5148
|
-
ports.fs.removeRecursive(paths.headroomLockFile);
|
|
5149
|
-
continue;
|
|
5150
|
-
}
|
|
5151
|
-
}
|
|
5152
|
-
}
|
|
5153
|
-
if (ports.now() >= deadline) {
|
|
5154
|
-
const lastError = state?.lastError;
|
|
5155
|
-
throw new HeadroomStartError(
|
|
5156
|
-
`the headroom daemon did not become ready within ${String(HEADROOM_START_TIMEOUT_MS)}ms` + (lastError === void 0 ? "" : ` (last error: ${lastError})`) + (awaitingAllowlist ? " (the running daemon's allowlist does not admit this launch's front door, and it did not restart)" : "") + `. Daemon log: ${paths.headroomLogPath}`
|
|
5157
|
-
);
|
|
5158
|
-
}
|
|
5159
|
-
ports.sleep(HEADROOM_LAUNCHER_POLL_MS);
|
|
5101
|
+
// src/usage/preflight.ts
|
|
5102
|
+
var MS_PER_SECOND2 = 1e3;
|
|
5103
|
+
var SECONDS_PER_MINUTE = 60;
|
|
5104
|
+
var MINUTES_PER_HOUR = 60;
|
|
5105
|
+
var HOURS_PER_DAY = 24;
|
|
5106
|
+
var WARNING_STATUSES = /* @__PURE__ */ new Set(["allowed_warning", "rejected"]);
|
|
5107
|
+
function formatAge(ms) {
|
|
5108
|
+
const minutes = Math.floor(ms / (MS_PER_SECOND2 * SECONDS_PER_MINUTE));
|
|
5109
|
+
if (minutes < MINUTES_PER_HOUR) {
|
|
5110
|
+
return `${String(Math.max(minutes, 0))}m`;
|
|
5160
5111
|
}
|
|
5112
|
+
const hours = Math.floor(minutes / MINUTES_PER_HOUR);
|
|
5113
|
+
return hours < HOURS_PER_DAY ? `${String(hours)}h` : `${String(Math.floor(hours / HOURS_PER_DAY))}d`;
|
|
5161
5114
|
}
|
|
5162
|
-
|
|
5163
|
-
|
|
5164
|
-
|
|
5165
|
-
|
|
5115
|
+
function effectiveWindow(window, nowMs) {
|
|
5116
|
+
const resetsAtMs = window.resetsAt === void 0 ? void 0 : Date.parse(window.resetsAt);
|
|
5117
|
+
if (resetsAtMs !== void 0 && resetsAtMs <= nowMs) {
|
|
5118
|
+
return { reset: true, utilization: 0 };
|
|
5119
|
+
}
|
|
5166
5120
|
return {
|
|
5167
|
-
|
|
5168
|
-
...
|
|
5169
|
-
...
|
|
5170
|
-
...
|
|
5171
|
-
...config.interceptToolResults === void 0 ? {} : { interceptToolResults: config.interceptToolResults },
|
|
5172
|
-
...config.readMaturation === void 0 ? {} : { readMaturation: config.readMaturation }
|
|
5121
|
+
reset: false,
|
|
5122
|
+
...window.utilization === void 0 ? {} : { utilization: window.utilization },
|
|
5123
|
+
...resetsAtMs === void 0 ? {} : { resetsAtMs },
|
|
5124
|
+
...window.status === void 0 ? {} : { status: window.status }
|
|
5173
5125
|
};
|
|
5174
5126
|
}
|
|
5175
|
-
function
|
|
5176
|
-
|
|
5177
|
-
|
|
5178
|
-
|
|
5179
|
-
|
|
5180
|
-
|
|
5181
|
-
|
|
5182
|
-
|
|
5127
|
+
function quotaWarnings(snapshot, provider, nowMs) {
|
|
5128
|
+
const rateLimit = snapshot?.providers[provider]?.rateLimit;
|
|
5129
|
+
const unified = rateLimit?.unified;
|
|
5130
|
+
if (snapshot === void 0 || rateLimit === void 0 || unified === void 0) {
|
|
5131
|
+
return [];
|
|
5132
|
+
}
|
|
5133
|
+
const age = formatAge(nowMs - Date.parse(rateLimit.observedAt));
|
|
5134
|
+
const windows = [
|
|
5135
|
+
{ name: "five-hour", window: unified.fiveHour },
|
|
5136
|
+
{ name: "seven-day", window: unified.sevenDay }
|
|
5183
5137
|
];
|
|
5184
|
-
}
|
|
5185
|
-
|
|
5186
|
-
|
|
5187
|
-
|
|
5188
|
-
|
|
5189
|
-
|
|
5138
|
+
return windows.flatMap(({ name, window }) => {
|
|
5139
|
+
const effective = window === void 0 ? void 0 : effectiveWindow(window, nowMs);
|
|
5140
|
+
if (window === void 0 || effective?.status === void 0 || !WARNING_STATUSES.has(effective.status)) {
|
|
5141
|
+
return [];
|
|
5142
|
+
}
|
|
5143
|
+
const reset = window.resetsAt === void 0 ? "" : `, resets ${window.resetsAt}`;
|
|
5144
|
+
const verdict = effective.status === "rejected" ? "exhausted" : "nearly used";
|
|
5145
|
+
return [`agent-shim: identity ${snapshot.identity}: the ${name} quota is ${verdict}${reset} (last seen ${age} ago)`];
|
|
5146
|
+
});
|
|
5190
5147
|
}
|
|
5191
5148
|
|
|
5192
|
-
// src/
|
|
5193
|
-
var
|
|
5194
|
-
var
|
|
5195
|
-
|
|
5196
|
-
|
|
5197
|
-
|
|
5198
|
-
|
|
5199
|
-
|
|
5200
|
-
|
|
5201
|
-
|
|
5202
|
-
|
|
5203
|
-
}
|
|
5204
|
-
|
|
5205
|
-
|
|
5206
|
-
|
|
5207
|
-
|
|
5208
|
-
|
|
5209
|
-
|
|
5210
|
-
|
|
5211
|
-
|
|
5212
|
-
|
|
5213
|
-
|
|
5214
|
-
|
|
5215
|
-
|
|
5149
|
+
// src/usage/plan.ts
|
|
5150
|
+
var import_zod6 = require("zod");
|
|
5151
|
+
var PlanClassSchema = import_zod6.z.union([
|
|
5152
|
+
import_zod6.z.strictObject({
|
|
5153
|
+
kind: import_zod6.z.literal("subscription"),
|
|
5154
|
+
/** The plan's size as a multiple of the smallest subscription tier (Max 5x is 5, Max 20x is 20). */
|
|
5155
|
+
capacity: import_zod6.z.number().positive(),
|
|
5156
|
+
/** False when the tier string named no multiplier and no tier this project knows, so `capacity` is the neutral 1 rather than a reading. */
|
|
5157
|
+
recognised: import_zod6.z.boolean(),
|
|
5158
|
+
/** The tier string the classification rests on, when the account had one. */
|
|
5159
|
+
tier: import_zod6.z.string().optional()
|
|
5160
|
+
}),
|
|
5161
|
+
import_zod6.z.strictObject({
|
|
5162
|
+
kind: import_zod6.z.literal("pay-per-use"),
|
|
5163
|
+
tier: import_zod6.z.string().optional()
|
|
5164
|
+
})
|
|
5165
|
+
]);
|
|
5166
|
+
var TIER_MULTIPLIER = /(?:^|_)(\d+)x$/;
|
|
5167
|
+
var ZERO_TIER = /(?:^|_)zero$/;
|
|
5168
|
+
var BASE_TIER = /(?:^|_)(?:pro|free)$/;
|
|
5169
|
+
function planOf(account) {
|
|
5170
|
+
const tier = account?.organizationRateLimitTier ?? account?.userRateLimitTier;
|
|
5171
|
+
const tierField = tier === void 0 ? {} : { tier };
|
|
5172
|
+
if (tier === void 0) {
|
|
5173
|
+
return { kind: "subscription", capacity: 1, recognised: false };
|
|
5216
5174
|
}
|
|
5217
|
-
if (
|
|
5218
|
-
return
|
|
5175
|
+
if (ZERO_TIER.test(tier)) {
|
|
5176
|
+
return { kind: "pay-per-use", ...tierField };
|
|
5219
5177
|
}
|
|
5220
|
-
|
|
5221
|
-
|
|
5178
|
+
const multiplier = TIER_MULTIPLIER.exec(tier)?.[1];
|
|
5179
|
+
if (multiplier !== void 0) {
|
|
5180
|
+
return { kind: "subscription", capacity: Number(multiplier), recognised: true, ...tierField };
|
|
5222
5181
|
}
|
|
5223
|
-
return
|
|
5182
|
+
return { kind: "subscription", capacity: 1, recognised: BASE_TIER.test(tier), ...tierField };
|
|
5224
5183
|
}
|
|
5225
|
-
|
|
5226
|
-
|
|
5227
|
-
|
|
5228
|
-
|
|
5229
|
-
|
|
5230
|
-
|
|
5231
|
-
const length = Buffer.byteLength(socketPath, "utf8");
|
|
5232
|
-
if (length > UNIX_SOCKET_PATH_MAX_BYTES) {
|
|
5233
|
-
return {
|
|
5234
|
-
refused: `the headroom socket path ${socketPath} is ${String(length)} bytes, longer than the ${String(UNIX_SOCKET_PATH_MAX_BYTES)} a unix socket path can hold; set AGENT_SHIM_HOME to a shorter directory`
|
|
5235
|
-
};
|
|
5236
|
-
}
|
|
5237
|
-
if (ports.lstat(paths.headroomSocketDir)?.kind === "symlink") {
|
|
5238
|
-
return { refused: `the headroom socket directory ${paths.headroomSocketDir} is a symlink; it must be the real directory` };
|
|
5184
|
+
|
|
5185
|
+
// src/usage/rateLimit.ts
|
|
5186
|
+
var MS_PER_SECOND3 = 1e3;
|
|
5187
|
+
function epochSecondsToIso(value) {
|
|
5188
|
+
if (value === void 0) {
|
|
5189
|
+
return void 0;
|
|
5239
5190
|
}
|
|
5240
|
-
|
|
5241
|
-
|
|
5242
|
-
return refusal === void 0 ? { socketPath } : { refused: refusal };
|
|
5191
|
+
const seconds = Number(value);
|
|
5192
|
+
return Number.isFinite(seconds) && seconds > 0 ? new Date(seconds * MS_PER_SECOND3).toISOString() : void 0;
|
|
5243
5193
|
}
|
|
5244
|
-
function
|
|
5245
|
-
|
|
5246
|
-
|
|
5247
|
-
const pid = HEADROOM_SOCKET_NAME.exec(name)?.[1];
|
|
5248
|
-
if (pid === void 0 || isRunning(Number.parseInt(pid, 10))) {
|
|
5249
|
-
continue;
|
|
5250
|
-
}
|
|
5251
|
-
fs12.removeRecursive(import_node_path11.default.join(paths.headroomSocketDir, name));
|
|
5252
|
-
removed.push(name);
|
|
5194
|
+
function nonNegativeNumber(value) {
|
|
5195
|
+
if (value === void 0 || value.trim() === "") {
|
|
5196
|
+
return void 0;
|
|
5253
5197
|
}
|
|
5254
|
-
|
|
5198
|
+
const parsed = Number(value);
|
|
5199
|
+
return Number.isFinite(parsed) && parsed >= 0 ? parsed : void 0;
|
|
5255
5200
|
}
|
|
5256
|
-
|
|
5257
|
-
|
|
5258
|
-
|
|
5259
|
-
|
|
5260
|
-
|
|
5261
|
-
|
|
5262
|
-
|
|
5263
|
-
const match = GIT_SPEC_RE.exec(spec);
|
|
5264
|
-
if (match === null) {
|
|
5265
|
-
return false;
|
|
5201
|
+
var UNIFIED_PREFIX = "anthropic-ratelimit-unified-";
|
|
5202
|
+
function unifiedWindow(headers, window) {
|
|
5203
|
+
const utilization = nonNegativeNumber(headers[`${UNIFIED_PREFIX}${window}-utilization`]);
|
|
5204
|
+
const resetsAt = epochSecondsToIso(headers[`${UNIFIED_PREFIX}${window}-reset`]);
|
|
5205
|
+
const status = headers[`${UNIFIED_PREFIX}${window}-status`];
|
|
5206
|
+
if (utilization === void 0 && resetsAt === void 0 && status === void 0) {
|
|
5207
|
+
return void 0;
|
|
5266
5208
|
}
|
|
5267
|
-
|
|
5268
|
-
return ref === void 0 || !COMMIT_SHA_RE.test(ref);
|
|
5269
|
-
}
|
|
5270
|
-
function pinnedGitCommit(spec) {
|
|
5271
|
-
const ref = GIT_SPEC_RE.exec(spec)?.[1];
|
|
5272
|
-
return ref !== void 0 && COMMIT_SHA_RE.test(ref) ? ref.toLowerCase() : void 0;
|
|
5209
|
+
return { ...utilization === void 0 ? {} : { utilization }, ...resetsAt === void 0 ? {} : { resetsAt }, ...status === void 0 ? {} : { status } };
|
|
5273
5210
|
}
|
|
5274
|
-
|
|
5275
|
-
|
|
5276
|
-
|
|
5211
|
+
function parseUnifiedRateLimit(headers) {
|
|
5212
|
+
if (!Object.keys(headers).some((name) => name.startsWith(UNIFIED_PREFIX))) {
|
|
5213
|
+
return void 0;
|
|
5214
|
+
}
|
|
5215
|
+
const status = headers[`${UNIFIED_PREFIX}status`];
|
|
5216
|
+
const fiveHour = unifiedWindow(headers, "5h");
|
|
5217
|
+
const sevenDay = unifiedWindow(headers, "7d");
|
|
5218
|
+
const representativeClaim = headers[`${UNIFIED_PREFIX}representative-claim`];
|
|
5219
|
+
const resetAt = epochSecondsToIso(headers[`${UNIFIED_PREFIX}reset`]);
|
|
5220
|
+
const overageStatus = headers[`${UNIFIED_PREFIX}overage-status`];
|
|
5277
5221
|
return {
|
|
5278
|
-
|
|
5279
|
-
|
|
5280
|
-
|
|
5222
|
+
...status === void 0 ? {} : { status },
|
|
5223
|
+
...fiveHour === void 0 ? {} : { fiveHour },
|
|
5224
|
+
...sevenDay === void 0 ? {} : { sevenDay },
|
|
5225
|
+
...representativeClaim === void 0 ? {} : { representativeClaim },
|
|
5226
|
+
...resetAt === void 0 ? {} : { resetAt },
|
|
5227
|
+
...overageStatus === void 0 ? {} : { overageStatus }
|
|
5281
5228
|
};
|
|
5282
5229
|
}
|
|
5283
|
-
|
|
5284
|
-
|
|
5285
|
-
var
|
|
5286
|
-
var
|
|
5287
|
-
|
|
5288
|
-
|
|
5289
|
-
|
|
5290
|
-
|
|
5230
|
+
|
|
5231
|
+
// src/usage/scan.ts
|
|
5232
|
+
var import_zod7 = require("zod");
|
|
5233
|
+
var AnthropicUsageSchema = import_zod7.z.looseObject({
|
|
5234
|
+
input_tokens: import_zod7.z.number().int().nonnegative().nullish(),
|
|
5235
|
+
output_tokens: import_zod7.z.number().int().nonnegative().nullish(),
|
|
5236
|
+
cache_creation_input_tokens: import_zod7.z.number().int().nonnegative().nullish(),
|
|
5237
|
+
cache_read_input_tokens: import_zod7.z.number().int().nonnegative().nullish()
|
|
5238
|
+
});
|
|
5239
|
+
var ErrorObjectSchema = import_zod7.z.looseObject({
|
|
5240
|
+
type: import_zod7.z.string().optional(),
|
|
5241
|
+
code: import_zod7.z.union([import_zod7.z.string(), import_zod7.z.number()]).optional(),
|
|
5242
|
+
message: import_zod7.z.string().optional()
|
|
5243
|
+
});
|
|
5244
|
+
|
|
5245
|
+
// src/usage/middleware.ts
|
|
5246
|
+
var ANTHROPIC_PROVIDER = "anthropic";
|
|
5247
|
+
|
|
5248
|
+
// src/usage/pick.ts
|
|
5249
|
+
var MS_PER_SECOND4 = 1e3;
|
|
5250
|
+
var MS_PER_HOUR = 36e5;
|
|
5251
|
+
var HOURS_PER_DAY2 = 24;
|
|
5252
|
+
var FIVE_HOURS = 5;
|
|
5253
|
+
var PROMPT_CACHE_TTL_HOURS = 1;
|
|
5254
|
+
var PERCENT = 100;
|
|
5255
|
+
var SEVEN_DAYS = 7;
|
|
5256
|
+
var FIVE_HOUR_WINDOW_MS = FIVE_HOURS * MS_PER_HOUR;
|
|
5257
|
+
var SEVEN_DAY_WINDOW_MS = SEVEN_DAYS * HOURS_PER_DAY2 * MS_PER_HOUR;
|
|
5258
|
+
var PROMPT_CACHE_TTL_MS = PROMPT_CACHE_TTL_HOURS * MS_PER_HOUR;
|
|
5259
|
+
var CLASS_ORDER = { scored: 0, unknown: 1, "pay-per-use": 2, ineligible: 3 };
|
|
5260
|
+
function unifiedOf(state) {
|
|
5261
|
+
return state?.rateLimit?.unified;
|
|
5291
5262
|
}
|
|
5292
|
-
function
|
|
5293
|
-
|
|
5294
|
-
|
|
5295
|
-
|
|
5296
|
-
const specifier = /==|>=|<=|!=|>|<|~=/.exec(source);
|
|
5297
|
-
if (specifier === null) {
|
|
5298
|
-
return true;
|
|
5299
|
-
}
|
|
5300
|
-
const installed = parseVersion(version);
|
|
5301
|
-
const wanted = parseVersion(source.slice(specifier.index + specifier[0].length));
|
|
5302
|
-
if (installed === void 0 || wanted === void 0) {
|
|
5303
|
-
return true;
|
|
5263
|
+
function limitBlockedUntil(state, nowMs) {
|
|
5264
|
+
const limit = state?.lastLimit;
|
|
5265
|
+
if (state === void 0 || limit === void 0) {
|
|
5266
|
+
return void 0;
|
|
5304
5267
|
}
|
|
5305
|
-
|
|
5306
|
-
|
|
5307
|
-
case "==":
|
|
5308
|
-
return cmp === 0;
|
|
5309
|
-
case "!=":
|
|
5310
|
-
return cmp !== 0;
|
|
5311
|
-
case ">=":
|
|
5312
|
-
return cmp >= 0;
|
|
5313
|
-
case "<=":
|
|
5314
|
-
return cmp <= 0;
|
|
5315
|
-
case ">":
|
|
5316
|
-
return cmp > 0;
|
|
5317
|
-
case "<":
|
|
5318
|
-
return cmp < 0;
|
|
5319
|
-
case "~=":
|
|
5320
|
-
return compareVersions(installed.slice(0, Math.max(0, wanted.length - 1)), wanted.slice(0, Math.max(0, wanted.length - 1))) === 0 && cmp >= 0;
|
|
5321
|
-
default:
|
|
5322
|
-
return true;
|
|
5268
|
+
if (Date.parse(state.lastRequestAt) > Date.parse(limit.observedAt)) {
|
|
5269
|
+
return void 0;
|
|
5323
5270
|
}
|
|
5271
|
+
const until = limit.resetAt === void 0 ? limit.retryAfterSeconds === void 0 ? void 0 : Date.parse(limit.observedAt) + limit.retryAfterSeconds * MS_PER_SECOND4 : Date.parse(limit.resetAt);
|
|
5272
|
+
return until !== void 0 && until > nowMs ? until : void 0;
|
|
5324
5273
|
}
|
|
5325
|
-
function
|
|
5326
|
-
const
|
|
5327
|
-
|
|
5274
|
+
function windowBlockedUntil(windows) {
|
|
5275
|
+
const resets = windows.flatMap((window) => window.status === "rejected" && window.resetsAtMs !== void 0 ? [window.resetsAtMs] : []);
|
|
5276
|
+
return resets.length === 0 ? void 0 : Math.max(...resets);
|
|
5277
|
+
}
|
|
5278
|
+
function fiveHourBurn(records) {
|
|
5279
|
+
const points = [];
|
|
5280
|
+
for (const record of records) {
|
|
5281
|
+
const window = record.rateLimitHeaders === void 0 ? void 0 : parseUnifiedRateLimit(record.rateLimitHeaders)?.fiveHour;
|
|
5282
|
+
if (window?.utilization !== void 0 && window.resetsAt !== void 0) {
|
|
5283
|
+
points.push({ resetsAt: window.resetsAt, point: { atMs: Date.parse(record.at), utilization: window.utilization } });
|
|
5284
|
+
}
|
|
5285
|
+
}
|
|
5286
|
+
const latest = points.at(-1)?.resetsAt;
|
|
5287
|
+
const current = points.filter((entry) => entry.resetsAt === latest).map((entry) => entry.point);
|
|
5288
|
+
const first = current.at(0);
|
|
5289
|
+
const last = current.at(-1);
|
|
5290
|
+
if (first === void 0 || last === void 0 || last.atMs <= first.atMs || last.utilization <= first.utilization) {
|
|
5328
5291
|
return void 0;
|
|
5329
5292
|
}
|
|
5330
|
-
return
|
|
5293
|
+
return (last.utilization - first.utilization) / (last.atMs - first.atMs);
|
|
5331
5294
|
}
|
|
5332
|
-
function
|
|
5333
|
-
|
|
5334
|
-
|
|
5335
|
-
|
|
5336
|
-
|
|
5337
|
-
|
|
5338
|
-
}
|
|
5295
|
+
function percent(fraction) {
|
|
5296
|
+
return `${String(Math.round(fraction * PERCENT))}%`;
|
|
5297
|
+
}
|
|
5298
|
+
function describeWindow(label, window, effective, nowMs) {
|
|
5299
|
+
if (effective.reset) {
|
|
5300
|
+
return `${label} window has reset`;
|
|
5339
5301
|
}
|
|
5340
|
-
|
|
5302
|
+
const used = effective.utilization === void 0 ? "usage unknown" : `${percent(effective.utilization)} used`;
|
|
5303
|
+
const resets = effective.resetsAtMs === void 0 ? "" : `, resets in ${formatAge(effective.resetsAtMs - nowMs)}`;
|
|
5304
|
+
return `${label} ${used}${resets}${window.status === "allowed_warning" ? " (nearly used)" : ""}`;
|
|
5341
5305
|
}
|
|
5342
|
-
|
|
5343
|
-
|
|
5344
|
-
|
|
5345
|
-
|
|
5346
|
-
const
|
|
5347
|
-
|
|
5348
|
-
|
|
5349
|
-
|
|
5306
|
+
function capacityOf(plan) {
|
|
5307
|
+
return plan.kind === "subscription" ? plan.capacity : 1;
|
|
5308
|
+
}
|
|
5309
|
+
function assess(member, nowMs) {
|
|
5310
|
+
const plan = planOf(member.account);
|
|
5311
|
+
const planReasons = plan.kind === "pay-per-use" ? ["billed by use (no plan allowance)"] : plan.recognised ? [`${String(plan.capacity)}x plan`] : [`plan tier ${plan.tier === void 0 ? "not known" : `"${plan.tier}" not recognised`}, counted as 1x`];
|
|
5312
|
+
const base = { identity: member.identity, plan };
|
|
5313
|
+
if (member.readError !== void 0) {
|
|
5314
|
+
return { candidate: { ...base, class: "unknown", reasons: [`usage state unreadable: ${member.readError}`, ...planReasons] } };
|
|
5350
5315
|
}
|
|
5351
|
-
|
|
5352
|
-
const
|
|
5353
|
-
|
|
5354
|
-
return
|
|
5355
|
-
}
|
|
5356
|
-
const
|
|
5357
|
-
|
|
5358
|
-
|
|
5359
|
-
|
|
5360
|
-
|
|
5361
|
-
|
|
5362
|
-
|
|
5363
|
-
|
|
5364
|
-
|
|
5365
|
-
|
|
5366
|
-
|
|
5367
|
-
|
|
5368
|
-
|
|
5369
|
-
|
|
5370
|
-
|
|
5371
|
-
|
|
5372
|
-
const versionOk = version2 !== void 0 && versionSatisfies(version2, config.source);
|
|
5373
|
-
const pinned = pinnedGitCommit(config.source);
|
|
5374
|
-
const commitOk = pinned === void 0 || ports.installedCommit() === pinned;
|
|
5375
|
-
if (versionOk && commitOk && (installedSource === void 0 || installedSource === config.source)) {
|
|
5376
|
-
installedSource = config.source;
|
|
5377
|
-
return true;
|
|
5378
|
-
}
|
|
5379
|
-
ports.log(`agent-shim headroom supervisor: installing headroom from ${config.source}`);
|
|
5380
|
-
const result = ports.install(config.source);
|
|
5381
|
-
if (!result.ok) {
|
|
5382
|
-
return false;
|
|
5316
|
+
const state = member.snapshot?.providers[ANTHROPIC_PROVIDER];
|
|
5317
|
+
const unified = unifiedOf(state);
|
|
5318
|
+
if (member.snapshot === void 0 || state === void 0 || unified === void 0) {
|
|
5319
|
+
return { candidate: { ...base, class: "unknown", reasons: ["no usage recorded yet, so its quota is unknown (turn on trackUsage for it)", ...planReasons] } };
|
|
5320
|
+
}
|
|
5321
|
+
const observedAgo = state.rateLimit === void 0 ? "" : ` (last seen ${formatAge(nowMs - Date.parse(state.rateLimit.observedAt))} ago)`;
|
|
5322
|
+
const fiveHourWindow = unified.fiveHour;
|
|
5323
|
+
const sevenDayWindow = unified.sevenDay;
|
|
5324
|
+
const five = fiveHourWindow === void 0 ? void 0 : effectiveWindow(fiveHourWindow, nowMs);
|
|
5325
|
+
const seven = sevenDayWindow === void 0 ? void 0 : effectiveWindow(sevenDayWindow, nowMs);
|
|
5326
|
+
const windowReasons = [
|
|
5327
|
+
...fiveHourWindow === void 0 || five === void 0 ? [] : [describeWindow("5h", fiveHourWindow, five, nowMs)],
|
|
5328
|
+
...sevenDayWindow === void 0 || seven === void 0 ? [] : [describeWindow("7d", sevenDayWindow, seven, nowMs)]
|
|
5329
|
+
];
|
|
5330
|
+
const blockedUntil = Math.max(
|
|
5331
|
+
windowBlockedUntil([five, seven].flatMap((window) => window === void 0 ? [] : [window])) ?? 0,
|
|
5332
|
+
limitBlockedUntil(state, nowMs) ?? 0
|
|
5333
|
+
);
|
|
5334
|
+
if (blockedUntil > nowMs) {
|
|
5335
|
+
if (unified.overageStatus === "allowed") {
|
|
5336
|
+
return { candidate: { ...base, class: "pay-per-use", reasons: [`plan exhausted until ${new Date(blockedUntil).toISOString()}, continues as extra usage`, ...windowReasons, ...planReasons] } };
|
|
5383
5337
|
}
|
|
5384
|
-
|
|
5385
|
-
return true;
|
|
5386
|
-
};
|
|
5387
|
-
const socket = prepareHeadroomSocket(fs12, ports.socketTrust, paths, ports.ownPid);
|
|
5388
|
-
if (socket.refused !== void 0) {
|
|
5389
|
-
return fail(socket.refused);
|
|
5338
|
+
return { candidate: { ...base, class: "ineligible", blockedUntilMs: blockedUntil, reasons: [`refused until ${new Date(blockedUntil).toISOString()} (in ${formatAge(blockedUntil - nowMs)})`, ...windowReasons, ...planReasons] } };
|
|
5390
5339
|
}
|
|
5391
|
-
|
|
5392
|
-
|
|
5393
|
-
if (!ensureInstalled()) {
|
|
5394
|
-
return fail(`could not install headroom from ${config.source}: install failed (is uv installed and on PATH?)`);
|
|
5340
|
+
if (plan.kind === "pay-per-use" || fiveHourWindow === void 0 && sevenDayWindow === void 0) {
|
|
5341
|
+
return { candidate: { ...base, class: "pay-per-use", reasons: [...plan.kind === "pay-per-use" ? planReasons : ["no plan windows reported, so usage bills as extra usage"]] } };
|
|
5395
5342
|
}
|
|
5396
|
-
const
|
|
5397
|
-
|
|
5398
|
-
|
|
5399
|
-
const orphanPid = previousState?.headroomPid;
|
|
5400
|
-
if (orphanPid !== void 0 && ports.isRunning(orphanPid)) {
|
|
5401
|
-
ports.log(`agent-shim headroom supervisor: stopping daemon pid ${String(orphanPid)} left behind by the previous supervisor`);
|
|
5402
|
-
ports.stopProcess(orphanPid);
|
|
5343
|
+
const basis = seven?.utilization !== void 0 ? { window: seven, windowMs: SEVEN_DAY_WINDOW_MS } : five?.utilization !== void 0 ? { window: five, windowMs: FIVE_HOUR_WINDOW_MS } : void 0;
|
|
5344
|
+
if (basis?.window.utilization === void 0) {
|
|
5345
|
+
return { candidate: { ...base, class: "unknown", reasons: ["quota windows reported no utilisation", ...windowReasons, ...planReasons] } };
|
|
5403
5346
|
}
|
|
5404
|
-
|
|
5405
|
-
|
|
5406
|
-
|
|
5407
|
-
|
|
5408
|
-
|
|
5409
|
-
|
|
5410
|
-
|
|
5411
|
-
|
|
5412
|
-
|
|
5413
|
-
|
|
5347
|
+
const remaining = Math.max(0, 1 - basis.window.utilization);
|
|
5348
|
+
const untilResetMs = basis.window.resetsAtMs === void 0 ? basis.windowMs : Math.max(basis.window.resetsAtMs - nowMs, MS_PER_SECOND4);
|
|
5349
|
+
const score = remaining * plan.capacity / (untilResetMs / MS_PER_HOUR);
|
|
5350
|
+
const fiveRemaining = five?.utilization === void 0 ? void 0 : Math.max(0, 1 - five.utilization);
|
|
5351
|
+
const fiveUntil = five?.resetsAtMs === void 0 ? FIVE_HOUR_WINDOW_MS : Math.max(five.resetsAtMs - nowMs, MS_PER_SECOND4);
|
|
5352
|
+
const burn = fiveHourBurn(member.records);
|
|
5353
|
+
return {
|
|
5354
|
+
candidate: { ...base, class: "scored", score, reasons: [...windowReasons.map((reason, index) => index === windowReasons.length - 1 ? `${reason}${observedAgo}` : reason), ...planReasons] },
|
|
5355
|
+
...fiveRemaining === void 0 ? {} : { fiveHour: { remaining: fiveRemaining, untilResetMs: fiveUntil } },
|
|
5356
|
+
...burn === void 0 ? {} : { burn }
|
|
5357
|
+
};
|
|
5358
|
+
}
|
|
5359
|
+
function rankPool(input) {
|
|
5360
|
+
const { members, nowMs } = input;
|
|
5361
|
+
const assessments = members.map((member) => assess(member, nowMs));
|
|
5362
|
+
const demands = assessments.flatMap(({ candidate, burn }) => burn === void 0 ? [] : [burn * capacityOf(candidate.plan)]);
|
|
5363
|
+
const sharedDemand = demands.length === 0 ? void 0 : Math.max(...demands);
|
|
5364
|
+
const candidates = assessments.map((assessment) => {
|
|
5365
|
+
const { candidate, fiveHour, burn } = assessment;
|
|
5366
|
+
const pace = burn ?? (sharedDemand === void 0 ? void 0 : sharedDemand / capacityOf(candidate.plan));
|
|
5367
|
+
if (candidate.class !== "scored" || fiveHour === void 0 || pace === void 0) {
|
|
5368
|
+
return { ...candidate, feasible: true };
|
|
5414
5369
|
}
|
|
5415
|
-
|
|
5416
|
-
|
|
5417
|
-
|
|
5418
|
-
const allowlist = allowlistOf(ports);
|
|
5419
|
-
const allowlistHash = hashAllowlist(allowlist);
|
|
5420
|
-
pruneDeadSessions(fs12, paths.headroomSessionsDir, ports.isRunning);
|
|
5421
|
-
const ownsNow = ownsState();
|
|
5422
|
-
if (!ownsNow && !superseded) {
|
|
5423
|
-
ports.log("agent-shim headroom supervisor: another supervisor now owns the state file; serving this daemon's own sessions until they end");
|
|
5370
|
+
const runsDryInMs = fiveHour.remaining / pace;
|
|
5371
|
+
if (runsDryInMs >= fiveHour.untilResetMs) {
|
|
5372
|
+
return { ...candidate, feasible: true };
|
|
5424
5373
|
}
|
|
5425
|
-
|
|
5426
|
-
|
|
5427
|
-
|
|
5428
|
-
|
|
5429
|
-
|
|
5430
|
-
|
|
5431
|
-
|
|
5432
|
-
|
|
5433
|
-
|
|
5434
|
-
|
|
5435
|
-
|
|
5436
|
-
|
|
5437
|
-
|
|
5438
|
-
|
|
5439
|
-
|
|
5440
|
-
return fail(`headroom failed to become ready ${String(consecutiveFailures)} times in a row; giving up`);
|
|
5441
|
-
}
|
|
5442
|
-
if (installedSource !== config.source && !ensureInstalled()) {
|
|
5443
|
-
return fail(`could not install headroom from ${config.source}: install failed (is uv installed and on PATH?)`);
|
|
5444
|
-
}
|
|
5445
|
-
const pid = ports.spawnHeadroom(socketPath, allowlist, config.settings);
|
|
5446
|
-
const ready = await waitUntilReady(ports, socketPath);
|
|
5447
|
-
if (ready) {
|
|
5448
|
-
consecutiveFailures = 0;
|
|
5449
|
-
headroomPid = pid;
|
|
5450
|
-
runningHash = allowlistHash;
|
|
5451
|
-
runningSettingsHash = settingsHash;
|
|
5452
|
-
const recorded = writeOwnState({
|
|
5453
|
-
supervisorPid: ports.ownPid,
|
|
5454
|
-
headroomPid: pid,
|
|
5455
|
-
socketPath,
|
|
5456
|
-
version,
|
|
5457
|
-
allowlistHash,
|
|
5458
|
-
settingsHash,
|
|
5459
|
-
installedSource: config.source
|
|
5460
|
-
});
|
|
5461
|
-
if (recorded) {
|
|
5462
|
-
fs12.removeRecursive(paths.headroomLockFile);
|
|
5463
|
-
}
|
|
5464
|
-
idleSince = void 0;
|
|
5465
|
-
ports.log(`agent-shim headroom supervisor: headroom pid ${String(pid)} ready on unix socket ${socketPath}`);
|
|
5466
|
-
} else {
|
|
5467
|
-
ports.stopProcess(pid);
|
|
5468
|
-
consecutiveFailures += 1;
|
|
5469
|
-
ports.log(
|
|
5470
|
-
`agent-shim headroom supervisor: headroom did not become ready on unix socket ${socketPath} (attempt ${String(consecutiveFailures)} of ${String(HEADROOM_START_RETRY_BUDGET)})`
|
|
5471
|
-
);
|
|
5472
|
-
await ports.sleep(backoffForAttempt(consecutiveFailures));
|
|
5473
|
-
continue;
|
|
5474
|
-
}
|
|
5475
|
-
} else {
|
|
5476
|
-
if (runningHash !== allowlistHash || runningSettingsHash !== settingsHash || installedSource !== config.source) {
|
|
5477
|
-
if (sessionsForSupervisor(fs12, paths.headroomSessionsDir, ports.ownPid).length === 0) {
|
|
5478
|
-
ports.log("agent-shim headroom supervisor: configuration drifted and no sessions are live; restarting headroom");
|
|
5479
|
-
ports.stopProcess(headroomPid);
|
|
5480
|
-
headroomPid = void 0;
|
|
5481
|
-
runningHash = void 0;
|
|
5482
|
-
runningSettingsHash = void 0;
|
|
5483
|
-
continue;
|
|
5484
|
-
}
|
|
5485
|
-
}
|
|
5486
|
-
const sessions = sessionsForSupervisor(fs12, paths.headroomSessionsDir, ports.ownPid);
|
|
5487
|
-
if (sessions.length === 0) {
|
|
5488
|
-
idleSince ??= ports.now();
|
|
5489
|
-
const idleMs = ports.now() - idleSince;
|
|
5490
|
-
if (idleMs >= config.idleShutdownMinutes * MS_PER_MINUTE2) {
|
|
5491
|
-
ports.log(
|
|
5492
|
-
`agent-shim headroom supervisor: no sessions for ${String(config.idleShutdownMinutes)} minute(s); stopping headroom and exiting`
|
|
5493
|
-
);
|
|
5494
|
-
ports.stopProcess(headroomPid);
|
|
5495
|
-
writeOwnState({ version });
|
|
5496
|
-
return 0;
|
|
5497
|
-
}
|
|
5498
|
-
} else {
|
|
5499
|
-
idleSince = void 0;
|
|
5500
|
-
}
|
|
5501
|
-
}
|
|
5502
|
-
await ports.sleep(HEADROOM_POLL_MS);
|
|
5503
|
-
}
|
|
5504
|
-
}
|
|
5505
|
-
function currentHeadroomAllowlist(fs12, paths) {
|
|
5506
|
-
const providers = readAllProviders(fs12, paths.providersDir).map((entry) => entry.provider);
|
|
5507
|
-
return headroomAllowlist(headroomUpstreams(providers, frontDoorOrigin(readFrontDoorState(fs12, paths.frontdoorStateFile))));
|
|
5508
|
-
}
|
|
5509
|
-
function allowlistOf(ports) {
|
|
5510
|
-
return currentHeadroomAllowlist(ports.fs, ports.paths);
|
|
5511
|
-
}
|
|
5512
|
-
async function waitUntilReady(ports, socketPath) {
|
|
5513
|
-
const deadline = ports.now() + HEADROOM_READY_TIMEOUT_MS;
|
|
5514
|
-
for (; ; ) {
|
|
5515
|
-
if (await ports.ready(socketPath)) {
|
|
5516
|
-
return true;
|
|
5517
|
-
}
|
|
5518
|
-
if (ports.now() >= deadline) {
|
|
5519
|
-
return false;
|
|
5520
|
-
}
|
|
5521
|
-
await ports.sleep(HEADROOM_POLL_MS);
|
|
5522
|
-
}
|
|
5523
|
-
}
|
|
5524
|
-
|
|
5525
|
-
// src/launcher/guard.ts
|
|
5526
|
-
var AMBIENT_CREDENTIAL_VARS = [
|
|
5527
|
-
"ANTHROPIC_API_KEY",
|
|
5528
|
-
"ANTHROPIC_AUTH_TOKEN",
|
|
5529
|
-
"CLAUDE_CODE_OAUTH_TOKEN",
|
|
5530
|
-
"CLAUDE_CODE_USE_BEDROCK",
|
|
5531
|
-
"CLAUDE_CODE_USE_VERTEX",
|
|
5532
|
-
"CLAUDE_CODE_USE_FOUNDRY"
|
|
5533
|
-
];
|
|
5534
|
-
function detectAmbientCredential(env, injected) {
|
|
5535
|
-
for (const variable of AMBIENT_CREDENTIAL_VARS) {
|
|
5536
|
-
const value = env[variable];
|
|
5537
|
-
if (value === void 0 || value === "") {
|
|
5538
|
-
continue;
|
|
5539
|
-
}
|
|
5540
|
-
if (injected?.variable === variable && value === injected.token) {
|
|
5541
|
-
continue;
|
|
5374
|
+
return { ...candidate, feasible: false, reasons: [`5h window would run dry in ${formatAge(runsDryInMs)}, before it resets in ${formatAge(fiveHour.untilResetMs)}`, ...candidate.reasons] };
|
|
5375
|
+
});
|
|
5376
|
+
const ordered = [...candidates].sort(
|
|
5377
|
+
(left, right) => CLASS_ORDER[left.class] - CLASS_ORDER[right.class] || Number(right.feasible) - Number(left.feasible) || (right.score ?? 0) - (left.score ?? 0) || left.identity.localeCompare(right.identity)
|
|
5378
|
+
);
|
|
5379
|
+
const sticky = input.sticky;
|
|
5380
|
+
const stickyIndex = sticky === void 0 ? -1 : ordered.findIndex((candidate) => candidate.identity === sticky.identity);
|
|
5381
|
+
const stickyCandidate = ordered[stickyIndex];
|
|
5382
|
+
if (sticky !== void 0 && stickyCandidate?.class === "scored" && stickyCandidate.feasible) {
|
|
5383
|
+
const ageMs = nowMs - Date.parse(sticky.at);
|
|
5384
|
+
const warm = ageMs <= PROMPT_CACHE_TTL_MS;
|
|
5385
|
+
if (input.resuming || warm) {
|
|
5386
|
+
const why = warm ? `used here ${formatAge(ageMs)} ago, prompt cache still warm` : "resuming a conversation started on this account";
|
|
5387
|
+
ordered.splice(stickyIndex, 1);
|
|
5388
|
+
ordered.unshift({ ...stickyCandidate, reasons: [why, ...stickyCandidate.reasons] });
|
|
5542
5389
|
}
|
|
5543
|
-
return { variable };
|
|
5544
|
-
}
|
|
5545
|
-
return void 0;
|
|
5546
|
-
}
|
|
5547
|
-
function formatAmbientCredentialGuardMessage(variable, identityName) {
|
|
5548
|
-
const identitySetCommand = identityName === void 0 ? "agent-shim identity set <name> --allow-ambient-credential" : `agent-shim identity set ${identityName} --allow-ambient-credential`;
|
|
5549
|
-
return [
|
|
5550
|
-
`error: ${variable} is set in the environment. This identity's isolated`,
|
|
5551
|
-
"credential would be bypassed \u2014 every identity authenticates as this same key",
|
|
5552
|
-
"while it's set. Unset it, or if this is deliberate, opt in per-launch with",
|
|
5553
|
-
"AGENT_SHIM_ALLOW_AMBIENT_CREDENTIAL=1, or persistently for this identity with",
|
|
5554
|
-
`\`${identitySetCommand}\`.`
|
|
5555
|
-
].join("\n");
|
|
5556
|
-
}
|
|
5557
|
-
function evaluateAmbientCredentialGuard(params) {
|
|
5558
|
-
const detected = detectAmbientCredential(params.env, params.injectedCredential);
|
|
5559
|
-
if (detected === void 0) {
|
|
5560
|
-
return { ok: true };
|
|
5561
|
-
}
|
|
5562
|
-
if (params.allowAmbientCredentialOverride || params.allowAmbientCredential || params.providerSelected === true) {
|
|
5563
|
-
return { ok: true };
|
|
5564
5390
|
}
|
|
5391
|
+
const pick = ordered.find((candidate) => candidate.class !== "ineligible");
|
|
5392
|
+
const returns = ordered.flatMap((candidate) => candidate.blockedUntilMs === void 0 ? [] : [{ identity: candidate.identity, atMs: candidate.blockedUntilMs }]);
|
|
5393
|
+
const earliestReturn = returns.length === 0 ? void 0 : returns.reduce((soonest, entry) => entry.atMs < soonest.atMs ? entry : soonest);
|
|
5565
5394
|
return {
|
|
5566
|
-
|
|
5567
|
-
|
|
5568
|
-
message: formatAmbientCredentialGuardMessage(detected.variable, params.identityName)
|
|
5395
|
+
candidates: ordered,
|
|
5396
|
+
...pick === void 0 ? { ...earliestReturn === void 0 ? {} : { earliestReturn } } : { pick }
|
|
5569
5397
|
};
|
|
5570
5398
|
}
|
|
5571
5399
|
|
|
5572
|
-
// src/
|
|
5573
|
-
var
|
|
5574
|
-
var
|
|
5575
|
-
|
|
5576
|
-
|
|
5577
|
-
|
|
5578
|
-
|
|
5579
|
-
|
|
5580
|
-
|
|
5581
|
-
|
|
5582
|
-
|
|
5583
|
-
|
|
5400
|
+
// src/usage/poolPick.ts
|
|
5401
|
+
var import_node_path11 = __toESM(require("node:path"), 1);
|
|
5402
|
+
var import_zod8 = require("zod");
|
|
5403
|
+
|
|
5404
|
+
// src/usage/store.ts
|
|
5405
|
+
var DAY_MS2 = 864e5;
|
|
5406
|
+
var DAYS_IN_WEEK = 7;
|
|
5407
|
+
var USAGE_RETENTION_MS = DAYS_IN_WEEK * DAY_MS2;
|
|
5408
|
+
|
|
5409
|
+
// src/usage/poolPick.ts
|
|
5410
|
+
var SCHEMA_VERSION = 1;
|
|
5411
|
+
var PickEntrySchema = import_zod8.z.strictObject({ identity: import_zod8.z.string().min(1), at: import_zod8.z.iso.datetime() });
|
|
5412
|
+
var PicksFileSchema = import_zod8.z.strictObject({
|
|
5413
|
+
schemaVersion: import_zod8.z.literal(SCHEMA_VERSION),
|
|
5414
|
+
picks: import_zod8.z.record(import_zod8.z.string().min(1), PickEntrySchema)
|
|
5415
|
+
});
|
|
5416
|
+
function errorMessage(error) {
|
|
5417
|
+
return error instanceof Error ? error.message : String(error);
|
|
5584
5418
|
}
|
|
5585
|
-
function
|
|
5586
|
-
|
|
5419
|
+
function loadPoolMembers(fs12, paths, identities, nowMs) {
|
|
5420
|
+
const windowStartMs = nowMs - FIVE_HOUR_WINDOW_MS;
|
|
5421
|
+
const log = readUsageLog(fs12, paths.usageLogDir, { sinceMs: windowStartMs });
|
|
5422
|
+
return identities.map((identity) => {
|
|
5423
|
+
const records = log.records.filter((record) => record.identity === identity && record.provider === ANTHROPIC_PROVIDER && Date.parse(record.at) >= windowStartMs);
|
|
5424
|
+
try {
|
|
5425
|
+
const snapshot = readUsageSnapshot(fs12, paths.usageSnapshotsDir, identity);
|
|
5426
|
+
const account = readAccountMetadata(fs12, paths.identitiesDir, identity) ?? snapshot?.account;
|
|
5427
|
+
return { identity, records, ...snapshot === void 0 ? {} : { snapshot }, ...account === void 0 ? {} : { account } };
|
|
5428
|
+
} catch (error) {
|
|
5429
|
+
if (error instanceof UsageSnapshotError || error instanceof AccountMetadataError) {
|
|
5430
|
+
return { identity, records, readError: errorMessage(error) };
|
|
5431
|
+
}
|
|
5432
|
+
throw error;
|
|
5433
|
+
}
|
|
5434
|
+
});
|
|
5587
5435
|
}
|
|
5588
|
-
function
|
|
5589
|
-
|
|
5590
|
-
|
|
5591
|
-
|
|
5436
|
+
function rankPoolFromStore(params) {
|
|
5437
|
+
return rankPool({
|
|
5438
|
+
members: loadPoolMembers(params.fs, params.paths, params.identities, params.nowMs),
|
|
5439
|
+
nowMs: params.nowMs,
|
|
5440
|
+
resuming: params.resuming,
|
|
5441
|
+
...params.sticky === void 0 ? {} : { sticky: params.sticky }
|
|
5442
|
+
});
|
|
5443
|
+
}
|
|
5444
|
+
function readPicksFile(fs12, file) {
|
|
5445
|
+
const empty = { schemaVersion: SCHEMA_VERSION, picks: {} };
|
|
5446
|
+
const raw = fs12.readFileUtf8(file);
|
|
5447
|
+
if (raw === void 0) {
|
|
5448
|
+
return { file: empty };
|
|
5449
|
+
}
|
|
5450
|
+
let parsed;
|
|
5451
|
+
try {
|
|
5452
|
+
parsed = JSON.parse(raw);
|
|
5453
|
+
} catch {
|
|
5454
|
+
return { file: empty, problem: `${file} is not valid JSON` };
|
|
5592
5455
|
}
|
|
5593
|
-
|
|
5456
|
+
const result = PicksFileSchema.safeParse(parsed);
|
|
5457
|
+
return result.success ? { file: result.data } : { file: empty, problem: `${file} is not a picks file this agent-shim can read` };
|
|
5594
5458
|
}
|
|
5595
|
-
function
|
|
5596
|
-
|
|
5597
|
-
|
|
5598
|
-
|
|
5599
|
-
configProfilesDir: import_node_path12.default.join(root, "config-profiles"),
|
|
5600
|
-
providersDir: import_node_path12.default.join(root, "providers"),
|
|
5601
|
-
directoryRulesFile: import_node_path12.default.join(root, "directory-rules.json"),
|
|
5602
|
-
activeIdentityFile: import_node_path12.default.join(root, "active-identity"),
|
|
5603
|
-
globalConfigFile: import_node_path12.default.join(root, "config.json"),
|
|
5604
|
-
categoriesLocalFile: import_node_path12.default.join(root, "categories.local.json"),
|
|
5605
|
-
claudeShimFile: import_node_path12.default.join(root, "claude-shim.json"),
|
|
5606
|
-
headroomDir: import_node_path12.default.join(root, "headroom"),
|
|
5607
|
-
headroomStateFile: import_node_path12.default.join(root, "headroom", `state.v${String(HEADROOM_STATE_SCHEMA_VERSION)}.json`),
|
|
5608
|
-
headroomSocketDir: import_node_path12.default.join(root, "headroom", "run"),
|
|
5609
|
-
headroomLockFile: import_node_path12.default.join(root, "headroom", "start.lock"),
|
|
5610
|
-
headroomSessionsDir: import_node_path12.default.join(root, "headroom", "sessions"),
|
|
5611
|
-
logsDir: import_node_path12.default.join(root, "logs"),
|
|
5612
|
-
headroomLogPath: import_node_path12.default.join(root, "logs", "headroom.log"),
|
|
5613
|
-
frontdoorDir: import_node_path12.default.join(root, "frontdoor"),
|
|
5614
|
-
frontdoorCaDir: import_node_path12.default.join(root, "frontdoor", "ca"),
|
|
5615
|
-
frontdoorCaCertFile: import_node_path12.default.join(root, "frontdoor", "ca", "ca.pem"),
|
|
5616
|
-
frontdoorCaKeyFile: import_node_path12.default.join(root, "frontdoor", "ca", "ca.key"),
|
|
5617
|
-
frontdoorCaBundlesDir: import_node_path12.default.join(root, "frontdoor", "ca", "bundles"),
|
|
5618
|
-
frontdoorStateFile: import_node_path12.default.join(root, "frontdoor", "state.json"),
|
|
5619
|
-
frontdoorLockFile: import_node_path12.default.join(root, "frontdoor", "start.lock"),
|
|
5620
|
-
frontdoorControlTokenFile: import_node_path12.default.join(root, "frontdoor", "control-token"),
|
|
5621
|
-
frontdoorSessionsDir: import_node_path12.default.join(root, "frontdoor", "sessions"),
|
|
5622
|
-
frontdoorLogPath: import_node_path12.default.join(root, "logs", "frontdoor.log"),
|
|
5623
|
-
usageDir: import_node_path12.default.join(root, "usage"),
|
|
5624
|
-
usageLogDir: import_node_path12.default.join(root, "usage", "log"),
|
|
5625
|
-
usageSnapshotsDir: import_node_path12.default.join(root, "usage", "snapshots"),
|
|
5626
|
-
usagePicksFile: import_node_path12.default.join(root, "usage", "picks.json")
|
|
5627
|
-
};
|
|
5459
|
+
function readStickyPick(fs12, picksFile, directory) {
|
|
5460
|
+
const read = readPicksFile(fs12, picksFile);
|
|
5461
|
+
const entry = read.file.picks[directory];
|
|
5462
|
+
return { ...entry === void 0 ? {} : { sticky: entry }, ...read.problem === void 0 ? {} : { problem: read.problem } };
|
|
5628
5463
|
}
|
|
5629
|
-
function
|
|
5630
|
-
|
|
5464
|
+
function recordStickyPick(fs12, picksFile, directory, identity, nowMs) {
|
|
5465
|
+
const current = readPicksFile(fs12, picksFile).file.picks;
|
|
5466
|
+
const kept = Object.entries(current).filter(([, entry]) => nowMs - Date.parse(entry.at) <= USAGE_RETENTION_MS);
|
|
5467
|
+
const next = { schemaVersion: SCHEMA_VERSION, picks: { ...Object.fromEntries(kept), [directory]: { identity, at: new Date(nowMs).toISOString() } } };
|
|
5468
|
+
fs12.mkdirPrivate(import_node_path11.default.dirname(picksFile));
|
|
5469
|
+
fs12.writeFilePrivate(picksFile, `${JSON.stringify(next, null, 2)}
|
|
5470
|
+
`);
|
|
5631
5471
|
}
|
|
5632
5472
|
|
|
5633
|
-
// src/identityStore.ts
|
|
5634
|
-
var import_node_fs4 = __toESM(require("node:fs"), 1);
|
|
5635
|
-
var import_node_path15 = __toESM(require("node:path"), 1);
|
|
5636
|
-
|
|
5637
5473
|
// src/launcher/identity.ts
|
|
5638
|
-
var
|
|
5474
|
+
var import_node_path12 = __toESM(require("node:path"), 1);
|
|
5639
5475
|
function poolNameOf(selector) {
|
|
5640
5476
|
return selector.startsWith(POOL_SELECTOR_PREFIX) ? selector.slice(POOL_SELECTOR_PREFIX.length) : void 0;
|
|
5641
5477
|
}
|
|
@@ -5684,1445 +5520,1775 @@ function decideConfigProfile(params) {
|
|
|
5684
5520
|
return { source: "none" };
|
|
5685
5521
|
}
|
|
5686
5522
|
function loadIdentity(identitiesDir, name, fs12) {
|
|
5687
|
-
return loadConfigFile(
|
|
5523
|
+
return loadConfigFile(import_node_path12.default.join(identitiesDir, name, "identity.json"), IdentitySchema, fs12.readConfigFile);
|
|
5688
5524
|
}
|
|
5689
5525
|
|
|
5690
|
-
// src/
|
|
5691
|
-
var
|
|
5692
|
-
var
|
|
5693
|
-
var
|
|
5694
|
-
|
|
5695
|
-
|
|
5696
|
-
|
|
5697
|
-
this.name = "ProfileNotFoundError";
|
|
5698
|
-
}
|
|
5699
|
-
profileName;
|
|
5700
|
-
};
|
|
5701
|
-
var ProfileAlreadyExistsError = class extends CliError {
|
|
5702
|
-
constructor(profileName) {
|
|
5703
|
-
super(`A configuration profile named "${profileName}" already exists.`);
|
|
5704
|
-
this.profileName = profileName;
|
|
5705
|
-
this.name = "ProfileAlreadyExistsError";
|
|
5706
|
-
}
|
|
5707
|
-
profileName;
|
|
5708
|
-
};
|
|
5709
|
-
var InvalidCategoryNameError = class extends CliError {
|
|
5710
|
-
constructor(categoryName) {
|
|
5711
|
-
super(`"${categoryName}" is not a category a configuration profile may toggle (runtime, history, knowledge, settings).`);
|
|
5712
|
-
this.categoryName = categoryName;
|
|
5713
|
-
this.name = "InvalidCategoryNameError";
|
|
5714
|
-
}
|
|
5715
|
-
categoryName;
|
|
5716
|
-
};
|
|
5717
|
-
function profileJsonPath(paths, name) {
|
|
5718
|
-
return import_node_path14.default.join(paths.configProfilesDir, `${name}.json`);
|
|
5526
|
+
// src/launcher/pool.ts
|
|
5527
|
+
var RESUME_FLAGS = /* @__PURE__ */ new Set(["--continue", "-c", "--resume", "-r"]);
|
|
5528
|
+
var TERMINATOR = "--";
|
|
5529
|
+
var REASONS_LOGGED = 3;
|
|
5530
|
+
function splitMembers(pool, paths, fs12) {
|
|
5531
|
+
const exists = (name) => loadIdentity(paths.identitiesDir, name, fs12) !== void 0;
|
|
5532
|
+
return { present: pool.identities.filter(exists), missing: pool.identities.filter((name) => !exists(name)) };
|
|
5719
5533
|
}
|
|
5720
|
-
function
|
|
5721
|
-
|
|
5534
|
+
function isResuming(passthrough) {
|
|
5535
|
+
const end = passthrough.indexOf(TERMINATOR);
|
|
5536
|
+
return (end === -1 ? passthrough : passthrough.slice(0, end)).some((token) => RESUME_FLAGS.has(token));
|
|
5722
5537
|
}
|
|
5723
|
-
function
|
|
5724
|
-
|
|
5725
|
-
|
|
5538
|
+
function resolvePoolLaunch(params) {
|
|
5539
|
+
const { poolName, log } = params;
|
|
5540
|
+
const pool = params.pools?.[poolName];
|
|
5541
|
+
if (pool === void 0) {
|
|
5542
|
+
return { ok: false, message: `agent-shim: no pool named "${poolName}" (selected via ${params.selectedVia}). Run \`agent-shim pool add ${poolName} --identity <name>...\` first.` };
|
|
5726
5543
|
}
|
|
5727
|
-
}
|
|
5728
|
-
|
|
5729
|
-
|
|
5730
|
-
}
|
|
5731
|
-
function createProfile(paths, name, extendsList, description) {
|
|
5732
|
-
if (profileExists(paths, name)) {
|
|
5733
|
-
throw new ProfileAlreadyExistsError(name);
|
|
5544
|
+
const { present: identities, missing } = splitMembers(pool, params.paths, params.fs);
|
|
5545
|
+
for (const name of missing) {
|
|
5546
|
+
log.warn(`agent-shim: pool "${poolName}" names identity "${name}", which does not exist; skipping it`);
|
|
5734
5547
|
}
|
|
5735
|
-
|
|
5736
|
-
|
|
5737
|
-
...description === void 0 ? {} : { description },
|
|
5738
|
-
...extendsList !== void 0 && extendsList.length > 0 ? { extends: [...extendsList] } : {}
|
|
5739
|
-
});
|
|
5740
|
-
if (!parsed.success) {
|
|
5741
|
-
throw new ConfigValidationError(filePath, parsed.error.issues);
|
|
5548
|
+
if (identities.length === 0) {
|
|
5549
|
+
return { ok: false, message: `agent-shim: no member of pool "${poolName}" is an existing identity.` };
|
|
5742
5550
|
}
|
|
5743
|
-
|
|
5744
|
-
|
|
5745
|
-
|
|
5746
|
-
|
|
5747
|
-
if (!import_node_fs3.default.existsSync(paths.configProfilesDir)) {
|
|
5748
|
-
return [];
|
|
5551
|
+
const resuming = isResuming(params.passthrough);
|
|
5552
|
+
const stickyRead = readStickyPick(params.usageFs, params.paths.usagePicksFile, params.cwd);
|
|
5553
|
+
if (stickyRead.problem !== void 0) {
|
|
5554
|
+
log.warn(`agent-shim: ${stickyRead.problem}; ignoring the last-pick record`);
|
|
5749
5555
|
}
|
|
5750
|
-
|
|
5751
|
-
|
|
5752
|
-
|
|
5753
|
-
const
|
|
5754
|
-
if (
|
|
5755
|
-
|
|
5556
|
+
for (; ; ) {
|
|
5557
|
+
const nowMs = params.now();
|
|
5558
|
+
const ranking = rankPoolFromStore({ fs: params.usageFs, paths: params.paths, identities, nowMs, resuming, ...stickyRead.sticky === void 0 ? {} : { sticky: stickyRead.sticky } });
|
|
5559
|
+
const { pick, earliestReturn } = ranking;
|
|
5560
|
+
if (pick !== void 0) {
|
|
5561
|
+
recordStickyPick(params.usageFs, params.paths.usagePicksFile, params.cwd, pick.identity, nowMs);
|
|
5562
|
+
return { ok: true, identity: pick.identity, explanation: `pool ${poolName}: ${pick.reasons.slice(0, REASONS_LOGGED).join("; ")}` };
|
|
5756
5563
|
}
|
|
5757
|
-
|
|
5758
|
-
|
|
5759
|
-
}
|
|
5760
|
-
function globalConfigPath(paths) {
|
|
5761
|
-
return paths.globalConfigFile;
|
|
5762
|
-
}
|
|
5763
|
-
function readGlobalConfig(paths) {
|
|
5764
|
-
return readJson(globalConfigPath(paths), GlobalConfigSchema);
|
|
5765
|
-
}
|
|
5766
|
-
function setGlobalDefaultProfile(paths, name) {
|
|
5767
|
-
return applyPatch(
|
|
5768
|
-
globalConfigPath(paths),
|
|
5769
|
-
GlobalConfigSchema,
|
|
5770
|
-
{ defaultConfigProfile: name },
|
|
5771
|
-
{ defaults: {} }
|
|
5772
|
-
);
|
|
5773
|
-
}
|
|
5774
|
-
function validateCategoryNames(patch) {
|
|
5775
|
-
for (const key of Object.keys(patch)) {
|
|
5776
|
-
if (!isOverridableCategory(key)) {
|
|
5777
|
-
throw new InvalidCategoryNameError(key);
|
|
5564
|
+
if (earliestReturn === void 0) {
|
|
5565
|
+
return { ok: false, message: `agent-shim: no member of pool "${poolName}" can be picked.` };
|
|
5778
5566
|
}
|
|
5567
|
+
const until = new Date(earliestReturn.atMs).toISOString();
|
|
5568
|
+
if (!params.wait) {
|
|
5569
|
+
return {
|
|
5570
|
+
ok: false,
|
|
5571
|
+
message: `agent-shim: every member of pool "${poolName}" is refused right now; the earliest, ${earliestReturn.identity}, returns at ${until} (in ${formatAge(earliestReturn.atMs - nowMs)}). Pass --wait to sleep until then.`
|
|
5572
|
+
};
|
|
5573
|
+
}
|
|
5574
|
+
log.info(`agent-shim: every member of pool "${poolName}" is refused; waiting until ${until} for ${earliestReturn.identity}`);
|
|
5575
|
+
params.sleep(Math.max(earliestReturn.atMs - nowMs, 0));
|
|
5779
5576
|
}
|
|
5780
5577
|
}
|
|
5781
|
-
|
|
5782
|
-
|
|
5783
|
-
|
|
5784
|
-
|
|
5785
|
-
|
|
5786
|
-
|
|
5787
|
-
|
|
5788
|
-
|
|
5789
|
-
|
|
5790
|
-
|
|
5791
|
-
|
|
5792
|
-
|
|
5793
|
-
return applyPatch(profileJsonPath(paths, name), ConfigProfileSchema, { entries: mergedEntries });
|
|
5794
|
-
}
|
|
5795
|
-
function setProfileLaunchFlags(paths, name, patch) {
|
|
5796
|
-
requireProfileExists(paths, name);
|
|
5797
|
-
const existing = readProfile(paths, name) ?? {};
|
|
5798
|
-
const mergedLaunch = { ...existing.launch, ...patch };
|
|
5799
|
-
return applyPatch(profileJsonPath(paths, name), ConfigProfileSchema, {
|
|
5800
|
-
// Read as `unknown` so the check sees the `undefined` a cleared key holds, which LaunchFlags' optional properties hide from the value type.
|
|
5801
|
-
launch: Object.values(mergedLaunch).every((value) => value === void 0) ? void 0 : mergedLaunch
|
|
5802
|
-
});
|
|
5578
|
+
|
|
5579
|
+
// src/poolPickReport.ts
|
|
5580
|
+
function candidateView(candidate) {
|
|
5581
|
+
return {
|
|
5582
|
+
identity: candidate.identity,
|
|
5583
|
+
class: candidate.class,
|
|
5584
|
+
...candidate.score === void 0 ? {} : { score: candidate.score },
|
|
5585
|
+
feasible: candidate.feasible,
|
|
5586
|
+
...candidate.blockedUntilMs === void 0 ? {} : { blockedUntil: new Date(candidate.blockedUntilMs).toISOString() },
|
|
5587
|
+
plan: candidate.plan,
|
|
5588
|
+
reasons: [...candidate.reasons]
|
|
5589
|
+
};
|
|
5803
5590
|
}
|
|
5804
|
-
function
|
|
5805
|
-
|
|
5806
|
-
|
|
5807
|
-
|
|
5808
|
-
|
|
5591
|
+
function collectPoolPick(params) {
|
|
5592
|
+
const { present, missing } = splitMembers(params.pool, params.paths, params.fs);
|
|
5593
|
+
const sticky = readStickyPick(params.usageFs, params.paths.usagePicksFile, params.directory);
|
|
5594
|
+
const ranking = rankPoolFromStore({
|
|
5595
|
+
fs: params.usageFs,
|
|
5596
|
+
paths: params.paths,
|
|
5597
|
+
identities: present,
|
|
5598
|
+
nowMs: params.nowMs,
|
|
5599
|
+
resuming: false,
|
|
5600
|
+
...sticky.sticky === void 0 ? {} : { sticky: sticky.sticky }
|
|
5809
5601
|
});
|
|
5810
|
-
|
|
5811
|
-
|
|
5812
|
-
|
|
5813
|
-
|
|
5602
|
+
return {
|
|
5603
|
+
pool: params.poolName,
|
|
5604
|
+
directory: params.directory,
|
|
5605
|
+
...ranking.pick === void 0 ? {} : { pick: ranking.pick.identity },
|
|
5606
|
+
candidates: ranking.candidates.map(candidateView),
|
|
5607
|
+
missing: [...missing],
|
|
5608
|
+
...ranking.earliestReturn === void 0 ? {} : { earliestReturn: { identity: ranking.earliestReturn.identity, at: new Date(ranking.earliestReturn.atMs).toISOString() } },
|
|
5609
|
+
...sticky.problem === void 0 ? {} : { stickyProblem: sticky.problem }
|
|
5610
|
+
};
|
|
5814
5611
|
}
|
|
5815
5612
|
|
|
5816
|
-
// src/
|
|
5817
|
-
var
|
|
5818
|
-
|
|
5819
|
-
|
|
5820
|
-
|
|
5821
|
-
|
|
5822
|
-
|
|
5823
|
-
|
|
5824
|
-
|
|
5825
|
-
|
|
5826
|
-
|
|
5827
|
-
|
|
5828
|
-
|
|
5829
|
-
|
|
5830
|
-
|
|
5831
|
-
|
|
5832
|
-
|
|
5833
|
-
|
|
5834
|
-
|
|
5835
|
-
|
|
5836
|
-
|
|
5837
|
-
|
|
5838
|
-
|
|
5839
|
-
|
|
5840
|
-
|
|
5841
|
-
|
|
5842
|
-
|
|
5843
|
-
|
|
5844
|
-
|
|
5845
|
-
const pool = readPools(paths)[name];
|
|
5846
|
-
if (pool === void 0) {
|
|
5847
|
-
throw new PoolNotFoundError(name);
|
|
5848
|
-
}
|
|
5849
|
-
return pool;
|
|
5850
|
-
}
|
|
5851
|
-
function writePools(paths, pools) {
|
|
5852
|
-
applyPatch(paths.globalConfigFile, GlobalConfigSchema, { pools }, { defaults: {} });
|
|
5853
|
-
}
|
|
5854
|
-
function addPool(paths, name, identities) {
|
|
5855
|
-
if (!PoolNameSchema.safeParse(name).success) {
|
|
5856
|
-
throw new InvalidPoolNameError(name);
|
|
5857
|
-
}
|
|
5858
|
-
const pools = readPools(paths);
|
|
5859
|
-
if (pools[name] !== void 0) {
|
|
5860
|
-
throw new PoolAlreadyExistsError(name);
|
|
5861
|
-
}
|
|
5862
|
-
const pool = { identities: [...identities] };
|
|
5863
|
-
writePools(paths, { ...pools, [name]: pool });
|
|
5864
|
-
return pool;
|
|
5865
|
-
}
|
|
5866
|
-
function setPool(paths, name, identities) {
|
|
5867
|
-
requirePool(paths, name);
|
|
5868
|
-
const pool = { identities: [...identities] };
|
|
5869
|
-
writePools(paths, { ...readPools(paths), [name]: pool });
|
|
5870
|
-
return pool;
|
|
5871
|
-
}
|
|
5872
|
-
function removePool(paths, name) {
|
|
5873
|
-
requirePool(paths, name);
|
|
5874
|
-
const remaining = Object.fromEntries(Object.entries(readPools(paths)).filter(([existing]) => existing !== name));
|
|
5875
|
-
writePools(paths, remaining);
|
|
5876
|
-
}
|
|
5613
|
+
// src/usage/pickReportSchema.ts
|
|
5614
|
+
var import_zod9 = require("zod");
|
|
5615
|
+
var PoolPickCandidateViewSchema = import_zod9.z.strictObject({
|
|
5616
|
+
identity: import_zod9.z.string(),
|
|
5617
|
+
/** In pick order: `scored` has usable quota data, `unknown` has none, `pay-per-use` bills by use, `ineligible` is refused right now. */
|
|
5618
|
+
class: import_zod9.z.enum(["scored", "unknown", "pay-per-use", "ineligible"]),
|
|
5619
|
+
/** Plan-size-weighted remaining quota per hour until its reset; present for `scored` only. */
|
|
5620
|
+
score: import_zod9.z.number().optional(),
|
|
5621
|
+
/** False when the five-hour window would run dry, at the observed pace, before it resets. */
|
|
5622
|
+
feasible: import_zod9.z.boolean(),
|
|
5623
|
+
/** When an `ineligible` member can be used again, as an ISO instant. */
|
|
5624
|
+
blockedUntil: import_zod9.z.iso.datetime().optional(),
|
|
5625
|
+
plan: PlanClassSchema,
|
|
5626
|
+
/** The facts behind the class and score, in the order they matter. */
|
|
5627
|
+
reasons: import_zod9.z.array(import_zod9.z.string())
|
|
5628
|
+
});
|
|
5629
|
+
var PoolPickReportSchema = import_zod9.z.strictObject({
|
|
5630
|
+
pool: import_zod9.z.string(),
|
|
5631
|
+
directory: import_zod9.z.string(),
|
|
5632
|
+
/** The member a launch would run as, absent when every member is refused. */
|
|
5633
|
+
pick: import_zod9.z.string().optional(),
|
|
5634
|
+
candidates: import_zod9.z.array(PoolPickCandidateViewSchema),
|
|
5635
|
+
/** Members that name an identity that does not exist; a launch skips them. */
|
|
5636
|
+
missing: import_zod9.z.array(import_zod9.z.string()),
|
|
5637
|
+
/** When nothing can be picked, the soonest any member returns. */
|
|
5638
|
+
earliestReturn: import_zod9.z.strictObject({ identity: import_zod9.z.string(), at: import_zod9.z.iso.datetime() }).optional(),
|
|
5639
|
+
/** Why the last-pick record could not be read, when that is the case. */
|
|
5640
|
+
stickyProblem: import_zod9.z.string().optional()
|
|
5641
|
+
});
|
|
5877
5642
|
|
|
5878
|
-
// src/
|
|
5879
|
-
var
|
|
5880
|
-
|
|
5881
|
-
|
|
5882
|
-
|
|
5883
|
-
|
|
5643
|
+
// src/headroom/ensure.ts
|
|
5644
|
+
var HEADROOM_START_TIMEOUT_MS = 12e4;
|
|
5645
|
+
var HEADROOM_LAUNCHER_POLL_MS = 250;
|
|
5646
|
+
var HeadroomStartError = class extends CliError {
|
|
5647
|
+
constructor(message) {
|
|
5648
|
+
super(message);
|
|
5649
|
+
this.name = "HeadroomStartError";
|
|
5884
5650
|
}
|
|
5885
|
-
name;
|
|
5886
5651
|
};
|
|
5887
|
-
|
|
5888
|
-
|
|
5889
|
-
|
|
5890
|
-
|
|
5891
|
-
|
|
5652
|
+
function ensureHeadroom(params) {
|
|
5653
|
+
const { paths, ports } = params;
|
|
5654
|
+
const deadline = ports.now() + HEADROOM_START_TIMEOUT_MS;
|
|
5655
|
+
let spawnedSupervisor = false;
|
|
5656
|
+
let awaitingAllowlist = false;
|
|
5657
|
+
for (; ; ) {
|
|
5658
|
+
const state = readHeadroomState(ports.fs, paths.headroomStateFile);
|
|
5659
|
+
if (state?.supervisorPid !== void 0 && ports.isRunning(state.supervisorPid)) {
|
|
5660
|
+
const daemonUp = state.socketPath !== void 0 && state.headroomPid !== void 0 && ports.isRunning(state.headroomPid);
|
|
5661
|
+
if (daemonUp && state.socketPath !== void 0) {
|
|
5662
|
+
const required = params.requiredAllowlistHash?.();
|
|
5663
|
+
if (required === void 0 || state.allowlistHash === required) {
|
|
5664
|
+
writeSession(ports.fs, paths.headroomSessionsDir, { pid: params.launcherPid, startedAt: ports.now(), supervisorPid: state.supervisorPid });
|
|
5665
|
+
return { socketPath: state.socketPath };
|
|
5666
|
+
}
|
|
5667
|
+
const holders = sessionsForSupervisor(ports.fs, paths.headroomSessionsDir, state.supervisorPid).filter((session) => ports.isRunning(session.pid));
|
|
5668
|
+
if (holders.length > 0) {
|
|
5669
|
+
throw new HeadroomStartError(
|
|
5670
|
+
`the running headroom daemon was started before this launch's front door address and would refuse every request this launch sends through it. It restarts once the launches using it end (pid ${holders.map((session) => String(session.pid)).join(", ")}); end them and launch again, or launch with --no-headroom.`
|
|
5671
|
+
);
|
|
5672
|
+
}
|
|
5673
|
+
awaitingAllowlist = true;
|
|
5674
|
+
}
|
|
5675
|
+
if (state.lastError !== void 0) {
|
|
5676
|
+
throw new HeadroomStartError(
|
|
5677
|
+
`the headroom daemon reported a fatal error and is not serving: ${state.lastError} (daemon log: ${paths.headroomLogPath})`
|
|
5678
|
+
);
|
|
5679
|
+
}
|
|
5680
|
+
} else if (!spawnedSupervisor) {
|
|
5681
|
+
ports.fs.mkdirp(paths.headroomDir);
|
|
5682
|
+
const created = ports.fs.writeFileExclusive(
|
|
5683
|
+
paths.headroomLockFile,
|
|
5684
|
+
`${JSON.stringify({ pid: params.launcherPid, at: ports.now() })}
|
|
5685
|
+
`
|
|
5686
|
+
);
|
|
5687
|
+
if (created) {
|
|
5688
|
+
ports.spawnSupervisor(paths);
|
|
5689
|
+
spawnedSupervisor = true;
|
|
5690
|
+
} else {
|
|
5691
|
+
const lock = readStartLock(ports.fs, paths.headroomLockFile);
|
|
5692
|
+
if (lock === void 0 || !ports.isRunning(lock.pid)) {
|
|
5693
|
+
ports.fs.removeRecursive(paths.headroomLockFile);
|
|
5694
|
+
continue;
|
|
5695
|
+
}
|
|
5696
|
+
}
|
|
5697
|
+
}
|
|
5698
|
+
if (ports.now() >= deadline) {
|
|
5699
|
+
const lastError = state?.lastError;
|
|
5700
|
+
throw new HeadroomStartError(
|
|
5701
|
+
`the headroom daemon did not become ready within ${String(HEADROOM_START_TIMEOUT_MS)}ms` + (lastError === void 0 ? "" : ` (last error: ${lastError})`) + (awaitingAllowlist ? " (the running daemon's allowlist does not admit this launch's front door, and it did not restart)" : "") + `. Daemon log: ${paths.headroomLogPath}`
|
|
5702
|
+
);
|
|
5703
|
+
}
|
|
5704
|
+
ports.sleep(HEADROOM_LAUNCHER_POLL_MS);
|
|
5892
5705
|
}
|
|
5893
|
-
|
|
5894
|
-
|
|
5895
|
-
|
|
5896
|
-
|
|
5897
|
-
|
|
5898
|
-
|
|
5899
|
-
|
|
5900
|
-
|
|
5901
|
-
|
|
5706
|
+
}
|
|
5707
|
+
|
|
5708
|
+
// src/headroom/settings.ts
|
|
5709
|
+
var import_node_crypto8 = require("node:crypto");
|
|
5710
|
+
function settingsOf(config) {
|
|
5711
|
+
return {
|
|
5712
|
+
...config.mode === void 0 ? {} : { mode: config.mode },
|
|
5713
|
+
...config.targetRatio === void 0 ? {} : { targetRatio: config.targetRatio },
|
|
5714
|
+
...config.ccr === void 0 ? {} : { ccr: config.ccr },
|
|
5715
|
+
...config.rolloutChannel === void 0 ? {} : { rolloutChannel: config.rolloutChannel },
|
|
5716
|
+
...config.interceptToolResults === void 0 ? {} : { interceptToolResults: config.interceptToolResults },
|
|
5717
|
+
...config.readMaturation === void 0 ? {} : { readMaturation: config.readMaturation }
|
|
5718
|
+
};
|
|
5719
|
+
}
|
|
5720
|
+
function settingsArgs(settings) {
|
|
5721
|
+
return [
|
|
5722
|
+
...settings.mode === void 0 ? [] : ["--mode", settings.mode],
|
|
5723
|
+
...settings.targetRatio === void 0 ? [] : ["--target-ratio", String(settings.targetRatio)],
|
|
5724
|
+
...settings.ccr === "lossless" ? ["--lossless"] : [],
|
|
5725
|
+
...settings.ccr === "none" ? ["--no-ccr"] : [],
|
|
5726
|
+
...settings.interceptToolResults === true ? ["--intercept-tool-results"] : [],
|
|
5727
|
+
...settings.readMaturation === true ? ["--read-maturation"] : []
|
|
5728
|
+
];
|
|
5729
|
+
}
|
|
5730
|
+
function settingsEnv(settings) {
|
|
5731
|
+
return settings.rolloutChannel === void 0 ? {} : { HEADROOM_ROLLOUT_CHANNEL: settings.rolloutChannel };
|
|
5732
|
+
}
|
|
5733
|
+
function hashSettings(settings) {
|
|
5734
|
+
return (0, import_node_crypto8.createHash)("sha256").update(JSON.stringify([...settingsArgs(settings), JSON.stringify(settingsEnv(settings))])).digest("hex");
|
|
5735
|
+
}
|
|
5736
|
+
|
|
5737
|
+
// src/headroom/socket.ts
|
|
5738
|
+
var import_node_path13 = __toESM(require("node:path"), 1);
|
|
5739
|
+
var GROUP_OR_OTHER_BITS = 63;
|
|
5740
|
+
var OCTAL_RADIX = 8;
|
|
5741
|
+
var MODE_DIGITS = 4;
|
|
5742
|
+
var HEADROOM_SOCKET_SUFFIX = ".sock";
|
|
5743
|
+
var HEADROOM_SOCKET_NAME = /^(\d+)\.sock$/;
|
|
5744
|
+
var UNIX_SOCKET_PATH_MAX_BYTES = 103;
|
|
5745
|
+
var PLATFORMS_WITHOUT_UNIX_SOCKETS = ["win32"];
|
|
5746
|
+
function headroomSocketPath(paths, supervisorPid) {
|
|
5747
|
+
return import_node_path13.default.join(paths.headroomSocketDir, `${String(supervisorPid)}${HEADROOM_SOCKET_SUFFIX}`);
|
|
5748
|
+
}
|
|
5749
|
+
function platformRefusal(platform) {
|
|
5750
|
+
return PLATFORMS_WITHOUT_UNIX_SOCKETS.includes(platform) ? `headroom routing needs a unix domain socket, which headroom cannot serve on ${platform}; agent-shim never falls back to a TCP port for this hop` : void 0;
|
|
5751
|
+
}
|
|
5752
|
+
function ownerOnlyRefusal(label, target, stat, expected, uid) {
|
|
5753
|
+
if (stat === void 0) {
|
|
5754
|
+
return `the headroom ${label} ${target} does not exist`;
|
|
5902
5755
|
}
|
|
5903
|
-
|
|
5904
|
-
};
|
|
5905
|
-
|
|
5906
|
-
|
|
5756
|
+
if (stat.kind === "symlink") {
|
|
5757
|
+
return `the headroom ${label} ${target} is a symlink; it must be the real ${expected === "dir" ? "directory" : "socket"}`;
|
|
5758
|
+
}
|
|
5759
|
+
if (stat.kind !== expected) {
|
|
5760
|
+
return `the headroom ${label} ${target} is not a ${expected === "dir" ? "directory" : "socket"}`;
|
|
5761
|
+
}
|
|
5762
|
+
if (stat.uid !== uid) {
|
|
5763
|
+
return `the headroom ${label} ${target} is owned by uid ${String(stat.uid)}, not by this user (uid ${String(uid)})`;
|
|
5764
|
+
}
|
|
5765
|
+
if ((stat.mode & GROUP_OR_OTHER_BITS) !== 0) {
|
|
5766
|
+
return `the headroom ${label} ${target} has mode ${stat.mode.toString(OCTAL_RADIX).padStart(MODE_DIGITS, "0")}, which lets other users reach it; it must be accessible to its owner only`;
|
|
5767
|
+
}
|
|
5768
|
+
return void 0;
|
|
5907
5769
|
}
|
|
5908
|
-
function
|
|
5909
|
-
|
|
5770
|
+
function prepareHeadroomSocket(fs12, ports, paths, supervisorPid) {
|
|
5771
|
+
const unsupported = platformRefusal(ports.platform);
|
|
5772
|
+
if (unsupported !== void 0) {
|
|
5773
|
+
return { refused: unsupported };
|
|
5774
|
+
}
|
|
5775
|
+
const socketPath = headroomSocketPath(paths, supervisorPid);
|
|
5776
|
+
const length = Buffer.byteLength(socketPath, "utf8");
|
|
5777
|
+
if (length > UNIX_SOCKET_PATH_MAX_BYTES) {
|
|
5778
|
+
return {
|
|
5779
|
+
refused: `the headroom socket path ${socketPath} is ${String(length)} bytes, longer than the ${String(UNIX_SOCKET_PATH_MAX_BYTES)} a unix socket path can hold; set AGENT_SHIM_HOME to a shorter directory`
|
|
5780
|
+
};
|
|
5781
|
+
}
|
|
5782
|
+
if (ports.lstat(paths.headroomSocketDir)?.kind === "symlink") {
|
|
5783
|
+
return { refused: `the headroom socket directory ${paths.headroomSocketDir} is a symlink; it must be the real directory` };
|
|
5784
|
+
}
|
|
5785
|
+
fs12.mkdirPrivate(paths.headroomSocketDir);
|
|
5786
|
+
const refusal = ownerOnlyRefusal("socket directory", paths.headroomSocketDir, ports.lstat(paths.headroomSocketDir), "dir", ports.currentUid());
|
|
5787
|
+
return refusal === void 0 ? { socketPath } : { refused: refusal };
|
|
5910
5788
|
}
|
|
5911
|
-
function
|
|
5912
|
-
|
|
5789
|
+
function pruneStaleHeadroomSockets(fs12, paths, isRunning) {
|
|
5790
|
+
const removed = [];
|
|
5791
|
+
for (const name of fs12.readdir(paths.headroomSocketDir)) {
|
|
5792
|
+
const pid = HEADROOM_SOCKET_NAME.exec(name)?.[1];
|
|
5793
|
+
if (pid === void 0 || isRunning(Number.parseInt(pid, 10))) {
|
|
5794
|
+
continue;
|
|
5795
|
+
}
|
|
5796
|
+
fs12.removeRecursive(import_node_path13.default.join(paths.headroomSocketDir, name));
|
|
5797
|
+
removed.push(name);
|
|
5798
|
+
}
|
|
5799
|
+
return removed;
|
|
5913
5800
|
}
|
|
5914
|
-
|
|
5915
|
-
|
|
5916
|
-
|
|
5801
|
+
|
|
5802
|
+
// src/headroom/source.ts
|
|
5803
|
+
var import_zod10 = require("zod");
|
|
5804
|
+
var GIT_SPEC_RE = /git\+[^@\s]+(?:@([^\s#]+))?/;
|
|
5805
|
+
var COMMIT_SHA_RE = /^[0-9a-f]{40}$/i;
|
|
5806
|
+
var DirectUrlSchema = import_zod10.z.object({ vcs_info: import_zod10.z.object({ commit_id: import_zod10.z.string() }) });
|
|
5807
|
+
function isMovingGitSource(spec) {
|
|
5808
|
+
const match = GIT_SPEC_RE.exec(spec);
|
|
5809
|
+
if (match === null) {
|
|
5810
|
+
return false;
|
|
5917
5811
|
}
|
|
5918
|
-
const
|
|
5919
|
-
|
|
5920
|
-
|
|
5812
|
+
const ref = match[1];
|
|
5813
|
+
return ref === void 0 || !COMMIT_SHA_RE.test(ref);
|
|
5814
|
+
}
|
|
5815
|
+
function pinnedGitCommit(spec) {
|
|
5816
|
+
const ref = GIT_SPEC_RE.exec(spec)?.[1];
|
|
5817
|
+
return ref !== void 0 && COMMIT_SHA_RE.test(ref) ? ref.toLowerCase() : void 0;
|
|
5818
|
+
}
|
|
5819
|
+
|
|
5820
|
+
// src/headroom/supervisor.ts
|
|
5821
|
+
function resolveSupervisorConfig(configured) {
|
|
5822
|
+
return {
|
|
5823
|
+
source: configured.source ?? HEADROOM_DEFAULT_SOURCE,
|
|
5824
|
+
idleShutdownMinutes: configured.idleShutdownMinutes ?? HEADROOM_DEFAULT_IDLE_SHUTDOWN_MINUTES,
|
|
5825
|
+
settings: settingsOf(configured)
|
|
5826
|
+
};
|
|
5827
|
+
}
|
|
5828
|
+
var HEADROOM_BACKOFF_BASE_MS = 500;
|
|
5829
|
+
var HEADROOM_BACKOFF_CAP_MS = 3e4;
|
|
5830
|
+
var HEADROOM_START_RETRY_BUDGET = 5;
|
|
5831
|
+
var HEADROOM_READY_TIMEOUT_MS = 15e3;
|
|
5832
|
+
var HEADROOM_POLL_MS = 1e3;
|
|
5833
|
+
var MS_PER_MINUTE2 = 6e4;
|
|
5834
|
+
function backoffForAttempt(attempt) {
|
|
5835
|
+
return Math.min(HEADROOM_BACKOFF_CAP_MS, HEADROOM_BACKOFF_BASE_MS * 2 ** (attempt - 1));
|
|
5836
|
+
}
|
|
5837
|
+
function versionSatisfies(version, source) {
|
|
5838
|
+
if (version === void 0) {
|
|
5839
|
+
return false;
|
|
5840
|
+
}
|
|
5841
|
+
const specifier = /==|>=|<=|!=|>|<|~=/.exec(source);
|
|
5842
|
+
if (specifier === null) {
|
|
5843
|
+
return true;
|
|
5844
|
+
}
|
|
5845
|
+
const installed = parseVersion(version);
|
|
5846
|
+
const wanted = parseVersion(source.slice(specifier.index + specifier[0].length));
|
|
5847
|
+
if (installed === void 0 || wanted === void 0) {
|
|
5848
|
+
return true;
|
|
5849
|
+
}
|
|
5850
|
+
const cmp = compareVersions(installed, wanted);
|
|
5851
|
+
switch (specifier[0]) {
|
|
5852
|
+
case "==":
|
|
5853
|
+
return cmp === 0;
|
|
5854
|
+
case "!=":
|
|
5855
|
+
return cmp !== 0;
|
|
5856
|
+
case ">=":
|
|
5857
|
+
return cmp >= 0;
|
|
5858
|
+
case "<=":
|
|
5859
|
+
return cmp <= 0;
|
|
5860
|
+
case ">":
|
|
5861
|
+
return cmp > 0;
|
|
5862
|
+
case "<":
|
|
5863
|
+
return cmp < 0;
|
|
5864
|
+
case "~=":
|
|
5865
|
+
return compareVersions(installed.slice(0, Math.max(0, wanted.length - 1)), wanted.slice(0, Math.max(0, wanted.length - 1))) === 0 && cmp >= 0;
|
|
5866
|
+
default:
|
|
5867
|
+
return true;
|
|
5921
5868
|
}
|
|
5922
|
-
writeJsonAtomic(identityJsonPath(paths, name), parsed.data);
|
|
5923
|
-
return parsed.data;
|
|
5924
5869
|
}
|
|
5925
|
-
function
|
|
5926
|
-
const
|
|
5927
|
-
if (
|
|
5928
|
-
|
|
5929
|
-
}
|
|
5930
|
-
|
|
5870
|
+
function parseVersion(input) {
|
|
5871
|
+
const match = /(\d+)(\.\d+)*/.exec(input);
|
|
5872
|
+
if (match === null) {
|
|
5873
|
+
return void 0;
|
|
5874
|
+
}
|
|
5875
|
+
return match[0].split(".").map((part) => Number.parseInt(part, 10));
|
|
5876
|
+
}
|
|
5877
|
+
function compareVersions(a, b) {
|
|
5878
|
+
for (let index = 0; index < Math.max(a.length, b.length); index += 1) {
|
|
5879
|
+
const left = a[index] ?? 0;
|
|
5880
|
+
const right = b[index] ?? 0;
|
|
5881
|
+
if (left !== right) {
|
|
5882
|
+
return left - right;
|
|
5883
|
+
}
|
|
5884
|
+
}
|
|
5885
|
+
return 0;
|
|
5886
|
+
}
|
|
5887
|
+
var HEADROOM_SUPERVISOR_STILL_RUNNING = -1;
|
|
5888
|
+
async function runSupervisor(initialConfig, ports, options = {}) {
|
|
5889
|
+
const { fs: fs12, paths } = ports;
|
|
5890
|
+
let config = initialConfig;
|
|
5891
|
+
const previousState = readHeadroomState(fs12, paths.headroomStateFile);
|
|
5892
|
+
if (previousState?.supervisorPid !== void 0 && previousState.supervisorPid !== ports.ownPid && ports.isRunning(previousState.supervisorPid)) {
|
|
5893
|
+
ports.log(`agent-shim headroom supervisor ${String(ports.ownPid)}: supervisor ${String(previousState.supervisorPid)} already owns the daemon; exiting`);
|
|
5894
|
+
return 0;
|
|
5895
|
+
}
|
|
5896
|
+
let installedSource = previousState?.installedSource;
|
|
5897
|
+
const ownsState = () => {
|
|
5898
|
+
const owner = readHeadroomState(fs12, paths.headroomStateFile)?.supervisorPid;
|
|
5899
|
+
return owner === void 0 || owner === ports.ownPid || !ports.isRunning(owner);
|
|
5900
|
+
};
|
|
5901
|
+
const writeOwnState = (state) => {
|
|
5902
|
+
if (!ownsState()) {
|
|
5903
|
+
return false;
|
|
5904
|
+
}
|
|
5905
|
+
writeHeadroomState(fs12, paths.headroomStateFile, state);
|
|
5906
|
+
return true;
|
|
5907
|
+
};
|
|
5908
|
+
const fail = (message) => {
|
|
5909
|
+
if (writeOwnState({ lastError: message })) {
|
|
5910
|
+
fs12.removeRecursive(paths.headroomLockFile);
|
|
5911
|
+
}
|
|
5912
|
+
ports.log(`agent-shim headroom supervisor: ${message}`);
|
|
5913
|
+
return 1;
|
|
5914
|
+
};
|
|
5915
|
+
const ensureInstalled = () => {
|
|
5916
|
+
const version2 = ports.headroomVersion();
|
|
5917
|
+
const versionOk = version2 !== void 0 && versionSatisfies(version2, config.source);
|
|
5918
|
+
const pinned = pinnedGitCommit(config.source);
|
|
5919
|
+
const commitOk = pinned === void 0 || ports.installedCommit() === pinned;
|
|
5920
|
+
if (versionOk && commitOk && (installedSource === void 0 || installedSource === config.source)) {
|
|
5921
|
+
installedSource = config.source;
|
|
5922
|
+
return true;
|
|
5923
|
+
}
|
|
5924
|
+
ports.log(`agent-shim headroom supervisor: installing headroom from ${config.source}`);
|
|
5925
|
+
const result = ports.install(config.source);
|
|
5926
|
+
if (!result.ok) {
|
|
5927
|
+
return false;
|
|
5928
|
+
}
|
|
5929
|
+
installedSource = config.source;
|
|
5930
|
+
return true;
|
|
5931
|
+
};
|
|
5932
|
+
const socket = prepareHeadroomSocket(fs12, ports.socketTrust, paths, ports.ownPid);
|
|
5933
|
+
if (socket.refused !== void 0) {
|
|
5934
|
+
return fail(socket.refused);
|
|
5935
|
+
}
|
|
5936
|
+
const { socketPath } = socket;
|
|
5937
|
+
pruneStaleHeadroomSockets(fs12, paths, ports.isRunning);
|
|
5938
|
+
if (!ensureInstalled()) {
|
|
5939
|
+
return fail(`could not install headroom from ${config.source}: install failed (is uv installed and on PATH?)`);
|
|
5940
|
+
}
|
|
5941
|
+
const version = ports.headroomVersion() ?? "unknown";
|
|
5942
|
+
writeOwnState({ supervisorPid: ports.ownPid, version, installedSource });
|
|
5943
|
+
ports.log(`agent-shim headroom supervisor ${String(ports.ownPid)}: managing headroom on allowlist [${allowlistOf(ports).join(", ")}]`);
|
|
5944
|
+
const orphanPid = previousState?.headroomPid;
|
|
5945
|
+
if (orphanPid !== void 0 && ports.isRunning(orphanPid)) {
|
|
5946
|
+
ports.log(`agent-shim headroom supervisor: stopping daemon pid ${String(orphanPid)} left behind by the previous supervisor`);
|
|
5947
|
+
ports.stopProcess(orphanPid);
|
|
5948
|
+
}
|
|
5949
|
+
let headroomPid;
|
|
5950
|
+
let runningHash;
|
|
5951
|
+
let runningSettingsHash;
|
|
5952
|
+
let consecutiveFailures = 0;
|
|
5953
|
+
let idleSince;
|
|
5954
|
+
let superseded = false;
|
|
5955
|
+
let ticks = 0;
|
|
5956
|
+
for (; ; ) {
|
|
5957
|
+
if (options.tickLimit !== void 0 && ticks >= options.tickLimit) {
|
|
5958
|
+
return HEADROOM_SUPERVISOR_STILL_RUNNING;
|
|
5959
|
+
}
|
|
5960
|
+
ticks += 1;
|
|
5961
|
+
config = ports.readConfig();
|
|
5962
|
+
const settingsHash = hashSettings(config.settings);
|
|
5963
|
+
const allowlist = allowlistOf(ports);
|
|
5964
|
+
const allowlistHash = hashAllowlist(allowlist);
|
|
5965
|
+
pruneDeadSessions(fs12, paths.headroomSessionsDir, ports.isRunning);
|
|
5966
|
+
const ownsNow = ownsState();
|
|
5967
|
+
if (!ownsNow && !superseded) {
|
|
5968
|
+
ports.log("agent-shim headroom supervisor: another supervisor now owns the state file; serving this daemon's own sessions until they end");
|
|
5969
|
+
}
|
|
5970
|
+
superseded = !ownsNow;
|
|
5971
|
+
const crashed = headroomPid !== void 0 && !ports.isRunning(headroomPid);
|
|
5972
|
+
if (headroomPid === void 0 || crashed) {
|
|
5973
|
+
if (crashed) {
|
|
5974
|
+
ports.log(`agent-shim headroom supervisor: headroom pid ${String(headroomPid)} died`);
|
|
5975
|
+
headroomPid = void 0;
|
|
5976
|
+
runningHash = void 0;
|
|
5977
|
+
runningSettingsHash = void 0;
|
|
5978
|
+
writeOwnState({
|
|
5979
|
+
supervisorPid: ports.ownPid,
|
|
5980
|
+
version,
|
|
5981
|
+
installedSource
|
|
5982
|
+
});
|
|
5983
|
+
}
|
|
5984
|
+
if (consecutiveFailures >= HEADROOM_START_RETRY_BUDGET) {
|
|
5985
|
+
return fail(`headroom failed to become ready ${String(consecutiveFailures)} times in a row; giving up`);
|
|
5986
|
+
}
|
|
5987
|
+
if (installedSource !== config.source && !ensureInstalled()) {
|
|
5988
|
+
return fail(`could not install headroom from ${config.source}: install failed (is uv installed and on PATH?)`);
|
|
5989
|
+
}
|
|
5990
|
+
const pid = ports.spawnHeadroom(socketPath, allowlist, config.settings);
|
|
5991
|
+
const ready = await waitUntilReady(ports, socketPath);
|
|
5992
|
+
if (ready) {
|
|
5993
|
+
consecutiveFailures = 0;
|
|
5994
|
+
headroomPid = pid;
|
|
5995
|
+
runningHash = allowlistHash;
|
|
5996
|
+
runningSettingsHash = settingsHash;
|
|
5997
|
+
const recorded = writeOwnState({
|
|
5998
|
+
supervisorPid: ports.ownPid,
|
|
5999
|
+
headroomPid: pid,
|
|
6000
|
+
socketPath,
|
|
6001
|
+
version,
|
|
6002
|
+
allowlistHash,
|
|
6003
|
+
settingsHash,
|
|
6004
|
+
installedSource: config.source
|
|
6005
|
+
});
|
|
6006
|
+
if (recorded) {
|
|
6007
|
+
fs12.removeRecursive(paths.headroomLockFile);
|
|
6008
|
+
}
|
|
6009
|
+
idleSince = void 0;
|
|
6010
|
+
ports.log(`agent-shim headroom supervisor: headroom pid ${String(pid)} ready on unix socket ${socketPath}`);
|
|
6011
|
+
} else {
|
|
6012
|
+
ports.stopProcess(pid);
|
|
6013
|
+
consecutiveFailures += 1;
|
|
6014
|
+
ports.log(
|
|
6015
|
+
`agent-shim headroom supervisor: headroom did not become ready on unix socket ${socketPath} (attempt ${String(consecutiveFailures)} of ${String(HEADROOM_START_RETRY_BUDGET)})`
|
|
6016
|
+
);
|
|
6017
|
+
await ports.sleep(backoffForAttempt(consecutiveFailures));
|
|
6018
|
+
continue;
|
|
6019
|
+
}
|
|
6020
|
+
} else {
|
|
6021
|
+
if (runningHash !== allowlistHash || runningSettingsHash !== settingsHash || installedSource !== config.source) {
|
|
6022
|
+
if (sessionsForSupervisor(fs12, paths.headroomSessionsDir, ports.ownPid).length === 0) {
|
|
6023
|
+
ports.log("agent-shim headroom supervisor: configuration drifted and no sessions are live; restarting headroom");
|
|
6024
|
+
ports.stopProcess(headroomPid);
|
|
6025
|
+
headroomPid = void 0;
|
|
6026
|
+
runningHash = void 0;
|
|
6027
|
+
runningSettingsHash = void 0;
|
|
6028
|
+
continue;
|
|
6029
|
+
}
|
|
6030
|
+
}
|
|
6031
|
+
const sessions = sessionsForSupervisor(fs12, paths.headroomSessionsDir, ports.ownPid);
|
|
6032
|
+
if (sessions.length === 0) {
|
|
6033
|
+
idleSince ??= ports.now();
|
|
6034
|
+
const idleMs = ports.now() - idleSince;
|
|
6035
|
+
if (idleMs >= config.idleShutdownMinutes * MS_PER_MINUTE2) {
|
|
6036
|
+
ports.log(
|
|
6037
|
+
`agent-shim headroom supervisor: no sessions for ${String(config.idleShutdownMinutes)} minute(s); stopping headroom and exiting`
|
|
6038
|
+
);
|
|
6039
|
+
ports.stopProcess(headroomPid);
|
|
6040
|
+
writeOwnState({ version });
|
|
6041
|
+
return 0;
|
|
6042
|
+
}
|
|
6043
|
+
} else {
|
|
6044
|
+
idleSince = void 0;
|
|
6045
|
+
}
|
|
6046
|
+
}
|
|
6047
|
+
await ports.sleep(HEADROOM_POLL_MS);
|
|
5931
6048
|
}
|
|
5932
|
-
writeTextAtomic(paths.activeIdentityFile, `${name}
|
|
5933
|
-
`);
|
|
5934
6049
|
}
|
|
5935
|
-
function
|
|
5936
|
-
|
|
5937
|
-
|
|
5938
|
-
}
|
|
5939
|
-
const raw = import_node_fs4.default.readFileSync(paths.activeIdentityFile, "utf8").trim();
|
|
5940
|
-
return raw === "" ? void 0 : raw;
|
|
6050
|
+
function currentHeadroomAllowlist(fs12, paths) {
|
|
6051
|
+
const providers = readAllProviders(fs12, paths.providersDir).map((entry) => entry.provider);
|
|
6052
|
+
return headroomAllowlist(headroomUpstreams(providers, frontDoorOrigin(readFrontDoorState(fs12, paths.frontdoorStateFile))));
|
|
5941
6053
|
}
|
|
5942
|
-
function
|
|
5943
|
-
return
|
|
6054
|
+
function allowlistOf(ports) {
|
|
6055
|
+
return currentHeadroomAllowlist(ports.fs, ports.paths);
|
|
5944
6056
|
}
|
|
5945
|
-
function
|
|
5946
|
-
|
|
5947
|
-
|
|
5948
|
-
|
|
5949
|
-
|
|
5950
|
-
return { problem: error.message.replace(/\s*\n\s*/g, " ") };
|
|
6057
|
+
async function waitUntilReady(ports, socketPath) {
|
|
6058
|
+
const deadline = ports.now() + HEADROOM_READY_TIMEOUT_MS;
|
|
6059
|
+
for (; ; ) {
|
|
6060
|
+
if (await ports.ready(socketPath)) {
|
|
6061
|
+
return true;
|
|
5951
6062
|
}
|
|
5952
|
-
|
|
6063
|
+
if (ports.now() >= deadline) {
|
|
6064
|
+
return false;
|
|
6065
|
+
}
|
|
6066
|
+
await ports.sleep(HEADROOM_POLL_MS);
|
|
5953
6067
|
}
|
|
5954
6068
|
}
|
|
5955
|
-
|
|
5956
|
-
|
|
5957
|
-
|
|
5958
|
-
|
|
5959
|
-
|
|
5960
|
-
|
|
5961
|
-
|
|
5962
|
-
|
|
5963
|
-
|
|
5964
|
-
|
|
6069
|
+
|
|
6070
|
+
// src/launcher/guard.ts
|
|
6071
|
+
var AMBIENT_CREDENTIAL_VARS = [
|
|
6072
|
+
"ANTHROPIC_API_KEY",
|
|
6073
|
+
"ANTHROPIC_AUTH_TOKEN",
|
|
6074
|
+
"CLAUDE_CODE_OAUTH_TOKEN",
|
|
6075
|
+
"CLAUDE_CODE_USE_BEDROCK",
|
|
6076
|
+
"CLAUDE_CODE_USE_VERTEX",
|
|
6077
|
+
"CLAUDE_CODE_USE_FOUNDRY"
|
|
6078
|
+
];
|
|
6079
|
+
function detectAmbientCredential(env, injected) {
|
|
6080
|
+
for (const variable of AMBIENT_CREDENTIAL_VARS) {
|
|
6081
|
+
const value = env[variable];
|
|
6082
|
+
if (value === void 0 || value === "") {
|
|
5965
6083
|
continue;
|
|
5966
6084
|
}
|
|
5967
|
-
|
|
5968
|
-
|
|
5969
|
-
|
|
5970
|
-
|
|
5971
|
-
}
|
|
5972
|
-
function setDefaultConfigProfile(paths, identityName, profileName) {
|
|
5973
|
-
if (!identityExists(paths, identityName)) {
|
|
5974
|
-
throw new IdentityNotFoundError(identityName);
|
|
6085
|
+
if (injected?.variable === variable && value === injected.token) {
|
|
6086
|
+
continue;
|
|
6087
|
+
}
|
|
6088
|
+
return { variable };
|
|
5975
6089
|
}
|
|
5976
|
-
return
|
|
5977
|
-
defaultConfigProfile: profileName
|
|
5978
|
-
});
|
|
6090
|
+
return void 0;
|
|
5979
6091
|
}
|
|
5980
|
-
function
|
|
5981
|
-
|
|
5982
|
-
|
|
5983
|
-
|
|
5984
|
-
|
|
5985
|
-
|
|
5986
|
-
|
|
6092
|
+
function formatAmbientCredentialGuardMessage(variable, identityName) {
|
|
6093
|
+
const identitySetCommand = identityName === void 0 ? "agent-shim identity set <name> --allow-ambient-credential" : `agent-shim identity set ${identityName} --allow-ambient-credential`;
|
|
6094
|
+
return [
|
|
6095
|
+
`error: ${variable} is set in the environment. This identity's isolated`,
|
|
6096
|
+
"credential would be bypassed \u2014 every identity authenticates as this same key",
|
|
6097
|
+
"while it's set. Unset it, or if this is deliberate, opt in per-launch with",
|
|
6098
|
+
"AGENT_SHIM_ALLOW_AMBIENT_CREDENTIAL=1, or persistently for this identity with",
|
|
6099
|
+
`\`${identitySetCommand}\`.`
|
|
6100
|
+
].join("\n");
|
|
5987
6101
|
}
|
|
5988
|
-
function
|
|
5989
|
-
const
|
|
5990
|
-
if (
|
|
5991
|
-
|
|
6102
|
+
function evaluateAmbientCredentialGuard(params) {
|
|
6103
|
+
const detected = detectAmbientCredential(params.env, params.injectedCredential);
|
|
6104
|
+
if (detected === void 0) {
|
|
6105
|
+
return { ok: true };
|
|
5992
6106
|
}
|
|
5993
|
-
if (
|
|
5994
|
-
return
|
|
6107
|
+
if (params.allowAmbientCredentialOverride || params.allowAmbientCredential || params.providerSelected === true) {
|
|
6108
|
+
return { ok: true };
|
|
5995
6109
|
}
|
|
5996
|
-
|
|
5997
|
-
|
|
5998
|
-
|
|
6110
|
+
return {
|
|
6111
|
+
ok: false,
|
|
6112
|
+
variable: detected.variable,
|
|
6113
|
+
message: formatAmbientCredentialGuardMessage(detected.variable, params.identityName)
|
|
6114
|
+
};
|
|
6115
|
+
}
|
|
6116
|
+
|
|
6117
|
+
// src/paths.ts
|
|
6118
|
+
var import_node_fs2 = __toESM(require("node:fs"), 1);
|
|
6119
|
+
var import_node_os = __toESM(require("node:os"), 1);
|
|
6120
|
+
var import_node_path14 = __toESM(require("node:path"), 1);
|
|
6121
|
+
function resolveAgentShimHome(env = process.env, home = import_node_os.default.homedir(), isDirectory = isExistingDirectory) {
|
|
6122
|
+
const fromEnv = env.AGENT_SHIM_HOME;
|
|
6123
|
+
if (fromEnv !== void 0 && fromEnv !== "") {
|
|
6124
|
+
return fromEnv;
|
|
5999
6125
|
}
|
|
6000
|
-
const
|
|
6001
|
-
const
|
|
6002
|
-
return
|
|
6003
|
-
credential: { sources: [...sources], ...target === void 0 ? {} : { target }, ...cache === void 0 ? {} : { cache } }
|
|
6004
|
-
});
|
|
6126
|
+
const current = import_node_path14.default.join(home, HOME_DIRNAME);
|
|
6127
|
+
const legacy = import_node_path14.default.join(home, LEGACY_HOME_DIRNAME);
|
|
6128
|
+
return !isDirectory(current) && isDirectory(legacy) ? legacy : current;
|
|
6005
6129
|
}
|
|
6006
|
-
function
|
|
6007
|
-
return
|
|
6130
|
+
function isExistingDirectory(candidate) {
|
|
6131
|
+
return import_node_fs2.default.statSync(candidate, { throwIfNoEntry: false })?.isDirectory() ?? false;
|
|
6008
6132
|
}
|
|
6009
|
-
function
|
|
6010
|
-
|
|
6011
|
-
|
|
6012
|
-
|
|
6013
|
-
for (const entry of import_node_fs4.default.readdirSync(paths.identitiesDir)) {
|
|
6014
|
-
if (belongsToIdentity(entry, name)) {
|
|
6015
|
-
import_node_fs4.default.rmSync(import_node_path15.default.join(paths.identitiesDir, entry), { recursive: true, force: true });
|
|
6016
|
-
}
|
|
6017
|
-
}
|
|
6018
|
-
if (readActiveIdentity(paths) === name) {
|
|
6019
|
-
import_node_fs4.default.rmSync(paths.activeIdentityFile);
|
|
6133
|
+
function resolveClaudeHome() {
|
|
6134
|
+
const fromEnv = process.env.AGENT_SHIM_CLAUDE_HOME;
|
|
6135
|
+
if (fromEnv !== void 0 && fromEnv !== "") {
|
|
6136
|
+
return fromEnv;
|
|
6020
6137
|
}
|
|
6138
|
+
return import_node_path14.default.join(import_node_os.default.homedir(), ".claude");
|
|
6139
|
+
}
|
|
6140
|
+
function buildLayoutPaths(root) {
|
|
6141
|
+
return {
|
|
6142
|
+
root,
|
|
6143
|
+
identitiesDir: import_node_path14.default.join(root, "identities"),
|
|
6144
|
+
configProfilesDir: import_node_path14.default.join(root, "config-profiles"),
|
|
6145
|
+
providersDir: import_node_path14.default.join(root, "providers"),
|
|
6146
|
+
directoryRulesFile: import_node_path14.default.join(root, "directory-rules.json"),
|
|
6147
|
+
activeIdentityFile: import_node_path14.default.join(root, "active-identity"),
|
|
6148
|
+
globalConfigFile: import_node_path14.default.join(root, "config.json"),
|
|
6149
|
+
categoriesLocalFile: import_node_path14.default.join(root, "categories.local.json"),
|
|
6150
|
+
claudeShimFile: import_node_path14.default.join(root, "claude-shim.json"),
|
|
6151
|
+
headroomDir: import_node_path14.default.join(root, "headroom"),
|
|
6152
|
+
headroomStateFile: import_node_path14.default.join(root, "headroom", `state.v${String(HEADROOM_STATE_SCHEMA_VERSION)}.json`),
|
|
6153
|
+
headroomSocketDir: import_node_path14.default.join(root, "headroom", "run"),
|
|
6154
|
+
headroomLockFile: import_node_path14.default.join(root, "headroom", "start.lock"),
|
|
6155
|
+
headroomSessionsDir: import_node_path14.default.join(root, "headroom", "sessions"),
|
|
6156
|
+
logsDir: import_node_path14.default.join(root, "logs"),
|
|
6157
|
+
headroomLogPath: import_node_path14.default.join(root, "logs", "headroom.log"),
|
|
6158
|
+
frontdoorDir: import_node_path14.default.join(root, "frontdoor"),
|
|
6159
|
+
frontdoorCaDir: import_node_path14.default.join(root, "frontdoor", "ca"),
|
|
6160
|
+
frontdoorCaCertFile: import_node_path14.default.join(root, "frontdoor", "ca", "ca.pem"),
|
|
6161
|
+
frontdoorCaKeyFile: import_node_path14.default.join(root, "frontdoor", "ca", "ca.key"),
|
|
6162
|
+
frontdoorCaBundlesDir: import_node_path14.default.join(root, "frontdoor", "ca", "bundles"),
|
|
6163
|
+
frontdoorStateFile: import_node_path14.default.join(root, "frontdoor", "state.json"),
|
|
6164
|
+
frontdoorLockFile: import_node_path14.default.join(root, "frontdoor", "start.lock"),
|
|
6165
|
+
frontdoorControlTokenFile: import_node_path14.default.join(root, "frontdoor", "control-token"),
|
|
6166
|
+
frontdoorSessionsDir: import_node_path14.default.join(root, "frontdoor", "sessions"),
|
|
6167
|
+
frontdoorLogPath: import_node_path14.default.join(root, "logs", "frontdoor.log"),
|
|
6168
|
+
usageDir: import_node_path14.default.join(root, "usage"),
|
|
6169
|
+
usageLogDir: import_node_path14.default.join(root, "usage", "log"),
|
|
6170
|
+
usageSnapshotsDir: import_node_path14.default.join(root, "usage", "snapshots"),
|
|
6171
|
+
usagePicksFile: import_node_path14.default.join(root, "usage", "picks.json")
|
|
6172
|
+
};
|
|
6173
|
+
}
|
|
6174
|
+
function resolveLayoutPaths() {
|
|
6175
|
+
return buildLayoutPaths(resolveAgentShimHome());
|
|
6021
6176
|
}
|
|
6022
6177
|
|
|
6023
|
-
// src/
|
|
6024
|
-
var
|
|
6178
|
+
// src/identityStore.ts
|
|
6179
|
+
var import_node_fs4 = __toESM(require("node:fs"), 1);
|
|
6025
6180
|
var import_node_path16 = __toESM(require("node:path"), 1);
|
|
6026
6181
|
|
|
6027
|
-
// src/
|
|
6028
|
-
var
|
|
6029
|
-
var
|
|
6030
|
-
var
|
|
6031
|
-
|
|
6032
|
-
|
|
6033
|
-
|
|
6034
|
-
|
|
6035
|
-
function effectiveStore(cache, platform) {
|
|
6036
|
-
return cache.store ?? (platform === "darwin" ? "keychain" : "file");
|
|
6037
|
-
}
|
|
6038
|
-
function ttlMs(cache) {
|
|
6039
|
-
if (cache.ttl === void 0) {
|
|
6040
|
-
return void 0;
|
|
6041
|
-
}
|
|
6042
|
-
const multiplier = MS_PER_UNIT[cache.ttl.slice(-1)];
|
|
6043
|
-
if (multiplier === void 0) {
|
|
6044
|
-
throw new Error(`credential cache ttl "${cache.ttl}" has no recognised unit`);
|
|
6045
|
-
}
|
|
6046
|
-
return Number(cache.ttl.slice(0, -1)) * multiplier;
|
|
6047
|
-
}
|
|
6048
|
-
function isFresh(entry, cache, now) {
|
|
6049
|
-
const limit = ttlMs(cache);
|
|
6050
|
-
if (entry.fetchedAt > now) {
|
|
6051
|
-
return false;
|
|
6182
|
+
// src/configProfilesStore.ts
|
|
6183
|
+
var import_node_fs3 = __toESM(require("node:fs"), 1);
|
|
6184
|
+
var import_node_path15 = __toESM(require("node:path"), 1);
|
|
6185
|
+
var ProfileNotFoundError = class extends CliError {
|
|
6186
|
+
constructor(profileName) {
|
|
6187
|
+
super(`No configuration profile named "${profileName}". Run \`agent-shim profile add ${profileName}\` first.`);
|
|
6188
|
+
this.profileName = profileName;
|
|
6189
|
+
this.name = "ProfileNotFoundError";
|
|
6052
6190
|
}
|
|
6053
|
-
|
|
6054
|
-
}
|
|
6055
|
-
|
|
6056
|
-
|
|
6057
|
-
|
|
6058
|
-
|
|
6059
|
-
|
|
6060
|
-
var GROUP_OTHER_PERMISSION_BITS = 63;
|
|
6061
|
-
var PERMISSION_BITS = 511;
|
|
6062
|
-
var OCTAL_RADIX2 = 8;
|
|
6063
|
-
function commandArgv(source) {
|
|
6064
|
-
if ("command" in source) {
|
|
6065
|
-
return source.command;
|
|
6191
|
+
profileName;
|
|
6192
|
+
};
|
|
6193
|
+
var ProfileAlreadyExistsError = class extends CliError {
|
|
6194
|
+
constructor(profileName) {
|
|
6195
|
+
super(`A configuration profile named "${profileName}" already exists.`);
|
|
6196
|
+
this.profileName = profileName;
|
|
6197
|
+
this.name = "ProfileAlreadyExistsError";
|
|
6066
6198
|
}
|
|
6067
|
-
|
|
6068
|
-
|
|
6199
|
+
profileName;
|
|
6200
|
+
};
|
|
6201
|
+
var InvalidCategoryNameError = class extends CliError {
|
|
6202
|
+
constructor(categoryName) {
|
|
6203
|
+
super(`"${categoryName}" is not a category a configuration profile may toggle (runtime, history, knowledge, settings).`);
|
|
6204
|
+
this.categoryName = categoryName;
|
|
6205
|
+
this.name = "InvalidCategoryNameError";
|
|
6069
6206
|
}
|
|
6070
|
-
|
|
6071
|
-
|
|
6207
|
+
categoryName;
|
|
6208
|
+
};
|
|
6209
|
+
function profileJsonPath(paths, name) {
|
|
6210
|
+
return import_node_path15.default.join(paths.configProfilesDir, `${name}.json`);
|
|
6072
6211
|
}
|
|
6073
|
-
function
|
|
6074
|
-
|
|
6075
|
-
return source.interactive ?? false;
|
|
6076
|
-
}
|
|
6077
|
-
if ("op" in source) {
|
|
6078
|
-
return source.interactive ?? (env.OP_SERVICE_ACCOUNT_TOKEN ?? "") === "";
|
|
6079
|
-
}
|
|
6080
|
-
return false;
|
|
6212
|
+
function profileExists(paths, name) {
|
|
6213
|
+
return import_node_fs3.default.existsSync(profileJsonPath(paths, name));
|
|
6081
6214
|
}
|
|
6082
|
-
function
|
|
6083
|
-
if (
|
|
6084
|
-
|
|
6215
|
+
function requireProfileExists(paths, name) {
|
|
6216
|
+
if (!profileExists(paths, name)) {
|
|
6217
|
+
throw new ProfileNotFoundError(name);
|
|
6085
6218
|
}
|
|
6086
|
-
|
|
6087
|
-
|
|
6219
|
+
}
|
|
6220
|
+
function readProfile(paths, name) {
|
|
6221
|
+
return readJson(profileJsonPath(paths, name), ConfigProfileSchema);
|
|
6222
|
+
}
|
|
6223
|
+
function createProfile(paths, name, extendsList, description) {
|
|
6224
|
+
if (profileExists(paths, name)) {
|
|
6225
|
+
throw new ProfileAlreadyExistsError(name);
|
|
6088
6226
|
}
|
|
6089
|
-
|
|
6090
|
-
|
|
6227
|
+
const filePath = profileJsonPath(paths, name);
|
|
6228
|
+
const parsed = ConfigProfileSchema.safeParse({
|
|
6229
|
+
...description === void 0 ? {} : { description },
|
|
6230
|
+
...extendsList !== void 0 && extendsList.length > 0 ? { extends: [...extendsList] } : {}
|
|
6231
|
+
});
|
|
6232
|
+
if (!parsed.success) {
|
|
6233
|
+
throw new ConfigValidationError(filePath, parsed.error.issues);
|
|
6091
6234
|
}
|
|
6092
|
-
|
|
6093
|
-
|
|
6235
|
+
writeJsonAtomic(filePath, parsed.data);
|
|
6236
|
+
return parsed.data;
|
|
6237
|
+
}
|
|
6238
|
+
function listProfiles(paths) {
|
|
6239
|
+
if (!import_node_fs3.default.existsSync(paths.configProfilesDir)) {
|
|
6240
|
+
return [];
|
|
6094
6241
|
}
|
|
6095
|
-
|
|
6096
|
-
|
|
6097
|
-
|
|
6098
|
-
|
|
6099
|
-
|
|
6100
|
-
|
|
6242
|
+
const names = import_node_fs3.default.readdirSync(paths.configProfilesDir, { withFileTypes: true }).filter((entry) => entry.isFile() && entry.name.endsWith(".json")).map((entry) => entry.name.slice(0, -".json".length)).sort();
|
|
6243
|
+
const result = [];
|
|
6244
|
+
for (const name of names) {
|
|
6245
|
+
const profile = readProfile(paths, name);
|
|
6246
|
+
if (profile !== void 0) {
|
|
6247
|
+
result.push({ name, profile });
|
|
6248
|
+
}
|
|
6101
6249
|
}
|
|
6102
|
-
return
|
|
6250
|
+
return result;
|
|
6103
6251
|
}
|
|
6104
|
-
function
|
|
6105
|
-
return
|
|
6106
|
-
target: credential.target ?? "bearer",
|
|
6107
|
-
sources: credential.sources.map(summariseSource),
|
|
6108
|
-
...credential.cache === void 0 ? {} : { cache: credential.cache }
|
|
6109
|
-
};
|
|
6252
|
+
function globalConfigPath(paths) {
|
|
6253
|
+
return paths.globalConfigFile;
|
|
6110
6254
|
}
|
|
6111
|
-
function
|
|
6112
|
-
|
|
6113
|
-
|
|
6114
|
-
|
|
6115
|
-
|
|
6116
|
-
|
|
6117
|
-
|
|
6118
|
-
|
|
6119
|
-
|
|
6120
|
-
|
|
6121
|
-
|
|
6122
|
-
|
|
6123
|
-
|
|
6124
|
-
|
|
6125
|
-
|
|
6126
|
-
|
|
6255
|
+
function readGlobalConfig(paths) {
|
|
6256
|
+
return readJson(globalConfigPath(paths), GlobalConfigSchema);
|
|
6257
|
+
}
|
|
6258
|
+
function setGlobalDefaultProfile(paths, name) {
|
|
6259
|
+
return applyPatch(
|
|
6260
|
+
globalConfigPath(paths),
|
|
6261
|
+
GlobalConfigSchema,
|
|
6262
|
+
{ defaultConfigProfile: name },
|
|
6263
|
+
{ defaults: {} }
|
|
6264
|
+
);
|
|
6265
|
+
}
|
|
6266
|
+
function validateCategoryNames(patch) {
|
|
6267
|
+
for (const key of Object.keys(patch)) {
|
|
6268
|
+
if (!isOverridableCategory(key)) {
|
|
6269
|
+
throw new InvalidCategoryNameError(key);
|
|
6270
|
+
}
|
|
6127
6271
|
}
|
|
6128
6272
|
}
|
|
6129
|
-
function
|
|
6130
|
-
|
|
6273
|
+
function setProfileCategories(paths, name, patch) {
|
|
6274
|
+
requireProfileExists(paths, name);
|
|
6275
|
+
const expandedPatch = expandAllCategoryKey(patch);
|
|
6276
|
+
validateCategoryNames(expandedPatch);
|
|
6277
|
+
const existing = readProfile(paths, name) ?? {};
|
|
6278
|
+
const mergedCategories = { ...existing.categories, ...expandedPatch };
|
|
6279
|
+
return applyPatch(profileJsonPath(paths, name), ConfigProfileSchema, { categories: mergedCategories });
|
|
6131
6280
|
}
|
|
6132
|
-
function
|
|
6133
|
-
|
|
6134
|
-
|
|
6281
|
+
function setProfileEntries(paths, name, patch) {
|
|
6282
|
+
requireProfileExists(paths, name);
|
|
6283
|
+
const existing = readProfile(paths, name) ?? {};
|
|
6284
|
+
const mergedEntries = { ...existing.entries, ...patch };
|
|
6285
|
+
return applyPatch(profileJsonPath(paths, name), ConfigProfileSchema, { entries: mergedEntries });
|
|
6135
6286
|
}
|
|
6136
|
-
function
|
|
6137
|
-
|
|
6287
|
+
function setProfileLaunchFlags(paths, name, patch) {
|
|
6288
|
+
requireProfileExists(paths, name);
|
|
6289
|
+
const existing = readProfile(paths, name) ?? {};
|
|
6290
|
+
const mergedLaunch = { ...existing.launch, ...patch };
|
|
6291
|
+
return applyPatch(profileJsonPath(paths, name), ConfigProfileSchema, {
|
|
6292
|
+
// Read as `unknown` so the check sees the `undefined` a cleared key holds, which LaunchFlags' optional properties hide from the value type.
|
|
6293
|
+
launch: Object.values(mergedLaunch).every((value) => value === void 0) ? void 0 : mergedLaunch
|
|
6294
|
+
});
|
|
6138
6295
|
}
|
|
6139
|
-
function
|
|
6140
|
-
|
|
6141
|
-
|
|
6142
|
-
|
|
6143
|
-
|
|
6144
|
-
}
|
|
6145
|
-
|
|
6146
|
-
|
|
6147
|
-
|
|
6148
|
-
|
|
6149
|
-
|
|
6150
|
-
|
|
6151
|
-
|
|
6152
|
-
|
|
6153
|
-
|
|
6154
|
-
|
|
6155
|
-
|
|
6156
|
-
|
|
6157
|
-
);
|
|
6158
|
-
}
|
|
6159
|
-
const token2 = read.content.trim();
|
|
6160
|
-
return token2 === "" ? none("is empty") : { ok: true, token: token2 };
|
|
6296
|
+
function setProfileMetadata(paths, name, patch) {
|
|
6297
|
+
requireProfileExists(paths, name);
|
|
6298
|
+
return applyPatch(profileJsonPath(paths, name), ConfigProfileSchema, {
|
|
6299
|
+
...patch.extends === void 0 ? {} : { extends: patch.extends.length === 0 ? void 0 : [...patch.extends] },
|
|
6300
|
+
...patch.description === void 0 ? {} : { description: patch.description === false ? void 0 : patch.description }
|
|
6301
|
+
});
|
|
6302
|
+
}
|
|
6303
|
+
function removeProfile(paths, name) {
|
|
6304
|
+
requireProfileExists(paths, name);
|
|
6305
|
+
import_node_fs3.default.rmSync(profileJsonPath(paths, name));
|
|
6306
|
+
}
|
|
6307
|
+
|
|
6308
|
+
// src/poolStore.ts
|
|
6309
|
+
var PoolNotFoundError = class extends CliError {
|
|
6310
|
+
constructor(poolName) {
|
|
6311
|
+
super(`No pool named "${poolName}". Run \`agent-shim pool add ${poolName} --identity <name>...\` first.`);
|
|
6312
|
+
this.poolName = poolName;
|
|
6313
|
+
this.name = "PoolNotFoundError";
|
|
6161
6314
|
}
|
|
6162
|
-
|
|
6163
|
-
|
|
6164
|
-
|
|
6165
|
-
|
|
6315
|
+
poolName;
|
|
6316
|
+
};
|
|
6317
|
+
var PoolAlreadyExistsError = class extends CliError {
|
|
6318
|
+
constructor(poolName) {
|
|
6319
|
+
super(`A pool named "${poolName}" already exists. Use \`agent-shim pool set ${poolName}\` to change its members.`);
|
|
6320
|
+
this.poolName = poolName;
|
|
6321
|
+
this.name = "PoolAlreadyExistsError";
|
|
6166
6322
|
}
|
|
6167
|
-
|
|
6168
|
-
|
|
6169
|
-
|
|
6170
|
-
|
|
6323
|
+
poolName;
|
|
6324
|
+
};
|
|
6325
|
+
var InvalidPoolNameError = class extends CliError {
|
|
6326
|
+
constructor(attemptedName) {
|
|
6327
|
+
super(`"${attemptedName}" is not a valid pool name: it must start with a letter or number and may then contain letters, numbers, dots, hyphens and underscores.`);
|
|
6328
|
+
this.attemptedName = attemptedName;
|
|
6329
|
+
this.name = "InvalidPoolNameError";
|
|
6171
6330
|
}
|
|
6172
|
-
|
|
6173
|
-
|
|
6174
|
-
|
|
6175
|
-
|
|
6331
|
+
attemptedName;
|
|
6332
|
+
};
|
|
6333
|
+
function readPools(paths) {
|
|
6334
|
+
return readGlobalConfig(paths)?.pools ?? {};
|
|
6335
|
+
}
|
|
6336
|
+
function requirePool(paths, name) {
|
|
6337
|
+
const pool = readPools(paths)[name];
|
|
6338
|
+
if (pool === void 0) {
|
|
6339
|
+
throw new PoolNotFoundError(name);
|
|
6176
6340
|
}
|
|
6177
|
-
|
|
6178
|
-
return token === "" ? none("printed no token") : { ok: true, token };
|
|
6341
|
+
return pool;
|
|
6179
6342
|
}
|
|
6180
|
-
function
|
|
6181
|
-
|
|
6182
|
-
return kind === "provider" ? `agent-shim credential warm --provider ${name ?? ""}` : `agent-shim credential warm ${name ?? ""}`;
|
|
6343
|
+
function writePools(paths, pools) {
|
|
6344
|
+
applyPatch(paths.globalConfigFile, GlobalConfigSchema, { pools }, { defaults: {} });
|
|
6183
6345
|
}
|
|
6184
|
-
function
|
|
6185
|
-
|
|
6186
|
-
|
|
6187
|
-
const cache = cacheBlock === void 0 ? void 0 : params.port.cache;
|
|
6188
|
-
const store = cacheBlock === void 0 || cache === void 0 ? void 0 : effectiveStore(cacheBlock, cache.platform);
|
|
6189
|
-
if (cacheBlock !== void 0 && cache !== void 0 && store !== void 0 && params.refresh !== true) {
|
|
6190
|
-
const entry = cache.port.read(store, params.subject);
|
|
6191
|
-
if (entry !== void 0 && isFresh(entry, cacheBlock, cache.now())) {
|
|
6192
|
-
return { ok: true, credential: { target, token: entry.token, source: entry.source, warnings: [], cachedAt: entry.fetchedAt } };
|
|
6193
|
-
}
|
|
6346
|
+
function addPool(paths, name, identities) {
|
|
6347
|
+
if (!PoolNameSchema.safeParse(name).success) {
|
|
6348
|
+
throw new InvalidPoolNameError(name);
|
|
6194
6349
|
}
|
|
6195
|
-
const
|
|
6196
|
-
|
|
6197
|
-
|
|
6198
|
-
const outcome = trySource(source, params);
|
|
6199
|
-
if (outcome.ok) {
|
|
6200
|
-
if (cache !== void 0 && store !== void 0) {
|
|
6201
|
-
cache.port.write(store, params.subject, { token: outcome.token, fetchedAt: cache.now(), source });
|
|
6202
|
-
}
|
|
6203
|
-
return { ok: true, credential: { target, token: outcome.token, source, warnings } };
|
|
6204
|
-
}
|
|
6205
|
-
const line = `${describeSource(source)} ${outcome.reason}`;
|
|
6206
|
-
attempts.push(line);
|
|
6207
|
-
if (outcome.warn) {
|
|
6208
|
-
warnings.push(`agent-shim: ${params.subject}: skipped ${line}`);
|
|
6209
|
-
}
|
|
6350
|
+
const pools = readPools(paths);
|
|
6351
|
+
if (pools[name] !== void 0) {
|
|
6352
|
+
throw new PoolAlreadyExistsError(name);
|
|
6210
6353
|
}
|
|
6211
|
-
const
|
|
6212
|
-
|
|
6354
|
+
const pool = { identities: [...identities] };
|
|
6355
|
+
writePools(paths, { ...pools, [name]: pool });
|
|
6356
|
+
return pool;
|
|
6213
6357
|
}
|
|
6214
|
-
function
|
|
6215
|
-
|
|
6216
|
-
|
|
6217
|
-
|
|
6218
|
-
|
|
6219
|
-
|
|
6358
|
+
function setPool(paths, name, identities) {
|
|
6359
|
+
requirePool(paths, name);
|
|
6360
|
+
const pool = { identities: [...identities] };
|
|
6361
|
+
writePools(paths, { ...readPools(paths), [name]: pool });
|
|
6362
|
+
return pool;
|
|
6363
|
+
}
|
|
6364
|
+
function removePool(paths, name) {
|
|
6365
|
+
requirePool(paths, name);
|
|
6366
|
+
const remaining = Object.fromEntries(Object.entries(readPools(paths)).filter(([existing]) => existing !== name));
|
|
6367
|
+
writePools(paths, remaining);
|
|
6220
6368
|
}
|
|
6221
6369
|
|
|
6222
|
-
// src/
|
|
6223
|
-
var
|
|
6370
|
+
// src/identityStore.ts
|
|
6371
|
+
var IdentityNotFoundError = class extends CliError {
|
|
6224
6372
|
constructor(name) {
|
|
6225
|
-
super(`No
|
|
6373
|
+
super(`No identity named "${name}". Run \`agent-shim identity add ${name}\` first.`);
|
|
6226
6374
|
this.name = name;
|
|
6227
|
-
this.name = "
|
|
6375
|
+
this.name = "IdentityNotFoundError";
|
|
6228
6376
|
}
|
|
6229
6377
|
name;
|
|
6230
6378
|
};
|
|
6231
|
-
var
|
|
6232
|
-
constructor(
|
|
6233
|
-
super(`
|
|
6234
|
-
this.
|
|
6235
|
-
this.name = "
|
|
6379
|
+
var IdentityAlreadyExistsError = class extends CliError {
|
|
6380
|
+
constructor(identityName) {
|
|
6381
|
+
super(`An identity named "${identityName}" already exists.`);
|
|
6382
|
+
this.identityName = identityName;
|
|
6383
|
+
this.name = "IdentityAlreadyExistsError";
|
|
6236
6384
|
}
|
|
6237
|
-
|
|
6385
|
+
identityName;
|
|
6238
6386
|
};
|
|
6239
|
-
var
|
|
6387
|
+
var InvalidIdentityNameError = class extends CliError {
|
|
6240
6388
|
constructor(attemptedName) {
|
|
6241
6389
|
super(
|
|
6242
|
-
`"${attemptedName}" is not a valid
|
|
6390
|
+
`"${attemptedName}" is not a valid identity name \u2014 identity names must start with a letter or number and may then contain letters, numbers, dots, hyphens, underscores, and at signs.`
|
|
6243
6391
|
);
|
|
6244
6392
|
this.attemptedName = attemptedName;
|
|
6245
|
-
this.name = "
|
|
6393
|
+
this.name = "InvalidIdentityNameError";
|
|
6246
6394
|
}
|
|
6247
6395
|
attemptedName;
|
|
6248
6396
|
};
|
|
6249
|
-
|
|
6250
|
-
|
|
6251
|
-
return import_node_path16.default.join(paths.providersDir, `${name}.json`);
|
|
6252
|
-
}
|
|
6253
|
-
function providerExists(paths, name) {
|
|
6254
|
-
return import_node_fs5.default.existsSync(providerJsonPath(paths, name));
|
|
6397
|
+
function identityJsonPath(paths, name) {
|
|
6398
|
+
return import_node_path16.default.join(paths.identitiesDir, name, "identity.json");
|
|
6255
6399
|
}
|
|
6256
|
-
|
|
6257
|
-
|
|
6258
|
-
var LEGACY_LITERAL_PLACEHOLDER = "<the value of env.ANTHROPIC_AUTH_TOKEN>";
|
|
6259
|
-
function isRecord3(value) {
|
|
6260
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
6400
|
+
function identityExists(paths, name) {
|
|
6401
|
+
return import_node_fs4.default.existsSync(identityJsonPath(paths, name));
|
|
6261
6402
|
}
|
|
6262
|
-
function
|
|
6263
|
-
|
|
6264
|
-
return void 0;
|
|
6265
|
-
}
|
|
6266
|
-
const env = isRecord3(raw.env) ? raw.env : void 0;
|
|
6267
|
-
const legacyEnvKeys = env === void 0 ? [] : Object.keys(env).filter((key) => LEGACY_ENV_CREDENTIAL_KEYS.includes(key));
|
|
6268
|
-
const fields = [...LEGACY_PROVIDER_FIELDS.filter((field) => field in raw), ...legacyEnvKeys.map((key) => `env.${key}`)];
|
|
6269
|
-
if (fields.length === 0) {
|
|
6270
|
-
return void 0;
|
|
6271
|
-
}
|
|
6272
|
-
const sources = [];
|
|
6273
|
-
if (typeof raw.tokenEnv === "string") {
|
|
6274
|
-
sources.push({ env: raw.tokenEnv });
|
|
6275
|
-
}
|
|
6276
|
-
if (Array.isArray(raw.tokenCommand)) {
|
|
6277
|
-
sources.push({ command: raw.tokenCommand });
|
|
6278
|
-
}
|
|
6279
|
-
if (typeof env?.ANTHROPIC_AUTH_TOKEN === "string" && env.ANTHROPIC_AUTH_TOKEN !== "") {
|
|
6280
|
-
sources.push({ literal: LEGACY_LITERAL_PLACEHOLDER });
|
|
6281
|
-
}
|
|
6282
|
-
const remainingEnv = env === void 0 ? void 0 : Object.fromEntries(Object.entries(env).filter(([key]) => !LEGACY_ENV_CREDENTIAL_KEYS.includes(key)));
|
|
6283
|
-
const replacedKeys = [...LEGACY_PROVIDER_FIELDS, "env"];
|
|
6284
|
-
const rest = Object.fromEntries(Object.entries(raw).filter(([key]) => !replacedKeys.includes(key)));
|
|
6285
|
-
return {
|
|
6286
|
-
fields,
|
|
6287
|
-
replacement: {
|
|
6288
|
-
...rest,
|
|
6289
|
-
credential: { sources, ...raw.authScheme === "apiKey" ? { target: "apiKey" } : {} },
|
|
6290
|
-
...remainingEnv === void 0 || Object.keys(remainingEnv).length === 0 ? {} : { env: remainingEnv }
|
|
6291
|
-
}
|
|
6292
|
-
};
|
|
6403
|
+
function readIdentity(paths, name) {
|
|
6404
|
+
return readJson(identityJsonPath(paths, name), IdentitySchema);
|
|
6293
6405
|
}
|
|
6294
|
-
|
|
6295
|
-
|
|
6296
|
-
|
|
6297
|
-
`${filePath} uses ${conversion.fields.join(", ")}, which a credential block replaced. Rewrite it as:
|
|
6298
|
-
` + JSON.stringify(conversion.replacement, null, 2)
|
|
6299
|
-
);
|
|
6300
|
-
this.filePath = filePath;
|
|
6301
|
-
this.conversion = conversion;
|
|
6302
|
-
this.name = "LegacyProviderFileError";
|
|
6303
|
-
}
|
|
6304
|
-
filePath;
|
|
6305
|
-
conversion;
|
|
6306
|
-
};
|
|
6307
|
-
function parseProviderFile(filePath, raw) {
|
|
6308
|
-
const conversion = legacyProviderConversion(raw);
|
|
6309
|
-
if (conversion !== void 0) {
|
|
6310
|
-
throw new LegacyProviderFileError(filePath, conversion);
|
|
6406
|
+
function addIdentity(paths, name) {
|
|
6407
|
+
if (identityExists(paths, name)) {
|
|
6408
|
+
throw new IdentityAlreadyExistsError(name);
|
|
6311
6409
|
}
|
|
6312
|
-
const parsed =
|
|
6410
|
+
const parsed = IdentitySchema.safeParse({ name, allowAmbientCredential: false });
|
|
6313
6411
|
if (!parsed.success) {
|
|
6314
|
-
throw new
|
|
6412
|
+
throw new InvalidIdentityNameError(name);
|
|
6315
6413
|
}
|
|
6414
|
+
writeJsonAtomic(identityJsonPath(paths, name), parsed.data);
|
|
6316
6415
|
return parsed.data;
|
|
6317
6416
|
}
|
|
6318
|
-
function
|
|
6319
|
-
const
|
|
6320
|
-
if (
|
|
6417
|
+
function useIdentity(paths, name) {
|
|
6418
|
+
const pool = poolNameOf(name);
|
|
6419
|
+
if (pool !== void 0) {
|
|
6420
|
+
requirePool(paths, pool);
|
|
6421
|
+
} else if (!identityExists(paths, name)) {
|
|
6422
|
+
throw new IdentityNotFoundError(name);
|
|
6423
|
+
}
|
|
6424
|
+
writeTextAtomic(paths.activeIdentityFile, `${name}
|
|
6425
|
+
`);
|
|
6426
|
+
}
|
|
6427
|
+
function readActiveIdentity(paths) {
|
|
6428
|
+
if (!import_node_fs4.default.existsSync(paths.activeIdentityFile)) {
|
|
6321
6429
|
return void 0;
|
|
6322
6430
|
}
|
|
6323
|
-
const raw =
|
|
6324
|
-
return
|
|
6431
|
+
const raw = import_node_fs4.default.readFileSync(paths.activeIdentityFile, "utf8").trim();
|
|
6432
|
+
return raw === "" ? void 0 : raw;
|
|
6325
6433
|
}
|
|
6326
|
-
function
|
|
6327
|
-
|
|
6328
|
-
const raw = port.readConfigFile(filePath);
|
|
6329
|
-
return raw === void 0 ? void 0 : parseProviderFile(filePath, raw);
|
|
6434
|
+
function isIdentityDirectoryName(name) {
|
|
6435
|
+
return !name.startsWith(".");
|
|
6330
6436
|
}
|
|
6331
|
-
function
|
|
6332
|
-
|
|
6333
|
-
(
|
|
6334
|
-
|
|
6335
|
-
|
|
6437
|
+
function readIdentityForListing(paths, name) {
|
|
6438
|
+
try {
|
|
6439
|
+
return readIdentity(paths, name);
|
|
6440
|
+
} catch (error) {
|
|
6441
|
+
if (error instanceof ConfigValidationError || error instanceof SyntaxError) {
|
|
6442
|
+
return { problem: error.message.replace(/\s*\n\s*/g, " ") };
|
|
6443
|
+
}
|
|
6444
|
+
throw error;
|
|
6445
|
+
}
|
|
6446
|
+
}
|
|
6447
|
+
function listIdentities(paths) {
|
|
6448
|
+
if (!import_node_fs4.default.existsSync(paths.identitiesDir)) {
|
|
6449
|
+
return [];
|
|
6450
|
+
}
|
|
6451
|
+
const active = readActiveIdentity(paths);
|
|
6452
|
+
const names = import_node_fs4.default.readdirSync(paths.identitiesDir, { withFileTypes: true }).filter((entry) => entry.isDirectory() && isIdentityDirectoryName(entry.name)).map((entry) => entry.name).sort();
|
|
6336
6453
|
const result = [];
|
|
6337
6454
|
for (const name of names) {
|
|
6338
|
-
|
|
6339
|
-
|
|
6340
|
-
provider = readProvider(paths, name);
|
|
6341
|
-
} catch (error) {
|
|
6342
|
-
if (!(error instanceof ConfigValidationError || error instanceof LegacyProviderFileError)) {
|
|
6343
|
-
throw error;
|
|
6344
|
-
}
|
|
6345
|
-
console.error(`agent-shim: providers/${name}.json is invalid and was skipped: ${error.message}`);
|
|
6455
|
+
const read = readIdentityForListing(paths, name);
|
|
6456
|
+
if (read === void 0) {
|
|
6346
6457
|
continue;
|
|
6347
6458
|
}
|
|
6348
|
-
|
|
6349
|
-
|
|
6350
|
-
}
|
|
6459
|
+
const isActive = name === active;
|
|
6460
|
+
result.push("problem" in read ? { name, isActive, problem: read.problem } : { name, identity: read, isActive });
|
|
6351
6461
|
}
|
|
6352
6462
|
return result;
|
|
6353
6463
|
}
|
|
6354
|
-
function
|
|
6355
|
-
|
|
6464
|
+
function setDefaultConfigProfile(paths, identityName, profileName) {
|
|
6465
|
+
if (!identityExists(paths, identityName)) {
|
|
6466
|
+
throw new IdentityNotFoundError(identityName);
|
|
6467
|
+
}
|
|
6468
|
+
return applyPatch(identityJsonPath(paths, identityName), IdentitySchema, {
|
|
6469
|
+
defaultConfigProfile: profileName
|
|
6470
|
+
});
|
|
6471
|
+
}
|
|
6472
|
+
function setAllowAmbientCredential(paths, identityName, allow) {
|
|
6473
|
+
if (!identityExists(paths, identityName)) {
|
|
6474
|
+
throw new IdentityNotFoundError(identityName);
|
|
6475
|
+
}
|
|
6476
|
+
return applyPatch(identityJsonPath(paths, identityName), IdentitySchema, {
|
|
6477
|
+
allowAmbientCredential: allow
|
|
6478
|
+
});
|
|
6479
|
+
}
|
|
6480
|
+
function setIdentityCredential(paths, identityName, change) {
|
|
6481
|
+
const existing = readIdentity(paths, identityName);
|
|
6482
|
+
if (existing === void 0) {
|
|
6483
|
+
throw new IdentityNotFoundError(identityName);
|
|
6484
|
+
}
|
|
6485
|
+
if (change === false) {
|
|
6486
|
+
return applyPatch(identityJsonPath(paths, identityName), IdentitySchema, { credential: void 0 });
|
|
6487
|
+
}
|
|
6488
|
+
const sources = change.sources ?? existing.credential?.sources;
|
|
6489
|
+
if (sources === void 0) {
|
|
6490
|
+
throw new UsageError(`Identity "${identityName}" has no credential yet: pass --credential to give it one before choosing its target.`);
|
|
6491
|
+
}
|
|
6492
|
+
const target = change.target ?? existing.credential?.target;
|
|
6493
|
+
const cache = change.cache === void 0 ? existing.credential?.cache : change.cache === false ? void 0 : change.cache;
|
|
6494
|
+
return applyPatch(identityJsonPath(paths, identityName), IdentitySchema, {
|
|
6495
|
+
credential: { sources: [...sources], ...target === void 0 ? {} : { target }, ...cache === void 0 ? {} : { cache } }
|
|
6496
|
+
});
|
|
6497
|
+
}
|
|
6498
|
+
function belongsToIdentity(entry, name) {
|
|
6499
|
+
return entry === name || entry === import_node_path16.default.basename(identityLockPath("", name)) || entry.startsWith(`.${name}.scratch.`) || entry.startsWith(`.${name}.previous.`);
|
|
6500
|
+
}
|
|
6501
|
+
function removeIdentity(paths, name) {
|
|
6502
|
+
if (!identityExists(paths, name)) {
|
|
6503
|
+
throw new IdentityNotFoundError(name);
|
|
6504
|
+
}
|
|
6505
|
+
for (const entry of import_node_fs4.default.readdirSync(paths.identitiesDir)) {
|
|
6506
|
+
if (belongsToIdentity(entry, name)) {
|
|
6507
|
+
import_node_fs4.default.rmSync(import_node_path16.default.join(paths.identitiesDir, entry), { recursive: true, force: true });
|
|
6508
|
+
}
|
|
6509
|
+
}
|
|
6510
|
+
if (readActiveIdentity(paths) === name) {
|
|
6511
|
+
import_node_fs4.default.rmSync(paths.activeIdentityFile);
|
|
6512
|
+
}
|
|
6513
|
+
}
|
|
6514
|
+
|
|
6515
|
+
// src/providersStore.ts
|
|
6516
|
+
var import_node_fs5 = __toESM(require("node:fs"), 1);
|
|
6517
|
+
var import_node_path17 = __toESM(require("node:path"), 1);
|
|
6518
|
+
|
|
6519
|
+
// src/credentialCache.ts
|
|
6520
|
+
var import_zod11 = require("zod");
|
|
6521
|
+
var MS_PER_UNIT = { s: 1e3, m: 6e4, h: 36e5, d: 864e5 };
|
|
6522
|
+
var CachedCredentialSchema = import_zod11.z.strictObject({
|
|
6523
|
+
token: import_zod11.z.string().min(1),
|
|
6524
|
+
fetchedAt: import_zod11.z.number().int().nonnegative(),
|
|
6525
|
+
source: CredentialSourceSchema
|
|
6526
|
+
});
|
|
6527
|
+
function effectiveStore(cache, platform) {
|
|
6528
|
+
return cache.store ?? (platform === "darwin" ? "keychain" : "file");
|
|
6529
|
+
}
|
|
6530
|
+
function ttlMs(cache) {
|
|
6531
|
+
if (cache.ttl === void 0) {
|
|
6532
|
+
return void 0;
|
|
6533
|
+
}
|
|
6534
|
+
const multiplier = MS_PER_UNIT[cache.ttl.slice(-1)];
|
|
6535
|
+
if (multiplier === void 0) {
|
|
6536
|
+
throw new Error(`credential cache ttl "${cache.ttl}" has no recognised unit`);
|
|
6537
|
+
}
|
|
6538
|
+
return Number(cache.ttl.slice(0, -1)) * multiplier;
|
|
6539
|
+
}
|
|
6540
|
+
function isFresh(entry, cache, now) {
|
|
6541
|
+
const limit = ttlMs(cache);
|
|
6542
|
+
if (entry.fetchedAt > now) {
|
|
6543
|
+
return false;
|
|
6544
|
+
}
|
|
6545
|
+
return limit === void 0 || now - entry.fetchedAt < limit;
|
|
6546
|
+
}
|
|
6547
|
+
function cacheAgeMs(entry, now) {
|
|
6548
|
+
return Math.max(0, now - entry.fetchedAt);
|
|
6549
|
+
}
|
|
6550
|
+
function describeCachedCredential(params) {
|
|
6551
|
+
const store = effectiveStore(params.cache, params.platform);
|
|
6552
|
+
let entry;
|
|
6356
6553
|
try {
|
|
6357
|
-
|
|
6358
|
-
} catch {
|
|
6359
|
-
return
|
|
6554
|
+
entry = params.port.read(store, params.owner);
|
|
6555
|
+
} catch (error) {
|
|
6556
|
+
return { store, status: "unreadable", reason: error instanceof Error ? error.message : String(error) };
|
|
6360
6557
|
}
|
|
6361
|
-
|
|
6558
|
+
if (entry === void 0) {
|
|
6559
|
+
return { store, status: "empty" };
|
|
6560
|
+
}
|
|
6561
|
+
const limit = ttlMs(params.cache);
|
|
6562
|
+
const ageMs = cacheAgeMs(entry, params.nowMs);
|
|
6563
|
+
return {
|
|
6564
|
+
store,
|
|
6565
|
+
status: isFresh(entry, params.cache, params.nowMs) ? "fresh" : "expired",
|
|
6566
|
+
ageMs,
|
|
6567
|
+
...limit === void 0 ? {} : { expiresInMs: limit - ageMs }
|
|
6568
|
+
};
|
|
6362
6569
|
}
|
|
6363
|
-
function
|
|
6364
|
-
|
|
6570
|
+
function formatCachedCredentialState(state) {
|
|
6571
|
+
if (state.status === "empty") {
|
|
6572
|
+
return `no cached entry in the ${state.store} store yet`;
|
|
6573
|
+
}
|
|
6574
|
+
if (state.status === "unreadable") {
|
|
6575
|
+
return `the ${state.store} store cannot be read here: ${state.reason}`;
|
|
6576
|
+
}
|
|
6577
|
+
if (state.status === "expired" && (state.expiresInMs === void 0 || state.expiresInMs > 0)) {
|
|
6578
|
+
return "cached with a timestamp in the future, treated as expired";
|
|
6579
|
+
}
|
|
6580
|
+
const age = `cached ${formatAge(state.ageMs)} ago`;
|
|
6581
|
+
if (state.expiresInMs === void 0) {
|
|
6582
|
+
return `${age}, no expiry`;
|
|
6583
|
+
}
|
|
6584
|
+
return state.status === "fresh" ? `${age}, expires in ${formatAge(state.expiresInMs)}` : `${age}, expired ${formatAge(-state.expiresInMs)} ago`;
|
|
6365
6585
|
}
|
|
6366
|
-
|
|
6367
|
-
|
|
6368
|
-
|
|
6369
|
-
|
|
6586
|
+
|
|
6587
|
+
// src/credential.ts
|
|
6588
|
+
var CREDENTIAL_UNAVAILABLE_EXIT = 64;
|
|
6589
|
+
var CREDENTIAL_COMMAND_TIMEOUT_MS = 1e4;
|
|
6590
|
+
var CREDENTIAL_INTERACTIVE_TIMEOUT_MS = 12e4;
|
|
6591
|
+
var GROUP_OTHER_PERMISSION_BITS = 63;
|
|
6592
|
+
var PERMISSION_BITS = 511;
|
|
6593
|
+
var OCTAL_RADIX2 = 8;
|
|
6594
|
+
function commandArgv(source) {
|
|
6595
|
+
if ("command" in source) {
|
|
6596
|
+
return source.command;
|
|
6597
|
+
}
|
|
6598
|
+
if ("op" in source) {
|
|
6599
|
+
return ["op", "read", source.op];
|
|
6600
|
+
}
|
|
6601
|
+
const account = source.keychain.account;
|
|
6602
|
+
return ["security", "find-generic-password", "-s", source.keychain.service, ...account === void 0 ? [] : ["-a", account], "-w"];
|
|
6603
|
+
}
|
|
6604
|
+
function isInteractiveSource(source, env) {
|
|
6605
|
+
if ("command" in source || "keychain" in source) {
|
|
6606
|
+
return source.interactive ?? false;
|
|
6370
6607
|
}
|
|
6371
|
-
|
|
6372
|
-
|
|
6373
|
-
|
|
6608
|
+
if ("op" in source) {
|
|
6609
|
+
return source.interactive ?? (env.OP_SERVICE_ACCOUNT_TOKEN ?? "") === "";
|
|
6610
|
+
}
|
|
6611
|
+
return false;
|
|
6374
6612
|
}
|
|
6375
|
-
function
|
|
6376
|
-
if (
|
|
6377
|
-
|
|
6613
|
+
function summariseSource(source) {
|
|
6614
|
+
if ("env" in source) {
|
|
6615
|
+
return { kind: "env", variable: source.env };
|
|
6378
6616
|
}
|
|
6379
|
-
if (
|
|
6380
|
-
|
|
6617
|
+
if ("file" in source) {
|
|
6618
|
+
return { kind: "file", path: source.file };
|
|
6381
6619
|
}
|
|
6382
|
-
|
|
6383
|
-
|
|
6384
|
-
throw new ProviderKindMismatchError("A codex provider has no base URL: the launcher points its sessions at the front-door daemon. Drop --base-url.");
|
|
6620
|
+
if ("command" in source) {
|
|
6621
|
+
return { kind: "command", program: source.command[0] };
|
|
6385
6622
|
}
|
|
6386
|
-
if (
|
|
6387
|
-
|
|
6623
|
+
if ("op" in source) {
|
|
6624
|
+
return { kind: "op", reference: source.op };
|
|
6388
6625
|
}
|
|
6389
|
-
if (
|
|
6390
|
-
|
|
6626
|
+
if ("keychain" in source) {
|
|
6627
|
+
return {
|
|
6628
|
+
kind: "keychain",
|
|
6629
|
+
service: source.keychain.service,
|
|
6630
|
+
...source.keychain.account === void 0 ? {} : { account: source.keychain.account }
|
|
6631
|
+
};
|
|
6391
6632
|
}
|
|
6392
|
-
|
|
6393
|
-
|
|
6394
|
-
|
|
6395
|
-
|
|
6633
|
+
return { kind: "literal" };
|
|
6634
|
+
}
|
|
6635
|
+
function summariseCredential(credential) {
|
|
6636
|
+
return {
|
|
6637
|
+
target: credential.target ?? "bearer",
|
|
6638
|
+
sources: credential.sources.map(summariseSource),
|
|
6639
|
+
...credential.cache === void 0 ? {} : { cache: credential.cache }
|
|
6396
6640
|
};
|
|
6397
|
-
|
|
6398
|
-
|
|
6399
|
-
)
|
|
6400
|
-
|
|
6401
|
-
|
|
6641
|
+
}
|
|
6642
|
+
function formatSourceSummary(summary) {
|
|
6643
|
+
switch (summary.kind) {
|
|
6644
|
+
case "env":
|
|
6645
|
+
return `env ${summary.variable}`;
|
|
6646
|
+
case "file":
|
|
6647
|
+
return `file ${summary.path}`;
|
|
6648
|
+
case "command":
|
|
6649
|
+
return `command ${summary.program}`;
|
|
6650
|
+
case "op":
|
|
6651
|
+
return `op ${summary.reference}`;
|
|
6652
|
+
case "keychain":
|
|
6653
|
+
return `keychain ${summary.service}${summary.account === void 0 ? "" : ` (account ${summary.account})`}`;
|
|
6654
|
+
case "literal":
|
|
6655
|
+
return "literal (non-secret placeholder)";
|
|
6656
|
+
default:
|
|
6657
|
+
return summary;
|
|
6402
6658
|
}
|
|
6403
|
-
writeJsonAtomic(providerJsonPath(paths, name), parsed.data);
|
|
6404
|
-
return parsed.data;
|
|
6405
6659
|
}
|
|
6406
|
-
function
|
|
6407
|
-
|
|
6408
|
-
|
|
6409
|
-
|
|
6660
|
+
function describeSource(source) {
|
|
6661
|
+
return formatSourceSummary(summariseSource(source));
|
|
6662
|
+
}
|
|
6663
|
+
function formatCredentialSummary(summary) {
|
|
6664
|
+
const cache = summary.cache === void 0 ? "" : `, cached ${summary.cache.ttl === void 0 ? "with no expiry" : `for ${summary.cache.ttl}`}${summary.cache.store === void 0 ? "" : ` in the ${summary.cache.store} store`}`;
|
|
6665
|
+
return `${summary.target} from ${summary.sources.map(formatSourceSummary).join(", then ")}${cache}`;
|
|
6666
|
+
}
|
|
6667
|
+
function describeCredential(credential) {
|
|
6668
|
+
return formatCredentialSummary(summariseCredential(credential));
|
|
6669
|
+
}
|
|
6670
|
+
function trySource(source, params) {
|
|
6671
|
+
const none = (reason, warn = false) => ({ ok: false, reason, warn });
|
|
6672
|
+
if ("env" in source) {
|
|
6673
|
+
const value = params.env[source.env];
|
|
6674
|
+
return value === void 0 || value === "" ? none("is unset or empty") : { ok: true, token: value };
|
|
6410
6675
|
}
|
|
6411
|
-
|
|
6412
|
-
|
|
6413
|
-
const target = input.target ?? existing.credential.target;
|
|
6414
|
-
const cache = input.cache === void 0 ? existing.credential.cache : input.cache === false ? void 0 : input.cache;
|
|
6415
|
-
if (isCodexProvider(existing) && input.baseUrl !== void 0) {
|
|
6416
|
-
throw new ProviderKindMismatchError(`Provider "${name}" is a codex provider, which has no base URL.`);
|
|
6676
|
+
if ("literal" in source) {
|
|
6677
|
+
return { ok: true, token: source.literal };
|
|
6417
6678
|
}
|
|
6418
|
-
if (
|
|
6419
|
-
|
|
6679
|
+
if ("file" in source) {
|
|
6680
|
+
const read = params.port.readSecretFile(source.file);
|
|
6681
|
+
if (!read.found) {
|
|
6682
|
+
return none("does not exist");
|
|
6683
|
+
}
|
|
6684
|
+
if (read.mode !== void 0 && (read.mode & GROUP_OTHER_PERMISSION_BITS) !== 0) {
|
|
6685
|
+
return none(
|
|
6686
|
+
`is readable or writable by group or others (mode ${(read.mode & PERMISSION_BITS).toString(OCTAL_RADIX2)}); run \`chmod 600 ${source.file}\``,
|
|
6687
|
+
true
|
|
6688
|
+
);
|
|
6689
|
+
}
|
|
6690
|
+
const token2 = read.content.trim();
|
|
6691
|
+
return token2 === "" ? none("is empty") : { ok: true, token: token2 };
|
|
6420
6692
|
}
|
|
6421
|
-
const
|
|
6422
|
-
|
|
6423
|
-
|
|
6424
|
-
|
|
6425
|
-
...target === void 0 ? {} : { target },
|
|
6426
|
-
...cache === void 0 ? {} : { cache }
|
|
6427
|
-
},
|
|
6428
|
-
env: Object.keys(env).length === 0 ? void 0 : env
|
|
6429
|
-
};
|
|
6430
|
-
let candidate;
|
|
6431
|
-
if (isCodexProvider(existing)) {
|
|
6432
|
-
const codex = {
|
|
6433
|
-
...existing.codex,
|
|
6434
|
-
...input.codex,
|
|
6435
|
-
...existing.codex?.models === void 0 && input.codex?.models === void 0 ? {} : { models: { ...existing.codex?.models, ...input.codex?.models } }
|
|
6436
|
-
};
|
|
6437
|
-
candidate = { ...existing, ...shared, codex: isEmptyCodexConfig(codex) ? void 0 : codex };
|
|
6438
|
-
} else {
|
|
6439
|
-
candidate = { ...existing, ...shared, ...input.baseUrl === void 0 ? {} : { baseUrl: input.baseUrl } };
|
|
6693
|
+
const argv = commandArgv(source);
|
|
6694
|
+
const interactive = isInteractiveSource(source, params.env);
|
|
6695
|
+
if (interactive && !params.port.personPresent()) {
|
|
6696
|
+
return none("needs a person to approve it, but there is no terminal or desktop session");
|
|
6440
6697
|
}
|
|
6441
|
-
const
|
|
6442
|
-
|
|
6443
|
-
|
|
6698
|
+
const timeoutMs = source.timeoutMs ?? (interactive ? CREDENTIAL_INTERACTIVE_TIMEOUT_MS : CREDENTIAL_COMMAND_TIMEOUT_MS);
|
|
6699
|
+
const result = params.port.runCommand(argv, { timeoutMs, interactive });
|
|
6700
|
+
if (result.timedOut) {
|
|
6701
|
+
return none(`timed out after ${String(timeoutMs)}ms`);
|
|
6444
6702
|
}
|
|
6445
|
-
|
|
6446
|
-
|
|
6447
|
-
}
|
|
6448
|
-
|
|
6449
|
-
if (!providerExists(paths, name)) {
|
|
6450
|
-
throw new ProviderNotFoundError(name);
|
|
6703
|
+
if (result.status !== 0) {
|
|
6704
|
+
const stderr = result.stderr.trim();
|
|
6705
|
+
const outcome = result.status === null ? "could not be run or was killed by a signal" : `exited with status ${String(result.status)}`;
|
|
6706
|
+
return none(`${outcome}${stderr === "" ? "" : `: ${stderr}`}`);
|
|
6451
6707
|
}
|
|
6452
|
-
|
|
6708
|
+
const token = result.stdout.trim();
|
|
6709
|
+
return token === "" ? none("printed no token") : { ok: true, token };
|
|
6453
6710
|
}
|
|
6454
|
-
function
|
|
6455
|
-
|
|
6456
|
-
|
|
6457
|
-
if (layer.launch?.provider !== void 0) {
|
|
6458
|
-
name = layer.launch.provider;
|
|
6459
|
-
}
|
|
6460
|
-
}
|
|
6461
|
-
return name;
|
|
6711
|
+
function warmCommandFor(subject) {
|
|
6712
|
+
const [kind, name] = subject.split(" ");
|
|
6713
|
+
return kind === "provider" ? `agent-shim credential warm --provider ${name ?? ""}` : `agent-shim credential warm ${name ?? ""}`;
|
|
6462
6714
|
}
|
|
6463
|
-
function
|
|
6464
|
-
const
|
|
6465
|
-
const
|
|
6466
|
-
|
|
6467
|
-
|
|
6468
|
-
|
|
6469
|
-
|
|
6470
|
-
|
|
6471
|
-
|
|
6472
|
-
|
|
6473
|
-
ok: false,
|
|
6474
|
-
status: 1,
|
|
6475
|
-
message: `agent-shim: no provider named "${name}". ` + (known.length > 0 ? `Known providers: ${known.join(", ")}.` : "No providers are defined yet; run `agent-shim provider add`.")
|
|
6476
|
-
};
|
|
6477
|
-
}
|
|
6478
|
-
if (params.credentials === void 0) {
|
|
6479
|
-
return { ok: false, status: 1, message: `agent-shim: provider ${name} needs its credential resolved, but this launcher has no credential port wired` };
|
|
6715
|
+
function resolveCredential(params) {
|
|
6716
|
+
const target = params.credential.target ?? "bearer";
|
|
6717
|
+
const cacheBlock = params.credential.cache;
|
|
6718
|
+
const cache = cacheBlock === void 0 ? void 0 : params.port.cache;
|
|
6719
|
+
const store = cacheBlock === void 0 || cache === void 0 ? void 0 : effectiveStore(cacheBlock, cache.platform);
|
|
6720
|
+
if (cacheBlock !== void 0 && cache !== void 0 && store !== void 0 && params.refresh !== true) {
|
|
6721
|
+
const entry = cache.port.read(store, params.subject);
|
|
6722
|
+
if (entry !== void 0 && isFresh(entry, cacheBlock, cache.now())) {
|
|
6723
|
+
return { ok: true, credential: { target, token: entry.token, source: entry.source, warnings: [], cachedAt: entry.fetchedAt } };
|
|
6724
|
+
}
|
|
6480
6725
|
}
|
|
6481
|
-
const
|
|
6482
|
-
|
|
6483
|
-
|
|
6726
|
+
const attempts = [];
|
|
6727
|
+
const warnings = [];
|
|
6728
|
+
for (const source of params.credential.sources) {
|
|
6729
|
+
const outcome = trySource(source, params);
|
|
6730
|
+
if (outcome.ok) {
|
|
6731
|
+
if (cache !== void 0 && store !== void 0) {
|
|
6732
|
+
cache.port.write(store, params.subject, { token: outcome.token, fetchedAt: cache.now(), source });
|
|
6733
|
+
}
|
|
6734
|
+
return { ok: true, credential: { target, token: outcome.token, source, warnings } };
|
|
6735
|
+
}
|
|
6736
|
+
const line = `${describeSource(source)} ${outcome.reason}`;
|
|
6737
|
+
attempts.push(line);
|
|
6738
|
+
if (outcome.warn) {
|
|
6739
|
+
warnings.push(`agent-shim: ${params.subject}: skipped ${line}`);
|
|
6740
|
+
}
|
|
6484
6741
|
}
|
|
6485
|
-
|
|
6742
|
+
const hint = cacheBlock === void 0 ? "" : `; fill the cache from a terminal with \`${warmCommandFor(params.subject)}\``;
|
|
6743
|
+
return { ok: false, message: `agent-shim: ${params.subject} has no usable credential: ${attempts.join("; ")}${hint}` };
|
|
6744
|
+
}
|
|
6745
|
+
function credentialVariables(target, token) {
|
|
6746
|
+
return {
|
|
6747
|
+
ANTHROPIC_AUTH_TOKEN: target === "bearer" ? token : void 0,
|
|
6748
|
+
ANTHROPIC_API_KEY: target === "apiKey" ? token : void 0,
|
|
6749
|
+
CLAUDE_CODE_OAUTH_TOKEN: target === "oauthToken" ? token : void 0
|
|
6750
|
+
};
|
|
6486
6751
|
}
|
|
6487
6752
|
|
|
6488
|
-
// src/
|
|
6489
|
-
var
|
|
6490
|
-
constructor(
|
|
6491
|
-
super(`No
|
|
6492
|
-
this.
|
|
6493
|
-
this.name = "
|
|
6753
|
+
// src/providersStore.ts
|
|
6754
|
+
var ProviderNotFoundError = class extends CliError {
|
|
6755
|
+
constructor(name) {
|
|
6756
|
+
super(`No provider named "${name}". Run \`agent-shim provider add ${name}\` first.`);
|
|
6757
|
+
this.name = name;
|
|
6758
|
+
this.name = "ProviderNotFoundError";
|
|
6494
6759
|
}
|
|
6495
|
-
|
|
6760
|
+
name;
|
|
6496
6761
|
};
|
|
6497
|
-
var
|
|
6498
|
-
constructor() {
|
|
6499
|
-
super(
|
|
6500
|
-
this.
|
|
6762
|
+
var ProviderAlreadyExistsError = class extends CliError {
|
|
6763
|
+
constructor(providerName) {
|
|
6764
|
+
super(`A provider named "${providerName}" already exists.`);
|
|
6765
|
+
this.providerName = providerName;
|
|
6766
|
+
this.name = "ProviderAlreadyExistsError";
|
|
6501
6767
|
}
|
|
6768
|
+
providerName;
|
|
6502
6769
|
};
|
|
6503
|
-
var
|
|
6504
|
-
constructor(
|
|
6505
|
-
super(
|
|
6506
|
-
|
|
6507
|
-
|
|
6770
|
+
var InvalidProviderNameError = class extends CliError {
|
|
6771
|
+
constructor(attemptedName) {
|
|
6772
|
+
super(
|
|
6773
|
+
`"${attemptedName}" is not a valid provider name. Provider names must start with a letter or number and may then contain letters, numbers, dots, hyphens, underscores, and at signs.`
|
|
6774
|
+
);
|
|
6775
|
+
this.attemptedName = attemptedName;
|
|
6776
|
+
this.name = "InvalidProviderNameError";
|
|
6508
6777
|
}
|
|
6509
|
-
|
|
6778
|
+
attemptedName;
|
|
6510
6779
|
};
|
|
6511
|
-
|
|
6512
|
-
|
|
6780
|
+
var PROVIDER_NAME_RE = /^[A-Za-z0-9][A-Za-z0-9._@-]*$/;
|
|
6781
|
+
function providerJsonPath(paths, name) {
|
|
6782
|
+
return import_node_path17.default.join(paths.providersDir, `${name}.json`);
|
|
6513
6783
|
}
|
|
6514
|
-
function
|
|
6515
|
-
|
|
6516
|
-
if (!parsed.success) {
|
|
6517
|
-
throw new ConfigValidationError(paths.directoryRulesFile, parsed.error.issues);
|
|
6518
|
-
}
|
|
6519
|
-
writeJsonAtomic(paths.directoryRulesFile, parsed.data);
|
|
6784
|
+
function providerExists(paths, name) {
|
|
6785
|
+
return import_node_fs5.default.existsSync(providerJsonPath(paths, name));
|
|
6520
6786
|
}
|
|
6521
|
-
|
|
6522
|
-
|
|
6787
|
+
var LEGACY_PROVIDER_FIELDS = ["tokenEnv", "tokenCommand", "authScheme"];
|
|
6788
|
+
var LEGACY_ENV_CREDENTIAL_KEYS = Object.values(CREDENTIAL_TARGET_VARS);
|
|
6789
|
+
var LEGACY_LITERAL_PLACEHOLDER = "<the value of env.ANTHROPIC_AUTH_TOKEN>";
|
|
6790
|
+
function isRecord3(value) {
|
|
6791
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
6523
6792
|
}
|
|
6524
|
-
function
|
|
6525
|
-
if (
|
|
6526
|
-
|
|
6793
|
+
function legacyProviderConversion(raw) {
|
|
6794
|
+
if (!isRecord3(raw) || "credential" in raw) {
|
|
6795
|
+
return void 0;
|
|
6527
6796
|
}
|
|
6528
|
-
const
|
|
6529
|
-
|
|
6530
|
-
|
|
6797
|
+
const env = isRecord3(raw.env) ? raw.env : void 0;
|
|
6798
|
+
const legacyEnvKeys = env === void 0 ? [] : Object.keys(env).filter((key) => LEGACY_ENV_CREDENTIAL_KEYS.includes(key));
|
|
6799
|
+
const fields = [...LEGACY_PROVIDER_FIELDS.filter((field) => field in raw), ...legacyEnvKeys.map((key) => `env.${key}`)];
|
|
6800
|
+
if (fields.length === 0) {
|
|
6801
|
+
return void 0;
|
|
6531
6802
|
}
|
|
6532
|
-
const
|
|
6533
|
-
|
|
6534
|
-
|
|
6535
|
-
}
|
|
6536
|
-
function ruleHasEffect(rule) {
|
|
6537
|
-
return rule.configProfile !== void 0 || rule.identity !== void 0 || rule.categories !== void 0 || rule.entries !== void 0 || rule.launch !== void 0;
|
|
6538
|
-
}
|
|
6539
|
-
function updateDirectoryRule(paths, rulePath, options) {
|
|
6540
|
-
const current = readDirectoryRules(paths);
|
|
6541
|
-
const index = current.rules.findIndex((rule) => rule.path === rulePath);
|
|
6542
|
-
const existing = index === -1 ? void 0 : current.rules[index];
|
|
6543
|
-
if (existing === void 0) {
|
|
6544
|
-
throw new DirectoryRuleNotFoundError(rulePath);
|
|
6803
|
+
const sources = [];
|
|
6804
|
+
if (typeof raw.tokenEnv === "string") {
|
|
6805
|
+
sources.push({ env: raw.tokenEnv });
|
|
6545
6806
|
}
|
|
6546
|
-
|
|
6547
|
-
|
|
6548
|
-
const nextIdentity = options.identity === void 0 ? identity : options.identity === false ? void 0 : options.identity;
|
|
6549
|
-
const updated = {
|
|
6550
|
-
...rest,
|
|
6551
|
-
...nextConfigProfile === void 0 ? {} : { configProfile: nextConfigProfile },
|
|
6552
|
-
...nextIdentity === void 0 ? {} : { identity: nextIdentity }
|
|
6553
|
-
};
|
|
6554
|
-
if (!ruleHasEffect(updated)) {
|
|
6555
|
-
throw new DirectoryRuleMissingTargetError();
|
|
6807
|
+
if (Array.isArray(raw.tokenCommand)) {
|
|
6808
|
+
sources.push({ command: raw.tokenCommand });
|
|
6556
6809
|
}
|
|
6557
|
-
|
|
6558
|
-
|
|
6559
|
-
|
|
6560
|
-
|
|
6561
|
-
|
|
6562
|
-
|
|
6810
|
+
if (typeof env?.ANTHROPIC_AUTH_TOKEN === "string" && env.ANTHROPIC_AUTH_TOKEN !== "") {
|
|
6811
|
+
sources.push({ literal: LEGACY_LITERAL_PLACEHOLDER });
|
|
6812
|
+
}
|
|
6813
|
+
const remainingEnv = env === void 0 ? void 0 : Object.fromEntries(Object.entries(env).filter(([key]) => !LEGACY_ENV_CREDENTIAL_KEYS.includes(key)));
|
|
6814
|
+
const replacedKeys = [...LEGACY_PROVIDER_FIELDS, "env"];
|
|
6815
|
+
const rest = Object.fromEntries(Object.entries(raw).filter(([key]) => !replacedKeys.includes(key)));
|
|
6563
6816
|
return {
|
|
6564
|
-
|
|
6565
|
-
|
|
6566
|
-
|
|
6817
|
+
fields,
|
|
6818
|
+
replacement: {
|
|
6819
|
+
...rest,
|
|
6820
|
+
credential: { sources, ...raw.authScheme === "apiKey" ? { target: "apiKey" } : {} },
|
|
6821
|
+
...remainingEnv === void 0 || Object.keys(remainingEnv).length === 0 ? {} : { env: remainingEnv }
|
|
6822
|
+
}
|
|
6567
6823
|
};
|
|
6568
6824
|
}
|
|
6569
|
-
|
|
6570
|
-
|
|
6571
|
-
|
|
6572
|
-
|
|
6573
|
-
|
|
6825
|
+
var LegacyProviderFileError = class extends CliError {
|
|
6826
|
+
constructor(filePath, conversion) {
|
|
6827
|
+
super(
|
|
6828
|
+
`${filePath} uses ${conversion.fields.join(", ")}, which a credential block replaced. Rewrite it as:
|
|
6829
|
+
` + JSON.stringify(conversion.replacement, null, 2)
|
|
6830
|
+
);
|
|
6831
|
+
this.filePath = filePath;
|
|
6832
|
+
this.conversion = conversion;
|
|
6833
|
+
this.name = "LegacyProviderFileError";
|
|
6574
6834
|
}
|
|
6575
|
-
|
|
6576
|
-
|
|
6577
|
-
|
|
6578
|
-
|
|
6579
|
-
|
|
6580
|
-
|
|
6581
|
-
|
|
6582
|
-
var import_node_path18 = __toESM(require("node:path"), 1);
|
|
6583
|
-
|
|
6584
|
-
// src/pathNorm.ts
|
|
6585
|
-
var import_node_path17 = __toESM(require("node:path"), 1);
|
|
6586
|
-
function expandTilde(value, home) {
|
|
6587
|
-
if (value === "~") {
|
|
6588
|
-
return home;
|
|
6835
|
+
filePath;
|
|
6836
|
+
conversion;
|
|
6837
|
+
};
|
|
6838
|
+
function parseProviderFile(filePath, raw) {
|
|
6839
|
+
const conversion = legacyProviderConversion(raw);
|
|
6840
|
+
if (conversion !== void 0) {
|
|
6841
|
+
throw new LegacyProviderFileError(filePath, conversion);
|
|
6589
6842
|
}
|
|
6590
|
-
|
|
6591
|
-
|
|
6843
|
+
const parsed = ProviderSchema.safeParse(raw);
|
|
6844
|
+
if (!parsed.success) {
|
|
6845
|
+
throw new ConfigValidationError(filePath, parsed.error.issues);
|
|
6592
6846
|
}
|
|
6593
|
-
return
|
|
6594
|
-
}
|
|
6595
|
-
function normaliseRulePath(rulePath, home) {
|
|
6596
|
-
return import_node_path17.default.resolve(expandTilde(rulePath, home));
|
|
6847
|
+
return parsed.data;
|
|
6597
6848
|
}
|
|
6598
|
-
|
|
6599
|
-
|
|
6600
|
-
|
|
6601
|
-
|
|
6602
|
-
function loadCascadeInput(params) {
|
|
6603
|
-
const globalConfig = loadConfigFile(params.paths.globalConfigFile, GlobalConfigSchema, params.read);
|
|
6604
|
-
const directoryRules = loadConfigFile(params.paths.directoryRulesFile, DirectoryRulesSchema, params.read);
|
|
6605
|
-
const loadProfile = (name) => {
|
|
6606
|
-
const filepath = import_node_path18.default.join(params.paths.configProfilesDir, `${name}.json`);
|
|
6607
|
-
const loaded = loadConfigFile(filepath, ConfigProfileSchema, params.read);
|
|
6608
|
-
if (loaded === void 0) {
|
|
6609
|
-
return void 0;
|
|
6610
|
-
}
|
|
6611
|
-
return { name, profile: loaded.config, entryOrder: loaded.entryOrder, filepath: loaded.filepath };
|
|
6612
|
-
};
|
|
6613
|
-
const limit = globalConfig?.config.walkUpLimit;
|
|
6614
|
-
const dirs = walkDirectoryAncestors(params.cwd, {
|
|
6615
|
-
home: params.home,
|
|
6616
|
-
...limit === void 0 ? {} : { limit: expandTilde(limit, params.home) },
|
|
6617
|
-
...params.isReadable === void 0 ? {} : { isReadable: params.isReadable }
|
|
6618
|
-
});
|
|
6619
|
-
const levels = [];
|
|
6620
|
-
for (const dir of dirs) {
|
|
6621
|
-
const portable = loadConfigFile(import_node_path18.default.join(dir, PORTABLE_CONFIG_FILENAME), PortableConfigSchema, params.read) ?? loadConfigFile(import_node_path18.default.join(dir, LEGACY_PORTABLE_CONFIG_FILENAME), PortableConfigSchema, params.read);
|
|
6622
|
-
const portableLocal = loadConfigFile(import_node_path18.default.join(dir, PORTABLE_LOCAL_CONFIG_FILENAME), PortableConfigSchema, params.read) ?? loadConfigFile(import_node_path18.default.join(dir, LEGACY_PORTABLE_LOCAL_CONFIG_FILENAME), PortableConfigSchema, params.read);
|
|
6623
|
-
const rules = (directoryRules?.config.rules ?? []).map((rule, index) => ({ rule, index })).filter(({ rule }) => normaliseRulePath(rule.path, params.home) === dir).map(({ rule, index }) => {
|
|
6624
|
-
const entryOrder = directoryRules?.ruleEntryOrders[index];
|
|
6625
|
-
return {
|
|
6626
|
-
rule,
|
|
6627
|
-
...entryOrder === void 0 ? {} : { entryOrder },
|
|
6628
|
-
filepath: params.paths.directoryRulesFile
|
|
6629
|
-
};
|
|
6630
|
-
});
|
|
6631
|
-
if (portable === void 0 && portableLocal === void 0 && rules.length === 0) {
|
|
6632
|
-
continue;
|
|
6633
|
-
}
|
|
6634
|
-
levels.push({
|
|
6635
|
-
dir,
|
|
6636
|
-
...portable === void 0 ? {} : { portable: { config: portable.config, entryOrder: portable.entryOrder, filepath: portable.filepath } },
|
|
6637
|
-
...rules.length === 0 ? {} : { rules },
|
|
6638
|
-
...portableLocal === void 0 ? {} : { portableLocal: { config: portableLocal.config, entryOrder: portableLocal.entryOrder, filepath: portableLocal.filepath } }
|
|
6639
|
-
});
|
|
6849
|
+
function readProvider(paths, name) {
|
|
6850
|
+
const filePath = providerJsonPath(paths, name);
|
|
6851
|
+
if (!import_node_fs5.default.existsSync(filePath)) {
|
|
6852
|
+
return void 0;
|
|
6640
6853
|
}
|
|
6641
|
-
const
|
|
6642
|
-
|
|
6643
|
-
...globalConfig === void 0 ? {} : { globalConfig: { config: globalConfig.config, entryOrder: globalConfig.entryOrder, filepath: globalConfig.filepath } },
|
|
6644
|
-
...params.baseConfigProfile === void 0 ? {} : { baseConfigProfile: params.baseConfigProfile },
|
|
6645
|
-
loadProfile,
|
|
6646
|
-
levels,
|
|
6647
|
-
...params.cliOverride === void 0 ? {} : { cliOverride: params.cliOverride }
|
|
6648
|
-
};
|
|
6649
|
-
return { input, ...globalConfig === void 0 ? {} : { globalConfig: globalConfig.config } };
|
|
6854
|
+
const raw = JSON.parse(import_node_fs5.default.readFileSync(filePath, "utf8"));
|
|
6855
|
+
return parseProviderFile(filePath, raw);
|
|
6650
6856
|
}
|
|
6651
|
-
function
|
|
6652
|
-
|
|
6653
|
-
|
|
6654
|
-
|
|
6655
|
-
|
|
6656
|
-
|
|
6657
|
-
|
|
6658
|
-
|
|
6659
|
-
|
|
6660
|
-
|
|
6661
|
-
|
|
6662
|
-
|
|
6663
|
-
|
|
6857
|
+
function loadProvider(providersDir, name, port) {
|
|
6858
|
+
const filePath = import_node_path17.default.join(providersDir, `${name}.json`);
|
|
6859
|
+
const raw = port.readConfigFile(filePath);
|
|
6860
|
+
return raw === void 0 ? void 0 : parseProviderFile(filePath, raw);
|
|
6861
|
+
}
|
|
6862
|
+
function listProviders(paths) {
|
|
6863
|
+
const names = listProviderNames(
|
|
6864
|
+
(dir) => import_node_fs5.default.readdirSync(dir),
|
|
6865
|
+
paths.providersDir
|
|
6866
|
+
);
|
|
6867
|
+
const result = [];
|
|
6868
|
+
for (const name of names) {
|
|
6869
|
+
let provider;
|
|
6870
|
+
try {
|
|
6871
|
+
provider = readProvider(paths, name);
|
|
6872
|
+
} catch (error) {
|
|
6873
|
+
if (!(error instanceof ConfigValidationError || error instanceof LegacyProviderFileError)) {
|
|
6874
|
+
throw error;
|
|
6664
6875
|
}
|
|
6876
|
+
console.error(`agent-shim: providers/${name}.json is invalid and was skipped: ${error.message}`);
|
|
6877
|
+
continue;
|
|
6878
|
+
}
|
|
6879
|
+
if (provider !== void 0) {
|
|
6880
|
+
result.push({ name, provider });
|
|
6665
6881
|
}
|
|
6666
6882
|
}
|
|
6667
|
-
return
|
|
6668
|
-
}
|
|
6669
|
-
|
|
6670
|
-
// src/usage/preflight.ts
|
|
6671
|
-
var MS_PER_SECOND2 = 1e3;
|
|
6672
|
-
var SECONDS_PER_MINUTE = 60;
|
|
6673
|
-
var MINUTES_PER_HOUR = 60;
|
|
6674
|
-
var HOURS_PER_DAY = 24;
|
|
6675
|
-
var WARNING_STATUSES = /* @__PURE__ */ new Set(["allowed_warning", "rejected"]);
|
|
6676
|
-
function formatAge(ms) {
|
|
6677
|
-
const minutes = Math.floor(ms / (MS_PER_SECOND2 * SECONDS_PER_MINUTE));
|
|
6678
|
-
if (minutes < MINUTES_PER_HOUR) {
|
|
6679
|
-
return `${String(Math.max(minutes, 0))}m`;
|
|
6680
|
-
}
|
|
6681
|
-
const hours = Math.floor(minutes / MINUTES_PER_HOUR);
|
|
6682
|
-
return hours < HOURS_PER_DAY ? `${String(hours)}h` : `${String(Math.floor(hours / HOURS_PER_DAY))}d`;
|
|
6683
|
-
}
|
|
6684
|
-
function effectiveWindow(window, nowMs) {
|
|
6685
|
-
const resetsAtMs = window.resetsAt === void 0 ? void 0 : Date.parse(window.resetsAt);
|
|
6686
|
-
if (resetsAtMs !== void 0 && resetsAtMs <= nowMs) {
|
|
6687
|
-
return { reset: true, utilization: 0 };
|
|
6688
|
-
}
|
|
6689
|
-
return {
|
|
6690
|
-
reset: false,
|
|
6691
|
-
...window.utilization === void 0 ? {} : { utilization: window.utilization },
|
|
6692
|
-
...resetsAtMs === void 0 ? {} : { resetsAtMs },
|
|
6693
|
-
...window.status === void 0 ? {} : { status: window.status }
|
|
6694
|
-
};
|
|
6883
|
+
return result;
|
|
6695
6884
|
}
|
|
6696
|
-
function
|
|
6697
|
-
|
|
6698
|
-
|
|
6699
|
-
|
|
6885
|
+
function listProviderNames(readdir, providersDir) {
|
|
6886
|
+
let entries;
|
|
6887
|
+
try {
|
|
6888
|
+
entries = readdir(providersDir);
|
|
6889
|
+
} catch {
|
|
6700
6890
|
return [];
|
|
6701
6891
|
}
|
|
6702
|
-
|
|
6703
|
-
const windows = [
|
|
6704
|
-
{ name: "five-hour", window: unified.fiveHour },
|
|
6705
|
-
{ name: "seven-day", window: unified.sevenDay }
|
|
6706
|
-
];
|
|
6707
|
-
return windows.flatMap(({ name, window }) => {
|
|
6708
|
-
const effective = window === void 0 ? void 0 : effectiveWindow(window, nowMs);
|
|
6709
|
-
if (window === void 0 || effective?.status === void 0 || !WARNING_STATUSES.has(effective.status)) {
|
|
6710
|
-
return [];
|
|
6711
|
-
}
|
|
6712
|
-
const reset = window.resetsAt === void 0 ? "" : `, resets ${window.resetsAt}`;
|
|
6713
|
-
const verdict = effective.status === "rejected" ? "exhausted" : "nearly used";
|
|
6714
|
-
return [`agent-shim: identity ${snapshot.identity}: the ${name} quota is ${verdict}${reset} (last seen ${age} ago)`];
|
|
6715
|
-
});
|
|
6892
|
+
return entries.filter((entry) => entry.endsWith(".json")).map((entry) => entry.slice(0, -".json".length)).sort();
|
|
6716
6893
|
}
|
|
6717
|
-
|
|
6718
|
-
|
|
6719
|
-
|
|
6720
|
-
var
|
|
6721
|
-
|
|
6722
|
-
|
|
6723
|
-
|
|
6724
|
-
var ZERO_TIER = /(?:^|_)zero$/;
|
|
6725
|
-
var BASE_TIER = /(?:^|_)(?:pro|free)$/;
|
|
6726
|
-
function planOf(account) {
|
|
6727
|
-
const tier = account?.organizationRateLimitTier ?? account?.userRateLimitTier;
|
|
6728
|
-
const tierField = tier === void 0 ? {} : { tier };
|
|
6729
|
-
if (tier === void 0) {
|
|
6730
|
-
return { kind: "subscription", capacity: 1, recognised: false };
|
|
6894
|
+
function describeProviderEndpoint(provider) {
|
|
6895
|
+
return isCodexProvider(provider) ? "codex translation daemon" : provider.baseUrl;
|
|
6896
|
+
}
|
|
6897
|
+
var ProviderKindMismatchError = class extends UsageError {
|
|
6898
|
+
constructor(message) {
|
|
6899
|
+
super(message);
|
|
6900
|
+
this.name = "ProviderKindMismatchError";
|
|
6731
6901
|
}
|
|
6732
|
-
|
|
6733
|
-
|
|
6902
|
+
};
|
|
6903
|
+
function isEmptyCodexConfig(config) {
|
|
6904
|
+
return config === void 0 || config.defaultModel === void 0 && config.effort === void 0 && (config.models === void 0 || Object.keys(config.models).length === 0);
|
|
6905
|
+
}
|
|
6906
|
+
function addProvider(paths, name, input) {
|
|
6907
|
+
if (providerExists(paths, name)) {
|
|
6908
|
+
throw new ProviderAlreadyExistsError(name);
|
|
6734
6909
|
}
|
|
6735
|
-
|
|
6736
|
-
|
|
6737
|
-
return { kind: "subscription", capacity: Number(multiplier), recognised: true, ...tierField };
|
|
6910
|
+
if (!PROVIDER_NAME_RE.test(name)) {
|
|
6911
|
+
throw new InvalidProviderNameError(name);
|
|
6738
6912
|
}
|
|
6739
|
-
|
|
6740
|
-
|
|
6741
|
-
|
|
6742
|
-
// src/usage/rateLimit.ts
|
|
6743
|
-
var MS_PER_SECOND3 = 1e3;
|
|
6744
|
-
function epochSecondsToIso(value) {
|
|
6745
|
-
if (value === void 0) {
|
|
6746
|
-
return void 0;
|
|
6913
|
+
const kind = input.kind ?? "http";
|
|
6914
|
+
if (kind === "codex" && input.baseUrl !== void 0) {
|
|
6915
|
+
throw new ProviderKindMismatchError("A codex provider has no base URL: the launcher points its sessions at the front-door daemon. Drop --base-url.");
|
|
6747
6916
|
}
|
|
6748
|
-
|
|
6749
|
-
|
|
6750
|
-
}
|
|
6751
|
-
function nonNegativeNumber(value) {
|
|
6752
|
-
if (value === void 0 || value.trim() === "") {
|
|
6753
|
-
return void 0;
|
|
6917
|
+
if (kind === "http" && input.baseUrl === void 0) {
|
|
6918
|
+
throw new ProviderKindMismatchError("An http provider needs --base-url.");
|
|
6754
6919
|
}
|
|
6755
|
-
|
|
6756
|
-
|
|
6757
|
-
}
|
|
6758
|
-
var UNIFIED_PREFIX = "anthropic-ratelimit-unified-";
|
|
6759
|
-
function unifiedWindow(headers, window) {
|
|
6760
|
-
const utilization = nonNegativeNumber(headers[`${UNIFIED_PREFIX}${window}-utilization`]);
|
|
6761
|
-
const resetsAt = epochSecondsToIso(headers[`${UNIFIED_PREFIX}${window}-reset`]);
|
|
6762
|
-
const status = headers[`${UNIFIED_PREFIX}${window}-status`];
|
|
6763
|
-
if (utilization === void 0 && resetsAt === void 0 && status === void 0) {
|
|
6764
|
-
return void 0;
|
|
6920
|
+
if (kind === "http" && !isEmptyCodexConfig(input.codex)) {
|
|
6921
|
+
throw new ProviderKindMismatchError("Codex settings apply only to a codex provider (--kind codex).");
|
|
6765
6922
|
}
|
|
6766
|
-
|
|
6923
|
+
const shared = {
|
|
6924
|
+
displayName: input.displayName,
|
|
6925
|
+
credential: { sources: input.sources, ...input.target === void 0 ? {} : { target: input.target } },
|
|
6926
|
+
...input.env === void 0 || Object.keys(input.env).length === 0 ? {} : { env: input.env }
|
|
6927
|
+
};
|
|
6928
|
+
const parsed = ProviderSchema.safeParse(
|
|
6929
|
+
kind === "codex" ? { kind, ...shared, ...isEmptyCodexConfig(input.codex) ? {} : { codex: input.codex } } : { ...shared, baseUrl: input.baseUrl }
|
|
6930
|
+
);
|
|
6931
|
+
if (!parsed.success) {
|
|
6932
|
+
throw new ConfigValidationError(providerJsonPath(paths, name), parsed.error.issues);
|
|
6933
|
+
}
|
|
6934
|
+
writeJsonAtomic(providerJsonPath(paths, name), parsed.data);
|
|
6935
|
+
return parsed.data;
|
|
6767
6936
|
}
|
|
6768
|
-
function
|
|
6769
|
-
|
|
6770
|
-
|
|
6937
|
+
function updateProvider(paths, name, input) {
|
|
6938
|
+
const existing = readProvider(paths, name);
|
|
6939
|
+
if (existing === void 0) {
|
|
6940
|
+
throw new ProviderNotFoundError(name);
|
|
6771
6941
|
}
|
|
6772
|
-
const
|
|
6773
|
-
const
|
|
6774
|
-
const
|
|
6775
|
-
const
|
|
6776
|
-
|
|
6777
|
-
|
|
6778
|
-
|
|
6779
|
-
|
|
6780
|
-
|
|
6781
|
-
|
|
6782
|
-
|
|
6783
|
-
...
|
|
6784
|
-
|
|
6942
|
+
const unset = new Set(input.unsetEnv);
|
|
6943
|
+
const env = Object.fromEntries(Object.entries({ ...existing.env, ...input.env }).filter(([key]) => !unset.has(key)));
|
|
6944
|
+
const target = input.target ?? existing.credential.target;
|
|
6945
|
+
const cache = input.cache === void 0 ? existing.credential.cache : input.cache === false ? void 0 : input.cache;
|
|
6946
|
+
if (isCodexProvider(existing) && input.baseUrl !== void 0) {
|
|
6947
|
+
throw new ProviderKindMismatchError(`Provider "${name}" is a codex provider, which has no base URL.`);
|
|
6948
|
+
}
|
|
6949
|
+
if (!isCodexProvider(existing) && !isEmptyCodexConfig(input.codex)) {
|
|
6950
|
+
throw new ProviderKindMismatchError(`Provider "${name}" is an http provider; codex settings apply only to a codex provider.`);
|
|
6951
|
+
}
|
|
6952
|
+
const shared = {
|
|
6953
|
+
...input.displayName === void 0 ? {} : { displayName: input.displayName },
|
|
6954
|
+
credential: {
|
|
6955
|
+
sources: input.sources ?? existing.credential.sources,
|
|
6956
|
+
...target === void 0 ? {} : { target },
|
|
6957
|
+
...cache === void 0 ? {} : { cache }
|
|
6958
|
+
},
|
|
6959
|
+
env: Object.keys(env).length === 0 ? void 0 : env
|
|
6785
6960
|
};
|
|
6786
|
-
|
|
6787
|
-
|
|
6788
|
-
|
|
6789
|
-
|
|
6790
|
-
|
|
6791
|
-
|
|
6792
|
-
|
|
6793
|
-
|
|
6794
|
-
|
|
6795
|
-
}
|
|
6796
|
-
var ErrorObjectSchema = import_zod8.z.looseObject({
|
|
6797
|
-
type: import_zod8.z.string().optional(),
|
|
6798
|
-
code: import_zod8.z.union([import_zod8.z.string(), import_zod8.z.number()]).optional(),
|
|
6799
|
-
message: import_zod8.z.string().optional()
|
|
6800
|
-
});
|
|
6801
|
-
|
|
6802
|
-
// src/usage/middleware.ts
|
|
6803
|
-
var ANTHROPIC_PROVIDER = "anthropic";
|
|
6804
|
-
|
|
6805
|
-
// src/usage/pick.ts
|
|
6806
|
-
var MS_PER_SECOND4 = 1e3;
|
|
6807
|
-
var MS_PER_HOUR = 36e5;
|
|
6808
|
-
var HOURS_PER_DAY2 = 24;
|
|
6809
|
-
var FIVE_HOURS = 5;
|
|
6810
|
-
var PROMPT_CACHE_TTL_HOURS = 1;
|
|
6811
|
-
var PERCENT = 100;
|
|
6812
|
-
var SEVEN_DAYS = 7;
|
|
6813
|
-
var FIVE_HOUR_WINDOW_MS = FIVE_HOURS * MS_PER_HOUR;
|
|
6814
|
-
var SEVEN_DAY_WINDOW_MS = SEVEN_DAYS * HOURS_PER_DAY2 * MS_PER_HOUR;
|
|
6815
|
-
var PROMPT_CACHE_TTL_MS = PROMPT_CACHE_TTL_HOURS * MS_PER_HOUR;
|
|
6816
|
-
var CLASS_ORDER = { scored: 0, unknown: 1, "pay-per-use": 2, ineligible: 3 };
|
|
6817
|
-
function unifiedOf(state) {
|
|
6818
|
-
return state?.rateLimit?.unified;
|
|
6819
|
-
}
|
|
6820
|
-
function limitBlockedUntil(state, nowMs) {
|
|
6821
|
-
const limit = state?.lastLimit;
|
|
6822
|
-
if (state === void 0 || limit === void 0) {
|
|
6823
|
-
return void 0;
|
|
6961
|
+
let candidate;
|
|
6962
|
+
if (isCodexProvider(existing)) {
|
|
6963
|
+
const codex = {
|
|
6964
|
+
...existing.codex,
|
|
6965
|
+
...input.codex,
|
|
6966
|
+
...existing.codex?.models === void 0 && input.codex?.models === void 0 ? {} : { models: { ...existing.codex?.models, ...input.codex?.models } }
|
|
6967
|
+
};
|
|
6968
|
+
candidate = { ...existing, ...shared, codex: isEmptyCodexConfig(codex) ? void 0 : codex };
|
|
6969
|
+
} else {
|
|
6970
|
+
candidate = { ...existing, ...shared, ...input.baseUrl === void 0 ? {} : { baseUrl: input.baseUrl } };
|
|
6824
6971
|
}
|
|
6825
|
-
|
|
6826
|
-
|
|
6972
|
+
const parsed = ProviderSchema.safeParse(candidate);
|
|
6973
|
+
if (!parsed.success) {
|
|
6974
|
+
throw new ConfigValidationError(providerJsonPath(paths, name), parsed.error.issues);
|
|
6827
6975
|
}
|
|
6828
|
-
|
|
6829
|
-
return
|
|
6976
|
+
writeJsonAtomic(providerJsonPath(paths, name), parsed.data);
|
|
6977
|
+
return parsed.data;
|
|
6830
6978
|
}
|
|
6831
|
-
function
|
|
6832
|
-
|
|
6833
|
-
|
|
6979
|
+
function removeProvider(paths, name) {
|
|
6980
|
+
if (!providerExists(paths, name)) {
|
|
6981
|
+
throw new ProviderNotFoundError(name);
|
|
6982
|
+
}
|
|
6983
|
+
import_node_fs5.default.rmSync(providerJsonPath(paths, name));
|
|
6834
6984
|
}
|
|
6835
|
-
function
|
|
6836
|
-
|
|
6837
|
-
for (const
|
|
6838
|
-
|
|
6839
|
-
|
|
6840
|
-
points.push({ resetsAt: window.resetsAt, point: { atMs: Date.parse(record.at), utilization: window.utilization } });
|
|
6985
|
+
function cascadeProviderName(cascade) {
|
|
6986
|
+
let name;
|
|
6987
|
+
for (const layer of assembleCascade(cascade).layers) {
|
|
6988
|
+
if (layer.launch?.provider !== void 0) {
|
|
6989
|
+
name = layer.launch.provider;
|
|
6841
6990
|
}
|
|
6842
6991
|
}
|
|
6843
|
-
|
|
6844
|
-
|
|
6845
|
-
|
|
6846
|
-
const
|
|
6847
|
-
|
|
6992
|
+
return name;
|
|
6993
|
+
}
|
|
6994
|
+
function resolveProvider(params) {
|
|
6995
|
+
const cliName = params.cliProvider !== void 0 && params.cliProvider !== "" ? params.cliProvider : void 0;
|
|
6996
|
+
const name = cliName ?? (params.cascade === void 0 ? void 0 : cascadeProviderName(params.cascade));
|
|
6997
|
+
if (name === void 0) {
|
|
6848
6998
|
return void 0;
|
|
6849
6999
|
}
|
|
6850
|
-
|
|
7000
|
+
const definition = loadProvider(params.paths.providersDir, name, params.port);
|
|
7001
|
+
if (definition === void 0) {
|
|
7002
|
+
const known = listProviderNames(params.port.readdir, params.paths.providersDir);
|
|
7003
|
+
return {
|
|
7004
|
+
ok: false,
|
|
7005
|
+
status: 1,
|
|
7006
|
+
message: `agent-shim: no provider named "${name}". ` + (known.length > 0 ? `Known providers: ${known.join(", ")}.` : "No providers are defined yet; run `agent-shim provider add`.")
|
|
7007
|
+
};
|
|
7008
|
+
}
|
|
7009
|
+
if (params.credentials === void 0) {
|
|
7010
|
+
return { ok: false, status: 1, message: `agent-shim: provider ${name} needs its credential resolved, but this launcher has no credential port wired` };
|
|
7011
|
+
}
|
|
7012
|
+
const resolution = resolveCredential({ credential: definition.credential, env: params.env, port: params.credentials, subject: `provider ${name}` });
|
|
7013
|
+
if (!resolution.ok) {
|
|
7014
|
+
return { ok: false, status: CREDENTIAL_UNAVAILABLE_EXIT, message: resolution.message };
|
|
7015
|
+
}
|
|
7016
|
+
return { ok: true, provider: { name, definition, credential: resolution.credential }, warnings: resolution.credential.warnings };
|
|
6851
7017
|
}
|
|
6852
|
-
|
|
6853
|
-
|
|
7018
|
+
|
|
7019
|
+
// src/directoryRulesStore.ts
|
|
7020
|
+
var DirectoryRuleNotFoundError = class extends CliError {
|
|
7021
|
+
constructor(rulePath) {
|
|
7022
|
+
super(`No directory rule found for path "${rulePath}".`);
|
|
7023
|
+
this.rulePath = rulePath;
|
|
7024
|
+
this.name = "DirectoryRuleNotFoundError";
|
|
7025
|
+
}
|
|
7026
|
+
rulePath;
|
|
7027
|
+
};
|
|
7028
|
+
var DirectoryRuleMissingTargetError = class extends CliError {
|
|
7029
|
+
constructor() {
|
|
7030
|
+
super("A directory rule must set at least one of --config-profile or --identity.");
|
|
7031
|
+
this.name = "DirectoryRuleMissingTargetError";
|
|
7032
|
+
}
|
|
7033
|
+
};
|
|
7034
|
+
var DirectoryRuleAlreadyExistsError = class extends CliError {
|
|
7035
|
+
constructor(rulePath) {
|
|
7036
|
+
super(`A directory rule for path "${rulePath}" already exists. Use \`agent-shim rule set\` to change it.`);
|
|
7037
|
+
this.rulePath = rulePath;
|
|
7038
|
+
this.name = "DirectoryRuleAlreadyExistsError";
|
|
7039
|
+
}
|
|
7040
|
+
rulePath;
|
|
7041
|
+
};
|
|
7042
|
+
function readDirectoryRules(paths) {
|
|
7043
|
+
return readJson(paths.directoryRulesFile, DirectoryRulesSchema) ?? { rules: [] };
|
|
6854
7044
|
}
|
|
6855
|
-
function
|
|
6856
|
-
|
|
6857
|
-
|
|
7045
|
+
function writeDirectoryRules(paths, rules) {
|
|
7046
|
+
const parsed = DirectoryRulesSchema.safeParse(rules);
|
|
7047
|
+
if (!parsed.success) {
|
|
7048
|
+
throw new ConfigValidationError(paths.directoryRulesFile, parsed.error.issues);
|
|
6858
7049
|
}
|
|
6859
|
-
|
|
6860
|
-
const resets = effective.resetsAtMs === void 0 ? "" : `, resets in ${formatAge(effective.resetsAtMs - nowMs)}`;
|
|
6861
|
-
return `${label} ${used}${resets}${window.status === "allowed_warning" ? " (nearly used)" : ""}`;
|
|
7050
|
+
writeJsonAtomic(paths.directoryRulesFile, parsed.data);
|
|
6862
7051
|
}
|
|
6863
|
-
function
|
|
6864
|
-
return
|
|
7052
|
+
function listDirectoryRules(paths) {
|
|
7053
|
+
return readDirectoryRules(paths).rules;
|
|
6865
7054
|
}
|
|
6866
|
-
function
|
|
6867
|
-
|
|
6868
|
-
|
|
6869
|
-
const base = { identity: member.identity, plan };
|
|
6870
|
-
if (member.readError !== void 0) {
|
|
6871
|
-
return { candidate: { ...base, class: "unknown", reasons: [`usage state unreadable: ${member.readError}`, ...planReasons] } };
|
|
6872
|
-
}
|
|
6873
|
-
const state = member.snapshot?.providers[ANTHROPIC_PROVIDER];
|
|
6874
|
-
const unified = unifiedOf(state);
|
|
6875
|
-
if (member.snapshot === void 0 || state === void 0 || unified === void 0) {
|
|
6876
|
-
return { candidate: { ...base, class: "unknown", reasons: ["no usage recorded yet, so its quota is unknown (turn on trackUsage for it)", ...planReasons] } };
|
|
7055
|
+
function addDirectoryRule(paths, rulePath, options) {
|
|
7056
|
+
if (options.configProfile === void 0 && options.identity === void 0) {
|
|
7057
|
+
throw new DirectoryRuleMissingTargetError();
|
|
6877
7058
|
}
|
|
6878
|
-
const
|
|
6879
|
-
|
|
6880
|
-
|
|
6881
|
-
const five = fiveHourWindow === void 0 ? void 0 : effectiveWindow(fiveHourWindow, nowMs);
|
|
6882
|
-
const seven = sevenDayWindow === void 0 ? void 0 : effectiveWindow(sevenDayWindow, nowMs);
|
|
6883
|
-
const windowReasons = [
|
|
6884
|
-
...fiveHourWindow === void 0 || five === void 0 ? [] : [describeWindow("5h", fiveHourWindow, five, nowMs)],
|
|
6885
|
-
...sevenDayWindow === void 0 || seven === void 0 ? [] : [describeWindow("7d", sevenDayWindow, seven, nowMs)]
|
|
6886
|
-
];
|
|
6887
|
-
const blockedUntil = Math.max(
|
|
6888
|
-
windowBlockedUntil([five, seven].flatMap((window) => window === void 0 ? [] : [window])) ?? 0,
|
|
6889
|
-
limitBlockedUntil(state, nowMs) ?? 0
|
|
6890
|
-
);
|
|
6891
|
-
if (blockedUntil > nowMs) {
|
|
6892
|
-
if (unified.overageStatus === "allowed") {
|
|
6893
|
-
return { candidate: { ...base, class: "pay-per-use", reasons: [`plan exhausted until ${new Date(blockedUntil).toISOString()}, continues as extra usage`, ...windowReasons, ...planReasons] } };
|
|
6894
|
-
}
|
|
6895
|
-
return { candidate: { ...base, class: "ineligible", blockedUntilMs: blockedUntil, reasons: [`refused until ${new Date(blockedUntil).toISOString()} (in ${formatAge(blockedUntil - nowMs)})`, ...windowReasons, ...planReasons] } };
|
|
7059
|
+
const current = readDirectoryRules(paths);
|
|
7060
|
+
if (current.rules.some((rule) => rule.path === rulePath)) {
|
|
7061
|
+
throw new DirectoryRuleAlreadyExistsError(rulePath);
|
|
6896
7062
|
}
|
|
6897
|
-
|
|
6898
|
-
|
|
7063
|
+
const created = buildNewRule(rulePath, options);
|
|
7064
|
+
writeDirectoryRules(paths, { ...current, rules: [...current.rules, created] });
|
|
7065
|
+
return created;
|
|
7066
|
+
}
|
|
7067
|
+
function ruleHasEffect(rule) {
|
|
7068
|
+
return rule.configProfile !== void 0 || rule.identity !== void 0 || rule.categories !== void 0 || rule.entries !== void 0 || rule.launch !== void 0;
|
|
7069
|
+
}
|
|
7070
|
+
function updateDirectoryRule(paths, rulePath, options) {
|
|
7071
|
+
const current = readDirectoryRules(paths);
|
|
7072
|
+
const index = current.rules.findIndex((rule) => rule.path === rulePath);
|
|
7073
|
+
const existing = index === -1 ? void 0 : current.rules[index];
|
|
7074
|
+
if (existing === void 0) {
|
|
7075
|
+
throw new DirectoryRuleNotFoundError(rulePath);
|
|
6899
7076
|
}
|
|
6900
|
-
const
|
|
6901
|
-
|
|
6902
|
-
|
|
7077
|
+
const { configProfile, identity, ...rest } = existing;
|
|
7078
|
+
const nextConfigProfile = options.configProfile === void 0 ? configProfile : options.configProfile === false ? void 0 : options.configProfile;
|
|
7079
|
+
const nextIdentity = options.identity === void 0 ? identity : options.identity === false ? void 0 : options.identity;
|
|
7080
|
+
const updated = {
|
|
7081
|
+
...rest,
|
|
7082
|
+
...nextConfigProfile === void 0 ? {} : { configProfile: nextConfigProfile },
|
|
7083
|
+
...nextIdentity === void 0 ? {} : { identity: nextIdentity }
|
|
7084
|
+
};
|
|
7085
|
+
if (!ruleHasEffect(updated)) {
|
|
7086
|
+
throw new DirectoryRuleMissingTargetError();
|
|
6903
7087
|
}
|
|
6904
|
-
const
|
|
6905
|
-
|
|
6906
|
-
|
|
6907
|
-
|
|
6908
|
-
|
|
6909
|
-
|
|
7088
|
+
const nextRules = [...current.rules];
|
|
7089
|
+
nextRules[index] = updated;
|
|
7090
|
+
writeDirectoryRules(paths, { ...current, rules: nextRules });
|
|
7091
|
+
return updated;
|
|
7092
|
+
}
|
|
7093
|
+
function buildNewRule(rulePath, options) {
|
|
6910
7094
|
return {
|
|
6911
|
-
|
|
6912
|
-
...
|
|
6913
|
-
...
|
|
7095
|
+
path: rulePath,
|
|
7096
|
+
...options.configProfile !== void 0 ? { configProfile: options.configProfile } : {},
|
|
7097
|
+
...options.identity !== void 0 ? { identity: options.identity } : {}
|
|
6914
7098
|
};
|
|
6915
7099
|
}
|
|
6916
|
-
function
|
|
6917
|
-
const
|
|
6918
|
-
const
|
|
6919
|
-
|
|
6920
|
-
|
|
6921
|
-
const candidates = assessments.map((assessment) => {
|
|
6922
|
-
const { candidate, fiveHour, burn } = assessment;
|
|
6923
|
-
const pace = burn ?? (sharedDemand === void 0 ? void 0 : sharedDemand / capacityOf(candidate.plan));
|
|
6924
|
-
if (candidate.class !== "scored" || fiveHour === void 0 || pace === void 0) {
|
|
6925
|
-
return { ...candidate, feasible: true };
|
|
6926
|
-
}
|
|
6927
|
-
const runsDryInMs = fiveHour.remaining / pace;
|
|
6928
|
-
if (runsDryInMs >= fiveHour.untilResetMs) {
|
|
6929
|
-
return { ...candidate, feasible: true };
|
|
6930
|
-
}
|
|
6931
|
-
return { ...candidate, feasible: false, reasons: [`5h window would run dry in ${formatAge(runsDryInMs)}, before it resets in ${formatAge(fiveHour.untilResetMs)}`, ...candidate.reasons] };
|
|
6932
|
-
});
|
|
6933
|
-
const ordered = [...candidates].sort(
|
|
6934
|
-
(left, right) => CLASS_ORDER[left.class] - CLASS_ORDER[right.class] || Number(right.feasible) - Number(left.feasible) || (right.score ?? 0) - (left.score ?? 0) || left.identity.localeCompare(right.identity)
|
|
6935
|
-
);
|
|
6936
|
-
const sticky = input.sticky;
|
|
6937
|
-
const stickyIndex = sticky === void 0 ? -1 : ordered.findIndex((candidate) => candidate.identity === sticky.identity);
|
|
6938
|
-
const stickyCandidate = ordered[stickyIndex];
|
|
6939
|
-
if (sticky !== void 0 && stickyCandidate?.class === "scored" && stickyCandidate.feasible) {
|
|
6940
|
-
const ageMs = nowMs - Date.parse(sticky.at);
|
|
6941
|
-
const warm = ageMs <= PROMPT_CACHE_TTL_MS;
|
|
6942
|
-
if (input.resuming || warm) {
|
|
6943
|
-
const why = warm ? `used here ${formatAge(ageMs)} ago, prompt cache still warm` : "resuming a conversation started on this account";
|
|
6944
|
-
ordered.splice(stickyIndex, 1);
|
|
6945
|
-
ordered.unshift({ ...stickyCandidate, reasons: [why, ...stickyCandidate.reasons] });
|
|
6946
|
-
}
|
|
7100
|
+
function removeDirectoryRule(paths, rulePath) {
|
|
7101
|
+
const current = readDirectoryRules(paths);
|
|
7102
|
+
const nextRules = current.rules.filter((rule) => rule.path !== rulePath);
|
|
7103
|
+
if (nextRules.length === current.rules.length) {
|
|
7104
|
+
throw new DirectoryRuleNotFoundError(rulePath);
|
|
6947
7105
|
}
|
|
6948
|
-
|
|
6949
|
-
const returns = ordered.flatMap((candidate) => candidate.blockedUntilMs === void 0 ? [] : [{ identity: candidate.identity, atMs: candidate.blockedUntilMs }]);
|
|
6950
|
-
const earliestReturn = returns.length === 0 ? void 0 : returns.reduce((soonest, entry) => entry.atMs < soonest.atMs ? entry : soonest);
|
|
6951
|
-
return {
|
|
6952
|
-
candidates: ordered,
|
|
6953
|
-
...pick === void 0 ? { ...earliestReturn === void 0 ? {} : { earliestReturn } } : { pick }
|
|
6954
|
-
};
|
|
7106
|
+
writeDirectoryRules(paths, { ...current, rules: nextRules });
|
|
6955
7107
|
}
|
|
6956
7108
|
|
|
6957
|
-
// src/
|
|
6958
|
-
var
|
|
6959
|
-
var DAYS_IN_WEEK = 7;
|
|
6960
|
-
var USAGE_RETENTION_MS = DAYS_IN_WEEK * DAY_MS2;
|
|
7109
|
+
// src/checkReport.ts
|
|
7110
|
+
var import_node_os4 = __toESM(require("node:os"), 1);
|
|
6961
7111
|
|
|
6962
|
-
// src/
|
|
6963
|
-
var
|
|
6964
|
-
|
|
6965
|
-
|
|
6966
|
-
|
|
6967
|
-
|
|
6968
|
-
|
|
6969
|
-
|
|
6970
|
-
return error instanceof Error ? error.message : String(error);
|
|
6971
|
-
}
|
|
6972
|
-
function loadPoolMembers(fs12, paths, identities, nowMs) {
|
|
6973
|
-
const windowStartMs = nowMs - FIVE_HOUR_WINDOW_MS;
|
|
6974
|
-
const log = readUsageLog(fs12, paths.usageLogDir, { sinceMs: windowStartMs });
|
|
6975
|
-
return identities.map((identity) => {
|
|
6976
|
-
const records = log.records.filter((record) => record.identity === identity && record.provider === ANTHROPIC_PROVIDER && Date.parse(record.at) >= windowStartMs);
|
|
6977
|
-
try {
|
|
6978
|
-
const snapshot = readUsageSnapshot(fs12, paths.usageSnapshotsDir, identity);
|
|
6979
|
-
const account = readAccountMetadata(fs12, paths.identitiesDir, identity) ?? snapshot?.account;
|
|
6980
|
-
return { identity, records, ...snapshot === void 0 ? {} : { snapshot }, ...account === void 0 ? {} : { account } };
|
|
6981
|
-
} catch (error) {
|
|
6982
|
-
if (error instanceof UsageSnapshotError || error instanceof AccountMetadataError) {
|
|
6983
|
-
return { identity, records, readError: errorMessage(error) };
|
|
6984
|
-
}
|
|
6985
|
-
throw error;
|
|
6986
|
-
}
|
|
6987
|
-
});
|
|
6988
|
-
}
|
|
6989
|
-
function rankPoolFromStore(params) {
|
|
6990
|
-
return rankPool({
|
|
6991
|
-
members: loadPoolMembers(params.fs, params.paths, params.identities, params.nowMs),
|
|
6992
|
-
nowMs: params.nowMs,
|
|
6993
|
-
resuming: params.resuming,
|
|
6994
|
-
...params.sticky === void 0 ? {} : { sticky: params.sticky }
|
|
6995
|
-
});
|
|
6996
|
-
}
|
|
6997
|
-
function readPicksFile(fs12, file) {
|
|
6998
|
-
const empty = { schemaVersion: SCHEMA_VERSION, picks: {} };
|
|
6999
|
-
const raw = fs12.readFileUtf8(file);
|
|
7000
|
-
if (raw === void 0) {
|
|
7001
|
-
return { file: empty };
|
|
7112
|
+
// src/launcher/cascade.ts
|
|
7113
|
+
var import_node_path19 = __toESM(require("node:path"), 1);
|
|
7114
|
+
|
|
7115
|
+
// src/pathNorm.ts
|
|
7116
|
+
var import_node_path18 = __toESM(require("node:path"), 1);
|
|
7117
|
+
function expandTilde(value, home) {
|
|
7118
|
+
if (value === "~") {
|
|
7119
|
+
return home;
|
|
7002
7120
|
}
|
|
7003
|
-
|
|
7004
|
-
|
|
7005
|
-
parsed = JSON.parse(raw);
|
|
7006
|
-
} catch {
|
|
7007
|
-
return { file: empty, problem: `${file} is not valid JSON` };
|
|
7121
|
+
if (value.startsWith("~/")) {
|
|
7122
|
+
return import_node_path18.default.join(home, value.slice(2));
|
|
7008
7123
|
}
|
|
7009
|
-
|
|
7010
|
-
return result.success ? { file: result.data } : { file: empty, problem: `${file} is not a picks file this agent-shim can read` };
|
|
7011
|
-
}
|
|
7012
|
-
function readStickyPick(fs12, picksFile, directory) {
|
|
7013
|
-
const read = readPicksFile(fs12, picksFile);
|
|
7014
|
-
const entry = read.file.picks[directory];
|
|
7015
|
-
return { ...entry === void 0 ? {} : { sticky: entry }, ...read.problem === void 0 ? {} : { problem: read.problem } };
|
|
7124
|
+
return value;
|
|
7016
7125
|
}
|
|
7017
|
-
function
|
|
7018
|
-
|
|
7019
|
-
const kept = Object.entries(current).filter(([, entry]) => nowMs - Date.parse(entry.at) <= USAGE_RETENTION_MS);
|
|
7020
|
-
const next = { schemaVersion: SCHEMA_VERSION, picks: { ...Object.fromEntries(kept), [directory]: { identity, at: new Date(nowMs).toISOString() } } };
|
|
7021
|
-
fs12.mkdirPrivate(import_node_path19.default.dirname(picksFile));
|
|
7022
|
-
fs12.writeFilePrivate(picksFile, `${JSON.stringify(next, null, 2)}
|
|
7023
|
-
`);
|
|
7126
|
+
function normaliseRulePath(rulePath, home) {
|
|
7127
|
+
return import_node_path18.default.resolve(expandTilde(rulePath, home));
|
|
7024
7128
|
}
|
|
7025
7129
|
|
|
7026
|
-
// src/launcher/
|
|
7027
|
-
var
|
|
7028
|
-
var
|
|
7029
|
-
|
|
7030
|
-
|
|
7031
|
-
const
|
|
7032
|
-
|
|
7033
|
-
}
|
|
7034
|
-
|
|
7035
|
-
|
|
7036
|
-
|
|
7037
|
-
}
|
|
7038
|
-
function resolvePoolLaunch(params) {
|
|
7039
|
-
const { poolName, log } = params;
|
|
7040
|
-
const pool = params.pools?.[poolName];
|
|
7041
|
-
if (pool === void 0) {
|
|
7042
|
-
return { ok: false, message: `agent-shim: no pool named "${poolName}" (selected via ${params.selectedVia}). Run \`agent-shim pool add ${poolName} --identity <name>...\` first.` };
|
|
7043
|
-
}
|
|
7044
|
-
const { present: identities, missing } = splitMembers(pool, params.paths, params.fs);
|
|
7045
|
-
for (const name of missing) {
|
|
7046
|
-
log.warn(`agent-shim: pool "${poolName}" names identity "${name}", which does not exist; skipping it`);
|
|
7047
|
-
}
|
|
7048
|
-
if (identities.length === 0) {
|
|
7049
|
-
return { ok: false, message: `agent-shim: no member of pool "${poolName}" is an existing identity.` };
|
|
7050
|
-
}
|
|
7051
|
-
const resuming = isResuming(params.passthrough);
|
|
7052
|
-
const stickyRead = readStickyPick(params.usageFs, params.paths.usagePicksFile, params.cwd);
|
|
7053
|
-
if (stickyRead.problem !== void 0) {
|
|
7054
|
-
log.warn(`agent-shim: ${stickyRead.problem}; ignoring the last-pick record`);
|
|
7055
|
-
}
|
|
7056
|
-
for (; ; ) {
|
|
7057
|
-
const nowMs = params.now();
|
|
7058
|
-
const ranking = rankPoolFromStore({ fs: params.usageFs, paths: params.paths, identities, nowMs, resuming, ...stickyRead.sticky === void 0 ? {} : { sticky: stickyRead.sticky } });
|
|
7059
|
-
const { pick, earliestReturn } = ranking;
|
|
7060
|
-
if (pick !== void 0) {
|
|
7061
|
-
recordStickyPick(params.usageFs, params.paths.usagePicksFile, params.cwd, pick.identity, nowMs);
|
|
7062
|
-
return { ok: true, identity: pick.identity, explanation: `pool ${poolName}: ${pick.reasons.slice(0, REASONS_LOGGED).join("; ")}` };
|
|
7063
|
-
}
|
|
7064
|
-
if (earliestReturn === void 0) {
|
|
7065
|
-
return { ok: false, message: `agent-shim: no member of pool "${poolName}" can be picked.` };
|
|
7130
|
+
// src/launcher/cascade.ts
|
|
7131
|
+
var PORTABLE_CONFIG_FILENAME = ".agent-shim.json";
|
|
7132
|
+
var PORTABLE_LOCAL_CONFIG_FILENAME = ".agent-shim.local.json";
|
|
7133
|
+
function loadCascadeInput(params) {
|
|
7134
|
+
const globalConfig = loadConfigFile(params.paths.globalConfigFile, GlobalConfigSchema, params.read);
|
|
7135
|
+
const directoryRules = loadConfigFile(params.paths.directoryRulesFile, DirectoryRulesSchema, params.read);
|
|
7136
|
+
const loadProfile = (name) => {
|
|
7137
|
+
const filepath = import_node_path19.default.join(params.paths.configProfilesDir, `${name}.json`);
|
|
7138
|
+
const loaded = loadConfigFile(filepath, ConfigProfileSchema, params.read);
|
|
7139
|
+
if (loaded === void 0) {
|
|
7140
|
+
return void 0;
|
|
7066
7141
|
}
|
|
7067
|
-
|
|
7068
|
-
|
|
7142
|
+
return { name, profile: loaded.config, entryOrder: loaded.entryOrder, filepath: loaded.filepath };
|
|
7143
|
+
};
|
|
7144
|
+
const limit = globalConfig?.config.walkUpLimit;
|
|
7145
|
+
const dirs = walkDirectoryAncestors(params.cwd, {
|
|
7146
|
+
home: params.home,
|
|
7147
|
+
...limit === void 0 ? {} : { limit: expandTilde(limit, params.home) },
|
|
7148
|
+
...params.isReadable === void 0 ? {} : { isReadable: params.isReadable }
|
|
7149
|
+
});
|
|
7150
|
+
const levels = [];
|
|
7151
|
+
for (const dir of dirs) {
|
|
7152
|
+
const portable = loadConfigFile(import_node_path19.default.join(dir, PORTABLE_CONFIG_FILENAME), PortableConfigSchema, params.read) ?? loadConfigFile(import_node_path19.default.join(dir, LEGACY_PORTABLE_CONFIG_FILENAME), PortableConfigSchema, params.read);
|
|
7153
|
+
const portableLocal = loadConfigFile(import_node_path19.default.join(dir, PORTABLE_LOCAL_CONFIG_FILENAME), PortableConfigSchema, params.read) ?? loadConfigFile(import_node_path19.default.join(dir, LEGACY_PORTABLE_LOCAL_CONFIG_FILENAME), PortableConfigSchema, params.read);
|
|
7154
|
+
const rules = (directoryRules?.config.rules ?? []).map((rule, index) => ({ rule, index })).filter(({ rule }) => normaliseRulePath(rule.path, params.home) === dir).map(({ rule, index }) => {
|
|
7155
|
+
const entryOrder = directoryRules?.ruleEntryOrders[index];
|
|
7069
7156
|
return {
|
|
7070
|
-
|
|
7071
|
-
|
|
7157
|
+
rule,
|
|
7158
|
+
...entryOrder === void 0 ? {} : { entryOrder },
|
|
7159
|
+
filepath: params.paths.directoryRulesFile
|
|
7072
7160
|
};
|
|
7161
|
+
});
|
|
7162
|
+
if (portable === void 0 && portableLocal === void 0 && rules.length === 0) {
|
|
7163
|
+
continue;
|
|
7164
|
+
}
|
|
7165
|
+
levels.push({
|
|
7166
|
+
dir,
|
|
7167
|
+
...portable === void 0 ? {} : { portable: { config: portable.config, entryOrder: portable.entryOrder, filepath: portable.filepath } },
|
|
7168
|
+
...rules.length === 0 ? {} : { rules },
|
|
7169
|
+
...portableLocal === void 0 ? {} : { portableLocal: { config: portableLocal.config, entryOrder: portableLocal.entryOrder, filepath: portableLocal.filepath } }
|
|
7170
|
+
});
|
|
7171
|
+
}
|
|
7172
|
+
const input = {
|
|
7173
|
+
home: params.home,
|
|
7174
|
+
...globalConfig === void 0 ? {} : { globalConfig: { config: globalConfig.config, entryOrder: globalConfig.entryOrder, filepath: globalConfig.filepath } },
|
|
7175
|
+
...params.baseConfigProfile === void 0 ? {} : { baseConfigProfile: params.baseConfigProfile },
|
|
7176
|
+
loadProfile,
|
|
7177
|
+
levels,
|
|
7178
|
+
...params.cliOverride === void 0 ? {} : { cliOverride: params.cliOverride }
|
|
7179
|
+
};
|
|
7180
|
+
return { input, ...globalConfig === void 0 ? {} : { globalConfig: globalConfig.config } };
|
|
7181
|
+
}
|
|
7182
|
+
function readDirectorySelections(loaded) {
|
|
7183
|
+
let identity;
|
|
7184
|
+
let configProfile;
|
|
7185
|
+
for (const level of loaded.input.levels ?? []) {
|
|
7186
|
+
for (const source of [level.portable?.config, ...(level.rules ?? []).map((entry) => entry.rule), level.portableLocal?.config]) {
|
|
7187
|
+
if (source === void 0) {
|
|
7188
|
+
continue;
|
|
7189
|
+
}
|
|
7190
|
+
if (source.identity !== void 0) {
|
|
7191
|
+
identity = source.identity;
|
|
7192
|
+
}
|
|
7193
|
+
if (source.configProfile !== void 0) {
|
|
7194
|
+
configProfile = source.configProfile;
|
|
7195
|
+
}
|
|
7073
7196
|
}
|
|
7074
|
-
log.info(`agent-shim: every member of pool "${poolName}" is refused; waiting until ${until} for ${earliestReturn.identity}`);
|
|
7075
|
-
params.sleep(Math.max(earliestReturn.atMs - nowMs, 0));
|
|
7076
7197
|
}
|
|
7198
|
+
return { ...identity === void 0 ? {} : { identity }, ...configProfile === void 0 ? {} : { configProfile } };
|
|
7077
7199
|
}
|
|
7078
7200
|
|
|
7079
|
-
// src/
|
|
7080
|
-
|
|
7081
|
-
|
|
7082
|
-
|
|
7083
|
-
|
|
7084
|
-
|
|
7085
|
-
|
|
7086
|
-
|
|
7087
|
-
|
|
7088
|
-
reasons: candidate.reasons
|
|
7089
|
-
};
|
|
7201
|
+
// src/realCredentialCache.ts
|
|
7202
|
+
var import_node_child_process = require("node:child_process");
|
|
7203
|
+
var import_node_fs6 = __toESM(require("node:fs"), 1);
|
|
7204
|
+
var import_node_path20 = __toESM(require("node:path"), 1);
|
|
7205
|
+
var KEYCHAIN_CACHE_SERVICE = "agent-shim-credential-cache";
|
|
7206
|
+
var CACHE_DIR_MODE = 448;
|
|
7207
|
+
var CACHE_FILE_MODE = 384;
|
|
7208
|
+
function cacheFileNameFor(owner) {
|
|
7209
|
+
return `${owner.replace(/[^A-Za-z0-9._-]/g, "_")}.json`;
|
|
7090
7210
|
}
|
|
7091
|
-
function
|
|
7092
|
-
|
|
7093
|
-
|
|
7094
|
-
|
|
7095
|
-
|
|
7096
|
-
|
|
7097
|
-
|
|
7098
|
-
|
|
7099
|
-
|
|
7100
|
-
|
|
7101
|
-
|
|
7211
|
+
function parseEntry(raw) {
|
|
7212
|
+
let json;
|
|
7213
|
+
try {
|
|
7214
|
+
json = JSON.parse(raw);
|
|
7215
|
+
} catch {
|
|
7216
|
+
return void 0;
|
|
7217
|
+
}
|
|
7218
|
+
const parsed = CachedCredentialSchema.safeParse(json);
|
|
7219
|
+
return parsed.success ? parsed.data : void 0;
|
|
7220
|
+
}
|
|
7221
|
+
function requireKeychain() {
|
|
7222
|
+
if (process.platform !== "darwin") {
|
|
7223
|
+
throw new Error("the keychain credential store needs macOS; use --credential-cache-store file");
|
|
7224
|
+
}
|
|
7225
|
+
}
|
|
7226
|
+
function security(args, stdin) {
|
|
7227
|
+
const result = (0, import_node_child_process.spawnSync)("security", args, { encoding: "utf8", ...stdin === void 0 ? {} : { input: stdin }, stdio: ["pipe", "pipe", "ignore"] });
|
|
7228
|
+
return { status: result.status, stdout: result.stdout };
|
|
7229
|
+
}
|
|
7230
|
+
function createRealCredentialCache(root) {
|
|
7231
|
+
const dir = import_node_path20.default.join(root, "credential-cache");
|
|
7232
|
+
const filePath = (owner) => import_node_path20.default.join(dir, cacheFileNameFor(owner));
|
|
7102
7233
|
return {
|
|
7103
|
-
|
|
7104
|
-
|
|
7105
|
-
|
|
7106
|
-
|
|
7107
|
-
|
|
7108
|
-
|
|
7109
|
-
|
|
7234
|
+
read(store, owner) {
|
|
7235
|
+
if (store === "file") {
|
|
7236
|
+
try {
|
|
7237
|
+
return parseEntry(import_node_fs6.default.readFileSync(filePath(owner), "utf8"));
|
|
7238
|
+
} catch {
|
|
7239
|
+
return void 0;
|
|
7240
|
+
}
|
|
7241
|
+
}
|
|
7242
|
+
requireKeychain();
|
|
7243
|
+
const result = security(["find-generic-password", "-s", KEYCHAIN_CACHE_SERVICE, "-a", owner, "-w"]);
|
|
7244
|
+
return result.status === 0 ? parseEntry(Buffer.from(result.stdout.trim(), "base64").toString("utf8")) : void 0;
|
|
7245
|
+
},
|
|
7246
|
+
write(store, owner, entry) {
|
|
7247
|
+
const serialised = JSON.stringify(entry);
|
|
7248
|
+
if (store === "file") {
|
|
7249
|
+
import_node_fs6.default.mkdirSync(dir, { recursive: true, mode: CACHE_DIR_MODE });
|
|
7250
|
+
import_node_fs6.default.chmodSync(dir, CACHE_DIR_MODE);
|
|
7251
|
+
const target = filePath(owner);
|
|
7252
|
+
const temp = `${target}.${String(process.pid)}.tmp`;
|
|
7253
|
+
import_node_fs6.default.writeFileSync(temp, serialised, { mode: CACHE_FILE_MODE });
|
|
7254
|
+
import_node_fs6.default.renameSync(temp, target);
|
|
7255
|
+
return;
|
|
7256
|
+
}
|
|
7257
|
+
requireKeychain();
|
|
7258
|
+
const encoded = Buffer.from(serialised, "utf8").toString("base64");
|
|
7259
|
+
const result = security(["-i"], `add-generic-password -U -s ${KEYCHAIN_CACHE_SERVICE} -a ${JSON.stringify(owner)} -w ${encoded}
|
|
7260
|
+
`);
|
|
7261
|
+
if (result.status !== 0) {
|
|
7262
|
+
throw new Error(`could not write the keychain credential cache for ${owner}`);
|
|
7263
|
+
}
|
|
7264
|
+
},
|
|
7265
|
+
remove(store, owner) {
|
|
7266
|
+
if (store === "file") {
|
|
7267
|
+
import_node_fs6.default.rmSync(filePath(owner), { force: true });
|
|
7268
|
+
return;
|
|
7269
|
+
}
|
|
7270
|
+
requireKeychain();
|
|
7271
|
+
security(["delete-generic-password", "-s", KEYCHAIN_CACHE_SERVICE, "-a", owner]);
|
|
7272
|
+
}
|
|
7110
7273
|
};
|
|
7111
7274
|
}
|
|
7275
|
+
function realCredentialCacheEnv(paths) {
|
|
7276
|
+
return { port: createRealCredentialCache(paths.root), platform: process.platform, now: () => Date.now() };
|
|
7277
|
+
}
|
|
7112
7278
|
|
|
7113
7279
|
// src/realPorts.ts
|
|
7114
|
-
var
|
|
7280
|
+
var import_node_child_process2 = require("node:child_process");
|
|
7115
7281
|
var import_node_crypto9 = require("node:crypto");
|
|
7116
|
-
var
|
|
7282
|
+
var import_node_fs7 = __toESM(require("node:fs"), 1);
|
|
7117
7283
|
var import_node_os3 = __toESM(require("node:os"), 1);
|
|
7118
|
-
var
|
|
7284
|
+
var import_node_path22 = __toESM(require("node:path"), 1);
|
|
7119
7285
|
var import_node_sea = require("node:sea");
|
|
7120
7286
|
|
|
7121
7287
|
// src/versionDiscovery.ts
|
|
7122
7288
|
var import_node_os2 = __toESM(require("node:os"), 1);
|
|
7123
|
-
var
|
|
7289
|
+
var import_node_path21 = __toESM(require("node:path"), 1);
|
|
7124
7290
|
function defaultVersionsDir() {
|
|
7125
|
-
return
|
|
7291
|
+
return import_node_path21.default.join(import_node_os2.default.homedir(), ".local", "share", "claude", "versions");
|
|
7126
7292
|
}
|
|
7127
7293
|
var NUMERIC_DOTTED_VERSION_RE = /^\d+(?:\.\d+)*$/;
|
|
7128
7294
|
function isNumericDottedVersion(name) {
|
|
@@ -7164,7 +7330,7 @@ function discoverClaudeBinary(options) {
|
|
|
7164
7330
|
const highestVersion = pickHighestVersion(entries);
|
|
7165
7331
|
if (highestVersion !== void 0) {
|
|
7166
7332
|
return {
|
|
7167
|
-
path:
|
|
7333
|
+
path: import_node_path21.default.join(versionsDir, highestVersion),
|
|
7168
7334
|
source: "versions-dir",
|
|
7169
7335
|
version: highestVersion
|
|
7170
7336
|
};
|
|
@@ -7187,7 +7353,7 @@ function isEnoent3(error) {
|
|
|
7187
7353
|
var realFsPort = {
|
|
7188
7354
|
readFileUtf8(filePath) {
|
|
7189
7355
|
try {
|
|
7190
|
-
return
|
|
7356
|
+
return import_node_fs7.default.readFileSync(filePath, "utf8");
|
|
7191
7357
|
} catch (error) {
|
|
7192
7358
|
if (isEnoent3(error)) {
|
|
7193
7359
|
return void 0;
|
|
@@ -7198,7 +7364,7 @@ var realFsPort = {
|
|
|
7198
7364
|
readConfigFile: cosmiconfigReader(),
|
|
7199
7365
|
readdir(dirPath) {
|
|
7200
7366
|
try {
|
|
7201
|
-
return
|
|
7367
|
+
return import_node_fs7.default.readdirSync(dirPath);
|
|
7202
7368
|
} catch (error) {
|
|
7203
7369
|
if (isEnoent3(error)) {
|
|
7204
7370
|
return [];
|
|
@@ -7217,7 +7383,7 @@ var realFarmFs = {
|
|
|
7217
7383
|
lstat(filePath) {
|
|
7218
7384
|
let stat;
|
|
7219
7385
|
try {
|
|
7220
|
-
stat =
|
|
7386
|
+
stat = import_node_fs7.default.lstatSync(filePath);
|
|
7221
7387
|
} catch (error) {
|
|
7222
7388
|
if (isEnoent3(error)) {
|
|
7223
7389
|
return void 0;
|
|
@@ -7229,7 +7395,7 @@ var realFarmFs = {
|
|
|
7229
7395
|
},
|
|
7230
7396
|
readdir(dirPath) {
|
|
7231
7397
|
try {
|
|
7232
|
-
return
|
|
7398
|
+
return import_node_fs7.default.readdirSync(dirPath);
|
|
7233
7399
|
} catch (error) {
|
|
7234
7400
|
if (isEnoent3(error) || isErrorWithCode(error, "ENOTDIR")) {
|
|
7235
7401
|
return [];
|
|
@@ -7238,23 +7404,23 @@ var realFarmFs = {
|
|
|
7238
7404
|
}
|
|
7239
7405
|
},
|
|
7240
7406
|
mkdirp(dirPath) {
|
|
7241
|
-
|
|
7407
|
+
import_node_fs7.default.mkdirSync(dirPath, { recursive: true });
|
|
7242
7408
|
},
|
|
7243
7409
|
symlink(target, linkPath) {
|
|
7244
|
-
|
|
7410
|
+
import_node_fs7.default.symlinkSync(target, linkPath);
|
|
7245
7411
|
},
|
|
7246
7412
|
rename(from, to) {
|
|
7247
|
-
|
|
7413
|
+
import_node_fs7.default.renameSync(from, to);
|
|
7248
7414
|
},
|
|
7249
7415
|
removeRecursive(targetPath) {
|
|
7250
|
-
|
|
7416
|
+
import_node_fs7.default.rmSync(targetPath, { recursive: true, force: true });
|
|
7251
7417
|
},
|
|
7252
7418
|
copyRecursive(from, to) {
|
|
7253
|
-
|
|
7419
|
+
import_node_fs7.default.cpSync(from, to, { recursive: true, force: true, verbatimSymlinks: true });
|
|
7254
7420
|
},
|
|
7255
7421
|
readFileUtf8(filePath) {
|
|
7256
7422
|
try {
|
|
7257
|
-
return
|
|
7423
|
+
return import_node_fs7.default.readFileSync(filePath, "utf8");
|
|
7258
7424
|
} catch (error) {
|
|
7259
7425
|
if (isEnoent3(error)) {
|
|
7260
7426
|
return void 0;
|
|
@@ -7263,36 +7429,36 @@ var realFarmFs = {
|
|
|
7263
7429
|
}
|
|
7264
7430
|
},
|
|
7265
7431
|
writeFileUtf8(filePath, contents) {
|
|
7266
|
-
|
|
7432
|
+
import_node_fs7.default.writeFileSync(filePath, contents, "utf8");
|
|
7267
7433
|
},
|
|
7268
7434
|
mkdirPrivate(dirPath) {
|
|
7269
|
-
|
|
7270
|
-
|
|
7435
|
+
import_node_fs7.default.mkdirSync(dirPath, { recursive: true, mode: OWNER_ONLY_DIR_MODE });
|
|
7436
|
+
import_node_fs7.default.chmodSync(dirPath, OWNER_ONLY_DIR_MODE);
|
|
7271
7437
|
},
|
|
7272
7438
|
writeFilePrivate(filePath, contents) {
|
|
7273
7439
|
const temp = `${filePath}.${String(process.pid)}.tmp`;
|
|
7274
|
-
|
|
7275
|
-
|
|
7276
|
-
|
|
7440
|
+
import_node_fs7.default.writeFileSync(temp, contents, { encoding: "utf8", mode: OWNER_ONLY_FILE_MODE });
|
|
7441
|
+
import_node_fs7.default.chmodSync(temp, OWNER_ONLY_FILE_MODE);
|
|
7442
|
+
import_node_fs7.default.renameSync(temp, filePath);
|
|
7277
7443
|
},
|
|
7278
7444
|
appendFilePrivate(filePath, contents) {
|
|
7279
|
-
const descriptor =
|
|
7445
|
+
const descriptor = import_node_fs7.default.openSync(filePath, "a", OWNER_ONLY_FILE_MODE);
|
|
7280
7446
|
try {
|
|
7281
|
-
if ((
|
|
7282
|
-
|
|
7447
|
+
if ((import_node_fs7.default.fstatSync(descriptor).mode & PERMISSION_BITS2) !== OWNER_ONLY_FILE_MODE) {
|
|
7448
|
+
import_node_fs7.default.fchmodSync(descriptor, OWNER_ONLY_FILE_MODE);
|
|
7283
7449
|
}
|
|
7284
7450
|
const bytes = Buffer.from(contents, "utf8");
|
|
7285
7451
|
let written = 0;
|
|
7286
7452
|
while (written < bytes.length) {
|
|
7287
|
-
written +=
|
|
7453
|
+
written += import_node_fs7.default.writeSync(descriptor, bytes, written, bytes.length - written);
|
|
7288
7454
|
}
|
|
7289
7455
|
} finally {
|
|
7290
|
-
|
|
7456
|
+
import_node_fs7.default.closeSync(descriptor);
|
|
7291
7457
|
}
|
|
7292
7458
|
},
|
|
7293
7459
|
writeFileExclusive(filePath, contents) {
|
|
7294
7460
|
try {
|
|
7295
|
-
|
|
7461
|
+
import_node_fs7.default.writeFileSync(filePath, contents, { encoding: "utf8", flag: "wx" });
|
|
7296
7462
|
return true;
|
|
7297
7463
|
} catch (error) {
|
|
7298
7464
|
if (isErrorWithCode(error, "EEXIST")) {
|
|
@@ -7303,7 +7469,7 @@ var realFarmFs = {
|
|
|
7303
7469
|
},
|
|
7304
7470
|
hashFile(filePath) {
|
|
7305
7471
|
try {
|
|
7306
|
-
return (0, import_node_crypto9.createHash)("sha256").update(
|
|
7472
|
+
return (0, import_node_crypto9.createHash)("sha256").update(import_node_fs7.default.readFileSync(filePath)).digest("hex");
|
|
7307
7473
|
} catch (error) {
|
|
7308
7474
|
if (isEnoent3(error) || isErrorWithCode(error, "EISDIR")) {
|
|
7309
7475
|
return void 0;
|
|
@@ -7325,7 +7491,7 @@ function realIsProcessAlive(pid) {
|
|
|
7325
7491
|
}
|
|
7326
7492
|
}
|
|
7327
7493
|
function realIsProcessZombie(pid) {
|
|
7328
|
-
const result = (0,
|
|
7494
|
+
const result = (0, import_node_child_process2.spawnSync)("ps", ["-o", "stat=", "-p", String(pid)], { encoding: "utf8" });
|
|
7329
7495
|
return result.status === 0 && result.stdout.trim().startsWith("Z");
|
|
7330
7496
|
}
|
|
7331
7497
|
function realIsProcessRunning(pid) {
|
|
@@ -7333,17 +7499,17 @@ function realIsProcessRunning(pid) {
|
|
|
7333
7499
|
}
|
|
7334
7500
|
var realRunPort = {
|
|
7335
7501
|
run(command, args) {
|
|
7336
|
-
const result = (0,
|
|
7502
|
+
const result = (0, import_node_child_process2.spawnSync)(command, [...args], { encoding: "utf8" });
|
|
7337
7503
|
return { status: result.status, stdout: result.stdout, stderr: result.stderr };
|
|
7338
7504
|
}
|
|
7339
7505
|
};
|
|
7340
7506
|
function expandHome2(filePath) {
|
|
7341
|
-
return filePath.startsWith("~/") ?
|
|
7507
|
+
return filePath.startsWith("~/") ? import_node_path22.default.join(import_node_os3.default.homedir(), filePath.slice(1)) : filePath;
|
|
7342
7508
|
}
|
|
7343
7509
|
var MACOS_GUI_SESSION_MANAGER = "Aqua";
|
|
7344
7510
|
function hasDesktopSession() {
|
|
7345
7511
|
if (process.platform === "darwin") {
|
|
7346
|
-
const result = (0,
|
|
7512
|
+
const result = (0, import_node_child_process2.spawnSync)("launchctl", ["managername"], { encoding: "utf8" });
|
|
7347
7513
|
return result.status === 0 && result.stdout.trim() === MACOS_GUI_SESSION_MANAGER;
|
|
7348
7514
|
}
|
|
7349
7515
|
if (process.platform === "win32") {
|
|
@@ -7357,8 +7523,8 @@ var realCredentialPort = {
|
|
|
7357
7523
|
let content;
|
|
7358
7524
|
let stat;
|
|
7359
7525
|
try {
|
|
7360
|
-
stat =
|
|
7361
|
-
content =
|
|
7526
|
+
stat = import_node_fs7.default.statSync(resolved);
|
|
7527
|
+
content = import_node_fs7.default.readFileSync(resolved, "utf8");
|
|
7362
7528
|
} catch (error) {
|
|
7363
7529
|
if (isEnoent3(error)) {
|
|
7364
7530
|
return { found: false };
|
|
@@ -7369,7 +7535,7 @@ var realCredentialPort = {
|
|
|
7369
7535
|
},
|
|
7370
7536
|
runCommand(argv, options) {
|
|
7371
7537
|
const [command, ...args] = argv;
|
|
7372
|
-
const result = (0,
|
|
7538
|
+
const result = (0, import_node_child_process2.spawnSync)(command, args, {
|
|
7373
7539
|
encoding: "utf8",
|
|
7374
7540
|
timeout: options.timeoutMs,
|
|
7375
7541
|
stdio: options.interactive ? ["inherit", "pipe", "inherit"] : ["ignore", "pipe", "pipe"]
|
|
@@ -7411,17 +7577,17 @@ function spawnDaemonThrough(executable) {
|
|
|
7411
7577
|
return (paths, subcommand, logPath) => spawnDetachedDaemon({ command: executable, args: [subcommand] }, paths, subcommand, logPath);
|
|
7412
7578
|
}
|
|
7413
7579
|
function spawnDetachedDaemon(invocation, paths, subcommand, logPath) {
|
|
7414
|
-
|
|
7415
|
-
const logFd =
|
|
7580
|
+
import_node_fs7.default.mkdirSync(import_node_path22.default.dirname(logPath), { recursive: true });
|
|
7581
|
+
const logFd = import_node_fs7.default.openSync(logPath, "a");
|
|
7416
7582
|
try {
|
|
7417
|
-
const child = (0,
|
|
7583
|
+
const child = (0, import_node_child_process2.spawn)(invocation.command, invocation.args, detachedDaemonSpawnOptions(logFd, { ...process.env, AGENT_SHIM_HOME: paths.root }));
|
|
7418
7584
|
child.unref();
|
|
7419
7585
|
if (child.pid === void 0) {
|
|
7420
7586
|
throw new Error(`spawning ${subcommand} returned no pid`);
|
|
7421
7587
|
}
|
|
7422
7588
|
return child.pid;
|
|
7423
7589
|
} finally {
|
|
7424
|
-
|
|
7590
|
+
import_node_fs7.default.closeSync(logFd);
|
|
7425
7591
|
}
|
|
7426
7592
|
}
|
|
7427
7593
|
function spawnHeadroomSupervisor(paths, spawnDaemon) {
|
|
@@ -7439,7 +7605,7 @@ var realHeadroomSocketTrust = {
|
|
|
7439
7605
|
lstat: (target) => {
|
|
7440
7606
|
let stat;
|
|
7441
7607
|
try {
|
|
7442
|
-
stat =
|
|
7608
|
+
stat = import_node_fs7.default.lstatSync(target);
|
|
7443
7609
|
} catch (error) {
|
|
7444
7610
|
if (isEnoent3(error)) {
|
|
7445
7611
|
return void 0;
|
|
@@ -7485,7 +7651,7 @@ var EXECUTE_BITS_MASK = 73;
|
|
|
7485
7651
|
function listVersionsDir(dir) {
|
|
7486
7652
|
let entries;
|
|
7487
7653
|
try {
|
|
7488
|
-
entries =
|
|
7654
|
+
entries = import_node_fs7.default.readdirSync(dir, { withFileTypes: true });
|
|
7489
7655
|
} catch (error) {
|
|
7490
7656
|
if (isEnoent3(error)) {
|
|
7491
7657
|
return [];
|
|
@@ -7493,8 +7659,8 @@ function listVersionsDir(dir) {
|
|
|
7493
7659
|
throw error;
|
|
7494
7660
|
}
|
|
7495
7661
|
return entries.filter((entry) => entry.isFile()).map((entry) => {
|
|
7496
|
-
const fullPath =
|
|
7497
|
-
const stat =
|
|
7662
|
+
const fullPath = import_node_path22.default.join(dir, entry.name);
|
|
7663
|
+
const stat = import_node_fs7.default.statSync(fullPath);
|
|
7498
7664
|
return {
|
|
7499
7665
|
name: entry.name,
|
|
7500
7666
|
isFile: true,
|
|
@@ -7508,7 +7674,7 @@ function windowsPathExtensions(pathext) {
|
|
|
7508
7674
|
return (pathext ?? WINDOWS_DEFAULT_PATHEXT).split(";").map((ext) => ext.trim()).filter((ext) => ext.length > 0);
|
|
7509
7675
|
}
|
|
7510
7676
|
function resolveExecutableCandidate(dir, name, env) {
|
|
7511
|
-
const candidate =
|
|
7677
|
+
const candidate = import_node_path22.default.join(dir, name);
|
|
7512
7678
|
if (env.platform === "win32") {
|
|
7513
7679
|
const extensions = windowsPathExtensions(env.pathext);
|
|
7514
7680
|
const alreadyHasRecognisedExtension = extensions.some((ext) => candidate.toLowerCase().endsWith(ext.toLowerCase()));
|
|
@@ -7528,7 +7694,7 @@ function resolveExecutableCandidate(dir, name, env) {
|
|
|
7528
7694
|
}
|
|
7529
7695
|
function realStatFileMode(candidate) {
|
|
7530
7696
|
try {
|
|
7531
|
-
const stat =
|
|
7697
|
+
const stat = import_node_fs7.default.statSync(candidate);
|
|
7532
7698
|
return stat.isFile() ? stat.mode : void 0;
|
|
7533
7699
|
} catch (error) {
|
|
7534
7700
|
if (isEnoent3(error)) {
|
|
@@ -7557,13 +7723,13 @@ function resolveOwnExecutablePath(env) {
|
|
|
7557
7723
|
if (env.argv1 !== void 0 && !env.argv1.includes("/") && !env.argv1.includes("\\")) {
|
|
7558
7724
|
return searchPathForExecutable(env.pathDirs, env.argv1, env.findExecutableInDir) ?? env.execPath;
|
|
7559
7725
|
}
|
|
7560
|
-
const candidate = env.argv1 === void 0 ? env.execPath :
|
|
7561
|
-
const candidateDir =
|
|
7562
|
-
const candidateDirOnPath = env.pathDirs.some((dir) =>
|
|
7726
|
+
const candidate = env.argv1 === void 0 ? env.execPath : import_node_path22.default.resolve(env.cwd, env.argv1);
|
|
7727
|
+
const candidateDir = import_node_path22.default.dirname(candidate);
|
|
7728
|
+
const candidateDirOnPath = env.pathDirs.some((dir) => import_node_path22.default.resolve(dir) === candidateDir);
|
|
7563
7729
|
if (candidateDirOnPath) {
|
|
7564
7730
|
return candidate;
|
|
7565
7731
|
}
|
|
7566
|
-
const viaPath = searchPathForExecutable(env.pathDirs,
|
|
7732
|
+
const viaPath = searchPathForExecutable(env.pathDirs, import_node_path22.default.basename(candidate), env.findExecutableInDir);
|
|
7567
7733
|
return viaPath ?? candidate;
|
|
7568
7734
|
}
|
|
7569
7735
|
function realOwnExecutablePath() {
|
|
@@ -7571,7 +7737,7 @@ function realOwnExecutablePath() {
|
|
|
7571
7737
|
argv1: process.argv[1],
|
|
7572
7738
|
execPath: process.execPath,
|
|
7573
7739
|
cwd: process.cwd(),
|
|
7574
|
-
pathDirs: (process.env.PATH ?? "").split(
|
|
7740
|
+
pathDirs: (process.env.PATH ?? "").split(import_node_path22.default.delimiter).filter((dir) => dir !== ""),
|
|
7575
7741
|
findExecutableInDir
|
|
7576
7742
|
});
|
|
7577
7743
|
}
|
|
@@ -7584,15 +7750,15 @@ function realContentSourcePath() {
|
|
|
7584
7750
|
function realResolveClaudeBinary(isOwnBinary) {
|
|
7585
7751
|
return () => discoverClaudeBinary({
|
|
7586
7752
|
listVersionsDir,
|
|
7587
|
-
pathDirs: (process.env.PATH ?? "").split(
|
|
7753
|
+
pathDirs: (process.env.PATH ?? "").split(import_node_path22.default.delimiter).filter((dir) => dir !== ""),
|
|
7588
7754
|
findExecutableInDir,
|
|
7589
7755
|
isOwnBinary
|
|
7590
7756
|
});
|
|
7591
7757
|
}
|
|
7592
7758
|
|
|
7593
7759
|
// src/checkReport.ts
|
|
7594
|
-
var
|
|
7595
|
-
var
|
|
7760
|
+
var import_node_path23 = __toESM(require("node:path"), 1);
|
|
7761
|
+
var import_zod12 = require("zod");
|
|
7596
7762
|
|
|
7597
7763
|
// src/cli/bool.ts
|
|
7598
7764
|
function parseBoolWord(input) {
|
|
@@ -7707,9 +7873,9 @@ function lookupKeychainService(run, farmRoot) {
|
|
|
7707
7873
|
note: serviceName === void 0 ? `A Keychain entry was found for account "${farmRoot}" but its service name could not be parsed from security's output.` : `Keychain service name for this identity: "${serviceName}".`
|
|
7708
7874
|
};
|
|
7709
7875
|
}
|
|
7710
|
-
var SettingsSecretsShapeSchema =
|
|
7711
|
-
env:
|
|
7712
|
-
hooks:
|
|
7876
|
+
var SettingsSecretsShapeSchema = import_zod12.z.looseObject({
|
|
7877
|
+
env: import_zod12.z.record(import_zod12.z.string(), import_zod12.z.unknown()).optional(),
|
|
7878
|
+
hooks: import_zod12.z.record(import_zod12.z.string(), import_zod12.z.array(import_zod12.z.unknown())).optional()
|
|
7713
7879
|
});
|
|
7714
7880
|
function hookCommandCountOf(group) {
|
|
7715
7881
|
if (typeof group !== "object" || group === null) {
|
|
@@ -7761,14 +7927,23 @@ function inspectSettingsExposure(params) {
|
|
|
7761
7927
|
}
|
|
7762
7928
|
return reports;
|
|
7763
7929
|
}
|
|
7764
|
-
function
|
|
7930
|
+
function cachedState(cacheEnv, owner, block) {
|
|
7931
|
+
if (cacheEnv === void 0 || block.cache === void 0) {
|
|
7932
|
+
return void 0;
|
|
7933
|
+
}
|
|
7934
|
+
return describeCachedCredential({ port: cacheEnv.port, platform: cacheEnv.platform, owner, cache: block.cache, nowMs: cacheEnv.now() });
|
|
7935
|
+
}
|
|
7936
|
+
function buildCredentialReport(provider, identity, identityName, cacheEnv) {
|
|
7765
7937
|
const identityCredential = identity?.credential === void 0 ? void 0 : summariseCredential(identity.credential);
|
|
7938
|
+
const identityCached = identity?.credential === void 0 || identityName === void 0 ? void 0 : cachedState(cacheEnv, `identity ${identityName}`, identity.credential);
|
|
7939
|
+
const providerCached = provider?.definition === void 0 ? void 0 : cachedState(cacheEnv, `provider ${provider.name}`, provider.definition.credential);
|
|
7766
7940
|
return {
|
|
7767
7941
|
applies: provider !== void 0 ? "provider" : identityCredential !== void 0 ? "identity" : "stored-login",
|
|
7768
7942
|
...provider === void 0 ? {} : {
|
|
7769
|
-
provider: provider.problem === void 0 ? { name: provider.name, credential: summariseCredential(provider.definition.credential) } : { name: provider.name, problem: provider.problem }
|
|
7943
|
+
provider: provider.problem === void 0 ? { name: provider.name, credential: summariseCredential(provider.definition.credential), ...providerCached === void 0 ? {} : { cached: providerCached } } : { name: provider.name, problem: provider.problem }
|
|
7770
7944
|
},
|
|
7771
|
-
...identityCredential === void 0 ? {} : { identity: identityCredential }
|
|
7945
|
+
...identityCredential === void 0 ? {} : { identity: identityCredential },
|
|
7946
|
+
...identityCached === void 0 ? {} : { identityCached }
|
|
7772
7947
|
};
|
|
7773
7948
|
}
|
|
7774
7949
|
function runCheck(params) {
|
|
@@ -7807,7 +7982,7 @@ function runCheck(params) {
|
|
|
7807
7982
|
ambientCredential,
|
|
7808
7983
|
...keychain === void 0 ? {} : { keychain },
|
|
7809
7984
|
settingsExposure,
|
|
7810
|
-
credential: buildCredentialReport(params.provider, params.identity)
|
|
7985
|
+
credential: buildCredentialReport(params.provider, params.identity, params.identityName, params.credentialCache)
|
|
7811
7986
|
};
|
|
7812
7987
|
}
|
|
7813
7988
|
function formatCheckReport(report) {
|
|
@@ -7845,12 +8020,12 @@ function formatCheckReport(report) {
|
|
|
7845
8020
|
const { credential } = report;
|
|
7846
8021
|
if (credential.provider !== void 0) {
|
|
7847
8022
|
lines.push(
|
|
7848
|
-
` Provider ${credential.provider.name}: ${credential.provider.credential === void 0 ? `unusable: ${credential.provider.problem ?? ""}` : formatCredentialSummary(credential.provider.credential)}`
|
|
8023
|
+
` Provider ${credential.provider.name}: ${credential.provider.credential === void 0 ? `unusable: ${credential.provider.problem ?? ""}` : formatCredentialSummary(credential.provider.credential)}${credential.provider.cached === void 0 ? "" : `; ${formatCachedCredentialState(credential.provider.cached)}`}`
|
|
7849
8024
|
);
|
|
7850
8025
|
}
|
|
7851
8026
|
if (credential.identity !== void 0) {
|
|
7852
8027
|
lines.push(
|
|
7853
|
-
` Identity ${report.identityName ?? "(none)"}: ${formatCredentialSummary(credential.identity)}${credential.applies === "provider" ? " (not used: the provider's credential applies)" : ""}`
|
|
8028
|
+
` Identity ${report.identityName ?? "(none)"}: ${formatCredentialSummary(credential.identity)}${credential.identityCached === void 0 ? "" : `; ${formatCachedCredentialState(credential.identityCached)}`}${credential.applies === "provider" ? " (not used: the provider's credential applies)" : ""}`
|
|
7854
8029
|
);
|
|
7855
8030
|
}
|
|
7856
8031
|
if (credential.applies === "stored-login") {
|
|
@@ -7959,10 +8134,10 @@ function collectCheckReport(params) {
|
|
|
7959
8134
|
}).input;
|
|
7960
8135
|
const providerName = cascadeProviderName(cascade);
|
|
7961
8136
|
const provider = providerName === void 0 ? void 0 : loadCheckProvider(paths, providerName);
|
|
7962
|
-
const farmRoot = identityDecision.name === void 0 ? void 0 :
|
|
8137
|
+
const farmRoot = identityDecision.name === void 0 ? void 0 : import_node_path23.default.join(paths.identitiesDir, identityDecision.name);
|
|
7963
8138
|
const settingsFiles = {
|
|
7964
|
-
"settings.json": realFsPort.readFileUtf8(
|
|
7965
|
-
"settings.local.json": realFsPort.readFileUtf8(
|
|
8139
|
+
"settings.json": realFsPort.readFileUtf8(import_node_path23.default.join(claudeHome, "settings.json")),
|
|
8140
|
+
"settings.local.json": realFsPort.readFileUtf8(import_node_path23.default.join(claudeHome, "settings.local.json"))
|
|
7966
8141
|
};
|
|
7967
8142
|
const report = runCheck({
|
|
7968
8143
|
cwd,
|
|
@@ -7983,6 +8158,7 @@ function collectCheckReport(params) {
|
|
|
7983
8158
|
...loadedIdentity === void 0 ? {} : { identity: loadedIdentity.config },
|
|
7984
8159
|
settingsFiles,
|
|
7985
8160
|
run: realRunPort,
|
|
8161
|
+
credentialCache: realCredentialCacheEnv(paths),
|
|
7986
8162
|
...farmRoot === void 0 ? {} : { farmRoot },
|
|
7987
8163
|
platform: process.platform,
|
|
7988
8164
|
...provider === void 0 ? {} : { provider }
|
|
@@ -7991,23 +8167,23 @@ function collectCheckReport(params) {
|
|
|
7991
8167
|
}
|
|
7992
8168
|
|
|
7993
8169
|
// src/claudeShim.ts
|
|
7994
|
-
var
|
|
7995
|
-
var
|
|
7996
|
-
var
|
|
7997
|
-
var ClaudeShimStateSchema =
|
|
7998
|
-
targetPath:
|
|
7999
|
-
method:
|
|
8000
|
-
installedAtMs:
|
|
8170
|
+
var import_node_fs8 = __toESM(require("node:fs"), 1);
|
|
8171
|
+
var import_node_path24 = __toESM(require("node:path"), 1);
|
|
8172
|
+
var import_zod13 = require("zod");
|
|
8173
|
+
var ClaudeShimStateSchema = import_zod13.z.strictObject({
|
|
8174
|
+
targetPath: import_zod13.z.string().min(1),
|
|
8175
|
+
method: import_zod13.z.enum(["hardlink", "copy"]),
|
|
8176
|
+
installedAtMs: import_zod13.z.number()
|
|
8001
8177
|
});
|
|
8002
8178
|
function commandFilename(ownExecutablePath, commandName) {
|
|
8003
8179
|
return ownExecutablePath.toLowerCase().endsWith(".exe") ? `${commandName}.exe` : commandName;
|
|
8004
8180
|
}
|
|
8005
8181
|
function resolveOwnBinaryCheck(paths, contentSourcePath) {
|
|
8006
8182
|
const state = readJson(paths.claudeShimFile, ClaudeShimStateSchema);
|
|
8007
|
-
const recordedTarget = state === void 0 ? void 0 :
|
|
8183
|
+
const recordedTarget = state === void 0 ? void 0 : import_node_path24.default.resolve(state.targetPath);
|
|
8008
8184
|
let ownStat;
|
|
8009
8185
|
return (candidate) => {
|
|
8010
|
-
if (recordedTarget !== void 0 &&
|
|
8186
|
+
if (recordedTarget !== void 0 && import_node_path24.default.resolve(candidate) === recordedTarget) {
|
|
8011
8187
|
return true;
|
|
8012
8188
|
}
|
|
8013
8189
|
ownStat ??= statOrUndefined(contentSourcePath);
|
|
@@ -8021,7 +8197,7 @@ function isEnoent4(error) {
|
|
|
8021
8197
|
}
|
|
8022
8198
|
function statOrUndefined(target) {
|
|
8023
8199
|
try {
|
|
8024
|
-
return
|
|
8200
|
+
return import_node_fs8.default.statSync(target);
|
|
8025
8201
|
} catch (error) {
|
|
8026
8202
|
if (isEnoent4(error)) {
|
|
8027
8203
|
return void 0;
|
|
@@ -8029,22 +8205,22 @@ function statOrUndefined(target) {
|
|
|
8029
8205
|
throw error;
|
|
8030
8206
|
}
|
|
8031
8207
|
}
|
|
8032
|
-
var nodeLinkFs = { link:
|
|
8208
|
+
var nodeLinkFs = { link: import_node_fs8.default.linkSync, copyFile: import_node_fs8.default.copyFileSync, chmod: import_node_fs8.default.chmodSync };
|
|
8033
8209
|
function findPathShadow(params) {
|
|
8034
|
-
const resolvedTargetDir =
|
|
8210
|
+
const resolvedTargetDir = import_node_path24.default.resolve(params.targetDir);
|
|
8035
8211
|
for (const dir of params.pathDirs) {
|
|
8036
8212
|
const found = params.findExecutableInDir(dir, params.targetFilename);
|
|
8037
8213
|
if (found === void 0) {
|
|
8038
8214
|
continue;
|
|
8039
8215
|
}
|
|
8040
|
-
return
|
|
8216
|
+
return import_node_path24.default.resolve(dir) === resolvedTargetDir ? { status: "ok" } : { status: "shadowed", by: found };
|
|
8041
8217
|
}
|
|
8042
|
-
return params.pathDirs.some((dir) =>
|
|
8218
|
+
return params.pathDirs.some((dir) => import_node_path24.default.resolve(dir) === resolvedTargetDir) ? { status: "ok" } : { status: "not-on-path" };
|
|
8043
8219
|
}
|
|
8044
8220
|
|
|
8045
8221
|
// src/doctorReport.ts
|
|
8046
|
-
var
|
|
8047
|
-
var
|
|
8222
|
+
var import_node_fs9 = __toESM(require("node:fs"), 1);
|
|
8223
|
+
var import_node_path25 = __toESM(require("node:path"), 1);
|
|
8048
8224
|
function refinePathShadow(status, ownExecutablePath, realpath) {
|
|
8049
8225
|
if (status.status !== "shadowed") {
|
|
8050
8226
|
return status;
|
|
@@ -8068,7 +8244,7 @@ function validateJson(schema, input) {
|
|
|
8068
8244
|
return { ok: true, data: result.data };
|
|
8069
8245
|
}
|
|
8070
8246
|
function pushPathResolution(push, resolution) {
|
|
8071
|
-
const ownDir =
|
|
8247
|
+
const ownDir = import_node_path25.default.dirname(resolution.ownExecutablePath);
|
|
8072
8248
|
switch (resolution.agentShim.status) {
|
|
8073
8249
|
case "ok":
|
|
8074
8250
|
push("path-resolution", "pass", `\`agent-shim\` on PATH resolves to this running executable, ${resolution.ownExecutablePath}.`, "agent-shim");
|
|
@@ -8110,7 +8286,14 @@ function pushPathResolution(push, resolution) {
|
|
|
8110
8286
|
break;
|
|
8111
8287
|
}
|
|
8112
8288
|
}
|
|
8113
|
-
function
|
|
8289
|
+
function cacheClause(cacheEnv, owner, block) {
|
|
8290
|
+
if (cacheEnv === void 0 || block.cache === void 0) {
|
|
8291
|
+
return { text: "", unreadable: false };
|
|
8292
|
+
}
|
|
8293
|
+
const state = describeCachedCredential({ port: cacheEnv.port, platform: cacheEnv.platform, owner, cache: block.cache, nowMs: cacheEnv.now() });
|
|
8294
|
+
return { text: `; ${formatCachedCredentialState(state)}`, unreadable: state.status === "unreadable" };
|
|
8295
|
+
}
|
|
8296
|
+
function pushProvider(push, entry, cacheEnv) {
|
|
8114
8297
|
if (entry.raw === void 0) {
|
|
8115
8298
|
push("provider", "fail", `${entry.path} is missing.`, entry.name);
|
|
8116
8299
|
return;
|
|
@@ -8132,18 +8315,19 @@ function pushProvider(push, entry) {
|
|
|
8132
8315
|
push("provider", "fail", new ConfigValidationError(entry.path, validated.error.issues).message, entry.name);
|
|
8133
8316
|
return;
|
|
8134
8317
|
}
|
|
8135
|
-
|
|
8318
|
+
const cache = cacheClause(cacheEnv, `provider ${entry.name}`, validated.data.credential);
|
|
8319
|
+
push("provider", cache.unreadable ? "fail" : "pass", `${entry.name} is valid (${describeProviderEndpoint(validated.data)}, credential ${describeCredential(validated.data.credential)})${cache.text}.`, entry.name);
|
|
8136
8320
|
}
|
|
8137
8321
|
function pushLegacyName(push, params) {
|
|
8138
8322
|
const legacyVariables = Object.keys(params.env).filter((name) => name.startsWith(LEGACY_ENV_PREFIX) && params.env[name] !== void 0).sort();
|
|
8139
|
-
if (legacyVariables.length === 0 &&
|
|
8323
|
+
if (legacyVariables.length === 0 && import_node_path25.default.basename(params.rootPath) !== LEGACY_HOME_DIRNAME) {
|
|
8140
8324
|
push("legacy-name", "pass", "Nothing here still uses the former `claude-use` name.");
|
|
8141
8325
|
return;
|
|
8142
8326
|
}
|
|
8143
8327
|
for (const name of legacyVariables) {
|
|
8144
8328
|
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);
|
|
8145
8329
|
}
|
|
8146
|
-
if (
|
|
8330
|
+
if (import_node_path25.default.basename(params.rootPath) === LEGACY_HOME_DIRNAME) {
|
|
8147
8331
|
push(
|
|
8148
8332
|
"legacy-name",
|
|
8149
8333
|
"warn",
|
|
@@ -8225,10 +8409,11 @@ function runDoctor(params) {
|
|
|
8225
8409
|
);
|
|
8226
8410
|
} else {
|
|
8227
8411
|
const credential = validated.data.credential;
|
|
8412
|
+
const cache = credential === void 0 ? { text: "", unreadable: false } : cacheClause(params.credentialCache, `identity ${entry.name}`, credential);
|
|
8228
8413
|
push(
|
|
8229
8414
|
"identity",
|
|
8230
|
-
"pass",
|
|
8231
|
-
`${entry.name} is valid and authenticates with ${credential === void 0 ? "its stored login" : `credential ${describeCredential(credential)}`}.`,
|
|
8415
|
+
cache.unreadable ? "fail" : "pass",
|
|
8416
|
+
`${entry.name} is valid and authenticates with ${credential === void 0 ? "its stored login" : `credential ${describeCredential(credential)}`}${cache.text}.`,
|
|
8232
8417
|
entry.name
|
|
8233
8418
|
);
|
|
8234
8419
|
}
|
|
@@ -8248,7 +8433,7 @@ function runDoctor(params) {
|
|
|
8248
8433
|
return poolName === void 0 ? validIdentityNames.has(selector) : poolName in pools;
|
|
8249
8434
|
};
|
|
8250
8435
|
for (const entry of params.providers) {
|
|
8251
|
-
pushProvider(push, entry);
|
|
8436
|
+
pushProvider(push, entry, params.credentialCache);
|
|
8252
8437
|
}
|
|
8253
8438
|
if (params.platform !== "darwin" || params.run === void 0) {
|
|
8254
8439
|
push("keychain", "pass", "Skipped (not macOS).");
|
|
@@ -8442,27 +8627,27 @@ function formatDoctorReport(report) {
|
|
|
8442
8627
|
}
|
|
8443
8628
|
function realpathOrSelf(target) {
|
|
8444
8629
|
try {
|
|
8445
|
-
return
|
|
8630
|
+
return import_node_fs9.default.realpathSync(target);
|
|
8446
8631
|
} catch {
|
|
8447
8632
|
return target;
|
|
8448
8633
|
}
|
|
8449
8634
|
}
|
|
8450
8635
|
function collectDoctorReport(params) {
|
|
8451
8636
|
const { paths } = params;
|
|
8452
|
-
const identityNames =
|
|
8637
|
+
const identityNames = import_node_fs9.default.existsSync(paths.identitiesDir) ? import_node_fs9.default.readdirSync(paths.identitiesDir, { withFileTypes: true }).filter((entry) => entry.isDirectory() && isIdentityDirectoryName(entry.name)).map((entry) => entry.name).sort() : [];
|
|
8453
8638
|
const identities = identityNames.map((name) => {
|
|
8454
|
-
const farmRoot =
|
|
8455
|
-
const identityPath =
|
|
8639
|
+
const farmRoot = import_node_path25.default.join(paths.identitiesDir, name);
|
|
8640
|
+
const identityPath = import_node_path25.default.join(farmRoot, "identity.json");
|
|
8456
8641
|
return { name, path: identityPath, raw: realFsPort.readFileUtf8(identityPath), farmRoot };
|
|
8457
8642
|
});
|
|
8458
|
-
const profileNames =
|
|
8643
|
+
const profileNames = import_node_fs9.default.existsSync(paths.configProfilesDir) ? import_node_fs9.default.readdirSync(paths.configProfilesDir, { withFileTypes: true }).filter((entry) => entry.isFile() && entry.name.endsWith(".json")).map((entry) => entry.name.slice(0, -".json".length)).sort() : [];
|
|
8459
8644
|
const configProfiles = profileNames.map((name) => {
|
|
8460
|
-
const profilePath =
|
|
8645
|
+
const profilePath = import_node_path25.default.join(paths.configProfilesDir, `${name}.json`);
|
|
8461
8646
|
return { name, path: profilePath, raw: realFsPort.readFileUtf8(profilePath) };
|
|
8462
8647
|
});
|
|
8463
|
-
const providerNames =
|
|
8648
|
+
const providerNames = import_node_fs9.default.existsSync(paths.providersDir) ? import_node_fs9.default.readdirSync(paths.providersDir, { withFileTypes: true }).filter((entry) => entry.isFile() && entry.name.endsWith(".json")).map((entry) => entry.name.slice(0, -".json".length)).sort() : [];
|
|
8464
8649
|
const providers = providerNames.map((name) => {
|
|
8465
|
-
const providerPath =
|
|
8650
|
+
const providerPath = import_node_path25.default.join(paths.providersDir, `${name}.json`);
|
|
8466
8651
|
return { name, path: providerPath, raw: realFsPort.readFileUtf8(providerPath) };
|
|
8467
8652
|
});
|
|
8468
8653
|
const ownExecutablePath = realOwnExecutablePath();
|
|
@@ -8474,12 +8659,12 @@ function collectDoctorReport(params) {
|
|
|
8474
8659
|
binaryDiscovery = { ok: false, message: error instanceof Error ? error.message : String(error) };
|
|
8475
8660
|
}
|
|
8476
8661
|
const shimState = readJson(paths.claudeShimFile, ClaudeShimStateSchema);
|
|
8477
|
-
const pathDirs = (params.env.PATH ?? "").split(
|
|
8662
|
+
const pathDirs = (params.env.PATH ?? "").split(import_node_path25.default.delimiter).filter((dir) => dir !== "");
|
|
8478
8663
|
const claudeShimShadow = shimState === void 0 ? void 0 : refinePathShadow(
|
|
8479
8664
|
findPathShadow({
|
|
8480
8665
|
pathDirs,
|
|
8481
|
-
targetDir:
|
|
8482
|
-
targetFilename:
|
|
8666
|
+
targetDir: import_node_path25.default.dirname(shimState.targetPath),
|
|
8667
|
+
targetFilename: import_node_path25.default.basename(shimState.targetPath),
|
|
8483
8668
|
findExecutableInDir
|
|
8484
8669
|
}),
|
|
8485
8670
|
shimState.targetPath,
|
|
@@ -8487,6 +8672,7 @@ function collectDoctorReport(params) {
|
|
|
8487
8672
|
);
|
|
8488
8673
|
const report = runDoctor({
|
|
8489
8674
|
env: params.env,
|
|
8675
|
+
credentialCache: realCredentialCacheEnv(paths),
|
|
8490
8676
|
identities,
|
|
8491
8677
|
configProfiles,
|
|
8492
8678
|
providers,
|
|
@@ -8495,14 +8681,14 @@ function collectDoctorReport(params) {
|
|
|
8495
8681
|
categoriesLocal: { path: paths.categoriesLocalFile, raw: realFsPort.readFileUtf8(paths.categoriesLocalFile) },
|
|
8496
8682
|
activeIdentity: { path: paths.activeIdentityFile, raw: realFsPort.readFileUtf8(paths.activeIdentityFile) },
|
|
8497
8683
|
binaryDiscovery,
|
|
8498
|
-
claudeShim: { state: shimState, targetExists: shimState !== void 0 &&
|
|
8684
|
+
claudeShim: { state: shimState, targetExists: shimState !== void 0 && import_node_fs9.default.existsSync(shimState.targetPath) },
|
|
8499
8685
|
rootPath: paths.root,
|
|
8500
8686
|
pathResolution: {
|
|
8501
8687
|
ownExecutablePath,
|
|
8502
8688
|
agentShim: refinePathShadow(
|
|
8503
8689
|
findPathShadow({
|
|
8504
8690
|
pathDirs,
|
|
8505
|
-
targetDir:
|
|
8691
|
+
targetDir: import_node_path25.default.dirname(ownExecutablePath),
|
|
8506
8692
|
targetFilename: commandFilename(ownExecutablePath, "agent-shim"),
|
|
8507
8693
|
findExecutableInDir
|
|
8508
8694
|
}),
|
|
@@ -8523,7 +8709,7 @@ function collectDoctorReport(params) {
|
|
|
8523
8709
|
|
|
8524
8710
|
// src/launcher.ts
|
|
8525
8711
|
var import_node_crypto10 = require("node:crypto");
|
|
8526
|
-
var
|
|
8712
|
+
var import_node_path27 = __toESM(require("node:path"), 1);
|
|
8527
8713
|
|
|
8528
8714
|
// src/launcher/argv.ts
|
|
8529
8715
|
var ConflictingIdentityError = class extends UsageError {
|
|
@@ -8775,7 +8961,7 @@ function buildCliOverride(params) {
|
|
|
8775
8961
|
}
|
|
8776
8962
|
|
|
8777
8963
|
// src/launcher/flags.ts
|
|
8778
|
-
var
|
|
8964
|
+
var import_node_path26 = __toESM(require("node:path"), 1);
|
|
8779
8965
|
|
|
8780
8966
|
// src/headroom/headers.ts
|
|
8781
8967
|
function mergeAnthropicCustomHeaders(existing, additions) {
|
|
@@ -8845,7 +9031,7 @@ function buildEnv(params) {
|
|
|
8845
9031
|
const parentCustomHeaders = params.baseEnv.ANTHROPIC_CUSTOM_HEADERS;
|
|
8846
9032
|
let providerCustomHeaders;
|
|
8847
9033
|
if (!params.configDirEscapeHatch && params.resolvedIdentityName !== void 0) {
|
|
8848
|
-
env.CLAUDE_CONFIG_DIR =
|
|
9034
|
+
env.CLAUDE_CONFIG_DIR = import_node_path26.default.join(params.identitiesDir, params.resolvedIdentityName);
|
|
8849
9035
|
}
|
|
8850
9036
|
if (params.provider !== void 0) {
|
|
8851
9037
|
const providerEnv = params.provider.definition.env ?? {};
|
|
@@ -9006,7 +9192,7 @@ function prepareLaunch(params) {
|
|
|
9006
9192
|
identityDefaultConfigProfile: loadedIdentity?.config.defaultConfigProfile,
|
|
9007
9193
|
globalDefaultConfigProfile: params.globalDefaultConfigProfile
|
|
9008
9194
|
});
|
|
9009
|
-
if (configProfileDecision.name !== void 0 && params.allowMissingConfigProfile !== true && fs12.readConfigFile(
|
|
9195
|
+
if (configProfileDecision.name !== void 0 && params.allowMissingConfigProfile !== true && fs12.readConfigFile(import_node_path27.default.join(paths.configProfilesDir, `${configProfileDecision.name}.json`)) === void 0) {
|
|
9010
9196
|
log.error(
|
|
9011
9197
|
`agent-shim: no configuration profile named "${configProfileDecision.name}" (selected via ${configProfileDecision.source}). Run \`agent-shim profile add ${configProfileDecision.name}\` first.`
|
|
9012
9198
|
);
|
|
@@ -9179,84 +9365,6 @@ function prepareLaunch(params) {
|
|
|
9179
9365
|
var import_node_os5 = __toESM(require("node:os"), 1);
|
|
9180
9366
|
var import_node_crypto12 = require("node:crypto");
|
|
9181
9367
|
|
|
9182
|
-
// src/realCredentialCache.ts
|
|
9183
|
-
var import_node_child_process2 = require("node:child_process");
|
|
9184
|
-
var import_node_fs9 = __toESM(require("node:fs"), 1);
|
|
9185
|
-
var import_node_path27 = __toESM(require("node:path"), 1);
|
|
9186
|
-
var KEYCHAIN_CACHE_SERVICE = "agent-shim-credential-cache";
|
|
9187
|
-
var CACHE_DIR_MODE = 448;
|
|
9188
|
-
var CACHE_FILE_MODE = 384;
|
|
9189
|
-
function cacheFileNameFor(owner) {
|
|
9190
|
-
return `${owner.replace(/[^A-Za-z0-9._-]/g, "_")}.json`;
|
|
9191
|
-
}
|
|
9192
|
-
function parseEntry(raw) {
|
|
9193
|
-
let json;
|
|
9194
|
-
try {
|
|
9195
|
-
json = JSON.parse(raw);
|
|
9196
|
-
} catch {
|
|
9197
|
-
return void 0;
|
|
9198
|
-
}
|
|
9199
|
-
const parsed = CachedCredentialSchema.safeParse(json);
|
|
9200
|
-
return parsed.success ? parsed.data : void 0;
|
|
9201
|
-
}
|
|
9202
|
-
function requireKeychain() {
|
|
9203
|
-
if (process.platform !== "darwin") {
|
|
9204
|
-
throw new Error("the keychain credential store needs macOS; use --credential-cache-store file");
|
|
9205
|
-
}
|
|
9206
|
-
}
|
|
9207
|
-
function security(args, stdin) {
|
|
9208
|
-
const result = (0, import_node_child_process2.spawnSync)("security", args, { encoding: "utf8", ...stdin === void 0 ? {} : { input: stdin }, stdio: ["pipe", "pipe", "ignore"] });
|
|
9209
|
-
return { status: result.status, stdout: result.stdout };
|
|
9210
|
-
}
|
|
9211
|
-
function createRealCredentialCache(root) {
|
|
9212
|
-
const dir = import_node_path27.default.join(root, "credential-cache");
|
|
9213
|
-
const filePath = (owner) => import_node_path27.default.join(dir, cacheFileNameFor(owner));
|
|
9214
|
-
return {
|
|
9215
|
-
read(store, owner) {
|
|
9216
|
-
if (store === "file") {
|
|
9217
|
-
try {
|
|
9218
|
-
return parseEntry(import_node_fs9.default.readFileSync(filePath(owner), "utf8"));
|
|
9219
|
-
} catch {
|
|
9220
|
-
return void 0;
|
|
9221
|
-
}
|
|
9222
|
-
}
|
|
9223
|
-
requireKeychain();
|
|
9224
|
-
const result = security(["find-generic-password", "-s", KEYCHAIN_CACHE_SERVICE, "-a", owner, "-w"]);
|
|
9225
|
-
return result.status === 0 ? parseEntry(Buffer.from(result.stdout.trim(), "base64").toString("utf8")) : void 0;
|
|
9226
|
-
},
|
|
9227
|
-
write(store, owner, entry) {
|
|
9228
|
-
const serialised = JSON.stringify(entry);
|
|
9229
|
-
if (store === "file") {
|
|
9230
|
-
import_node_fs9.default.mkdirSync(dir, { recursive: true, mode: CACHE_DIR_MODE });
|
|
9231
|
-
import_node_fs9.default.chmodSync(dir, CACHE_DIR_MODE);
|
|
9232
|
-
const target = filePath(owner);
|
|
9233
|
-
const temp = `${target}.${String(process.pid)}.tmp`;
|
|
9234
|
-
import_node_fs9.default.writeFileSync(temp, serialised, { mode: CACHE_FILE_MODE });
|
|
9235
|
-
import_node_fs9.default.renameSync(temp, target);
|
|
9236
|
-
return;
|
|
9237
|
-
}
|
|
9238
|
-
requireKeychain();
|
|
9239
|
-
const encoded = Buffer.from(serialised, "utf8").toString("base64");
|
|
9240
|
-
const result = security(["-i"], `add-generic-password -U -s ${KEYCHAIN_CACHE_SERVICE} -a ${JSON.stringify(owner)} -w ${encoded}
|
|
9241
|
-
`);
|
|
9242
|
-
if (result.status !== 0) {
|
|
9243
|
-
throw new Error(`could not write the keychain credential cache for ${owner}`);
|
|
9244
|
-
}
|
|
9245
|
-
},
|
|
9246
|
-
remove(store, owner) {
|
|
9247
|
-
if (store === "file") {
|
|
9248
|
-
import_node_fs9.default.rmSync(filePath(owner), { force: true });
|
|
9249
|
-
return;
|
|
9250
|
-
}
|
|
9251
|
-
requireKeychain();
|
|
9252
|
-
security(["delete-generic-password", "-s", KEYCHAIN_CACHE_SERVICE, "-a", owner]);
|
|
9253
|
-
}
|
|
9254
|
-
};
|
|
9255
|
-
}
|
|
9256
|
-
function realCredentialCacheEnv(paths) {
|
|
9257
|
-
return { port: createRealCredentialCache(paths.root), platform: process.platform, now: () => Date.now() };
|
|
9258
|
-
}
|
|
9259
|
-
|
|
9260
9368
|
// src/frontdoor/realFrontDoorPort.ts
|
|
9261
9369
|
var import_node_fs10 = __toESM(require("node:fs"), 1);
|
|
9262
9370
|
|
|
@@ -9521,8 +9629,11 @@ function prepareClaudeLaunch(options) {
|
|
|
9521
9629
|
InvalidProviderNameError,
|
|
9522
9630
|
LaunchRefusedError,
|
|
9523
9631
|
LegacyProviderFileError,
|
|
9632
|
+
PROMPT_CACHE_TTL_MS,
|
|
9633
|
+
PlanClassSchema,
|
|
9524
9634
|
PoolNameSchema,
|
|
9525
9635
|
PoolNotFoundError,
|
|
9636
|
+
PoolPickReportSchema,
|
|
9526
9637
|
PoolSchema,
|
|
9527
9638
|
PortableConfigSchema,
|
|
9528
9639
|
ProfileAlreadyExistsError,
|
|
@@ -9559,16 +9670,19 @@ function prepareClaudeLaunch(options) {
|
|
|
9559
9670
|
checkReportToJson,
|
|
9560
9671
|
collectCheckReport,
|
|
9561
9672
|
collectDoctorReport,
|
|
9673
|
+
collectPoolPick,
|
|
9562
9674
|
createLeafCache,
|
|
9563
9675
|
createProfile,
|
|
9564
9676
|
createRcControlHandler,
|
|
9565
9677
|
createRcSessionTracker,
|
|
9566
9678
|
describeProviderEndpoint,
|
|
9567
9679
|
detectAmbientCredential,
|
|
9680
|
+
effectiveWindow,
|
|
9568
9681
|
ensureCa,
|
|
9569
9682
|
ensureFrontDoor,
|
|
9570
9683
|
ensureHeadroom,
|
|
9571
9684
|
evaluateAmbientCredentialGuard,
|
|
9685
|
+
evaluateWhen,
|
|
9572
9686
|
formatAmbientCredentialGuardMessage,
|
|
9573
9687
|
formatCheckReport,
|
|
9574
9688
|
formatDoctorReport,
|
|
@@ -9586,13 +9700,16 @@ function prepareClaudeLaunch(options) {
|
|
|
9586
9700
|
listProfiles,
|
|
9587
9701
|
listProviders,
|
|
9588
9702
|
listUsageSnapshots,
|
|
9703
|
+
matchBranch,
|
|
9589
9704
|
mintLeaf,
|
|
9590
9705
|
observingRoutedRoute,
|
|
9591
9706
|
parseConnectTarget,
|
|
9707
|
+
planOf,
|
|
9592
9708
|
prepareClaudeLaunch,
|
|
9593
9709
|
prepareLaunch,
|
|
9594
9710
|
profileExists,
|
|
9595
9711
|
providerExists,
|
|
9712
|
+
rankPool,
|
|
9596
9713
|
rcEventWriteResultFromAnswer,
|
|
9597
9714
|
rcObserverAsPassthrough,
|
|
9598
9715
|
readActiveIdentity,
|