agent-shim 11.83.4 → 11.83.6
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 +384 -186
- 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.6",
|
|
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>",
|
|
@@ -68738,9 +68743,12 @@ var init_cloudUpstream = __esm({
|
|
|
68738
68743
|
AntigravityUpstreamError = class extends Error {
|
|
68739
68744
|
status;
|
|
68740
68745
|
retryAfter;
|
|
68746
|
+
/** The backend's own answer, as it sent it, which carries more than the message says (the model a 429 names and when its allowance lifts). */
|
|
68747
|
+
body;
|
|
68741
68748
|
constructor(status, message, retryAfter) {
|
|
68742
68749
|
super(`Google Antigravity API error (${String(status)}): ${message}`);
|
|
68743
68750
|
this.name = "AntigravityUpstreamError";
|
|
68751
|
+
this.body = message;
|
|
68744
68752
|
this.status = status;
|
|
68745
68753
|
this.retryAfter = retryAfter;
|
|
68746
68754
|
}
|
|
@@ -68789,6 +68797,60 @@ function antigravityQuotaPressure(quota, model) {
|
|
|
68789
68797
|
const pressures = [windowPressure(fiveHour, FIVE_HOUR_PERIOD_SECONDS), windowPressure(weekly, WEEK_PERIOD_SECONDS)].filter((pressure) => pressure !== void 0);
|
|
68790
68798
|
return pressures.length === 0 ? void 0 : Math.min(...pressures);
|
|
68791
68799
|
}
|
|
68800
|
+
function parseQuotaExhaustion(body, nowMs) {
|
|
68801
|
+
let parsed;
|
|
68802
|
+
try {
|
|
68803
|
+
parsed = JSON.parse(body);
|
|
68804
|
+
} catch {
|
|
68805
|
+
return void 0;
|
|
68806
|
+
}
|
|
68807
|
+
const details = isRecord7(parsed) && isRecord7(parsed.error) && Array.isArray(parsed.error.details) ? parsed.error.details : [];
|
|
68808
|
+
let model;
|
|
68809
|
+
let resetAtMs;
|
|
68810
|
+
for (const detail of details) {
|
|
68811
|
+
if (!isRecord7(detail)) {
|
|
68812
|
+
continue;
|
|
68813
|
+
}
|
|
68814
|
+
if (detail.reason === "QUOTA_EXHAUSTED" && isRecord7(detail.metadata)) {
|
|
68815
|
+
const named = detail.metadata.model;
|
|
68816
|
+
const stamp = typeof detail.metadata.quotaResetTimeStamp === "string" ? Date.parse(detail.metadata.quotaResetTimeStamp) : Number.NaN;
|
|
68817
|
+
model = typeof named === "string" && named !== "" ? named : void 0;
|
|
68818
|
+
resetAtMs = Number.isNaN(stamp) ? void 0 : stamp;
|
|
68819
|
+
} else if (typeof detail.retryDelay === "string" && resetAtMs === void 0) {
|
|
68820
|
+
const seconds = RETRY_DELAY.exec(detail.retryDelay)?.groups?.seconds;
|
|
68821
|
+
resetAtMs = seconds === void 0 ? void 0 : nowMs + Math.ceil(Number(seconds) * MS_PER_SECOND9);
|
|
68822
|
+
}
|
|
68823
|
+
}
|
|
68824
|
+
return model === void 0 || resetAtMs === void 0 ? void 0 : { model, resetAtMs };
|
|
68825
|
+
}
|
|
68826
|
+
function bucketKeyOf(model, resetInSeconds) {
|
|
68827
|
+
const lower = model.toLowerCase();
|
|
68828
|
+
if (lower.includes("argon")) {
|
|
68829
|
+
return "gemini-argon-wtu-weekly";
|
|
68830
|
+
}
|
|
68831
|
+
const withinFiveHours = resetInSeconds <= FIVE_HOUR_PERIOD_SECONDS;
|
|
68832
|
+
if (lower.includes("gemini")) {
|
|
68833
|
+
return withinFiveHours ? "gemini-5h" : "gemini-weekly";
|
|
68834
|
+
}
|
|
68835
|
+
return withinFiveHours ? "3p-5h" : "3p-weekly";
|
|
68836
|
+
}
|
|
68837
|
+
function quotaWithExhaustions(quota, exhaustions, nowMs) {
|
|
68838
|
+
const spent = [...exhaustions].filter(([, resetAtMs]) => resetAtMs > nowMs);
|
|
68839
|
+
if (spent.length === 0) {
|
|
68840
|
+
return quota;
|
|
68841
|
+
}
|
|
68842
|
+
const merged = { ...quota };
|
|
68843
|
+
for (const [model, resetAtMs] of spent) {
|
|
68844
|
+
const resetIn = Math.ceil((resetAtMs - nowMs) / MS_PER_SECOND9);
|
|
68845
|
+
const key = bucketKeyOf(model, resetIn);
|
|
68846
|
+
const known = merged[key];
|
|
68847
|
+
if (known?.remaining_fraction === 0 && (known.reset_in_seconds ?? 0) >= resetIn) {
|
|
68848
|
+
continue;
|
|
68849
|
+
}
|
|
68850
|
+
merged[key] = { remaining_fraction: 0, reset_in_seconds: resetIn };
|
|
68851
|
+
}
|
|
68852
|
+
return merged;
|
|
68853
|
+
}
|
|
68792
68854
|
function calculateUtilization(remainingFraction) {
|
|
68793
68855
|
if (remainingFraction === void 0 || !Number.isFinite(remainingFraction)) {
|
|
68794
68856
|
return void 0;
|
|
@@ -68970,7 +69032,7 @@ function ageQuotaMap(quota, elapsedMs) {
|
|
|
68970
69032
|
Object.entries(quota).map(([key, bucket]) => [key, bucket?.reset_in_seconds === void 0 ? bucket : { ...bucket, reset_in_seconds: Math.max(0, bucket.reset_in_seconds - elapsedSec) }])
|
|
68971
69033
|
);
|
|
68972
69034
|
}
|
|
68973
|
-
var MS_PER_SECOND9, DEFAULT_RETRY_AFTER_SECONDS, FRACTION_DIGITS, GEMINI_5H_KEYS, GEMINI_WEEKLY_KEYS, ARGON_WEEKLY_KEYS, THIRD_PARTY_5H_KEYS, THIRD_PARTY_WEEKLY_KEYS, QUOTA_FAMILY_WINDOWS, SECONDS_PER_HOUR, HOURS_PER_FIVE_HOUR_WINDOW, DAYS_PER_WEEK, HOURS_PER_DAY4, FIVE_HOUR_PERIOD_SECONDS, WEEK_PERIOD_SECONDS, ANTIGRAVITY_QUOTA_REFRESH_MS;
|
|
69035
|
+
var MS_PER_SECOND9, DEFAULT_RETRY_AFTER_SECONDS, FRACTION_DIGITS, GEMINI_5H_KEYS, GEMINI_WEEKLY_KEYS, ARGON_WEEKLY_KEYS, THIRD_PARTY_5H_KEYS, THIRD_PARTY_WEEKLY_KEYS, QUOTA_FAMILY_WINDOWS, SECONDS_PER_HOUR, HOURS_PER_FIVE_HOUR_WINDOW, DAYS_PER_WEEK, HOURS_PER_DAY4, FIVE_HOUR_PERIOD_SECONDS, WEEK_PERIOD_SECONDS, RETRY_DELAY, ANTIGRAVITY_QUOTA_REFRESH_MS;
|
|
68974
69036
|
var init_quota = __esm({
|
|
68975
69037
|
"src/antigravity/quota.ts"() {
|
|
68976
69038
|
"use strict";
|
|
@@ -68997,6 +69059,7 @@ var init_quota = __esm({
|
|
|
68997
69059
|
HOURS_PER_DAY4 = 24;
|
|
68998
69060
|
FIVE_HOUR_PERIOD_SECONDS = HOURS_PER_FIVE_HOUR_WINDOW * SECONDS_PER_HOUR;
|
|
68999
69061
|
WEEK_PERIOD_SECONDS = DAYS_PER_WEEK * HOURS_PER_DAY4 * SECONDS_PER_HOUR;
|
|
69062
|
+
RETRY_DELAY = /^(?<seconds>\d+(?:\.\d+)?)s$/u;
|
|
69000
69063
|
ANTIGRAVITY_QUOTA_REFRESH_MS = 6e4;
|
|
69001
69064
|
}
|
|
69002
69065
|
});
|
|
@@ -71163,7 +71226,13 @@ var init_providerQuota = __esm({
|
|
|
71163
71226
|
/** The account's paid subscription; absent when the account has none. */
|
|
71164
71227
|
paidTier: external_exports.object({ name: external_exports.string().optional(), id: external_exports.string().optional() }).optional()
|
|
71165
71228
|
});
|
|
71166
|
-
ANTIGRAVITY_WINDOW_MS = {
|
|
71229
|
+
ANTIGRAVITY_WINDOW_MS = {
|
|
71230
|
+
"gemini-5h": FIVE_HOURS_MS,
|
|
71231
|
+
"3p-5h": FIVE_HOURS_MS,
|
|
71232
|
+
"gemini-weekly": WEEK_MS,
|
|
71233
|
+
"3p-weekly": WEEK_MS,
|
|
71234
|
+
"gemini-argon-wtu-weekly": WEEK_MS
|
|
71235
|
+
};
|
|
71167
71236
|
antigravityQuotaAdapter = {
|
|
71168
71237
|
source: ANTIGRAVITY_SOURCE,
|
|
71169
71238
|
matches: (baseUrl) => URL.canParse(baseUrl) && new URL(baseUrl).hostname === ANTIGRAVITY_HOST,
|
|
@@ -126078,6 +126147,17 @@ var import_node_https = __toESM(require("node:https"), 1);
|
|
|
126078
126147
|
var import_node_net2 = __toESM(require("node:net"), 1);
|
|
126079
126148
|
init_legacy();
|
|
126080
126149
|
|
|
126150
|
+
// src/frontdoor/machineLoad.ts
|
|
126151
|
+
var import_node_os14 = __toESM(require("node:os"), 1);
|
|
126152
|
+
var processorShare = (reading) => reading.loadAverage <= reading.cpus ? 1 : reading.cpus / reading.loadAverage;
|
|
126153
|
+
function readMachineLoad() {
|
|
126154
|
+
const [oneMinute] = import_node_os14.default.loadavg();
|
|
126155
|
+
if (oneMinute === void 0) {
|
|
126156
|
+
throw new Error("os.loadavg() returned no one-minute load average");
|
|
126157
|
+
}
|
|
126158
|
+
return { loadAverage: oneMinute, cpus: import_node_os14.default.cpus().length };
|
|
126159
|
+
}
|
|
126160
|
+
|
|
126081
126161
|
// src/frontdoor/rcControl.ts
|
|
126082
126162
|
var https = __toESM(require("node:https"), 1);
|
|
126083
126163
|
init_capability();
|
|
@@ -126764,35 +126844,54 @@ async function listenFrontDoor(server, options = {}) {
|
|
|
126764
126844
|
if (options.onError !== void 0) {
|
|
126765
126845
|
server.on("error", options.onError);
|
|
126766
126846
|
}
|
|
126767
|
-
|
|
126847
|
+
await awaitStartHealth(
|
|
126848
|
+
{
|
|
126849
|
+
probe: async () => await frontDoorHealthy(bound, ca2),
|
|
126850
|
+
now: () => Date.now(),
|
|
126851
|
+
sleep: async (ms) => {
|
|
126852
|
+
await new Promise((resolve3) => {
|
|
126853
|
+
setTimeout(resolve3, ms);
|
|
126854
|
+
});
|
|
126855
|
+
},
|
|
126856
|
+
readLoad: readMachineLoad
|
|
126857
|
+
},
|
|
126858
|
+
`127.0.0.1:${String(bound)}`
|
|
126859
|
+
);
|
|
126860
|
+
return {
|
|
126861
|
+
port: bound,
|
|
126862
|
+
close: async () => {
|
|
126863
|
+
await new Promise((resolve3) => {
|
|
126864
|
+
server.close(() => {
|
|
126865
|
+
resolve3(void 0);
|
|
126866
|
+
});
|
|
126867
|
+
server.closeAllConnections();
|
|
126868
|
+
});
|
|
126869
|
+
},
|
|
126870
|
+
// The port is released as the close runs, before the first await (see `trackConnections` for what happens to the connections already accepted).
|
|
126871
|
+
drain: async () => {
|
|
126872
|
+
await new Promise((resolve3) => {
|
|
126873
|
+
connections.drain(() => {
|
|
126874
|
+
resolve3(void 0);
|
|
126875
|
+
});
|
|
126876
|
+
});
|
|
126877
|
+
}
|
|
126878
|
+
};
|
|
126879
|
+
}
|
|
126880
|
+
async function awaitStartHealth(ports, address) {
|
|
126881
|
+
const startedAt = ports.now();
|
|
126882
|
+
let scheduledMs = 0;
|
|
126883
|
+
let countedTo = startedAt;
|
|
126768
126884
|
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
|
-
};
|
|
126885
|
+
if (await ports.probe()) {
|
|
126886
|
+
return;
|
|
126789
126887
|
}
|
|
126790
|
-
|
|
126791
|
-
|
|
126888
|
+
const now = ports.now();
|
|
126889
|
+
scheduledMs += (now - countedTo) * processorShare(ports.readLoad());
|
|
126890
|
+
countedTo = now;
|
|
126891
|
+
if (scheduledMs >= HEALTH_START_BUDGET_MS) {
|
|
126892
|
+
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
126893
|
}
|
|
126793
|
-
await
|
|
126794
|
-
setTimeout(resolve3, HEALTH_RETRY_MS);
|
|
126795
|
-
});
|
|
126894
|
+
await ports.sleep(HEALTH_RETRY_MS);
|
|
126796
126895
|
}
|
|
126797
126896
|
}
|
|
126798
126897
|
function trackConnections(server) {
|
|
@@ -134484,7 +134583,7 @@ var Builder = class _Builder {
|
|
|
134484
134583
|
});
|
|
134485
134584
|
}
|
|
134486
134585
|
};
|
|
134487
|
-
var
|
|
134586
|
+
var os14 = Builder.create();
|
|
134488
134587
|
|
|
134489
134588
|
// node_modules/.pnpm/@orpc+openapi@2.0.0-beta.43/node_modules/@orpc/openapi/dist/index.mjs
|
|
134490
134589
|
var DEFS_REF_PREFIX = "#/$defs/";
|
|
@@ -138848,7 +138947,7 @@ function doorApiBearer(headers) {
|
|
|
138848
138947
|
return typeof presented === "string" && presented.slice(0, bearerPrefix).toLowerCase() === "bearer " ? presented.slice(bearerPrefix) : void 0;
|
|
138849
138948
|
}
|
|
138850
138949
|
function doorApiAuth(expectedToken) {
|
|
138851
|
-
return
|
|
138950
|
+
return os14.$context().use(({ context, next }) => {
|
|
138852
138951
|
const token = doorApiBearer(context.headers);
|
|
138853
138952
|
if (token === void 0 || !isLiveCapability(token, [expectedToken])) {
|
|
138854
138953
|
throw new ORPCError("UNAUTHORIZED", { message: "the front door's typed API demands this generation's control token as a Bearer credential" });
|
|
@@ -141811,6 +141910,15 @@ function exhaustedMessage(exhaustion) {
|
|
|
141811
141910
|
function createAntigravityRoute(ports) {
|
|
141812
141911
|
const fallbackId = ports.fallbackId ?? (() => (0, import_node_crypto24.randomUUID)());
|
|
141813
141912
|
const lastRouted = ports.lastRouted ?? /* @__PURE__ */ new Map();
|
|
141913
|
+
const exhaustedModels = ports.exhaustedModels ?? /* @__PURE__ */ new Map();
|
|
141914
|
+
const liveQuota = (nowMs) => {
|
|
141915
|
+
for (const [model, resetAtMs] of exhaustedModels) {
|
|
141916
|
+
if (resetAtMs <= nowMs) {
|
|
141917
|
+
exhaustedModels.delete(model);
|
|
141918
|
+
}
|
|
141919
|
+
}
|
|
141920
|
+
return quotaWithExhaustions(ports.quotaSource?.(), exhaustedModels, nowMs);
|
|
141921
|
+
};
|
|
141814
141922
|
return async (request7) => {
|
|
141815
141923
|
await Promise.resolve();
|
|
141816
141924
|
if (request7.method !== "POST") {
|
|
@@ -141864,71 +141972,90 @@ function createAntigravityRoute(ports) {
|
|
|
141864
141972
|
const requestedModel = parsed.data.model ?? config2.defaultModel;
|
|
141865
141973
|
const nowMs = ports.now?.() ?? Date.now();
|
|
141866
141974
|
const sessionKey = parsed.data.metadata?.user_id === void 0 ? void 0 : `${parsed.data.metadata.user_id}\0${parsed.data.model ?? ""}`;
|
|
141867
|
-
const
|
|
141868
|
-
|
|
141869
|
-
|
|
141870
|
-
|
|
141871
|
-
|
|
141872
|
-
|
|
141873
|
-
|
|
141874
|
-
|
|
141975
|
+
const routeRequest = () => {
|
|
141976
|
+
const routed = translateRequest(parsed.data, config2, { quota: liveQuota(nowMs), nowMs, previous: sessionKey === void 0 ? void 0 : lastRouted.get(sessionKey) });
|
|
141977
|
+
if (sessionKey !== void 0) {
|
|
141978
|
+
lastRouted.delete(sessionKey);
|
|
141979
|
+
lastRouted.set(sessionKey, routed.model);
|
|
141980
|
+
if (lastRouted.size > ROUTING_MEMORY_SESSIONS) {
|
|
141981
|
+
const oldest = lastRouted.keys().next();
|
|
141982
|
+
if (oldest.done !== true) {
|
|
141983
|
+
lastRouted.delete(oldest.value);
|
|
141984
|
+
}
|
|
141875
141985
|
}
|
|
141876
141986
|
}
|
|
141877
|
-
|
|
141878
|
-
|
|
141879
|
-
|
|
141880
|
-
|
|
141881
|
-
|
|
141882
|
-
|
|
141883
|
-
|
|
141884
|
-
|
|
141885
|
-
|
|
141886
|
-
model: translated.model,
|
|
141887
|
-
request: translated.request,
|
|
141888
|
-
signal: request7.signal,
|
|
141889
|
-
connector: ports.localConnector
|
|
141890
|
-
}) : callCloudAntigravity(
|
|
141891
|
-
{
|
|
141987
|
+
return routed;
|
|
141988
|
+
};
|
|
141989
|
+
let translated = routeRequest();
|
|
141990
|
+
const tried = /* @__PURE__ */ new Set();
|
|
141991
|
+
let iterator;
|
|
141992
|
+
let firstResult;
|
|
141993
|
+
for (; ; ) {
|
|
141994
|
+
tried.add(translated.model);
|
|
141995
|
+
const upstreamChunks2 = config2.mode === "local" ? callLocalAntigravity({
|
|
141892
141996
|
config: config2,
|
|
141893
141997
|
model: translated.model,
|
|
141894
141998
|
request: translated.request,
|
|
141895
|
-
|
|
141896
|
-
|
|
141897
|
-
|
|
141898
|
-
|
|
141899
|
-
|
|
141900
|
-
|
|
141901
|
-
|
|
141902
|
-
|
|
141903
|
-
|
|
141904
|
-
|
|
141905
|
-
|
|
141906
|
-
|
|
141907
|
-
|
|
141908
|
-
|
|
141909
|
-
|
|
141910
|
-
|
|
141911
|
-
|
|
141912
|
-
|
|
141999
|
+
signal: request7.signal,
|
|
142000
|
+
connector: ports.localConnector
|
|
142001
|
+
}) : callCloudAntigravity(
|
|
142002
|
+
{
|
|
142003
|
+
config: config2,
|
|
142004
|
+
model: translated.model,
|
|
142005
|
+
request: translated.request,
|
|
142006
|
+
token,
|
|
142007
|
+
credentialTarget,
|
|
142008
|
+
signal: request7.signal
|
|
142009
|
+
},
|
|
142010
|
+
ports.fetchFn
|
|
142011
|
+
);
|
|
142012
|
+
iterator = upstreamChunks2[Symbol.asyncIterator]();
|
|
142013
|
+
try {
|
|
142014
|
+
firstResult = await iterator.next();
|
|
142015
|
+
break;
|
|
142016
|
+
} catch (error63) {
|
|
142017
|
+
if (error63 instanceof AntigravityUpstreamError) {
|
|
142018
|
+
const is429 = error63.status === HTTP_STATUS.tooManyRequests;
|
|
142019
|
+
const learned = is429 ? parseQuotaExhaustion(error63.body, nowMs) : void 0;
|
|
142020
|
+
if (learned !== void 0) {
|
|
142021
|
+
exhaustedModels.set(learned.model, learned.resetAtMs);
|
|
142022
|
+
const next = routeRequest();
|
|
142023
|
+
if (!tried.has(next.model)) {
|
|
142024
|
+
translated = next;
|
|
142025
|
+
continue;
|
|
142026
|
+
}
|
|
142027
|
+
}
|
|
142028
|
+
const quota = liveQuota(nowMs);
|
|
142029
|
+
const quotaHeaders3 = unifiedAntigravityQuotaHeaders({ quota, rejected: is429, nowMs, model: translated.model });
|
|
142030
|
+
const retryAfter = is429 && quotaHeaders3["retry-after"] === void 0 ? parseRetryAfterSeconds(error63.retryAfter) : void 0;
|
|
142031
|
+
const exhaustion = is429 ? antigravityQuotaExhaustion(quota, translated.model, nowMs) : void 0;
|
|
142032
|
+
const errorType = is429 ? "rate_limit_error" : "api_error";
|
|
142033
|
+
return {
|
|
142034
|
+
status: error63.status,
|
|
142035
|
+
headers: {
|
|
142036
|
+
"Content-Type": "application/json",
|
|
142037
|
+
...quotaHeaders3,
|
|
142038
|
+
...retryAfter !== void 0 ? { "retry-after": String(retryAfter) } : {}
|
|
142039
|
+
},
|
|
142040
|
+
body: JSON.stringify({ type: "error", error: { type: errorType, message: exhaustion === void 0 ? error63.message : exhaustedMessage(exhaustion) } })
|
|
142041
|
+
};
|
|
142042
|
+
}
|
|
142043
|
+
const errMsg = error63 instanceof Error ? error63.message : String(error63);
|
|
141913
142044
|
return {
|
|
141914
|
-
status:
|
|
141915
|
-
headers: {
|
|
141916
|
-
|
|
141917
|
-
...quotaHeaders3,
|
|
141918
|
-
...retryAfter !== void 0 ? { "retry-after": String(retryAfter) } : {}
|
|
141919
|
-
},
|
|
141920
|
-
body: JSON.stringify({ type: "error", error: { type: errorType, message: exhaustion === void 0 ? error63.message : exhaustedMessage(exhaustion) } })
|
|
142045
|
+
status: HTTP_STATUS.badGateway,
|
|
142046
|
+
headers: { "Content-Type": "application/json" },
|
|
142047
|
+
body: JSON.stringify({ type: "error", error: { type: "api_error", message: errMsg } })
|
|
141921
142048
|
};
|
|
141922
142049
|
}
|
|
141923
|
-
const errMsg = error63 instanceof Error ? error63.message : String(error63);
|
|
141924
|
-
return {
|
|
141925
|
-
status: HTTP_STATUS.badGateway,
|
|
141926
|
-
headers: { "Content-Type": "application/json" },
|
|
141927
|
-
body: JSON.stringify({ type: "error", error: { type: "api_error", message: errMsg } })
|
|
141928
|
-
};
|
|
141929
142050
|
}
|
|
142051
|
+
const relay = createAntigravityRelay({
|
|
142052
|
+
// The frame carries the model that actually served the request, as the real API echoes the concrete model behind an alias: a usage record read from the response then attributes quota to the backend model, not the tier alias the session typed.
|
|
142053
|
+
servedModel: translated.model,
|
|
142054
|
+
toolNames: translated.toolNames,
|
|
142055
|
+
fallbackId
|
|
142056
|
+
});
|
|
141930
142057
|
const quotaHeaders2 = unifiedAntigravityQuotaHeaders({
|
|
141931
|
-
quota:
|
|
142058
|
+
quota: liveQuota(nowMs),
|
|
141932
142059
|
rejected: false,
|
|
141933
142060
|
nowMs,
|
|
141934
142061
|
model: translated.model
|
|
@@ -142392,6 +142519,7 @@ function createProviderRouteResolver(deps) {
|
|
|
142392
142519
|
const resolveCredential2 = shareInFlightResolutions(resolveCredentialAsync);
|
|
142393
142520
|
const antigravityQuotaSources = /* @__PURE__ */ new Map();
|
|
142394
142521
|
const antigravityRoutingMemory = /* @__PURE__ */ new Map();
|
|
142522
|
+
const antigravityExhaustedModels = /* @__PURE__ */ new Map();
|
|
142395
142523
|
const definesProvider = (name) => {
|
|
142396
142524
|
try {
|
|
142397
142525
|
return loadProvider(deps.providersDir, name, deps.fs) !== void 0;
|
|
@@ -142410,6 +142538,15 @@ function createProviderRouteResolver(deps) {
|
|
|
142410
142538
|
antigravityRoutingMemory.set(provider, created);
|
|
142411
142539
|
return created;
|
|
142412
142540
|
};
|
|
142541
|
+
const exhaustedModelsFor = (provider) => {
|
|
142542
|
+
const existing = antigravityExhaustedModels.get(provider);
|
|
142543
|
+
if (existing !== void 0) {
|
|
142544
|
+
return existing;
|
|
142545
|
+
}
|
|
142546
|
+
const created = /* @__PURE__ */ new Map();
|
|
142547
|
+
antigravityExhaustedModels.set(provider, created);
|
|
142548
|
+
return created;
|
|
142549
|
+
};
|
|
142413
142550
|
const antigravityQuotaOf = (provider, definition, config2) => {
|
|
142414
142551
|
const existing = antigravityQuotaSources.get(provider);
|
|
142415
142552
|
if (existing !== void 0) {
|
|
@@ -142505,7 +142642,8 @@ function createProviderRouteResolver(deps) {
|
|
|
142505
142642
|
};
|
|
142506
142643
|
},
|
|
142507
142644
|
quotaSource: antigravityQuotaOf(provider, antigravityProvider, config2),
|
|
142508
|
-
lastRouted: memoryFor(provider)
|
|
142645
|
+
lastRouted: memoryFor(provider),
|
|
142646
|
+
exhaustedModels: exhaustedModelsFor(provider)
|
|
142509
142647
|
},
|
|
142510
142648
|
directOrigin2(deps.directPort()),
|
|
142511
142649
|
provider
|
|
@@ -145631,6 +145769,72 @@ var DOOR_RESPAWN_MAX_GENERATIONS = 3;
|
|
|
145631
145769
|
var DOOR_RESPAWN_COOLDOWN_CAP_MS = DOOR_STALL_BOUND_MS * DOOR_RESPAWN_MAX_GENERATIONS;
|
|
145632
145770
|
var CHECKS_PER_PROBE_DEADLINE = 2;
|
|
145633
145771
|
var DOOR_WATCHDOG_CHECK_MS = PROBE_TIMEOUT_MS / CHECKS_PER_PROBE_DEADLINE;
|
|
145772
|
+
var RESPAWN_SOURCE = `
|
|
145773
|
+
const log = (line) => {
|
|
145774
|
+
if (logFile === undefined) return;
|
|
145775
|
+
try {
|
|
145776
|
+
fs.appendFileSync(logFile, new Date().toISOString() + " frontdoor " + String(ownPid) + ": " + line + "\\n");
|
|
145777
|
+
} catch (error) {
|
|
145778
|
+
// Nowhere left to report a failed log write to; the thread's work goes on without it.
|
|
145779
|
+
}
|
|
145780
|
+
};
|
|
145781
|
+
// Whether a process is alive: signal 0 only tests, and EPERM means it exists under another user.
|
|
145782
|
+
const isRunning = (pid) => {
|
|
145783
|
+
try {
|
|
145784
|
+
process.kill(pid, 0);
|
|
145785
|
+
return true;
|
|
145786
|
+
} catch (error) {
|
|
145787
|
+
return error.code === "EPERM";
|
|
145788
|
+
}
|
|
145789
|
+
};
|
|
145790
|
+
// 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.
|
|
145791
|
+
const liveLockHolder = () => {
|
|
145792
|
+
let holder;
|
|
145793
|
+
try {
|
|
145794
|
+
holder = JSON.parse(fs.readFileSync(startLockFile, "utf8")).pid;
|
|
145795
|
+
} catch (error) {
|
|
145796
|
+
return undefined;
|
|
145797
|
+
}
|
|
145798
|
+
if (typeof holder === "number" && isRunning(holder)) return holder;
|
|
145799
|
+
fs.rmSync(startLockFile, { force: true });
|
|
145800
|
+
return undefined;
|
|
145801
|
+
};
|
|
145802
|
+
// 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.
|
|
145803
|
+
const claimStartLock = (holder) => {
|
|
145804
|
+
try {
|
|
145805
|
+
fs.writeFileSync(startLockFile, JSON.stringify({ pid: holder, at: Date.now() }) + "\\n", { flag: "wx" });
|
|
145806
|
+
return true;
|
|
145807
|
+
} catch (error) {
|
|
145808
|
+
if (error.code === "EEXIST") return false;
|
|
145809
|
+
throw error;
|
|
145810
|
+
}
|
|
145811
|
+
};
|
|
145812
|
+
const spawnReplacement = () => {
|
|
145813
|
+
if (respawn === undefined || logFile === undefined) return;
|
|
145814
|
+
const nextGeneration = respawnGeneration + 1;
|
|
145815
|
+
const cooldownMs = Math.min(Math.max(0, nextGeneration - respawnMaxGeneration) * cooldownStepMs, cooldownCapMs);
|
|
145816
|
+
const startingBy = liveLockHolder();
|
|
145817
|
+
if (startingBy !== undefined) {
|
|
145818
|
+
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");
|
|
145819
|
+
return;
|
|
145820
|
+
}
|
|
145821
|
+
try {
|
|
145822
|
+
const out = fs.openSync(logFile, "a");
|
|
145823
|
+
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) }) });
|
|
145824
|
+
child.unref();
|
|
145825
|
+
fs.closeSync(out);
|
|
145826
|
+
if (!claimStartLock(child.pid)) {
|
|
145827
|
+
// 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.
|
|
145828
|
+
process.kill(child.pid, "SIGKILL");
|
|
145829
|
+
log("withdrew replacement door " + String(child.pid) + ": a launcher took the start lock first and its door is the one starting");
|
|
145830
|
+
return;
|
|
145831
|
+
}
|
|
145832
|
+
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" : ""));
|
|
145833
|
+
} catch (error) {
|
|
145834
|
+
log("could not start a replacement door: " + (error instanceof Error ? error.message : String(error)));
|
|
145835
|
+
}
|
|
145836
|
+
};
|
|
145837
|
+
`;
|
|
145634
145838
|
var WATCHDOG_SOURCE = `
|
|
145635
145839
|
const { workerData, parentPort } = require("node:worker_threads");
|
|
145636
145840
|
const fs = require("node:fs");
|
|
@@ -145647,7 +145851,8 @@ let scheduledMs = 0;
|
|
|
145647
145851
|
let waitingOutStarvation = false;
|
|
145648
145852
|
let stopped = false;
|
|
145649
145853
|
const readLoad = () => machineLoad === undefined ? { loadAverage: os.loadavg()[0], cpus: os.cpus().length } : machineLoad;
|
|
145650
|
-
|
|
145854
|
+
// 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.
|
|
145855
|
+
const processorShare = ${processorShare.toString()};
|
|
145651
145856
|
const describeLoad = (reading) => reading.loadAverage.toFixed(1) + " across " + String(reading.cpus) + " cpus";
|
|
145652
145857
|
const record = (message) => {
|
|
145653
145858
|
try {
|
|
@@ -145660,14 +145865,7 @@ const record = (message) => {
|
|
|
145660
145865
|
// The state file is a courtesy to whoever looks next; the process still has to end.
|
|
145661
145866
|
}
|
|
145662
145867
|
};
|
|
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
|
-
};
|
|
145868
|
+
${RESPAWN_SOURCE}
|
|
145671
145869
|
const MS_PER_SECOND = 1000;
|
|
145672
145870
|
// Enough of the stack to read the caller chain from the timer or socket callback down to the call that held the loop.
|
|
145673
145871
|
const STACK_FRAMES_LOGGED = 12;
|
|
@@ -145708,62 +145906,6 @@ const describeMainThread = (waitMs, resume) => new Promise((resolve) => {
|
|
|
145708
145906
|
finish("the main thread could not be inspected: " + (error instanceof Error ? error.message : String(error)));
|
|
145709
145907
|
}
|
|
145710
145908
|
});
|
|
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
145909
|
// 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
145910
|
const takeNativeSample = () => new Promise((resolve) => {
|
|
145769
145911
|
if (nativeSample === undefined) { resolve(); return; }
|
|
@@ -145854,12 +145996,13 @@ parentPort.on("message", (message) => {
|
|
|
145854
145996
|
}
|
|
145855
145997
|
});
|
|
145856
145998
|
`;
|
|
145999
|
+
var RESPAWN_ENV_NAMES = { awaitPidEnv: DOOR_AWAIT_PID_ENV, respawnGenerationEnv: DOOR_RESPAWN_GENERATION_ENV, delayEnv: DOOR_RESPAWN_DELAY_ENV };
|
|
145857
146000
|
function startThreadWatchdog(params) {
|
|
145858
146001
|
const shared = new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT);
|
|
145859
146002
|
const counter = new Int32Array(shared);
|
|
145860
146003
|
const worker = new import_node_worker_threads2.Worker(WATCHDOG_SOURCE, {
|
|
145861
146004
|
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,
|
|
146005
|
+
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
146006
|
});
|
|
145864
146007
|
worker.unref();
|
|
145865
146008
|
const beat = setInterval(() => {
|
|
@@ -145884,6 +146027,25 @@ function startThreadWatchdog(params) {
|
|
|
145884
146027
|
}
|
|
145885
146028
|
};
|
|
145886
146029
|
}
|
|
146030
|
+
var NEXT_GENERATION_SOURCE = `
|
|
146031
|
+
const { workerData } = require("node:worker_threads");
|
|
146032
|
+
const fs = require("node:fs");
|
|
146033
|
+
const { ownPid, logFile, respawn, respawnGeneration, respawnMaxGeneration, cooldownStepMs, cooldownCapMs, startLockFile, awaitPidEnv, respawnGenerationEnv, delayEnv } = workerData;
|
|
146034
|
+
${RESPAWN_SOURCE}
|
|
146035
|
+
spawnReplacement();
|
|
146036
|
+
`;
|
|
146037
|
+
async function startNextRespawnGeneration(params) {
|
|
146038
|
+
const worker = new import_node_worker_threads2.Worker(NEXT_GENERATION_SOURCE, {
|
|
146039
|
+
eval: true,
|
|
146040
|
+
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 }
|
|
146041
|
+
});
|
|
146042
|
+
await new Promise((resolve3, reject) => {
|
|
146043
|
+
worker.once("error", reject);
|
|
146044
|
+
worker.once("exit", () => {
|
|
146045
|
+
resolve3();
|
|
146046
|
+
});
|
|
146047
|
+
});
|
|
146048
|
+
}
|
|
145887
146049
|
|
|
145888
146050
|
// src/frontdoor/commands.ts
|
|
145889
146051
|
init_probe();
|
|
@@ -146049,6 +146211,16 @@ function realFrontDoorSupervisorPorts(paths, respawnGeneration, lifecycle, track
|
|
|
146049
146211
|
const log = (line) => {
|
|
146050
146212
|
appendDoorLog(paths, `frontdoor ${String(process.pid)}: ${line}`);
|
|
146051
146213
|
};
|
|
146214
|
+
const respawnChain = () => ({
|
|
146215
|
+
ownPid: process.pid,
|
|
146216
|
+
logFile: paths.frontdoorLogPath,
|
|
146217
|
+
respawn: respawnInvocation(paths),
|
|
146218
|
+
respawnGeneration,
|
|
146219
|
+
respawnMaxGeneration: DOOR_RESPAWN_MAX_GENERATIONS,
|
|
146220
|
+
cooldownStepMs: DOOR_STALL_BOUND_MS,
|
|
146221
|
+
cooldownCapMs: DOOR_RESPAWN_COOLDOWN_CAP_MS,
|
|
146222
|
+
startLockFile: paths.frontdoorLockFile
|
|
146223
|
+
});
|
|
146052
146224
|
let directPort = 0;
|
|
146053
146225
|
const rcSelfHost = rcSelfHostFromEnv(process.env);
|
|
146054
146226
|
const codexPorts = createCodexRoutePorts(log, paths.chatgptSignInFile);
|
|
@@ -146500,20 +146672,19 @@ function realFrontDoorSupervisorPorts(paths, respawnGeneration, lifecycle, track
|
|
|
146500
146672
|
return { port: handle.port, listening: server, close: handle.close, drain: handle.drain };
|
|
146501
146673
|
},
|
|
146502
146674
|
closeRcStreamHub: rcHub.close,
|
|
146675
|
+
respawnChain: {
|
|
146676
|
+
generation: respawnGeneration,
|
|
146677
|
+
startNext: async () => {
|
|
146678
|
+
await startNextRespawnGeneration(respawnChain());
|
|
146679
|
+
}
|
|
146680
|
+
},
|
|
146503
146681
|
startWatchdog: () => startThreadWatchdog({
|
|
146682
|
+
...respawnChain(),
|
|
146504
146683
|
stateFile: paths.frontdoorStateFile,
|
|
146505
|
-
ownPid: process.pid,
|
|
146506
146684
|
boundMs: DOOR_STALL_BOUND_MS,
|
|
146507
146685
|
checkEveryMs: DOOR_WATCHDOG_CHECK_MS,
|
|
146508
146686
|
pauseWaitMs: DOOR_WATCHDOG_CHECK_MS,
|
|
146509
146687
|
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
146688
|
...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
146689
|
}),
|
|
146519
146690
|
// 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 +146798,7 @@ function registerFrontDoorCommand(program2, deps) {
|
|
|
146627
146798
|
|
|
146628
146799
|
// src/statusline/commands.ts
|
|
146629
146800
|
var import_node_child_process9 = require("node:child_process");
|
|
146630
|
-
var
|
|
146801
|
+
var import_node_os16 = __toESM(require("node:os"), 1);
|
|
146631
146802
|
var import_node_path70 = __toESM(require("node:path"), 1);
|
|
146632
146803
|
init_commandDeps();
|
|
146633
146804
|
init_load();
|
|
@@ -146769,20 +146940,21 @@ function windowsOf(states, nowMs) {
|
|
|
146769
146940
|
let fiveHourResetAt;
|
|
146770
146941
|
let sevenDayUsed;
|
|
146771
146942
|
let sevenDayResetAt;
|
|
146943
|
+
let bindingUsed;
|
|
146772
146944
|
for (const state of states) {
|
|
146773
146945
|
const unified = state.rateLimit?.unified;
|
|
146774
146946
|
if (unified === void 0) {
|
|
146775
146947
|
continue;
|
|
146776
146948
|
}
|
|
146777
146949
|
const five = livePercentOf(unified.fiveHour, nowMs);
|
|
146778
|
-
if (five !== void 0 && (fiveHourUsed === void 0 || five > fiveHourUsed)) {
|
|
146779
|
-
fiveHourUsed = five;
|
|
146780
|
-
fiveHourResetAt = unified.fiveHour?.resetsAt;
|
|
146781
|
-
}
|
|
146782
146950
|
const seven = livePercentOf(unified.sevenDay, nowMs);
|
|
146783
|
-
|
|
146951
|
+
const max = five === void 0 ? seven : seven === void 0 ? five : Math.max(five, seven);
|
|
146952
|
+
if (max !== void 0 && (bindingUsed === void 0 || max > bindingUsed)) {
|
|
146953
|
+
bindingUsed = max;
|
|
146954
|
+
fiveHourUsed = five;
|
|
146955
|
+
fiveHourResetAt = five === void 0 ? void 0 : unified.fiveHour?.resetsAt;
|
|
146784
146956
|
sevenDayUsed = seven;
|
|
146785
|
-
sevenDayResetAt = unified.sevenDay?.resetsAt;
|
|
146957
|
+
sevenDayResetAt = seven === void 0 ? void 0 : unified.sevenDay?.resetsAt;
|
|
146786
146958
|
}
|
|
146787
146959
|
}
|
|
146788
146960
|
return { fiveHourUsed, fiveHourResetAt, sevenDayUsed, sevenDayResetAt };
|
|
@@ -146828,8 +147000,9 @@ function antigravityQuotaMapOf(payload) {
|
|
|
146828
147000
|
);
|
|
146829
147001
|
}
|
|
146830
147002
|
function bucketView(bucket, nowMs) {
|
|
147003
|
+
const expired = bucket?.reset_in_seconds !== void 0 && Number.isFinite(bucket.reset_in_seconds) && bucket.reset_in_seconds <= 0;
|
|
146831
147004
|
return {
|
|
146832
|
-
used: bucket?.remaining_fraction === void 0 || !Number.isFinite(bucket.remaining_fraction) ? void 0 : (1 - Math.min(1, Math.max(0, bucket.remaining_fraction))) * FULL_PERCENT2,
|
|
147005
|
+
used: bucket?.remaining_fraction === void 0 || !Number.isFinite(bucket.remaining_fraction) ? void 0 : expired ? 0 : (1 - Math.min(1, Math.max(0, bucket.remaining_fraction))) * FULL_PERCENT2,
|
|
146833
147006
|
resetAt: bucket?.reset_in_seconds === void 0 || !Number.isFinite(bucket.reset_in_seconds) ? void 0 : isoOf(nowMs + bucket.reset_in_seconds * MS_PER_SECOND18)
|
|
146834
147007
|
};
|
|
146835
147008
|
}
|
|
@@ -146879,10 +147052,12 @@ function enrichStatuslinePayload(params) {
|
|
|
146879
147052
|
...params.modelChoice === void 0 ? {} : { modelChoice: params.modelChoice },
|
|
146880
147053
|
...params.doorCostUsd === void 0 ? {} : { doorCostUsd: params.doorCostUsd }
|
|
146881
147054
|
};
|
|
147055
|
+
let scopedName;
|
|
146882
147056
|
if (params.snapshot !== void 0) {
|
|
146883
|
-
const
|
|
147057
|
+
const routedProvider = routedProviderOf(params);
|
|
147058
|
+
scopedName = providerScopedState(params.snapshot, params.providerName, params.env.AGENT_SHIM_PROVIDER) ?? providerScopedState(params.snapshot, routedProvider, routedProvider);
|
|
146884
147059
|
const scopedState = scopedName === void 0 ? void 0 : params.snapshot.providers[scopedName];
|
|
146885
|
-
const states = summary.provider === void 0 ? Object.values(params.snapshot.providers) : scopedState === void 0 ? [] : [scopedState];
|
|
147060
|
+
const states = summary.provider === void 0 && scopedState === void 0 ? Object.values(params.snapshot.providers) : scopedState === void 0 ? [] : [scopedState];
|
|
146886
147061
|
let email3;
|
|
146887
147062
|
let sub;
|
|
146888
147063
|
let plan;
|
|
@@ -146913,7 +147088,7 @@ function enrichStatuslinePayload(params) {
|
|
|
146913
147088
|
);
|
|
146914
147089
|
summary = { ...summary, ...windowsOf(states, params.nowMs), providerAccountEmail: email3, providerAccountSub: sub, providerPlan: plan, providerQuotaWindows, quotaFamilies: quotaFamiliesOf(providerBuckets, params.nowMs) };
|
|
146915
147090
|
}
|
|
146916
|
-
if (summary.provider === void 0) {
|
|
147091
|
+
if (summary.provider === void 0 && scopedName === void 0) {
|
|
146917
147092
|
const agyBuckets = antigravityQuotaMapOf(params.payload);
|
|
146918
147093
|
if (agyBuckets !== void 0) {
|
|
146919
147094
|
summary = { ...summary, quotaFamilies: quotaFamiliesOf(agyBuckets, params.nowMs) };
|
|
@@ -146935,6 +147110,29 @@ function enrichStatuslinePayload(params) {
|
|
|
146935
147110
|
}
|
|
146936
147111
|
return { payload: enriched, summary };
|
|
146937
147112
|
}
|
|
147113
|
+
function routedProviderOf(params) {
|
|
147114
|
+
if (params.modelChoice?.provider !== void 0 && params.modelChoice.provider !== "") {
|
|
147115
|
+
return params.modelChoice.provider;
|
|
147116
|
+
}
|
|
147117
|
+
const targetPrefix = prefixBeforeSlash(params.routedTarget);
|
|
147118
|
+
if (targetPrefix !== void 0) {
|
|
147119
|
+
return targetPrefix;
|
|
147120
|
+
}
|
|
147121
|
+
const model = isObject4(params.payload) && isObject4(params.payload.model) ? params.payload.model : void 0;
|
|
147122
|
+
return prefixBeforeSlash(typeof model?.id === "string" ? model.id : void 0) ?? prefixBeforeSlash(typeof model?.display_name === "string" ? model.display_name : void 0);
|
|
147123
|
+
}
|
|
147124
|
+
function prefixBeforeSlash(value3) {
|
|
147125
|
+
if (value3 === void 0) {
|
|
147126
|
+
return void 0;
|
|
147127
|
+
}
|
|
147128
|
+
const slash = value3.indexOf("/");
|
|
147129
|
+
if (slash <= 0) {
|
|
147130
|
+
return void 0;
|
|
147131
|
+
}
|
|
147132
|
+
const prefix = value3.slice(0, slash).trim();
|
|
147133
|
+
const rest = value3.slice(slash + 1).trim();
|
|
147134
|
+
return prefix === "" || rest === "" ? void 0 : prefix;
|
|
147135
|
+
}
|
|
146938
147136
|
function providerScopedState(snapshot, providerName, providerDisplayName) {
|
|
146939
147137
|
if (providerName !== void 0 && providerName in snapshot.providers) {
|
|
146940
147138
|
return providerName;
|
|
@@ -147418,7 +147616,7 @@ function contextViewOf(frame) {
|
|
|
147418
147616
|
// src/statusline/ports.ts
|
|
147419
147617
|
init_blockingSpawn();
|
|
147420
147618
|
var import_node_fs26 = __toESM(require("node:fs"), 1);
|
|
147421
|
-
var
|
|
147619
|
+
var import_node_os15 = __toESM(require("node:os"), 1);
|
|
147422
147620
|
var import_node_path63 = __toESM(require("node:path"), 1);
|
|
147423
147621
|
|
|
147424
147622
|
// src/statusline/memoryUse.ts
|
|
@@ -147552,7 +147750,7 @@ function discard(target) {
|
|
|
147552
147750
|
}
|
|
147553
147751
|
}
|
|
147554
147752
|
function readMemoryUse() {
|
|
147555
|
-
const totalBytes =
|
|
147753
|
+
const totalBytes = import_node_os15.default.totalmem();
|
|
147556
147754
|
if (process.platform === "darwin") {
|
|
147557
147755
|
const output2 = runWithPipe(RUN_TIMEOUT_MS, "/usr/bin/vm_stat", [], process.cwd());
|
|
147558
147756
|
const usedBytes = output2 === void 0 ? void 0 : usedBytesFromVmStat(output2);
|
|
@@ -147562,13 +147760,13 @@ function readMemoryUse() {
|
|
|
147562
147760
|
const meminfo = readText("/proc/meminfo");
|
|
147563
147761
|
return meminfo === void 0 ? void 0 : memoryUseFromMeminfo(meminfo);
|
|
147564
147762
|
}
|
|
147565
|
-
return { usedBytes: totalBytes -
|
|
147763
|
+
return { usedBytes: totalBytes - import_node_os15.default.freemem(), totalBytes };
|
|
147566
147764
|
}
|
|
147567
147765
|
function realStatuslinePorts(env, stateDirectory, runTimeoutMs = RUN_TIMEOUT_MS) {
|
|
147568
147766
|
const { locale, timeZone } = Intl.DateTimeFormat().resolvedOptions();
|
|
147569
147767
|
return {
|
|
147570
147768
|
env,
|
|
147571
|
-
homeDirectory:
|
|
147769
|
+
homeDirectory: import_node_os15.default.homedir(),
|
|
147572
147770
|
stateDirectory,
|
|
147573
147771
|
clock: { locale, timeZone },
|
|
147574
147772
|
readText,
|
|
@@ -151240,7 +151438,7 @@ function registerStatuslineCommand(program2, deps) {
|
|
|
151240
151438
|
} else {
|
|
151241
151439
|
const configDir = process.env.CLAUDE_CONFIG_DIR;
|
|
151242
151440
|
try {
|
|
151243
|
-
account = readAccountMetadataFile(realFarmFs, configDir === void 0 || configDir === "" ? import_node_path70.default.join(
|
|
151441
|
+
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
151442
|
} catch {
|
|
151245
151443
|
account = void 0;
|
|
151246
151444
|
}
|
|
@@ -151289,7 +151487,7 @@ function registerStatuslineCommand(program2, deps) {
|
|
|
151289
151487
|
});
|
|
151290
151488
|
return;
|
|
151291
151489
|
}
|
|
151292
|
-
const live = statuslineSettingsForRender({ env: process.env, cwd: process.cwd(), home:
|
|
151490
|
+
const live = statuslineSettingsForRender({ env: process.env, cwd: process.cwd(), home: import_node_os16.default.homedir(), paths: deps.paths, fs: { ...realFsPort, readConfigFile: cosmiconfigReader() } });
|
|
151293
151491
|
if (live.problem !== void 0) {
|
|
151294
151492
|
process.stderr.write(`agent-shim: statusline: ${live.problem}. Drawing with the defaults.
|
|
151295
151493
|
`);
|
|
@@ -151302,7 +151500,7 @@ function registerStatuslineCommand(program2, deps) {
|
|
|
151302
151500
|
let stackedUnderDefault = false;
|
|
151303
151501
|
if (isAntigravityPayload(payload)) {
|
|
151304
151502
|
try {
|
|
151305
|
-
stackedUnderDefault = antigravityStacksWithDefault(realFarmFs,
|
|
151503
|
+
stackedUnderDefault = antigravityStacksWithDefault(realFarmFs, import_node_os16.default.homedir());
|
|
151306
151504
|
} catch {
|
|
151307
151505
|
stackedUnderDefault = false;
|
|
151308
151506
|
}
|
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.6",
|
|
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.6",
|
|
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.6",
|
|
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>",
|