agent-shim 11.83.4 → 11.83.5
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 +186 -118
- package/dist/index.cjs +10 -5
- package/dist/index.mjs +10 -5
- package/dist/types/index.d.ts +8 -1
- package/package.json +1 -1
package/dist/cli.cjs
CHANGED
|
@@ -23762,9 +23762,9 @@ var require_env_paths = __commonJS({
|
|
|
23762
23762
|
"node_modules/.pnpm/env-paths@2.2.1/node_modules/env-paths/index.js"(exports2, module2) {
|
|
23763
23763
|
"use strict";
|
|
23764
23764
|
var path79 = require("path");
|
|
23765
|
-
var
|
|
23766
|
-
var homedir =
|
|
23767
|
-
var tmpdir =
|
|
23765
|
+
var os17 = require("os");
|
|
23766
|
+
var homedir = os17.homedir();
|
|
23767
|
+
var tmpdir = os17.tmpdir();
|
|
23768
23768
|
var { env } = process;
|
|
23769
23769
|
var macos = (name) => {
|
|
23770
23770
|
const library = path79.join(homedir, "Library");
|
|
@@ -36845,13 +36845,18 @@ async function serveFrontDoor(idleShutdownMinutes, ports, options) {
|
|
|
36845
36845
|
});
|
|
36846
36846
|
const { predecessor } = ports;
|
|
36847
36847
|
const sourceOf = (listener, preferredPort) => predecessor === void 0 ? { preferredPort } : { inherit: async () => await predecessor.take(listener) };
|
|
36848
|
-
const fail = (message) => {
|
|
36848
|
+
const fail = async (message) => {
|
|
36849
36849
|
ports.closeRcStreamHub();
|
|
36850
36850
|
if (predecessor === void 0) {
|
|
36851
36851
|
writeFrontDoorState(fs32, paths.frontdoorStateFile, { lastError: message, ...sticky() });
|
|
36852
36852
|
fs32.removeRecursive(paths.frontdoorLockFile);
|
|
36853
36853
|
}
|
|
36854
36854
|
ports.log(`agent-shim frontdoor supervisor: ${message}`);
|
|
36855
|
+
const chain = ports.respawnChain;
|
|
36856
|
+
if (predecessor === void 0 && chain !== void 0 && chain.generation > 0) {
|
|
36857
|
+
ports.log(`agent-shim frontdoor supervisor ${String(ports.ownPid)}: this door is generation ${String(chain.generation)} of the watchdog's respawn chain and nothing waits on it, so it starts generation ${String(chain.generation + 1)} rather than leaving no door`);
|
|
36858
|
+
await chain.startNext();
|
|
36859
|
+
}
|
|
36855
36860
|
return 1;
|
|
36856
36861
|
};
|
|
36857
36862
|
if (predecessor === void 0) {
|
|
@@ -36863,7 +36868,7 @@ async function serveFrontDoor(idleShutdownMinutes, ports, options) {
|
|
|
36863
36868
|
http9 = await ports.startProviderListener(sourceOf("provider", lastPort));
|
|
36864
36869
|
} catch (error63) {
|
|
36865
36870
|
ports.doorHealth.listenerFailed("provider", error63 instanceof Error ? error63.message : String(error63));
|
|
36866
|
-
return fail(`could not start the provider listener: ${error63 instanceof Error ? error63.message : String(error63)}`);
|
|
36871
|
+
return await fail(`could not start the provider listener: ${error63 instanceof Error ? error63.message : String(error63)}`);
|
|
36867
36872
|
}
|
|
36868
36873
|
if (previousSticky !== void 0 && http9.port !== previousSticky) {
|
|
36869
36874
|
ports.log(`agent-shim frontdoor supervisor: sticky port ${String(previousSticky)} was occupied; moving to ${String(http9.port)} (sessions launched against the old port are stale until they relaunch)`);
|
|
@@ -36876,7 +36881,7 @@ async function serveFrontDoor(idleShutdownMinutes, ports, options) {
|
|
|
36876
36881
|
} catch (error63) {
|
|
36877
36882
|
await http9.close();
|
|
36878
36883
|
ports.doorHealth.listenerFailed("connect", error63 instanceof Error ? error63.message : String(error63));
|
|
36879
|
-
return fail(`could not start the CONNECT surface: ${error63 instanceof Error ? error63.message : String(error63)}`);
|
|
36884
|
+
return await fail(`could not start the CONNECT surface: ${error63 instanceof Error ? error63.message : String(error63)}`);
|
|
36880
36885
|
}
|
|
36881
36886
|
if (previousStickyConnect !== void 0 && connect3.port !== previousStickyConnect) {
|
|
36882
36887
|
ports.log(`agent-shim frontdoor supervisor: sticky CONNECT port ${String(previousStickyConnect)} was occupied; moving to ${String(connect3.port)} (OAuth sessions launched against the old port are stale until they relaunch)`);
|
|
@@ -36890,7 +36895,7 @@ async function serveFrontDoor(idleShutdownMinutes, ports, options) {
|
|
|
36890
36895
|
await connect3.close();
|
|
36891
36896
|
await http9.close();
|
|
36892
36897
|
ports.doorHealth.listenerFailed("direct", error63 instanceof Error ? error63.message : String(error63));
|
|
36893
|
-
return fail(`could not start the direct listener: ${error63 instanceof Error ? error63.message : String(error63)}`);
|
|
36898
|
+
return await fail(`could not start the direct listener: ${error63 instanceof Error ? error63.message : String(error63)}`);
|
|
36894
36899
|
}
|
|
36895
36900
|
if (previousStickyDirect !== void 0 && direct.port !== previousStickyDirect) {
|
|
36896
36901
|
ports.log(`agent-shim frontdoor supervisor: sticky direct port ${String(previousStickyDirect)} was occupied; moving to ${String(direct.port)} (headroom admits the new address once its supervisor rewrites the allowlist file)`);
|
|
@@ -39981,7 +39986,7 @@ var init_package = __esm({
|
|
|
39981
39986
|
"package.json"() {
|
|
39982
39987
|
package_default = {
|
|
39983
39988
|
name: "agent-shim",
|
|
39984
|
-
version: "11.83.
|
|
39989
|
+
version: "11.83.5",
|
|
39985
39990
|
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.",
|
|
39986
39991
|
license: "MIT",
|
|
39987
39992
|
author: "Joseph Mearman <joseph@mearman.co.uk>",
|
|
@@ -126078,6 +126083,17 @@ var import_node_https = __toESM(require("node:https"), 1);
|
|
|
126078
126083
|
var import_node_net2 = __toESM(require("node:net"), 1);
|
|
126079
126084
|
init_legacy();
|
|
126080
126085
|
|
|
126086
|
+
// src/frontdoor/machineLoad.ts
|
|
126087
|
+
var import_node_os14 = __toESM(require("node:os"), 1);
|
|
126088
|
+
var processorShare = (reading) => reading.loadAverage <= reading.cpus ? 1 : reading.cpus / reading.loadAverage;
|
|
126089
|
+
function readMachineLoad() {
|
|
126090
|
+
const [oneMinute] = import_node_os14.default.loadavg();
|
|
126091
|
+
if (oneMinute === void 0) {
|
|
126092
|
+
throw new Error("os.loadavg() returned no one-minute load average");
|
|
126093
|
+
}
|
|
126094
|
+
return { loadAverage: oneMinute, cpus: import_node_os14.default.cpus().length };
|
|
126095
|
+
}
|
|
126096
|
+
|
|
126081
126097
|
// src/frontdoor/rcControl.ts
|
|
126082
126098
|
var https = __toESM(require("node:https"), 1);
|
|
126083
126099
|
init_capability();
|
|
@@ -126764,35 +126780,54 @@ async function listenFrontDoor(server, options = {}) {
|
|
|
126764
126780
|
if (options.onError !== void 0) {
|
|
126765
126781
|
server.on("error", options.onError);
|
|
126766
126782
|
}
|
|
126767
|
-
|
|
126783
|
+
await awaitStartHealth(
|
|
126784
|
+
{
|
|
126785
|
+
probe: async () => await frontDoorHealthy(bound, ca2),
|
|
126786
|
+
now: () => Date.now(),
|
|
126787
|
+
sleep: async (ms) => {
|
|
126788
|
+
await new Promise((resolve3) => {
|
|
126789
|
+
setTimeout(resolve3, ms);
|
|
126790
|
+
});
|
|
126791
|
+
},
|
|
126792
|
+
readLoad: readMachineLoad
|
|
126793
|
+
},
|
|
126794
|
+
`127.0.0.1:${String(bound)}`
|
|
126795
|
+
);
|
|
126796
|
+
return {
|
|
126797
|
+
port: bound,
|
|
126798
|
+
close: async () => {
|
|
126799
|
+
await new Promise((resolve3) => {
|
|
126800
|
+
server.close(() => {
|
|
126801
|
+
resolve3(void 0);
|
|
126802
|
+
});
|
|
126803
|
+
server.closeAllConnections();
|
|
126804
|
+
});
|
|
126805
|
+
},
|
|
126806
|
+
// The port is released as the close runs, before the first await (see `trackConnections` for what happens to the connections already accepted).
|
|
126807
|
+
drain: async () => {
|
|
126808
|
+
await new Promise((resolve3) => {
|
|
126809
|
+
connections.drain(() => {
|
|
126810
|
+
resolve3(void 0);
|
|
126811
|
+
});
|
|
126812
|
+
});
|
|
126813
|
+
}
|
|
126814
|
+
};
|
|
126815
|
+
}
|
|
126816
|
+
async function awaitStartHealth(ports, address) {
|
|
126817
|
+
const startedAt = ports.now();
|
|
126818
|
+
let scheduledMs = 0;
|
|
126819
|
+
let countedTo = startedAt;
|
|
126768
126820
|
for (; ; ) {
|
|
126769
|
-
if (await
|
|
126770
|
-
return
|
|
126771
|
-
port: bound,
|
|
126772
|
-
close: async () => {
|
|
126773
|
-
await new Promise((resolve3) => {
|
|
126774
|
-
server.close(() => {
|
|
126775
|
-
resolve3(void 0);
|
|
126776
|
-
});
|
|
126777
|
-
server.closeAllConnections();
|
|
126778
|
-
});
|
|
126779
|
-
},
|
|
126780
|
-
// The port is released as the close runs, before the first await (see `trackConnections` for what happens to the connections already accepted).
|
|
126781
|
-
drain: async () => {
|
|
126782
|
-
await new Promise((resolve3) => {
|
|
126783
|
-
connections.drain(() => {
|
|
126784
|
-
resolve3(void 0);
|
|
126785
|
-
});
|
|
126786
|
-
});
|
|
126787
|
-
}
|
|
126788
|
-
};
|
|
126821
|
+
if (await ports.probe()) {
|
|
126822
|
+
return;
|
|
126789
126823
|
}
|
|
126790
|
-
|
|
126791
|
-
|
|
126824
|
+
const now = ports.now();
|
|
126825
|
+
scheduledMs += (now - countedTo) * processorShare(ports.readLoad());
|
|
126826
|
+
countedTo = now;
|
|
126827
|
+
if (scheduledMs >= HEALTH_START_BUDGET_MS) {
|
|
126828
|
+
throw new Error(`the front door listener on ${address} did not answer its health probe within ${String(HEALTH_START_BUDGET_MS)}ms of processor time (${String(now - startedAt)}ms of wall time)`);
|
|
126792
126829
|
}
|
|
126793
|
-
await
|
|
126794
|
-
setTimeout(resolve3, HEALTH_RETRY_MS);
|
|
126795
|
-
});
|
|
126830
|
+
await ports.sleep(HEALTH_RETRY_MS);
|
|
126796
126831
|
}
|
|
126797
126832
|
}
|
|
126798
126833
|
function trackConnections(server) {
|
|
@@ -134484,7 +134519,7 @@ var Builder = class _Builder {
|
|
|
134484
134519
|
});
|
|
134485
134520
|
}
|
|
134486
134521
|
};
|
|
134487
|
-
var
|
|
134522
|
+
var os14 = Builder.create();
|
|
134488
134523
|
|
|
134489
134524
|
// node_modules/.pnpm/@orpc+openapi@2.0.0-beta.43/node_modules/@orpc/openapi/dist/index.mjs
|
|
134490
134525
|
var DEFS_REF_PREFIX = "#/$defs/";
|
|
@@ -138848,7 +138883,7 @@ function doorApiBearer(headers) {
|
|
|
138848
138883
|
return typeof presented === "string" && presented.slice(0, bearerPrefix).toLowerCase() === "bearer " ? presented.slice(bearerPrefix) : void 0;
|
|
138849
138884
|
}
|
|
138850
138885
|
function doorApiAuth(expectedToken) {
|
|
138851
|
-
return
|
|
138886
|
+
return os14.$context().use(({ context, next }) => {
|
|
138852
138887
|
const token = doorApiBearer(context.headers);
|
|
138853
138888
|
if (token === void 0 || !isLiveCapability(token, [expectedToken])) {
|
|
138854
138889
|
throw new ORPCError("UNAUTHORIZED", { message: "the front door's typed API demands this generation's control token as a Bearer credential" });
|
|
@@ -145631,6 +145666,72 @@ var DOOR_RESPAWN_MAX_GENERATIONS = 3;
|
|
|
145631
145666
|
var DOOR_RESPAWN_COOLDOWN_CAP_MS = DOOR_STALL_BOUND_MS * DOOR_RESPAWN_MAX_GENERATIONS;
|
|
145632
145667
|
var CHECKS_PER_PROBE_DEADLINE = 2;
|
|
145633
145668
|
var DOOR_WATCHDOG_CHECK_MS = PROBE_TIMEOUT_MS / CHECKS_PER_PROBE_DEADLINE;
|
|
145669
|
+
var RESPAWN_SOURCE = `
|
|
145670
|
+
const log = (line) => {
|
|
145671
|
+
if (logFile === undefined) return;
|
|
145672
|
+
try {
|
|
145673
|
+
fs.appendFileSync(logFile, new Date().toISOString() + " frontdoor " + String(ownPid) + ": " + line + "\\n");
|
|
145674
|
+
} catch (error) {
|
|
145675
|
+
// Nowhere left to report a failed log write to; the thread's work goes on without it.
|
|
145676
|
+
}
|
|
145677
|
+
};
|
|
145678
|
+
// Whether a process is alive: signal 0 only tests, and EPERM means it exists under another user.
|
|
145679
|
+
const isRunning = (pid) => {
|
|
145680
|
+
try {
|
|
145681
|
+
process.kill(pid, 0);
|
|
145682
|
+
return true;
|
|
145683
|
+
} catch (error) {
|
|
145684
|
+
return error.code === "EPERM";
|
|
145685
|
+
}
|
|
145686
|
+
};
|
|
145687
|
+
// The pid holding the start lock when that holder is alive, which means a door is already being started and another must not be: the launcher's ensure and this respawn are the two things that start a door, and the lock is the one protocol that keeps them from starting two. A dead holder's lock is litter and is cleared, exactly as the launcher's ensure clears it.
|
|
145688
|
+
const liveLockHolder = () => {
|
|
145689
|
+
let holder;
|
|
145690
|
+
try {
|
|
145691
|
+
holder = JSON.parse(fs.readFileSync(startLockFile, "utf8")).pid;
|
|
145692
|
+
} catch (error) {
|
|
145693
|
+
return undefined;
|
|
145694
|
+
}
|
|
145695
|
+
if (typeof holder === "number" && isRunning(holder)) return holder;
|
|
145696
|
+
fs.rmSync(startLockFile, { force: true });
|
|
145697
|
+
return undefined;
|
|
145698
|
+
};
|
|
145699
|
+
// Creates the lock naming the replacement as its holder, atomically (the wx flag), so the launcher's ensure sees a live holder while the replacement boots and waits for it instead of starting a door of its own; the replacement removes the lock once it is serving, as every door does.
|
|
145700
|
+
const claimStartLock = (holder) => {
|
|
145701
|
+
try {
|
|
145702
|
+
fs.writeFileSync(startLockFile, JSON.stringify({ pid: holder, at: Date.now() }) + "\\n", { flag: "wx" });
|
|
145703
|
+
return true;
|
|
145704
|
+
} catch (error) {
|
|
145705
|
+
if (error.code === "EEXIST") return false;
|
|
145706
|
+
throw error;
|
|
145707
|
+
}
|
|
145708
|
+
};
|
|
145709
|
+
const spawnReplacement = () => {
|
|
145710
|
+
if (respawn === undefined || logFile === undefined) return;
|
|
145711
|
+
const nextGeneration = respawnGeneration + 1;
|
|
145712
|
+
const cooldownMs = Math.min(Math.max(0, nextGeneration - respawnMaxGeneration) * cooldownStepMs, cooldownCapMs);
|
|
145713
|
+
const startingBy = liveLockHolder();
|
|
145714
|
+
if (startingBy !== undefined) {
|
|
145715
|
+
log("not starting a replacement: process " + String(startingBy) + " holds the start lock, so a door is already being started and a second one would race it for the sticky ports");
|
|
145716
|
+
return;
|
|
145717
|
+
}
|
|
145718
|
+
try {
|
|
145719
|
+
const out = fs.openSync(logFile, "a");
|
|
145720
|
+
const child = require("node:child_process").spawn(respawn.command, respawn.args, { detached: true, stdio: ["ignore", out, out], env: Object.assign({}, respawn.env, { [awaitPidEnv]: String(ownPid), [respawnGenerationEnv]: String(nextGeneration), [delayEnv]: String(cooldownMs) }) });
|
|
145721
|
+
child.unref();
|
|
145722
|
+
fs.closeSync(out);
|
|
145723
|
+
if (!claimStartLock(child.pid)) {
|
|
145724
|
+
// A launcher took the lock between the check and the spawn, so its door is the one that is starting: this one must not also bind.
|
|
145725
|
+
process.kill(child.pid, "SIGKILL");
|
|
145726
|
+
log("withdrew replacement door " + String(child.pid) + ": a launcher took the start lock first and its door is the one starting");
|
|
145727
|
+
return;
|
|
145728
|
+
}
|
|
145729
|
+
log("started replacement door " + String(child.pid) + " of generation " + String(nextGeneration) + ", which binds once this process is gone" + (cooldownMs > 0 ? " and a " + String(cooldownMs) + "ms cooldown has passed, since the chain has gone through " + String(respawnMaxGeneration) + " consecutive replacements" : ""));
|
|
145730
|
+
} catch (error) {
|
|
145731
|
+
log("could not start a replacement door: " + (error instanceof Error ? error.message : String(error)));
|
|
145732
|
+
}
|
|
145733
|
+
};
|
|
145734
|
+
`;
|
|
145634
145735
|
var WATCHDOG_SOURCE = `
|
|
145635
145736
|
const { workerData, parentPort } = require("node:worker_threads");
|
|
145636
145737
|
const fs = require("node:fs");
|
|
@@ -145647,7 +145748,8 @@ let scheduledMs = 0;
|
|
|
145647
145748
|
let waitingOutStarvation = false;
|
|
145648
145749
|
let stopped = false;
|
|
145649
145750
|
const readLoad = () => machineLoad === undefined ? { loadAverage: os.loadavg()[0], cpus: os.cpus().length } : machineLoad;
|
|
145650
|
-
|
|
145751
|
+
// The main thread's own formula, embedded as its source text (see \`processorShare\`), so the stall bound and the start-up probe budget are counted alike.
|
|
145752
|
+
const processorShare = ${processorShare.toString()};
|
|
145651
145753
|
const describeLoad = (reading) => reading.loadAverage.toFixed(1) + " across " + String(reading.cpus) + " cpus";
|
|
145652
145754
|
const record = (message) => {
|
|
145653
145755
|
try {
|
|
@@ -145660,14 +145762,7 @@ const record = (message) => {
|
|
|
145660
145762
|
// The state file is a courtesy to whoever looks next; the process still has to end.
|
|
145661
145763
|
}
|
|
145662
145764
|
};
|
|
145663
|
-
|
|
145664
|
-
if (logFile === undefined) return;
|
|
145665
|
-
try {
|
|
145666
|
-
fs.appendFileSync(logFile, new Date().toISOString() + " frontdoor " + String(ownPid) + ": " + line + "\\n");
|
|
145667
|
-
} catch (error) {
|
|
145668
|
-
// Nowhere left to report a failed log write to; the process still has to end.
|
|
145669
|
-
}
|
|
145670
|
-
};
|
|
145765
|
+
${RESPAWN_SOURCE}
|
|
145671
145766
|
const MS_PER_SECOND = 1000;
|
|
145672
145767
|
// Enough of the stack to read the caller chain from the timer or socket callback down to the call that held the loop.
|
|
145673
145768
|
const STACK_FRAMES_LOGGED = 12;
|
|
@@ -145708,62 +145803,6 @@ const describeMainThread = (waitMs, resume) => new Promise((resolve) => {
|
|
|
145708
145803
|
finish("the main thread could not be inspected: " + (error instanceof Error ? error.message : String(error)));
|
|
145709
145804
|
}
|
|
145710
145805
|
});
|
|
145711
|
-
// Whether a process is alive: signal 0 only tests, and EPERM means it exists under another user.
|
|
145712
|
-
const isRunning = (pid) => {
|
|
145713
|
-
try {
|
|
145714
|
-
process.kill(pid, 0);
|
|
145715
|
-
return true;
|
|
145716
|
-
} catch (error) {
|
|
145717
|
-
return error.code === "EPERM";
|
|
145718
|
-
}
|
|
145719
|
-
};
|
|
145720
|
-
// The pid holding the start lock when that holder is alive, which means a door is already being started and another must not be: the launcher's ensure and this respawn are the two things that start a door, and the lock is the one protocol that keeps them from starting two. A dead holder's lock is litter and is cleared, exactly as the launcher's ensure clears it.
|
|
145721
|
-
const liveLockHolder = () => {
|
|
145722
|
-
let holder;
|
|
145723
|
-
try {
|
|
145724
|
-
holder = JSON.parse(fs.readFileSync(startLockFile, "utf8")).pid;
|
|
145725
|
-
} catch (error) {
|
|
145726
|
-
return undefined;
|
|
145727
|
-
}
|
|
145728
|
-
if (typeof holder === "number" && isRunning(holder)) return holder;
|
|
145729
|
-
fs.rmSync(startLockFile, { force: true });
|
|
145730
|
-
return undefined;
|
|
145731
|
-
};
|
|
145732
|
-
// Creates the lock naming the replacement as its holder, atomically (the wx flag), so the launcher's ensure sees a live holder while the replacement boots and waits for it instead of starting a door of its own; the replacement removes the lock once it is serving, as every door does.
|
|
145733
|
-
const claimStartLock = (holder) => {
|
|
145734
|
-
try {
|
|
145735
|
-
fs.writeFileSync(startLockFile, JSON.stringify({ pid: holder, at: Date.now() }) + "\\n", { flag: "wx" });
|
|
145736
|
-
return true;
|
|
145737
|
-
} catch (error) {
|
|
145738
|
-
if (error.code === "EEXIST") return false;
|
|
145739
|
-
throw error;
|
|
145740
|
-
}
|
|
145741
|
-
};
|
|
145742
|
-
const spawnReplacement = () => {
|
|
145743
|
-
if (respawn === undefined || logFile === undefined) return;
|
|
145744
|
-
const nextGeneration = respawnGeneration + 1;
|
|
145745
|
-
const cooldownMs = Math.min(Math.max(0, nextGeneration - respawnMaxGeneration) * cooldownStepMs, cooldownCapMs);
|
|
145746
|
-
const startingBy = liveLockHolder();
|
|
145747
|
-
if (startingBy !== undefined) {
|
|
145748
|
-
log("not starting a replacement: process " + String(startingBy) + " holds the start lock, so a door is already being started and a second one would race it for the sticky ports");
|
|
145749
|
-
return;
|
|
145750
|
-
}
|
|
145751
|
-
try {
|
|
145752
|
-
const out = fs.openSync(logFile, "a");
|
|
145753
|
-
const child = require("node:child_process").spawn(respawn.command, respawn.args, { detached: true, stdio: ["ignore", out, out], env: Object.assign({}, respawn.env, { [awaitPidEnv]: String(ownPid), [respawnGenerationEnv]: String(nextGeneration), [delayEnv]: String(cooldownMs) }) });
|
|
145754
|
-
child.unref();
|
|
145755
|
-
fs.closeSync(out);
|
|
145756
|
-
if (!claimStartLock(child.pid)) {
|
|
145757
|
-
// A launcher took the lock between the check and the spawn, so its door is the one that is starting: this one must not also bind.
|
|
145758
|
-
process.kill(child.pid, "SIGKILL");
|
|
145759
|
-
log("withdrew replacement door " + String(child.pid) + ": a launcher took the start lock first and its door is the one starting");
|
|
145760
|
-
return;
|
|
145761
|
-
}
|
|
145762
|
-
log("started replacement door " + String(child.pid) + " of generation " + String(nextGeneration) + ", which binds once this process is gone" + (cooldownMs > 0 ? " and a " + String(cooldownMs) + "ms cooldown has passed, since the stall has recurred through " + String(respawnMaxGeneration) + " consecutive replacements" : ""));
|
|
145763
|
-
} catch (error) {
|
|
145764
|
-
log("could not start a replacement door: " + (error instanceof Error ? error.message : String(error)));
|
|
145765
|
-
}
|
|
145766
|
-
};
|
|
145767
145806
|
// Captures where a main thread that could not be paused is held natively, with the platform's own sampler, so a stall the inspector cannot name still leaves a stack to read. The wait is the sampling time plus the sampler's start-up and symbolication, stretched by the processor share the machine's load leaves it, and the capture never delays the process ending beyond that. The sampler writes its report only once it has finished, so one ended at the deadline, or one that failed, leaves no file, and the log says which rather than naming a file that is not there.
|
|
145768
145807
|
const takeNativeSample = () => new Promise((resolve) => {
|
|
145769
145808
|
if (nativeSample === undefined) { resolve(); return; }
|
|
@@ -145854,12 +145893,13 @@ parentPort.on("message", (message) => {
|
|
|
145854
145893
|
}
|
|
145855
145894
|
});
|
|
145856
145895
|
`;
|
|
145896
|
+
var RESPAWN_ENV_NAMES = { awaitPidEnv: DOOR_AWAIT_PID_ENV, respawnGenerationEnv: DOOR_RESPAWN_GENERATION_ENV, delayEnv: DOOR_RESPAWN_DELAY_ENV };
|
|
145857
145897
|
function startThreadWatchdog(params) {
|
|
145858
145898
|
const shared = new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT);
|
|
145859
145899
|
const counter = new Int32Array(shared);
|
|
145860
145900
|
const worker = new import_node_worker_threads2.Worker(WATCHDOG_SOURCE, {
|
|
145861
145901
|
eval: true,
|
|
145862
|
-
workerData: { shared, boundMs: params.boundMs, checkEveryMs: params.checkEveryMs, pauseWaitMs: params.pauseWaitMs, stateFile: params.stateFile, ownPid: params.ownPid, action: params.action, logFile: params.logFile, respawn: params.respawn, respawnGeneration: params.respawnGeneration, respawnMaxGeneration: params.respawnMaxGeneration, cooldownStepMs: params.cooldownStepMs, cooldownCapMs: params.cooldownCapMs, startLockFile: params.startLockFile,
|
|
145902
|
+
workerData: { shared, boundMs: params.boundMs, checkEveryMs: params.checkEveryMs, pauseWaitMs: params.pauseWaitMs, stateFile: params.stateFile, ownPid: params.ownPid, action: params.action, logFile: params.logFile, respawn: params.respawn, respawnGeneration: params.respawnGeneration, respawnMaxGeneration: params.respawnMaxGeneration, cooldownStepMs: params.cooldownStepMs, cooldownCapMs: params.cooldownCapMs, startLockFile: params.startLockFile, ...RESPAWN_ENV_NAMES, nativeSample: params.nativeSample, machineLoad: params.machineLoad }
|
|
145863
145903
|
});
|
|
145864
145904
|
worker.unref();
|
|
145865
145905
|
const beat = setInterval(() => {
|
|
@@ -145884,6 +145924,25 @@ function startThreadWatchdog(params) {
|
|
|
145884
145924
|
}
|
|
145885
145925
|
};
|
|
145886
145926
|
}
|
|
145927
|
+
var NEXT_GENERATION_SOURCE = `
|
|
145928
|
+
const { workerData } = require("node:worker_threads");
|
|
145929
|
+
const fs = require("node:fs");
|
|
145930
|
+
const { ownPid, logFile, respawn, respawnGeneration, respawnMaxGeneration, cooldownStepMs, cooldownCapMs, startLockFile, awaitPidEnv, respawnGenerationEnv, delayEnv } = workerData;
|
|
145931
|
+
${RESPAWN_SOURCE}
|
|
145932
|
+
spawnReplacement();
|
|
145933
|
+
`;
|
|
145934
|
+
async function startNextRespawnGeneration(params) {
|
|
145935
|
+
const worker = new import_node_worker_threads2.Worker(NEXT_GENERATION_SOURCE, {
|
|
145936
|
+
eval: true,
|
|
145937
|
+
workerData: { ownPid: params.ownPid, logFile: params.logFile, respawn: params.respawn, respawnGeneration: params.respawnGeneration, respawnMaxGeneration: params.respawnMaxGeneration, cooldownStepMs: params.cooldownStepMs, cooldownCapMs: params.cooldownCapMs, startLockFile: params.startLockFile, ...RESPAWN_ENV_NAMES }
|
|
145938
|
+
});
|
|
145939
|
+
await new Promise((resolve3, reject) => {
|
|
145940
|
+
worker.once("error", reject);
|
|
145941
|
+
worker.once("exit", () => {
|
|
145942
|
+
resolve3();
|
|
145943
|
+
});
|
|
145944
|
+
});
|
|
145945
|
+
}
|
|
145887
145946
|
|
|
145888
145947
|
// src/frontdoor/commands.ts
|
|
145889
145948
|
init_probe();
|
|
@@ -146049,6 +146108,16 @@ function realFrontDoorSupervisorPorts(paths, respawnGeneration, lifecycle, track
|
|
|
146049
146108
|
const log = (line) => {
|
|
146050
146109
|
appendDoorLog(paths, `frontdoor ${String(process.pid)}: ${line}`);
|
|
146051
146110
|
};
|
|
146111
|
+
const respawnChain = () => ({
|
|
146112
|
+
ownPid: process.pid,
|
|
146113
|
+
logFile: paths.frontdoorLogPath,
|
|
146114
|
+
respawn: respawnInvocation(paths),
|
|
146115
|
+
respawnGeneration,
|
|
146116
|
+
respawnMaxGeneration: DOOR_RESPAWN_MAX_GENERATIONS,
|
|
146117
|
+
cooldownStepMs: DOOR_STALL_BOUND_MS,
|
|
146118
|
+
cooldownCapMs: DOOR_RESPAWN_COOLDOWN_CAP_MS,
|
|
146119
|
+
startLockFile: paths.frontdoorLockFile
|
|
146120
|
+
});
|
|
146052
146121
|
let directPort = 0;
|
|
146053
146122
|
const rcSelfHost = rcSelfHostFromEnv(process.env);
|
|
146054
146123
|
const codexPorts = createCodexRoutePorts(log, paths.chatgptSignInFile);
|
|
@@ -146500,20 +146569,19 @@ function realFrontDoorSupervisorPorts(paths, respawnGeneration, lifecycle, track
|
|
|
146500
146569
|
return { port: handle.port, listening: server, close: handle.close, drain: handle.drain };
|
|
146501
146570
|
},
|
|
146502
146571
|
closeRcStreamHub: rcHub.close,
|
|
146572
|
+
respawnChain: {
|
|
146573
|
+
generation: respawnGeneration,
|
|
146574
|
+
startNext: async () => {
|
|
146575
|
+
await startNextRespawnGeneration(respawnChain());
|
|
146576
|
+
}
|
|
146577
|
+
},
|
|
146503
146578
|
startWatchdog: () => startThreadWatchdog({
|
|
146579
|
+
...respawnChain(),
|
|
146504
146580
|
stateFile: paths.frontdoorStateFile,
|
|
146505
|
-
ownPid: process.pid,
|
|
146506
146581
|
boundMs: DOOR_STALL_BOUND_MS,
|
|
146507
146582
|
checkEveryMs: DOOR_WATCHDOG_CHECK_MS,
|
|
146508
146583
|
pauseWaitMs: DOOR_WATCHDOG_CHECK_MS,
|
|
146509
146584
|
action: "kill-process",
|
|
146510
|
-
logFile: paths.frontdoorLogPath,
|
|
146511
|
-
respawn: respawnInvocation(paths),
|
|
146512
|
-
respawnGeneration,
|
|
146513
|
-
respawnMaxGeneration: DOOR_RESPAWN_MAX_GENERATIONS,
|
|
146514
|
-
cooldownStepMs: DOOR_STALL_BOUND_MS,
|
|
146515
|
-
cooldownCapMs: DOOR_RESPAWN_COOLDOWN_CAP_MS,
|
|
146516
|
-
startLockFile: paths.frontdoorLockFile,
|
|
146517
146585
|
...process.platform === "darwin" ? { nativeSample: { command: MACOS_SAMPLER, args: ["{pid}", "{seconds}", "-file", "{file}"], directory: import_node_path61.default.join(import_node_path61.default.dirname(paths.frontdoorLogPath), "stall-samples"), seconds: Math.max(1, Math.ceil(DOOR_WATCHDOG_CHECK_MS / MS_PER_SECOND17)), overheadMs: PROBE_TIMEOUT_MS, keep: DOOR_RESPAWN_MAX_GENERATIONS + 1 } } : {}
|
|
146518
146586
|
}),
|
|
146519
146587
|
// The launch lifecycle publisher over the same backbone the typed API serves: the tick's registry facts go in here, and the door's own register, prune and end moments come out as source-tagged events.
|
|
@@ -146627,7 +146695,7 @@ function registerFrontDoorCommand(program2, deps) {
|
|
|
146627
146695
|
|
|
146628
146696
|
// src/statusline/commands.ts
|
|
146629
146697
|
var import_node_child_process9 = require("node:child_process");
|
|
146630
|
-
var
|
|
146698
|
+
var import_node_os16 = __toESM(require("node:os"), 1);
|
|
146631
146699
|
var import_node_path70 = __toESM(require("node:path"), 1);
|
|
146632
146700
|
init_commandDeps();
|
|
146633
146701
|
init_load();
|
|
@@ -147418,7 +147486,7 @@ function contextViewOf(frame) {
|
|
|
147418
147486
|
// src/statusline/ports.ts
|
|
147419
147487
|
init_blockingSpawn();
|
|
147420
147488
|
var import_node_fs26 = __toESM(require("node:fs"), 1);
|
|
147421
|
-
var
|
|
147489
|
+
var import_node_os15 = __toESM(require("node:os"), 1);
|
|
147422
147490
|
var import_node_path63 = __toESM(require("node:path"), 1);
|
|
147423
147491
|
|
|
147424
147492
|
// src/statusline/memoryUse.ts
|
|
@@ -147552,7 +147620,7 @@ function discard(target) {
|
|
|
147552
147620
|
}
|
|
147553
147621
|
}
|
|
147554
147622
|
function readMemoryUse() {
|
|
147555
|
-
const totalBytes =
|
|
147623
|
+
const totalBytes = import_node_os15.default.totalmem();
|
|
147556
147624
|
if (process.platform === "darwin") {
|
|
147557
147625
|
const output2 = runWithPipe(RUN_TIMEOUT_MS, "/usr/bin/vm_stat", [], process.cwd());
|
|
147558
147626
|
const usedBytes = output2 === void 0 ? void 0 : usedBytesFromVmStat(output2);
|
|
@@ -147562,13 +147630,13 @@ function readMemoryUse() {
|
|
|
147562
147630
|
const meminfo = readText("/proc/meminfo");
|
|
147563
147631
|
return meminfo === void 0 ? void 0 : memoryUseFromMeminfo(meminfo);
|
|
147564
147632
|
}
|
|
147565
|
-
return { usedBytes: totalBytes -
|
|
147633
|
+
return { usedBytes: totalBytes - import_node_os15.default.freemem(), totalBytes };
|
|
147566
147634
|
}
|
|
147567
147635
|
function realStatuslinePorts(env, stateDirectory, runTimeoutMs = RUN_TIMEOUT_MS) {
|
|
147568
147636
|
const { locale, timeZone } = Intl.DateTimeFormat().resolvedOptions();
|
|
147569
147637
|
return {
|
|
147570
147638
|
env,
|
|
147571
|
-
homeDirectory:
|
|
147639
|
+
homeDirectory: import_node_os15.default.homedir(),
|
|
147572
147640
|
stateDirectory,
|
|
147573
147641
|
clock: { locale, timeZone },
|
|
147574
147642
|
readText,
|
|
@@ -151240,7 +151308,7 @@ function registerStatuslineCommand(program2, deps) {
|
|
|
151240
151308
|
} else {
|
|
151241
151309
|
const configDir = process.env.CLAUDE_CONFIG_DIR;
|
|
151242
151310
|
try {
|
|
151243
|
-
account = readAccountMetadataFile(realFarmFs, configDir === void 0 || configDir === "" ? import_node_path70.default.join(
|
|
151311
|
+
account = readAccountMetadataFile(realFarmFs, configDir === void 0 || configDir === "" ? import_node_path70.default.join(import_node_os16.default.homedir(), ".claude.json") : import_node_path70.default.join(configDir, ".claude.json"));
|
|
151244
151312
|
} catch {
|
|
151245
151313
|
account = void 0;
|
|
151246
151314
|
}
|
|
@@ -151289,7 +151357,7 @@ function registerStatuslineCommand(program2, deps) {
|
|
|
151289
151357
|
});
|
|
151290
151358
|
return;
|
|
151291
151359
|
}
|
|
151292
|
-
const live = statuslineSettingsForRender({ env: process.env, cwd: process.cwd(), home:
|
|
151360
|
+
const live = statuslineSettingsForRender({ env: process.env, cwd: process.cwd(), home: import_node_os16.default.homedir(), paths: deps.paths, fs: { ...realFsPort, readConfigFile: cosmiconfigReader() } });
|
|
151293
151361
|
if (live.problem !== void 0) {
|
|
151294
151362
|
process.stderr.write(`agent-shim: statusline: ${live.problem}. Drawing with the defaults.
|
|
151295
151363
|
`);
|
|
@@ -151302,7 +151370,7 @@ function registerStatuslineCommand(program2, deps) {
|
|
|
151302
151370
|
let stackedUnderDefault = false;
|
|
151303
151371
|
if (isAntigravityPayload(payload)) {
|
|
151304
151372
|
try {
|
|
151305
|
-
stackedUnderDefault = antigravityStacksWithDefault(realFarmFs,
|
|
151373
|
+
stackedUnderDefault = antigravityStacksWithDefault(realFarmFs, import_node_os16.default.homedir());
|
|
151306
151374
|
} catch {
|
|
151307
151375
|
stackedUnderDefault = false;
|
|
151308
151376
|
}
|
package/dist/index.cjs
CHANGED
|
@@ -4183,13 +4183,18 @@ async function serveFrontDoor(idleShutdownMinutes, ports, options) {
|
|
|
4183
4183
|
});
|
|
4184
4184
|
const { predecessor } = ports;
|
|
4185
4185
|
const sourceOf = (listener, preferredPort) => predecessor === void 0 ? { preferredPort } : { inherit: async () => await predecessor.take(listener) };
|
|
4186
|
-
const fail = (message) => {
|
|
4186
|
+
const fail = async (message) => {
|
|
4187
4187
|
ports.closeRcStreamHub();
|
|
4188
4188
|
if (predecessor === void 0) {
|
|
4189
4189
|
writeFrontDoorState(fs15, paths.frontdoorStateFile, { lastError: message, ...sticky() });
|
|
4190
4190
|
fs15.removeRecursive(paths.frontdoorLockFile);
|
|
4191
4191
|
}
|
|
4192
4192
|
ports.log(`agent-shim frontdoor supervisor: ${message}`);
|
|
4193
|
+
const chain = ports.respawnChain;
|
|
4194
|
+
if (predecessor === void 0 && chain !== void 0 && chain.generation > 0) {
|
|
4195
|
+
ports.log(`agent-shim frontdoor supervisor ${String(ports.ownPid)}: this door is generation ${String(chain.generation)} of the watchdog's respawn chain and nothing waits on it, so it starts generation ${String(chain.generation + 1)} rather than leaving no door`);
|
|
4196
|
+
await chain.startNext();
|
|
4197
|
+
}
|
|
4193
4198
|
return 1;
|
|
4194
4199
|
};
|
|
4195
4200
|
if (predecessor === void 0) {
|
|
@@ -4201,7 +4206,7 @@ async function serveFrontDoor(idleShutdownMinutes, ports, options) {
|
|
|
4201
4206
|
http3 = await ports.startProviderListener(sourceOf("provider", lastPort));
|
|
4202
4207
|
} catch (error) {
|
|
4203
4208
|
ports.doorHealth.listenerFailed("provider", error instanceof Error ? error.message : String(error));
|
|
4204
|
-
return fail(`could not start the provider listener: ${error instanceof Error ? error.message : String(error)}`);
|
|
4209
|
+
return await fail(`could not start the provider listener: ${error instanceof Error ? error.message : String(error)}`);
|
|
4205
4210
|
}
|
|
4206
4211
|
if (previousSticky !== void 0 && http3.port !== previousSticky) {
|
|
4207
4212
|
ports.log(`agent-shim frontdoor supervisor: sticky port ${String(previousSticky)} was occupied; moving to ${String(http3.port)} (sessions launched against the old port are stale until they relaunch)`);
|
|
@@ -4214,7 +4219,7 @@ async function serveFrontDoor(idleShutdownMinutes, ports, options) {
|
|
|
4214
4219
|
} catch (error) {
|
|
4215
4220
|
await http3.close();
|
|
4216
4221
|
ports.doorHealth.listenerFailed("connect", error instanceof Error ? error.message : String(error));
|
|
4217
|
-
return fail(`could not start the CONNECT surface: ${error instanceof Error ? error.message : String(error)}`);
|
|
4222
|
+
return await fail(`could not start the CONNECT surface: ${error instanceof Error ? error.message : String(error)}`);
|
|
4218
4223
|
}
|
|
4219
4224
|
if (previousStickyConnect !== void 0 && connect3.port !== previousStickyConnect) {
|
|
4220
4225
|
ports.log(`agent-shim frontdoor supervisor: sticky CONNECT port ${String(previousStickyConnect)} was occupied; moving to ${String(connect3.port)} (OAuth sessions launched against the old port are stale until they relaunch)`);
|
|
@@ -4228,7 +4233,7 @@ async function serveFrontDoor(idleShutdownMinutes, ports, options) {
|
|
|
4228
4233
|
await connect3.close();
|
|
4229
4234
|
await http3.close();
|
|
4230
4235
|
ports.doorHealth.listenerFailed("direct", error instanceof Error ? error.message : String(error));
|
|
4231
|
-
return fail(`could not start the direct listener: ${error instanceof Error ? error.message : String(error)}`);
|
|
4236
|
+
return await fail(`could not start the direct listener: ${error instanceof Error ? error.message : String(error)}`);
|
|
4232
4237
|
}
|
|
4233
4238
|
if (previousStickyDirect !== void 0 && direct.port !== previousStickyDirect) {
|
|
4234
4239
|
ports.log(`agent-shim frontdoor supervisor: sticky direct port ${String(previousStickyDirect)} was occupied; moving to ${String(direct.port)} (headroom admits the new address once its supervisor rewrites the allowlist file)`);
|
|
@@ -4848,7 +4853,7 @@ var init_package = __esm({
|
|
|
4848
4853
|
"package.json"() {
|
|
4849
4854
|
package_default = {
|
|
4850
4855
|
name: "agent-shim",
|
|
4851
|
-
version: "11.83.
|
|
4856
|
+
version: "11.83.5",
|
|
4852
4857
|
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.",
|
|
4853
4858
|
license: "MIT",
|
|
4854
4859
|
author: "Joseph Mearman <joseph@mearman.co.uk>",
|
package/dist/index.mjs
CHANGED
|
@@ -4160,13 +4160,18 @@ async function serveFrontDoor(idleShutdownMinutes, ports, options) {
|
|
|
4160
4160
|
});
|
|
4161
4161
|
const { predecessor } = ports;
|
|
4162
4162
|
const sourceOf = (listener, preferredPort) => predecessor === void 0 ? { preferredPort } : { inherit: async () => await predecessor.take(listener) };
|
|
4163
|
-
const fail = (message) => {
|
|
4163
|
+
const fail = async (message) => {
|
|
4164
4164
|
ports.closeRcStreamHub();
|
|
4165
4165
|
if (predecessor === void 0) {
|
|
4166
4166
|
writeFrontDoorState(fs15, paths.frontdoorStateFile, { lastError: message, ...sticky() });
|
|
4167
4167
|
fs15.removeRecursive(paths.frontdoorLockFile);
|
|
4168
4168
|
}
|
|
4169
4169
|
ports.log(`agent-shim frontdoor supervisor: ${message}`);
|
|
4170
|
+
const chain = ports.respawnChain;
|
|
4171
|
+
if (predecessor === void 0 && chain !== void 0 && chain.generation > 0) {
|
|
4172
|
+
ports.log(`agent-shim frontdoor supervisor ${String(ports.ownPid)}: this door is generation ${String(chain.generation)} of the watchdog's respawn chain and nothing waits on it, so it starts generation ${String(chain.generation + 1)} rather than leaving no door`);
|
|
4173
|
+
await chain.startNext();
|
|
4174
|
+
}
|
|
4170
4175
|
return 1;
|
|
4171
4176
|
};
|
|
4172
4177
|
if (predecessor === void 0) {
|
|
@@ -4178,7 +4183,7 @@ async function serveFrontDoor(idleShutdownMinutes, ports, options) {
|
|
|
4178
4183
|
http3 = await ports.startProviderListener(sourceOf("provider", lastPort));
|
|
4179
4184
|
} catch (error) {
|
|
4180
4185
|
ports.doorHealth.listenerFailed("provider", error instanceof Error ? error.message : String(error));
|
|
4181
|
-
return fail(`could not start the provider listener: ${error instanceof Error ? error.message : String(error)}`);
|
|
4186
|
+
return await fail(`could not start the provider listener: ${error instanceof Error ? error.message : String(error)}`);
|
|
4182
4187
|
}
|
|
4183
4188
|
if (previousSticky !== void 0 && http3.port !== previousSticky) {
|
|
4184
4189
|
ports.log(`agent-shim frontdoor supervisor: sticky port ${String(previousSticky)} was occupied; moving to ${String(http3.port)} (sessions launched against the old port are stale until they relaunch)`);
|
|
@@ -4191,7 +4196,7 @@ async function serveFrontDoor(idleShutdownMinutes, ports, options) {
|
|
|
4191
4196
|
} catch (error) {
|
|
4192
4197
|
await http3.close();
|
|
4193
4198
|
ports.doorHealth.listenerFailed("connect", error instanceof Error ? error.message : String(error));
|
|
4194
|
-
return fail(`could not start the CONNECT surface: ${error instanceof Error ? error.message : String(error)}`);
|
|
4199
|
+
return await fail(`could not start the CONNECT surface: ${error instanceof Error ? error.message : String(error)}`);
|
|
4195
4200
|
}
|
|
4196
4201
|
if (previousStickyConnect !== void 0 && connect3.port !== previousStickyConnect) {
|
|
4197
4202
|
ports.log(`agent-shim frontdoor supervisor: sticky CONNECT port ${String(previousStickyConnect)} was occupied; moving to ${String(connect3.port)} (OAuth sessions launched against the old port are stale until they relaunch)`);
|
|
@@ -4205,7 +4210,7 @@ async function serveFrontDoor(idleShutdownMinutes, ports, options) {
|
|
|
4205
4210
|
await connect3.close();
|
|
4206
4211
|
await http3.close();
|
|
4207
4212
|
ports.doorHealth.listenerFailed("direct", error instanceof Error ? error.message : String(error));
|
|
4208
|
-
return fail(`could not start the direct listener: ${error instanceof Error ? error.message : String(error)}`);
|
|
4213
|
+
return await fail(`could not start the direct listener: ${error instanceof Error ? error.message : String(error)}`);
|
|
4209
4214
|
}
|
|
4210
4215
|
if (previousStickyDirect !== void 0 && direct.port !== previousStickyDirect) {
|
|
4211
4216
|
ports.log(`agent-shim frontdoor supervisor: sticky direct port ${String(previousStickyDirect)} was occupied; moving to ${String(direct.port)} (headroom admits the new address once its supervisor rewrites the allowlist file)`);
|
|
@@ -4824,7 +4829,7 @@ var init_package = __esm({
|
|
|
4824
4829
|
"package.json"() {
|
|
4825
4830
|
package_default = {
|
|
4826
4831
|
name: "agent-shim",
|
|
4827
|
-
version: "11.83.
|
|
4832
|
+
version: "11.83.5",
|
|
4828
4833
|
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.",
|
|
4829
4834
|
license: "MIT",
|
|
4830
4835
|
author: "Joseph Mearman <joseph@mearman.co.uk>",
|
package/dist/types/index.d.ts
CHANGED
|
@@ -26355,6 +26355,13 @@ interface FrontDoorSupervisorPorts {
|
|
|
26355
26355
|
* The door this one replaces through a handover, when it was started for one: its listeners are adopted from that door's sockets instead of bound, the state file is not written until this door accepts on all three (the old door owns it and keeps serving until then), and the old door is told once this door serves. Absent for every other start.
|
|
26356
26356
|
*/
|
|
26357
26357
|
readonly predecessor?: Predecessor;
|
|
26358
|
+
/**
|
|
26359
|
+
* The watchdog's respawn chain this door belongs to: `generation` is how many watchdog replacements produced it (0 for a door a launch or `frontdoor restart` started), and `startNext` starts the door of the next generation the way the watchdog starts one on a stall (see `startNextRespawnGeneration`). A door of generation 1 or more whose start fails calls `startNext` before it exits, once its listeners are down and it has released the start lock, because nobody else would start a door: the stalled door that started it is gone and no launch is waiting on it, so every registered session would get connection refused until some later launch happened to start one. A door a launch started reports its failure to that launch instead, and a handover successor leaves the door it was replacing serving. Optional for a host that does not respawn.
|
|
26360
|
+
*/
|
|
26361
|
+
readonly respawnChain?: {
|
|
26362
|
+
readonly generation: number;
|
|
26363
|
+
readonly startNext: () => Promise<void>;
|
|
26364
|
+
};
|
|
26358
26365
|
/** Stops the work the door runs on its own account rather than for a request (the usage, window, job and catalogue keepers), called once when a drain begins so the successor's are the only ones acting. Optional because a host without such work has nothing to stop. */
|
|
26359
26366
|
readonly stopBackgroundWork?: () => void;
|
|
26360
26367
|
/**
|
|
@@ -26383,7 +26390,7 @@ interface RunFrontDoorSupervisorOptions {
|
|
|
26383
26390
|
/**
|
|
26384
26391
|
* 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.
|
|
26385
26392
|
*
|
|
26386
|
-
* 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,
|
|
26393
|
+
* 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, or, for a stall or a failed start in a door the watchdog's respawn chain started, the next generation of that chain (see `FrontDoorSupervisorPorts.respawnChain`). Keeping the headroom daemon alive is the headroom supervisor's job, not this one's; the two daemons idle out independently.
|
|
26387
26394
|
*/
|
|
26388
26395
|
declare function runFrontDoorSupervisor(idleShutdownMinutes: number, ports: FrontDoorSupervisorPorts, options?: RunFrontDoorSupervisorOptions): Promise<number>;
|
|
26389
26396
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agent-shim",
|
|
3
|
-
"version": "11.83.
|
|
3
|
+
"version": "11.83.5",
|
|
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>",
|