claude-use 9.12.0 → 9.13.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 +225 -28
- package/dist/index.cjs +206 -25
- package/dist/index.mjs +206 -25
- package/dist/types/index.d.ts +60 -7
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -2573,7 +2573,7 @@ function listFrontDoorSessions(fs12, sessionsDir) {
|
|
|
2573
2573
|
try {
|
|
2574
2574
|
const parsed = FrontDoorSessionSchema.safeParse(JSON.parse(fs12.readFileUtf8(path8.join(sessionsDir, name)) ?? ""));
|
|
2575
2575
|
if (parsed.success) {
|
|
2576
|
-
sessions.push({ pid: parsed.data.pid, startedAt: parsed.data.startedAt });
|
|
2576
|
+
sessions.push({ pid: parsed.data.pid, startedAt: parsed.data.startedAt, ...parsed.data.supervisorPid === void 0 ? {} : { supervisorPid: parsed.data.supervisorPid } });
|
|
2577
2577
|
}
|
|
2578
2578
|
} catch {
|
|
2579
2579
|
continue;
|
|
@@ -2599,7 +2599,7 @@ var init_state = __esm({
|
|
|
2599
2599
|
"src/frontdoor/state.ts"() {
|
|
2600
2600
|
"use strict";
|
|
2601
2601
|
FRONT_DOOR_PROTOCOL = 3;
|
|
2602
|
-
FrontDoorSessionSchema = z3.strictObject({ pid: z3.number().int().positive(), startedAt: z3.number(), token: z3.string().min(1) });
|
|
2602
|
+
FrontDoorSessionSchema = z3.strictObject({ pid: z3.number().int().positive(), startedAt: z3.number(), token: z3.string().min(1), supervisorPid: z3.number().int().positive().optional() });
|
|
2603
2603
|
FrontDoorStateSchema = z3.strictObject({
|
|
2604
2604
|
/**
|
|
2605
2605
|
* The launcher-to-door wire protocol this supervisor speaks, written once it is serving; absent in state written by a release that predates the field, which `ensureFrontDoor` reads as protocol 0. A launcher replaces a door whose protocol is lower than its own (see `FRONT_DOOR_PROTOCOL`).
|
|
@@ -2639,7 +2639,7 @@ var init_package = __esm({
|
|
|
2639
2639
|
"package.json"() {
|
|
2640
2640
|
package_default = {
|
|
2641
2641
|
name: "claude-use",
|
|
2642
|
-
version: "9.
|
|
2642
|
+
version: "9.13.0",
|
|
2643
2643
|
description: "A profile manager and launcher for Claude Code that lets one person run multiple logins from one machine while controlling what gets shared between them.",
|
|
2644
2644
|
license: "MIT",
|
|
2645
2645
|
author: "Joseph Mearman <joseph@mearman.co.uk>",
|
|
@@ -2742,6 +2742,36 @@ var init_package = __esm({
|
|
|
2742
2742
|
}
|
|
2743
2743
|
});
|
|
2744
2744
|
|
|
2745
|
+
// src/frontdoor/supervisorProcesses.ts
|
|
2746
|
+
function parseFrontDoorSupervisorPids(psOutput) {
|
|
2747
|
+
const pids = [];
|
|
2748
|
+
for (const line of psOutput.split("\n")) {
|
|
2749
|
+
const [pidText, ...argumentsList] = line.trim().split(/\s+/);
|
|
2750
|
+
const pid = Number(pidText);
|
|
2751
|
+
if (Number.isInteger(pid) && pid > 0 && argumentsList.includes(FRONT_DOOR_SUPERVISOR_ARGUMENT)) {
|
|
2752
|
+
pids.push(pid);
|
|
2753
|
+
}
|
|
2754
|
+
}
|
|
2755
|
+
return pids.sort((a, b) => a - b);
|
|
2756
|
+
}
|
|
2757
|
+
function listFrontDoorSupervisors(run, uid) {
|
|
2758
|
+
const result = run.run("ps", ["-U", String(uid), "-o", "pid=,command="]);
|
|
2759
|
+
if (result.status === null) {
|
|
2760
|
+
return { ok: false, message: "ps could not be run" };
|
|
2761
|
+
}
|
|
2762
|
+
if (result.status !== 0) {
|
|
2763
|
+
return { ok: false, message: `ps exited ${String(result.status)}${result.stderr.trim() === "" ? "" : `: ${result.stderr.trim()}`}` };
|
|
2764
|
+
}
|
|
2765
|
+
return { ok: true, pids: parseFrontDoorSupervisorPids(result.stdout) };
|
|
2766
|
+
}
|
|
2767
|
+
var FRONT_DOOR_SUPERVISOR_ARGUMENT;
|
|
2768
|
+
var init_supervisorProcesses = __esm({
|
|
2769
|
+
"src/frontdoor/supervisorProcesses.ts"() {
|
|
2770
|
+
"use strict";
|
|
2771
|
+
FRONT_DOOR_SUPERVISOR_ARGUMENT = "__frontdoor-supervisor";
|
|
2772
|
+
}
|
|
2773
|
+
});
|
|
2774
|
+
|
|
2745
2775
|
// src/headroom/state.ts
|
|
2746
2776
|
import { createHash as createHash3 } from "node:crypto";
|
|
2747
2777
|
import path11 from "node:path";
|
|
@@ -3338,9 +3368,15 @@ async function runSupervisor(initialConfig, ports, options = {}) {
|
|
|
3338
3368
|
await ports.sleep(HEADROOM_POLL_MS);
|
|
3339
3369
|
}
|
|
3340
3370
|
}
|
|
3371
|
+
function currentHeadroomAllowlistInputs(fs12, paths) {
|
|
3372
|
+
return {
|
|
3373
|
+
providers: readAllProviders(fs12, paths.providersDir).map((entry) => entry.provider),
|
|
3374
|
+
frontDoorOrigin: frontDoorOrigin(readFrontDoorState(fs12, paths.frontdoorStateFile))
|
|
3375
|
+
};
|
|
3376
|
+
}
|
|
3341
3377
|
function currentHeadroomAllowlist(fs12, paths) {
|
|
3342
|
-
const
|
|
3343
|
-
return headroomAllowlist(headroomUpstreams(providers, frontDoorOrigin
|
|
3378
|
+
const inputs = currentHeadroomAllowlistInputs(fs12, paths);
|
|
3379
|
+
return headroomAllowlist(headroomUpstreams(inputs.providers, inputs.frontDoorOrigin));
|
|
3344
3380
|
}
|
|
3345
3381
|
function allowlistOf(ports) {
|
|
3346
3382
|
return currentHeadroomAllowlist(ports.fs, ports.paths);
|
|
@@ -3408,6 +3444,10 @@ function realIsProcessZombie(pid) {
|
|
|
3408
3444
|
function realIsProcessRunning(pid) {
|
|
3409
3445
|
return realIsProcessAlive(pid) && !realIsProcessZombie(pid);
|
|
3410
3446
|
}
|
|
3447
|
+
function realIsFrontDoorSupervisor(pid) {
|
|
3448
|
+
const result = spawnSync("ps", ["-o", "pid=,command=", "-p", String(pid)], { encoding: "utf8" });
|
|
3449
|
+
return result.status === 0 && parseFrontDoorSupervisorPids(result.stdout).includes(pid);
|
|
3450
|
+
}
|
|
3411
3451
|
function expandHome2(filePath) {
|
|
3412
3452
|
return filePath.startsWith("~/") ? path13.join(os3.homedir(), filePath.slice(1)) : filePath;
|
|
3413
3453
|
}
|
|
@@ -3611,6 +3651,7 @@ var init_realPorts = __esm({
|
|
|
3611
3651
|
"use strict";
|
|
3612
3652
|
init_load();
|
|
3613
3653
|
init_versionDiscovery();
|
|
3654
|
+
init_supervisorProcesses();
|
|
3614
3655
|
init_ensure();
|
|
3615
3656
|
init_supervisor();
|
|
3616
3657
|
init_state2();
|
|
@@ -4645,7 +4686,7 @@ function assessIdentity(member, nowMs) {
|
|
|
4645
4686
|
);
|
|
4646
4687
|
if (blockedUntil > nowMs) {
|
|
4647
4688
|
if (unified.overageStatus === "allowed") {
|
|
4648
|
-
return { candidate: { ...base, class: "pay-per-use", reasons: [`plan exhausted until ${new Date(blockedUntil).toISOString()}, continues as extra usage`, ...windowReasons, ...planReasons] } };
|
|
4689
|
+
return { candidate: { ...base, class: "pay-per-use", planReturnsAtMs: blockedUntil, reasons: [`plan exhausted until ${new Date(blockedUntil).toISOString()} (in ${formatAge(blockedUntil - nowMs)}), continues as extra usage`, ...windowReasons, ...planReasons] } };
|
|
4649
4690
|
}
|
|
4650
4691
|
return { candidate: { ...base, class: "ineligible", blockedUntilMs: blockedUntil, reasons: [`refused until ${new Date(blockedUntil).toISOString()} (in ${formatAge(blockedUntil - nowMs)})`, ...unified.fallbackAvailable === true ? ["a fallback is on offer, so requests for some models may still be served"] : [], ...windowReasons, ...overageReasons, ...planReasons] } };
|
|
4651
4692
|
}
|
|
@@ -4760,7 +4801,8 @@ function rankPool(input) {
|
|
|
4760
4801
|
return {
|
|
4761
4802
|
candidates: ordered,
|
|
4762
4803
|
...pick === void 0 ? { ...earliestReturn === void 0 ? {} : { earliestReturn } } : { pick },
|
|
4763
|
-
...movedOff === void 0 || pick === void 0 ? {} : { movedOff }
|
|
4804
|
+
...movedOff === void 0 || pick === void 0 ? {} : { movedOff },
|
|
4805
|
+
...pick?.planReturnsAtMs === void 0 ? {} : { planReturn: { identity: pick.identity, atMs: pick.planReturnsAtMs } }
|
|
4764
4806
|
};
|
|
4765
4807
|
}
|
|
4766
4808
|
var MS_PER_SECOND4, MS_PER_HOUR2, HOURS_PER_DAY2, FIVE_HOURS, PROMPT_CACHE_TTL_HOURS, PERCENT, SEVEN_DAYS, FIVE_HOUR_WINDOW_MS, SEVEN_DAY_WINDOW_MS, PROMPT_CACHE_TTL_MS, CLASS_ORDER;
|
|
@@ -6140,32 +6182,50 @@ function ensureFrontDoor(params) {
|
|
|
6140
6182
|
let replaced = false;
|
|
6141
6183
|
const distrusted = /* @__PURE__ */ new Set();
|
|
6142
6184
|
let lastRejection;
|
|
6185
|
+
const verifyWithRetry = (port) => {
|
|
6186
|
+
let verdict = ports.verifyListener(port);
|
|
6187
|
+
for (let attempt = 1; !verdict.ok && attempt < FRONTDOOR_PROBE_ATTEMPTS; attempt += 1) {
|
|
6188
|
+
ports.sleep(FRONTDOOR_LAUNCHER_POLL_MS);
|
|
6189
|
+
verdict = ports.verifyListener(port);
|
|
6190
|
+
}
|
|
6191
|
+
return verdict;
|
|
6192
|
+
};
|
|
6193
|
+
const stopAndAwaitExit = (supervisorPid, failure) => {
|
|
6194
|
+
ports.stopSupervisor(supervisorPid);
|
|
6195
|
+
while (ports.isRunning(supervisorPid)) {
|
|
6196
|
+
if (ports.now() >= deadline) {
|
|
6197
|
+
throw new FrontDoorStartError(`${failure}. Daemon log: ${paths.frontdoorLogPath}`);
|
|
6198
|
+
}
|
|
6199
|
+
ports.sleep(FRONTDOOR_LAUNCHER_POLL_MS);
|
|
6200
|
+
}
|
|
6201
|
+
};
|
|
6143
6202
|
for (; ; ) {
|
|
6144
6203
|
const state = readFrontDoorState(ports.fs, paths.frontdoorStateFile);
|
|
6145
6204
|
const supervisorPid = state?.supervisorPid;
|
|
6146
6205
|
if (supervisorPid !== void 0 && !distrusted.has(supervisorPid) && ports.isRunning(supervisorPid)) {
|
|
6147
6206
|
if (state?.port !== void 0 && state.connectPort !== void 0) {
|
|
6148
|
-
const verdict =
|
|
6207
|
+
const verdict = verifyWithRetry(state.port);
|
|
6149
6208
|
if (verdict.ok && !replaced && !spawned && (params.replace === true || (state.protocol ?? 0) < FRONT_DOOR_PROTOCOL)) {
|
|
6150
|
-
|
|
6151
|
-
|
|
6152
|
-
|
|
6153
|
-
|
|
6154
|
-
}
|
|
6155
|
-
ports.sleep(FRONTDOOR_LAUNCHER_POLL_MS);
|
|
6156
|
-
}
|
|
6209
|
+
stopAndAwaitExit(
|
|
6210
|
+
supervisorPid,
|
|
6211
|
+
`the front door (pid ${String(supervisorPid)}, protocol ${String(state.protocol ?? 0)}; this launcher speaks protocol ${String(FRONT_DOOR_PROTOCOL)}) was asked to be replaced and did not exit`
|
|
6212
|
+
);
|
|
6157
6213
|
replaced = true;
|
|
6158
6214
|
continue;
|
|
6159
6215
|
}
|
|
6160
6216
|
if (verdict.ok) {
|
|
6161
6217
|
const token = randomUUID3();
|
|
6162
|
-
writeFrontDoorSession(ports.fs, paths.frontdoorSessionsDir, { pid: params.launcherPid, startedAt: ports.now(), token });
|
|
6218
|
+
writeFrontDoorSession(ports.fs, paths.frontdoorSessionsDir, { pid: params.launcherPid, startedAt: ports.now(), token, supervisorPid });
|
|
6163
6219
|
return { port: state.port, connectPort: state.connectPort, token };
|
|
6164
6220
|
}
|
|
6165
6221
|
lastRejection = `the listener on 127.0.0.1:${String(state.port)} (recorded for pid ${String(supervisorPid)}) failed authentication: ${verdict.reason}`;
|
|
6166
6222
|
if (spawned) {
|
|
6167
6223
|
throw new FrontDoorStartError(`${lastRejection}; refusing to send this session's credentials to it. Daemon log: ${paths.frontdoorLogPath}`);
|
|
6168
6224
|
}
|
|
6225
|
+
if (ports.isFrontDoorSupervisor(supervisorPid)) {
|
|
6226
|
+
stopAndAwaitExit(supervisorPid, `the front door (pid ${String(supervisorPid)}) stopped answering and did not exit when asked to`);
|
|
6227
|
+
continue;
|
|
6228
|
+
}
|
|
6169
6229
|
distrusted.add(supervisorPid);
|
|
6170
6230
|
continue;
|
|
6171
6231
|
}
|
|
@@ -6196,7 +6256,7 @@ function ensureFrontDoor(params) {
|
|
|
6196
6256
|
ports.sleep(FRONTDOOR_LAUNCHER_POLL_MS);
|
|
6197
6257
|
}
|
|
6198
6258
|
}
|
|
6199
|
-
var FRONTDOOR_START_TIMEOUT_MS, FRONTDOOR_LAUNCHER_POLL_MS, FrontDoorStartError;
|
|
6259
|
+
var FRONTDOOR_START_TIMEOUT_MS, FRONTDOOR_LAUNCHER_POLL_MS, FRONTDOOR_PROBE_ATTEMPTS, FrontDoorStartError;
|
|
6200
6260
|
var init_ensure2 = __esm({
|
|
6201
6261
|
"src/frontdoor/ensure.ts"() {
|
|
6202
6262
|
"use strict";
|
|
@@ -6205,6 +6265,7 @@ var init_ensure2 = __esm({
|
|
|
6205
6265
|
init_state();
|
|
6206
6266
|
FRONTDOOR_START_TIMEOUT_MS = 3e4;
|
|
6207
6267
|
FRONTDOOR_LAUNCHER_POLL_MS = 100;
|
|
6268
|
+
FRONTDOOR_PROBE_ATTEMPTS = 3;
|
|
6208
6269
|
FrontDoorStartError = class extends CliError {
|
|
6209
6270
|
constructor(message) {
|
|
6210
6271
|
super(message);
|
|
@@ -6688,7 +6749,12 @@ function resolvePoolLaunch(params) {
|
|
|
6688
6749
|
if (graph.ranking.candidates.length === 0) {
|
|
6689
6750
|
return { ok: false, message: `agent-shim: no member of pool "${poolName}" is an existing identity.` };
|
|
6690
6751
|
}
|
|
6691
|
-
const { pick, earliestReturn, movedOff } = graph.ranking;
|
|
6752
|
+
const { pick, earliestReturn, movedOff, planReturn } = graph.ranking;
|
|
6753
|
+
if (pick !== void 0 && params.wait && planReturn !== void 0) {
|
|
6754
|
+
log.info(`agent-shim: pool "${poolName}" would continue ${planReturn.identity} on extra usage; waiting until ${new Date(planReturn.atMs).toISOString()} for its plan window`);
|
|
6755
|
+
params.sleep(Math.max(planReturn.atMs - nowMs, 0));
|
|
6756
|
+
continue;
|
|
6757
|
+
}
|
|
6692
6758
|
if (pick !== void 0) {
|
|
6693
6759
|
if (params.recordPick) {
|
|
6694
6760
|
recordStickyPick(params.usageFs, params.paths.usagePicksFile, params.cwd, pick.identity, nowMs);
|
|
@@ -7391,6 +7457,7 @@ function realEnsurePorts(paths, spawnDaemon) {
|
|
|
7391
7457
|
now: () => Date.now(),
|
|
7392
7458
|
sleep: realSleepSync,
|
|
7393
7459
|
spawnSupervisor: (layout) => spawnDaemon(layout, "__frontdoor-supervisor", layout.frontdoorLogPath),
|
|
7460
|
+
isFrontDoorSupervisor: realIsFrontDoorSupervisor,
|
|
7394
7461
|
stopSupervisor: (pid) => {
|
|
7395
7462
|
process.kill(pid, "SIGTERM");
|
|
7396
7463
|
},
|
|
@@ -8291,16 +8358,27 @@ async function runFrontDoorSupervisor(idleShutdownMinutes, ports, options = {})
|
|
|
8291
8358
|
ports.log(`agent-shim frontdoor supervisor ${String(ports.ownPid)}: front door on 127.0.0.1:${String(http3.port)}, CONNECT surface on 127.0.0.1:${String(connect3.port)}`);
|
|
8292
8359
|
let idleSince;
|
|
8293
8360
|
let ticks = 0;
|
|
8361
|
+
const supersedingOwner = () => {
|
|
8362
|
+
const owner = readFrontDoorState(fs12, paths.frontdoorStateFile)?.supervisorPid;
|
|
8363
|
+
return owner !== void 0 && owner !== ports.ownPid && ports.isRunning(owner) ? owner : void 0;
|
|
8364
|
+
};
|
|
8365
|
+
let supersededBy;
|
|
8366
|
+
let served;
|
|
8294
8367
|
const binaryReplaced = () => {
|
|
8295
8368
|
const current = ports.statOwnExecutable();
|
|
8296
8369
|
return current !== void 0 && servingBinary !== void 0 && (current.dev !== servingBinary.dev || current.ino !== servingBinary.ino || current.size !== servingBinary.size || current.mtimeMs !== servingBinary.mtimeMs);
|
|
8297
8370
|
};
|
|
8298
|
-
const
|
|
8371
|
+
const closeServing = async () => {
|
|
8299
8372
|
await direct.close();
|
|
8300
8373
|
await connect3.close();
|
|
8301
8374
|
await http3.close();
|
|
8302
8375
|
ports.closeRcStreamHub();
|
|
8303
|
-
|
|
8376
|
+
};
|
|
8377
|
+
const shutdown = async () => {
|
|
8378
|
+
await closeServing();
|
|
8379
|
+
if (supersedingOwner() === void 0) {
|
|
8380
|
+
writeFrontDoorState(fs12, paths.frontdoorStateFile, sticky());
|
|
8381
|
+
}
|
|
8304
8382
|
return 0;
|
|
8305
8383
|
};
|
|
8306
8384
|
for (; ; ) {
|
|
@@ -8313,7 +8391,28 @@ async function runFrontDoorSupervisor(idleShutdownMinutes, ports, options = {})
|
|
|
8313
8391
|
ports.observeLaunchRegistry(listed, pruned);
|
|
8314
8392
|
ports.checkQuotaExpiry();
|
|
8315
8393
|
const prunedPids = new Set(pruned);
|
|
8316
|
-
|
|
8394
|
+
const live = listed.filter((session) => !prunedPids.has(session.pid));
|
|
8395
|
+
if (supersededBy === void 0) {
|
|
8396
|
+
supersededBy = supersedingOwner();
|
|
8397
|
+
if (supersededBy !== void 0) {
|
|
8398
|
+
ports.log(`agent-shim frontdoor supervisor ${String(ports.ownPid)}: supervisor ${String(supersededBy)} now owns the front door; taking no new sessions and exiting once the sessions this door serves have ended`);
|
|
8399
|
+
ports.doorHealth.superseded(supersededBy);
|
|
8400
|
+
await ports.sleep(FRONTDOOR_POLL_MS);
|
|
8401
|
+
continue;
|
|
8402
|
+
}
|
|
8403
|
+
} else {
|
|
8404
|
+
const owner = supersededBy;
|
|
8405
|
+
served = (served ?? live.filter((session) => session.pid !== ports.ownPid && session.pid !== owner && (session.supervisorPid === void 0 || session.supervisorPid === ports.ownPid))).filter((own) => live.some((session) => session.pid === own.pid && session.startedAt === own.startedAt));
|
|
8406
|
+
if (served.length === 0) {
|
|
8407
|
+
ports.log("agent-shim frontdoor supervisor: the sessions this superseded door served have ended; closing the front door and exiting");
|
|
8408
|
+
ports.doorHealth.drained();
|
|
8409
|
+
await closeServing();
|
|
8410
|
+
return 0;
|
|
8411
|
+
}
|
|
8412
|
+
await ports.sleep(FRONTDOOR_POLL_MS);
|
|
8413
|
+
continue;
|
|
8414
|
+
}
|
|
8415
|
+
if (live.length === 0) {
|
|
8317
8416
|
if (ticks > 1 && binaryReplaced()) {
|
|
8318
8417
|
ports.log("agent-shim frontdoor supervisor: the installed binary changed and no sessions are live; turning the door over for the next launch");
|
|
8319
8418
|
ports.doorHealth.binaryTurnover();
|
|
@@ -12467,7 +12566,55 @@ init_credential();
|
|
|
12467
12566
|
init_credentialCache();
|
|
12468
12567
|
init_realCredentialCache();
|
|
12469
12568
|
init_source();
|
|
12569
|
+
|
|
12570
|
+
// src/headroom/allowlistDrift.ts
|
|
12571
|
+
init_state2();
|
|
12572
|
+
function diagnoseAllowlistDrift(params) {
|
|
12573
|
+
const { recordedHash, providers, frontDoorOrigin: frontDoorOrigin2 } = params;
|
|
12574
|
+
if (recordedHash === void 0 || recordedHash === hashAllowlist(headroomAllowlist(headroomUpstreams(providers, frontDoorOrigin2)))) {
|
|
12575
|
+
return void 0;
|
|
12576
|
+
}
|
|
12577
|
+
const originIsInput = providers.length > 0 && frontDoorOrigin2 !== void 0;
|
|
12578
|
+
if (!originIsInput) {
|
|
12579
|
+
return ["provider-files"];
|
|
12580
|
+
}
|
|
12581
|
+
return recordedHash === hashAllowlist(headroomAllowlist(headroomUpstreams(providers, void 0))) ? ["front-door-origin"] : ["provider-files", "front-door-origin"];
|
|
12582
|
+
}
|
|
12583
|
+
|
|
12584
|
+
// src/doctorReport.ts
|
|
12470
12585
|
init_state2();
|
|
12586
|
+
init_supervisor();
|
|
12587
|
+
init_state();
|
|
12588
|
+
|
|
12589
|
+
// src/doctorFrontDoor.ts
|
|
12590
|
+
function pushFrontDoor(push, supervisors, registeredPid) {
|
|
12591
|
+
if (!supervisors.ok) {
|
|
12592
|
+
push("frontdoor", "warn", `Could not list processes to look for duplicate front door supervisors: ${supervisors.message}.`);
|
|
12593
|
+
return;
|
|
12594
|
+
}
|
|
12595
|
+
const { pids } = supervisors;
|
|
12596
|
+
if (pids.length === 0) {
|
|
12597
|
+
push("frontdoor", "pass", "No front door supervisor is running.");
|
|
12598
|
+
return;
|
|
12599
|
+
}
|
|
12600
|
+
const [only, ...rest] = pids;
|
|
12601
|
+
if (only !== void 0 && rest.length === 0) {
|
|
12602
|
+
push("frontdoor", "pass", `One front door supervisor is running (pid ${String(only)}).`);
|
|
12603
|
+
return;
|
|
12604
|
+
}
|
|
12605
|
+
const serving = registeredPid !== void 0 && pids.includes(registeredPid) ? `The front door state file names pid ${String(registeredPid)} as the serving supervisor.` : "The front door state file names no running supervisor.";
|
|
12606
|
+
for (const pid of pids.filter((candidate) => candidate !== registeredPid)) {
|
|
12607
|
+
push(
|
|
12608
|
+
"frontdoor",
|
|
12609
|
+
"fail",
|
|
12610
|
+
`Front door supervisor pid ${String(pid)} is running beside ${String(pids.length - 1)} other(s). ${serving} Stop it with \`kill ${String(pid)}\`; launches still connected to it lose their door.`,
|
|
12611
|
+
String(pid)
|
|
12612
|
+
);
|
|
12613
|
+
}
|
|
12614
|
+
}
|
|
12615
|
+
|
|
12616
|
+
// src/doctorReport.ts
|
|
12617
|
+
init_supervisorProcesses();
|
|
12471
12618
|
init_legacy();
|
|
12472
12619
|
init_providersStore();
|
|
12473
12620
|
init_guard();
|
|
@@ -12490,7 +12637,8 @@ var DOCTOR_SECTIONS = [
|
|
|
12490
12637
|
"global-config",
|
|
12491
12638
|
"categories-local",
|
|
12492
12639
|
"active-identity",
|
|
12493
|
-
"headroom"
|
|
12640
|
+
"headroom",
|
|
12641
|
+
"frontdoor"
|
|
12494
12642
|
];
|
|
12495
12643
|
function refinePathShadow(status, ownExecutablePath, realpath) {
|
|
12496
12644
|
if (status.status !== "shadowed") {
|
|
@@ -12886,6 +13034,17 @@ function runDoctor(params) {
|
|
|
12886
13034
|
`Headroom daemon is up on unix socket ${state.socketPath} (supervisor ${String(state.supervisorPid)}, daemon ${String(state.headroomPid)}).`
|
|
12887
13035
|
);
|
|
12888
13036
|
}
|
|
13037
|
+
const allowlist = params.headroom.allowlist;
|
|
13038
|
+
if (supervisorAlive && headroomAlive && state.socketPath !== void 0 && allowlist?.driftInputs?.includes("front-door-origin") === true) {
|
|
13039
|
+
const origin = allowlist.frontDoorOrigin ?? "";
|
|
13040
|
+
const certainty = allowlist.driftInputs.includes("provider-files") ? "may exclude" : "excludes";
|
|
13041
|
+
push(
|
|
13042
|
+
"headroom",
|
|
13043
|
+
"fail",
|
|
13044
|
+
`Headroom daemon ${String(state.headroomPid)} was started with an allowlist that ${certainty} the serving front door's direct origin ${origin}, so it refuses every request a provider launch sends back through the door. Its supervisor restarts it once no launch is registered against it; \`agent-shim headroom status\` lists the registered launches, and \`--no-headroom\` launches are unaffected.`,
|
|
13045
|
+
String(state.headroomPid)
|
|
13046
|
+
);
|
|
13047
|
+
}
|
|
12889
13048
|
if (state.lastError !== void 0 && supervisorAlive) {
|
|
12890
13049
|
push("headroom", "warn", `Headroom recorded a previous error: ${state.lastError}`);
|
|
12891
13050
|
}
|
|
@@ -12898,6 +13057,10 @@ function runDoctor(params) {
|
|
|
12898
13057
|
}
|
|
12899
13058
|
}
|
|
12900
13059
|
}
|
|
13060
|
+
if (params.frontDoor !== void 0) {
|
|
13061
|
+
const validated3 = params.frontDoor.state.raw === void 0 ? void 0 : validateJson(FrontDoorStateSchema, params.frontDoor.state);
|
|
13062
|
+
pushFrontDoor(push, params.frontDoor.supervisors, validated3?.ok === true ? validated3.data.supervisorPid : void 0);
|
|
13063
|
+
}
|
|
12901
13064
|
if (params.activeIdentity.raw === void 0) {
|
|
12902
13065
|
push("active-identity", "pass", "No active identity set.");
|
|
12903
13066
|
} else {
|
|
@@ -12927,6 +13090,7 @@ var SECTION_TITLES = {
|
|
|
12927
13090
|
"directory-rules": "Directory rules",
|
|
12928
13091
|
"global-config": "Global config",
|
|
12929
13092
|
headroom: "Headroom daemon",
|
|
13093
|
+
frontdoor: "Front door",
|
|
12930
13094
|
"categories-local": "categories.local.json",
|
|
12931
13095
|
"active-identity": "Active identity"
|
|
12932
13096
|
};
|
|
@@ -12944,6 +13108,7 @@ var SECTION_ORDER = [
|
|
|
12944
13108
|
"directory-rules",
|
|
12945
13109
|
"global-config",
|
|
12946
13110
|
"headroom",
|
|
13111
|
+
"frontdoor",
|
|
12947
13112
|
"categories-local",
|
|
12948
13113
|
"active-identity"
|
|
12949
13114
|
];
|
|
@@ -13021,6 +13186,9 @@ function collectDoctorReport(params) {
|
|
|
13021
13186
|
shimState.targetPath,
|
|
13022
13187
|
realpathOrSelf
|
|
13023
13188
|
);
|
|
13189
|
+
const uid = process.getuid?.();
|
|
13190
|
+
const allowlistInputs = currentHeadroomAllowlistInputs(realFarmFs, paths);
|
|
13191
|
+
const servingHeadroom = resolveServingHeadroomState(realFarmFs, { stateFile: paths.headroomStateFile, legacyStateFile: paths.headroomLegacyStateFile }, realIsProcessRunning);
|
|
13024
13192
|
const report = runDoctor({
|
|
13025
13193
|
env: params.env,
|
|
13026
13194
|
credentialCache: realCredentialCacheEnv(paths),
|
|
@@ -13059,8 +13227,13 @@ function collectDoctorReport(params) {
|
|
|
13059
13227
|
const statePath = resolved?.path ?? paths.headroomStateFile;
|
|
13060
13228
|
return { path: statePath, raw: realFarmFs.readFileUtf8(statePath) };
|
|
13061
13229
|
})(),
|
|
13062
|
-
isRunning: realIsProcessRunning
|
|
13063
|
-
|
|
13230
|
+
isRunning: realIsProcessRunning,
|
|
13231
|
+
allowlist: {
|
|
13232
|
+
driftInputs: diagnoseAllowlistDrift({ recordedHash: servingHeadroom?.state.allowlistHash, ...allowlistInputs }),
|
|
13233
|
+
frontDoorOrigin: allowlistInputs.frontDoorOrigin
|
|
13234
|
+
}
|
|
13235
|
+
},
|
|
13236
|
+
...uid === void 0 ? {} : { frontDoor: { state: { path: paths.frontdoorStateFile, raw: realFsPort.readFileUtf8(paths.frontdoorStateFile) }, supervisors: listFrontDoorSupervisors(realRunPort, uid) } }
|
|
13064
13237
|
});
|
|
13065
13238
|
return report;
|
|
13066
13239
|
}
|
|
@@ -13762,7 +13935,9 @@ var DoorHealthEventSchema = z23.discriminatedUnion("kind", [
|
|
|
13762
13935
|
z23.strictObject({ kind: z23.literal("generation"), pid: z23.number().int().positive(), providerPort: z23.number().int().positive(), connectPort: z23.number().int().positive(), directPort: z23.number().int().positive(), observedAt: z23.number() }),
|
|
13763
13936
|
z23.strictObject({ kind: z23.literal("listenerFailed"), pid: z23.number().int().positive(), listener: z23.enum(["provider", "connect", "direct"]), message: z23.string(), observedAt: z23.number() }),
|
|
13764
13937
|
z23.strictObject({ kind: z23.literal("binaryTurnover"), pid: z23.number().int().positive(), observedAt: z23.number() }),
|
|
13765
|
-
z23.strictObject({ kind: z23.literal("idleShutdown"), pid: z23.number().int().positive(), observedAt: z23.number() })
|
|
13938
|
+
z23.strictObject({ kind: z23.literal("idleShutdown"), pid: z23.number().int().positive(), observedAt: z23.number() }),
|
|
13939
|
+
z23.strictObject({ kind: z23.literal("superseded"), pid: z23.number().int().positive(), ownerPid: z23.number().int().positive(), observedAt: z23.number() }),
|
|
13940
|
+
z23.strictObject({ kind: z23.literal("drained"), pid: z23.number().int().positive(), observedAt: z23.number() })
|
|
13766
13941
|
]);
|
|
13767
13942
|
var QuotaExpiringEventSchema = z23.strictObject({
|
|
13768
13943
|
identity: z23.string().min(1),
|
|
@@ -14259,6 +14434,12 @@ function createDoorHealthPublisher(hub, now, pid) {
|
|
|
14259
14434
|
},
|
|
14260
14435
|
binaryTurnover: () => {
|
|
14261
14436
|
publisher.publish({ kind: "binaryTurnover", pid, observedAt: now() });
|
|
14437
|
+
},
|
|
14438
|
+
superseded: (ownerPid) => {
|
|
14439
|
+
publisher.publish({ kind: "superseded", pid, ownerPid, observedAt: now() });
|
|
14440
|
+
},
|
|
14441
|
+
drained: () => {
|
|
14442
|
+
publisher.publish({ kind: "drained", pid, observedAt: now() });
|
|
14262
14443
|
}
|
|
14263
14444
|
};
|
|
14264
14445
|
}
|
package/dist/types/index.d.ts
CHANGED
|
@@ -4586,6 +4586,18 @@ type PathShadowStatus = {
|
|
|
4586
4586
|
readonly by: string;
|
|
4587
4587
|
};
|
|
4588
4588
|
|
|
4589
|
+
/** One input the headroom allowlist is computed from: the provider definitions on disk, or the front door's direct origin. */
|
|
4590
|
+
type AllowlistDriftInput = "provider-files" | "front-door-origin";
|
|
4591
|
+
|
|
4592
|
+
/** What listing the front-door supervisors found: their pids, or why the process table could not be read. */
|
|
4593
|
+
type FrontDoorSupervisorListing = {
|
|
4594
|
+
readonly ok: true;
|
|
4595
|
+
readonly pids: readonly number[];
|
|
4596
|
+
} | {
|
|
4597
|
+
readonly ok: false;
|
|
4598
|
+
readonly message: string;
|
|
4599
|
+
};
|
|
4600
|
+
|
|
4589
4601
|
/** The result of a successful discovery. */
|
|
4590
4602
|
interface DiscoveredClaudeBinary {
|
|
4591
4603
|
/** Full path to the discovered `claude` executable. */
|
|
@@ -4604,7 +4616,7 @@ type ClaudeBinaryResolver = (request?: Readonly<ClaudeBinaryRequest>) => Discove
|
|
|
4604
4616
|
|
|
4605
4617
|
declare const DOCTOR_SEVERITIES: readonly ["pass", "warn", "fail"];
|
|
4606
4618
|
type DoctorSeverity = (typeof DOCTOR_SEVERITIES)[number];
|
|
4607
|
-
declare const DOCTOR_SECTIONS: readonly ["ambient-credential", "binary-discovery", "claude-shim", "path-resolution", "legacy-name", "config-profile", "identity", "sign-in", "pool", "provider", "keychain", "directory-rules", "global-config", "categories-local", "active-identity", "headroom"];
|
|
4619
|
+
declare const DOCTOR_SECTIONS: readonly ["ambient-credential", "binary-discovery", "claude-shim", "path-resolution", "legacy-name", "config-profile", "identity", "sign-in", "pool", "provider", "keychain", "directory-rules", "global-config", "categories-local", "active-identity", "headroom", "frontdoor"];
|
|
4608
4620
|
type DoctorSection = (typeof DOCTOR_SECTIONS)[number];
|
|
4609
4621
|
/** One line of `agent-shim doctor`'s report. `subject` names the identity/profile/rule the finding is about, when the section has more than one of those. */
|
|
4610
4622
|
interface DoctorFinding {
|
|
@@ -4700,6 +4712,18 @@ interface RunDoctorParams {
|
|
|
4700
4712
|
readonly headroom: {
|
|
4701
4713
|
readonly state: DoctorFileInput;
|
|
4702
4714
|
readonly isRunning: (pid: number) => boolean;
|
|
4715
|
+
/** What the daemon's allowlist is measured against. Omit to skip the allowlist check; with it, a daemon whose allowlist may exclude the serving door's direct origin is a failure. */
|
|
4716
|
+
readonly allowlist?: {
|
|
4717
|
+
/** The inputs that could explain the recorded allowlist hash not matching the current allowlist, or undefined when it matches. */
|
|
4718
|
+
readonly driftInputs: readonly AllowlistDriftInput[] | undefined;
|
|
4719
|
+
/** The serving front door's direct origin, or undefined before it has ever served. */
|
|
4720
|
+
readonly frontDoorOrigin: string | undefined;
|
|
4721
|
+
};
|
|
4722
|
+
};
|
|
4723
|
+
/** The front door's state.json and the supervisor processes alive for this user. Omit to skip the front-door checks (the platform cannot list processes); with it, more than one supervisor alive at once is a failure naming each superseded one. */
|
|
4724
|
+
readonly frontDoor?: {
|
|
4725
|
+
readonly state: DoctorFileInput;
|
|
4726
|
+
readonly supervisors: FrontDoorSupervisorListing;
|
|
4703
4727
|
};
|
|
4704
4728
|
}
|
|
4705
4729
|
/**
|
|
@@ -4888,11 +4912,14 @@ declare const UsageSnapshotSchema: z.ZodObject<{
|
|
|
4888
4912
|
}, z.core.$strict>;
|
|
4889
4913
|
type UsageSnapshot = z.infer<typeof UsageSnapshotSchema>;
|
|
4890
4914
|
|
|
4891
|
-
/**
|
|
4915
|
+
/**
|
|
4916
|
+
* The record held in one front-door session-registry file: the launcher's pid plus the per-launch capability token its child presents on every request, and the supervisor of the door the launch was sent to. `supervisorPid` is absent on a record written before it existed and on a door's own transparent-surface record; such a launch cannot be attributed to a door, so a superseded door treats it as its own.
|
|
4917
|
+
*/
|
|
4892
4918
|
declare const FrontDoorSessionSchema: z.ZodObject<{
|
|
4893
4919
|
pid: z.ZodNumber;
|
|
4894
4920
|
startedAt: z.ZodNumber;
|
|
4895
4921
|
token: z.ZodString;
|
|
4922
|
+
supervisorPid: z.ZodOptional<z.ZodNumber>;
|
|
4896
4923
|
}, z.core.$strict>;
|
|
4897
4924
|
type FrontDoorSession = z.infer<typeof FrontDoorSessionSchema>;
|
|
4898
4925
|
/**
|
|
@@ -4911,7 +4938,7 @@ declare const FrontDoorStateSchema: z.ZodObject<{
|
|
|
4911
4938
|
}, z.core.$strict>;
|
|
4912
4939
|
type FrontDoorState = z.infer<typeof FrontDoorStateSchema>;
|
|
4913
4940
|
/** A registered launch as status and the idle decision see it: the pid and start time, never the token, so nothing that prints or serialises a session can leak the capability. */
|
|
4914
|
-
type FrontDoorSessionSummary = Pick<FrontDoorSession, "pid" | "startedAt">;
|
|
4941
|
+
type FrontDoorSessionSummary = Pick<FrontDoorSession, "pid" | "startedAt" | "supervisorPid">;
|
|
4915
4942
|
|
|
4916
4943
|
/** How a sign-out went: whether OpenAI was told, so the person knows the grant is dead on its side too. */
|
|
4917
4944
|
interface SiwcLogoutResult {
|
|
@@ -6283,7 +6310,7 @@ declare const LaunchLifecycleEventSchema: z.ZodObject<{
|
|
|
6283
6310
|
/** One launch lifecycle event, as the TypeScript the publisher emits and its consumers handle. */
|
|
6284
6311
|
type LaunchLifecycleEvent = z.output<typeof LaunchLifecycleEventSchema>;
|
|
6285
6312
|
/**
|
|
6286
|
-
* One door health event: the supervisor's own state transitions, observed at the moment they happened in this process. `generation` is the door fully serving (every listener bound and the state file naming it); `listenerFailed` is a start failure that ends the generation, naming which listener and why; `binaryTurnover` is the door retiring because the installed binary changed and no session is live, so the next launch serves from the new one; `idleShutdown` is the door closing itself with an empty session registry.
|
|
6313
|
+
* One door health event: the supervisor's own state transitions, observed at the moment they happened in this process. `generation` is the door fully serving (every listener bound and the state file naming it); `listenerFailed` is a start failure that ends the generation, naming which listener and why; `binaryTurnover` is the door retiring because the installed binary changed and no session is live, so the next launch serves from the new one; `idleShutdown` is the door closing itself with an empty session registry; `superseded` is the state file coming to name another live supervisor, `ownerPid`, after which this door takes no new sessions; `drained` is a superseded door closing itself because every session it served has ended.
|
|
6287
6314
|
*/
|
|
6288
6315
|
declare const DoorHealthEventSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
6289
6316
|
kind: z.ZodLiteral<"generation">;
|
|
@@ -6310,6 +6337,15 @@ declare const DoorHealthEventSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
6310
6337
|
kind: z.ZodLiteral<"idleShutdown">;
|
|
6311
6338
|
pid: z.ZodNumber;
|
|
6312
6339
|
observedAt: z.ZodNumber;
|
|
6340
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
6341
|
+
kind: z.ZodLiteral<"superseded">;
|
|
6342
|
+
pid: z.ZodNumber;
|
|
6343
|
+
ownerPid: z.ZodNumber;
|
|
6344
|
+
observedAt: z.ZodNumber;
|
|
6345
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
6346
|
+
kind: z.ZodLiteral<"drained">;
|
|
6347
|
+
pid: z.ZodNumber;
|
|
6348
|
+
observedAt: z.ZodNumber;
|
|
6313
6349
|
}, z.core.$strict>], "kind">;
|
|
6314
6350
|
/** One door health event, as the TypeScript the publisher emits and its consumers handle. */
|
|
6315
6351
|
type DoorHealthEvent = z.output<typeof DoorHealthEventSchema>;
|
|
@@ -7387,6 +7423,7 @@ declare function createControlApiRouter(deps: ControlApiDeps): {
|
|
|
7387
7423
|
"config-profile": "config-profile";
|
|
7388
7424
|
identity: "identity";
|
|
7389
7425
|
provider: "provider";
|
|
7426
|
+
frontdoor: "frontdoor";
|
|
7390
7427
|
pool: "pool";
|
|
7391
7428
|
keychain: "keychain";
|
|
7392
7429
|
"ambient-credential": "ambient-credential";
|
|
@@ -9369,6 +9406,7 @@ declare function createDoorApiRouter(deps: DoorApiDeps): {
|
|
|
9369
9406
|
"config-profile": "config-profile";
|
|
9370
9407
|
identity: "identity";
|
|
9371
9408
|
provider: "provider";
|
|
9409
|
+
frontdoor: "frontdoor";
|
|
9372
9410
|
pool: "pool";
|
|
9373
9411
|
keychain: "keychain";
|
|
9374
9412
|
"ambient-credential": "ambient-credential";
|
|
@@ -11175,6 +11213,7 @@ declare const DoctorFindingSchema: z.ZodObject<{
|
|
|
11175
11213
|
"config-profile": "config-profile";
|
|
11176
11214
|
identity: "identity";
|
|
11177
11215
|
provider: "provider";
|
|
11216
|
+
frontdoor: "frontdoor";
|
|
11178
11217
|
pool: "pool";
|
|
11179
11218
|
keychain: "keychain";
|
|
11180
11219
|
"ambient-credential": "ambient-credential";
|
|
@@ -11205,6 +11244,7 @@ declare const DoctorRunOutputSchema: z.ZodObject<{
|
|
|
11205
11244
|
"config-profile": "config-profile";
|
|
11206
11245
|
identity: "identity";
|
|
11207
11246
|
provider: "provider";
|
|
11247
|
+
frontdoor: "frontdoor";
|
|
11208
11248
|
pool: "pool";
|
|
11209
11249
|
keychain: "keychain";
|
|
11210
11250
|
"ambient-credential": "ambient-credential";
|
|
@@ -11397,7 +11437,7 @@ interface LaunchEventPublisher {
|
|
|
11397
11437
|
declare function createLaunchEventPublisher(hub: DoorEventHub, now: () => number): LaunchEventPublisher;
|
|
11398
11438
|
|
|
11399
11439
|
/**
|
|
11400
|
-
* The door health publisher: the supervisor's own state transitions as backbone events, so a consumer of the door learns the door itself changed and not only its sessions. The publisher emits nothing of its own: the supervisor tells it the moments it already lives through (every listener bound, a start failure that ends the generation, the binary turnover, the idle shutdown), each published the moment it happens rather than at a tick, because these are process facts, not registry facts diffed between observations.
|
|
11440
|
+
* The door health publisher: the supervisor's own state transitions as backbone events, so a consumer of the door learns the door itself changed and not only its sessions. The publisher emits nothing of its own: the supervisor tells it the moments it already lives through (every listener bound, a start failure that ends the generation, the binary turnover, the idle shutdown, the supersession and the drained exit that follows it), each published the moment it happens rather than at a tick, because these are process facts, not registry facts diffed between observations.
|
|
11401
11441
|
*/
|
|
11402
11442
|
/** Everything the door health publisher needs: the backbone it publishes on and the clock its events are observed at. */
|
|
11403
11443
|
interface DoorHealthPublisher {
|
|
@@ -11413,6 +11453,10 @@ interface DoorHealthPublisher {
|
|
|
11413
11453
|
readonly binaryTurnover: () => void;
|
|
11414
11454
|
/** Publishes the idle shutdown: the door closing itself with an empty session registry. */
|
|
11415
11455
|
readonly idleShutdown: () => void;
|
|
11456
|
+
/** Publishes the supersession: the state file naming another live supervisor, `ownerPid`, so this door takes no new sessions and serves only those it already had. */
|
|
11457
|
+
readonly superseded: (ownerPid: number) => void;
|
|
11458
|
+
/** Publishes the drained exit: a superseded door closing itself because every session it served has ended. */
|
|
11459
|
+
readonly drained: () => void;
|
|
11416
11460
|
}
|
|
11417
11461
|
/** Creates the door health publisher. One per door process, fed by the supervisor. */
|
|
11418
11462
|
declare function createDoorHealthPublisher(hub: DoorEventHub, now: () => number, pid: number): DoorHealthPublisher;
|
|
@@ -11662,8 +11706,10 @@ interface EnsureFrontDoorPorts {
|
|
|
11662
11706
|
readonly spawnSupervisor: (paths: LayoutPaths) => number;
|
|
11663
11707
|
/** Authenticates the provider listener on `port`: a TLS handshake chaining to agent-shim's CA and a healthy answer, with no capability sent (see `probeFrontDoorSync`). */
|
|
11664
11708
|
readonly verifyListener: (port: number) => ListenerVerdict;
|
|
11665
|
-
/** Asks a running front-door supervisor to exit, without waiting for it to: the caller polls `isRunning`. Only ever called for a pid whose recorded listener has just authenticated as agent-shim's own. */
|
|
11709
|
+
/** Asks a running front-door supervisor to exit, without waiting for it to: the caller polls `isRunning`. Only ever called for a pid whose recorded listener has just authenticated as agent-shim's own, or whose process is agent-shim's front-door supervisor (`isFrontDoorSupervisor`). */
|
|
11666
11710
|
readonly stopSupervisor: (pid: number) => void;
|
|
11711
|
+
/** Whether `pid` is a live agent-shim front-door supervisor process, read from the process's own command line. This is what separates a wedged door of this tool, which a replacement must retire so the two never coexist, from an unrelated process that reuses the recorded pid, which must never be signalled. */
|
|
11712
|
+
readonly isFrontDoorSupervisor: (pid: number) => boolean;
|
|
11667
11713
|
}
|
|
11668
11714
|
/**
|
|
11669
11715
|
* Brings the front door up for this launch, or finds it serving, and registers this launcher pid in its session registry: the fact that keeps the door from idling out while this session lives, and the record that holds this launch's capability token. The same lock-and-poll coordination as headroom's and the old codex daemon's ensure: the exclusive-create start lock decides which of several concurrent launches spawns the one supervisor, everyone waits on state.json, and a lock whose holder died is removed and retried. Ready means state names a live supervisor and both listeners' ports, which the supervisor writes only after both have bound (and the provider listener has answered its own health probe).
|
|
@@ -11751,7 +11797,7 @@ interface RunFrontDoorSupervisorOptions {
|
|
|
11751
11797
|
readonly tickLimit?: number;
|
|
11752
11798
|
}
|
|
11753
11799
|
/**
|
|
11754
|
-
* Runs the front-door supervisor: binds all three listeners (the HTTPS provider listener, the CONNECT surface and the plain-HTTP direct listener, each on its sticky port), records the serving state, and shuts down with an empty session registry, either at the first such tick after the executable it serves as has been replaced on disk (so an applied update reaches the door without waiting out the idle window) or after `idleShutdownMinutes` of it. Returns the exit code: 0 for
|
|
11800
|
+
* Runs the front-door supervisor: binds all three listeners (the HTTPS provider listener, the CONNECT surface and the plain-HTTP direct listener, each on its sticky port), records the serving state, and shuts down with an empty session registry, either at the first such tick after the executable it serves as has been replaced on disk (so an applied update reaches the door without waiting out the idle window) or after `idleShutdownMinutes` of it. A door whose state file comes to name another live supervisor is superseded: from then on it takes no new sessions, never writes the state file again, and exits as soon as the sessions it was serving have ended. Returns the exit code: 0 for any of these retirements, 1 for a fatal start failure.
|
|
11755
11801
|
*
|
|
11756
11802
|
* The listeners live in this process, so there is no child to keep alive: a crash of this process is a crash of every routed session's door at once, and recovery is the next launch's ensure spawning a replacement on the same sticky ports, which is exactly the failure model the issue asks to settle with tests. Keeping the headroom daemon alive is the headroom supervisor's job, not this one's; the two daemons idle out independently.
|
|
11757
11803
|
*/
|
|
@@ -11902,6 +11948,8 @@ interface Candidate {
|
|
|
11902
11948
|
readonly headroom?: number;
|
|
11903
11949
|
/** When an `ineligible` candidate can be used again. */
|
|
11904
11950
|
readonly blockedUntilMs?: number;
|
|
11951
|
+
/** When the exhausted plan window of a `pay-per-use` candidate that is only on extra usage because its plan ran out resets, so a launch can hold for it rather than spend. Absent for a candidate that bills by use with no plan allowance. */
|
|
11952
|
+
readonly planReturnsAtMs?: number;
|
|
11905
11953
|
readonly plan: PlanClass;
|
|
11906
11954
|
/** True when the member's policy condition could not be decided and it is ranked last within its class, naming the missing fact in its reasons. */
|
|
11907
11955
|
readonly policyDemoted?: boolean;
|
|
@@ -11918,6 +11966,11 @@ interface PoolRanking {
|
|
|
11918
11966
|
readonly identity: string;
|
|
11919
11967
|
readonly atMs: number;
|
|
11920
11968
|
};
|
|
11969
|
+
/** When the pick continues on extra usage only because its plan ran out, the identity and the instant its plan window resets: what a launch that would rather wait than spend sleeps until. Absent when the pick is on plan quota, bills by use with no plan, or no member can be picked. */
|
|
11970
|
+
readonly planReturn?: {
|
|
11971
|
+
readonly identity: string;
|
|
11972
|
+
readonly atMs: number;
|
|
11973
|
+
};
|
|
11921
11974
|
/** The member a resumed or continued conversation started on but moved off, and why, when a launch that resumes could not keep it. One sentence for the launch decision line and `check`. */
|
|
11922
11975
|
readonly movedOff?: {
|
|
11923
11976
|
readonly identity: string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-use",
|
|
3
|
-
"version": "9.
|
|
3
|
+
"version": "9.13.0",
|
|
4
4
|
"description": "A profile manager and launcher for Claude Code that lets one person run multiple logins from one machine while controlling what gets shared between them.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Joseph Mearman <joseph@mearman.co.uk>",
|