agent-shim 8.0.0 → 8.0.1
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 +251 -240
- package/dist/index.cjs +3 -3
- package/dist/index.mjs +3 -3
- package/dist/types/index.d.ts +2 -2
- package/package.json +1 -1
package/dist/cli.cjs
CHANGED
|
@@ -61039,7 +61039,7 @@ function registerIdentityCommand(program2, deps) {
|
|
|
61039
61039
|
// package.json
|
|
61040
61040
|
var package_default = {
|
|
61041
61041
|
name: "agent-shim",
|
|
61042
|
-
version: "8.0.
|
|
61042
|
+
version: "8.0.1",
|
|
61043
61043
|
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.",
|
|
61044
61044
|
license: "MIT",
|
|
61045
61045
|
author: "Joseph Mearman <joseph@mearman.co.uk>",
|
|
@@ -68037,13 +68037,231 @@ function registerDoctorCommand(program2, deps) {
|
|
|
68037
68037
|
}
|
|
68038
68038
|
|
|
68039
68039
|
// src/headroom/commands.ts
|
|
68040
|
-
var
|
|
68040
|
+
var import_node_fs16 = __toESM(require("node:fs"), 1);
|
|
68041
68041
|
var import_node_http2 = __toESM(require("node:http"), 1);
|
|
68042
|
-
var
|
|
68042
|
+
var import_node_path36 = __toESM(require("node:path"), 1);
|
|
68043
68043
|
var import_node_child_process5 = require("node:child_process");
|
|
68044
68044
|
|
|
68045
|
-
// src/
|
|
68045
|
+
// src/frontdoor/realFrontDoorPort.ts
|
|
68046
|
+
var import_node_fs15 = __toESM(require("node:fs"), 1);
|
|
68047
|
+
|
|
68048
|
+
// src/frontdoor/ensure.ts
|
|
68046
68049
|
var import_node_crypto12 = require("node:crypto");
|
|
68050
|
+
var FRONTDOOR_START_TIMEOUT_MS = 3e4;
|
|
68051
|
+
var FRONTDOOR_LAUNCHER_POLL_MS = 100;
|
|
68052
|
+
var FrontDoorStartError = class extends CliError {
|
|
68053
|
+
constructor(message) {
|
|
68054
|
+
super(message);
|
|
68055
|
+
this.name = "FrontDoorStartError";
|
|
68056
|
+
}
|
|
68057
|
+
};
|
|
68058
|
+
function ensureFrontDoor(params) {
|
|
68059
|
+
const { paths, ports } = params;
|
|
68060
|
+
const deadline = ports.now() + FRONTDOOR_START_TIMEOUT_MS;
|
|
68061
|
+
let spawned = false;
|
|
68062
|
+
let replaced = false;
|
|
68063
|
+
const distrusted = /* @__PURE__ */ new Set();
|
|
68064
|
+
let lastRejection;
|
|
68065
|
+
for (; ; ) {
|
|
68066
|
+
const state = readFrontDoorState(ports.fs, paths.frontdoorStateFile);
|
|
68067
|
+
const supervisorPid = state?.supervisorPid;
|
|
68068
|
+
if (supervisorPid !== void 0 && !distrusted.has(supervisorPid) && ports.isRunning(supervisorPid)) {
|
|
68069
|
+
if (state?.port !== void 0 && state.connectPort !== void 0) {
|
|
68070
|
+
const verdict = ports.verifyListener(state.port);
|
|
68071
|
+
if (verdict.ok && (state.protocol ?? 0) < FRONT_DOOR_PROTOCOL && !replaced) {
|
|
68072
|
+
ports.stopSupervisor(supervisorPid);
|
|
68073
|
+
while (ports.isRunning(supervisorPid)) {
|
|
68074
|
+
if (ports.now() >= deadline) {
|
|
68075
|
+
throw new FrontDoorStartError(`agent-shim: the front door (pid ${String(supervisorPid)}, protocol ${String(state.protocol ?? 0)}) is older than this launcher (protocol ${String(FRONT_DOOR_PROTOCOL)}) and did not exit when asked. Daemon log: ${paths.frontdoorLogPath}`);
|
|
68076
|
+
}
|
|
68077
|
+
ports.sleep(FRONTDOOR_LAUNCHER_POLL_MS);
|
|
68078
|
+
}
|
|
68079
|
+
replaced = true;
|
|
68080
|
+
continue;
|
|
68081
|
+
}
|
|
68082
|
+
if (verdict.ok) {
|
|
68083
|
+
const token = (0, import_node_crypto12.randomUUID)();
|
|
68084
|
+
writeFrontDoorSession(ports.fs, paths.frontdoorSessionsDir, { pid: params.launcherPid, startedAt: ports.now(), token });
|
|
68085
|
+
return { port: state.port, connectPort: state.connectPort, token };
|
|
68086
|
+
}
|
|
68087
|
+
lastRejection = `the listener on 127.0.0.1:${String(state.port)} (recorded for pid ${String(supervisorPid)}) failed authentication: ${verdict.reason}`;
|
|
68088
|
+
if (spawned) {
|
|
68089
|
+
throw new FrontDoorStartError(`agent-shim: ${lastRejection}; refusing to send this session's credentials to it. Daemon log: ${paths.frontdoorLogPath}`);
|
|
68090
|
+
}
|
|
68091
|
+
distrusted.add(supervisorPid);
|
|
68092
|
+
continue;
|
|
68093
|
+
}
|
|
68094
|
+
if (state?.lastError !== void 0) {
|
|
68095
|
+
throw new FrontDoorStartError(`agent-shim: the front door reported a fatal error and is not serving: ${state.lastError} (daemon log: ${paths.frontdoorLogPath})`);
|
|
68096
|
+
}
|
|
68097
|
+
} else if (!spawned) {
|
|
68098
|
+
ports.fs.mkdirp(paths.frontdoorDir);
|
|
68099
|
+
const created = ports.fs.writeFileExclusive(paths.frontdoorLockFile, `${JSON.stringify({ pid: params.launcherPid, at: ports.now() })}
|
|
68100
|
+
`);
|
|
68101
|
+
if (created) {
|
|
68102
|
+
ports.spawnSupervisor(paths);
|
|
68103
|
+
spawned = true;
|
|
68104
|
+
} else {
|
|
68105
|
+
const lock = readStartLock(ports.fs, paths.frontdoorLockFile);
|
|
68106
|
+
if (lock === void 0 || !ports.isRunning(lock.pid)) {
|
|
68107
|
+
ports.fs.removeRecursive(paths.frontdoorLockFile);
|
|
68108
|
+
continue;
|
|
68109
|
+
}
|
|
68110
|
+
}
|
|
68111
|
+
}
|
|
68112
|
+
if (ports.now() >= deadline) {
|
|
68113
|
+
const lastError = state?.lastError;
|
|
68114
|
+
throw new FrontDoorStartError(
|
|
68115
|
+
`agent-shim: the front door did not become ready within ${String(FRONTDOOR_START_TIMEOUT_MS)}ms` + (lastError === void 0 ? "" : ` (last error: ${lastError})`) + (lastRejection === void 0 ? "" : ` (${lastRejection})`) + `. Daemon log: ${paths.frontdoorLogPath}`
|
|
68116
|
+
);
|
|
68117
|
+
}
|
|
68118
|
+
ports.sleep(FRONTDOOR_LAUNCHER_POLL_MS);
|
|
68119
|
+
}
|
|
68120
|
+
}
|
|
68121
|
+
|
|
68122
|
+
// src/frontdoor/probe.ts
|
|
68123
|
+
var import_node_worker_threads = require("node:worker_threads");
|
|
68124
|
+
var PROBE_TIMEOUT_MS = 2e3;
|
|
68125
|
+
var PROBE_WAIT_MARGIN_MS = 1e3;
|
|
68126
|
+
var REASON_BYTES = 1024;
|
|
68127
|
+
var HEADER_SLOTS = 2;
|
|
68128
|
+
var INT32_BYTES = 4;
|
|
68129
|
+
var VERDICT_PENDING = 0;
|
|
68130
|
+
var VERDICT_OK = 1;
|
|
68131
|
+
var VERDICT_FAILED = 2;
|
|
68132
|
+
var PROBE_SOURCE = `
|
|
68133
|
+
const { workerData } = require("node:worker_threads");
|
|
68134
|
+
const https = require("node:https");
|
|
68135
|
+
const { port, ca, timeoutMs, shared, ok, failed, headerSlots } = workerData;
|
|
68136
|
+
const header = new Int32Array(shared, 0, headerSlots);
|
|
68137
|
+
const reason = new Uint8Array(shared, headerSlots * 4);
|
|
68138
|
+
let done = false;
|
|
68139
|
+
const finish = (verdict, message) => {
|
|
68140
|
+
if (done) return;
|
|
68141
|
+
done = true;
|
|
68142
|
+
const bytes = Buffer.from(String(message), "utf8").subarray(0, reason.length);
|
|
68143
|
+
reason.set(bytes);
|
|
68144
|
+
Atomics.store(header, 1, bytes.length);
|
|
68145
|
+
Atomics.store(header, 0, verdict);
|
|
68146
|
+
Atomics.notify(header, 0);
|
|
68147
|
+
};
|
|
68148
|
+
const request = https.get({ host: "127.0.0.1", port, path: "/healthz", ca: [ca], agent: false }, (response) => {
|
|
68149
|
+
let body = "";
|
|
68150
|
+
response.setEncoding("utf8");
|
|
68151
|
+
response.on("data", (chunk) => { body += chunk; });
|
|
68152
|
+
response.on("end", () => {
|
|
68153
|
+
if (response.statusCode === 200 && body === "ok") finish(ok, "");
|
|
68154
|
+
else finish(failed, "the listener answered its health probe with HTTP " + String(response.statusCode));
|
|
68155
|
+
});
|
|
68156
|
+
response.on("error", (error) => finish(failed, error.message));
|
|
68157
|
+
});
|
|
68158
|
+
// A hard deadline over the whole exchange, handshake included: a listener that accepts the connection and then says nothing must still fail the probe.
|
|
68159
|
+
setTimeout(() => { request.destroy(new Error("no answer within " + String(timeoutMs) + "ms")); }, timeoutMs);
|
|
68160
|
+
request.on("error", (error) => finish(failed, (error.code ? error.code + ": " : "") + error.message));
|
|
68161
|
+
`;
|
|
68162
|
+
function probeFrontDoorSync(port, caPem) {
|
|
68163
|
+
const shared = new SharedArrayBuffer(HEADER_SLOTS * INT32_BYTES + REASON_BYTES);
|
|
68164
|
+
const header = new Int32Array(shared, 0, HEADER_SLOTS);
|
|
68165
|
+
const worker = new import_node_worker_threads.Worker(PROBE_SOURCE, {
|
|
68166
|
+
eval: true,
|
|
68167
|
+
workerData: { port, ca: caPem, timeoutMs: PROBE_TIMEOUT_MS, shared, ok: VERDICT_OK, failed: VERDICT_FAILED, headerSlots: HEADER_SLOTS }
|
|
68168
|
+
});
|
|
68169
|
+
worker.unref();
|
|
68170
|
+
try {
|
|
68171
|
+
const waited = Atomics.wait(header, 0, VERDICT_PENDING, PROBE_TIMEOUT_MS + PROBE_WAIT_MARGIN_MS);
|
|
68172
|
+
const verdict = Atomics.load(header, 0);
|
|
68173
|
+
if (waited === "timed-out" || verdict === VERDICT_PENDING) {
|
|
68174
|
+
return { ok: false, reason: `the probe did not finish within ${String(PROBE_TIMEOUT_MS + PROBE_WAIT_MARGIN_MS)}ms` };
|
|
68175
|
+
}
|
|
68176
|
+
if (verdict === VERDICT_OK) {
|
|
68177
|
+
return { ok: true };
|
|
68178
|
+
}
|
|
68179
|
+
const length = Atomics.load(header, 1);
|
|
68180
|
+
return { ok: false, reason: Buffer.from(new Uint8Array(shared, HEADER_SLOTS * INT32_BYTES, length)).toString("utf8") };
|
|
68181
|
+
} finally {
|
|
68182
|
+
void worker.terminate();
|
|
68183
|
+
}
|
|
68184
|
+
}
|
|
68185
|
+
|
|
68186
|
+
// src/frontdoor/trust.ts
|
|
68187
|
+
var import_node_crypto13 = require("node:crypto");
|
|
68188
|
+
var import_node_path35 = __toESM(require("node:path"), 1);
|
|
68189
|
+
var BUNDLE_NAME_HEX_DIGITS = 16;
|
|
68190
|
+
function resolveTrustBundle(params) {
|
|
68191
|
+
const { caCertFile, bundlesDir, variable, inherited, fs: fs19 } = params;
|
|
68192
|
+
if (inherited === void 0 || inherited === "" || import_node_path35.default.resolve(inherited) === import_node_path35.default.resolve(caCertFile)) {
|
|
68193
|
+
return { path: caCertFile };
|
|
68194
|
+
}
|
|
68195
|
+
const caPem = fs19.readFileUtf8(caCertFile);
|
|
68196
|
+
let inheritedPem;
|
|
68197
|
+
try {
|
|
68198
|
+
inheritedPem = fs19.readFileUtf8(inherited);
|
|
68199
|
+
} catch (error62) {
|
|
68200
|
+
return {
|
|
68201
|
+
path: caCertFile,
|
|
68202
|
+
warning: `agent-shim: ${variable} names ${inherited}, which could not be read (${error62 instanceof Error ? error62.message : String(error62)}); the child trusts agent-shim's front-door CA on top of the system store, and nothing from that file`
|
|
68203
|
+
};
|
|
68204
|
+
}
|
|
68205
|
+
if (inheritedPem.includes(caPem.trim())) {
|
|
68206
|
+
return { path: inherited };
|
|
68207
|
+
}
|
|
68208
|
+
const combined = `${inheritedPem.trimEnd()}
|
|
68209
|
+
${caPem}`;
|
|
68210
|
+
const bundle = import_node_path35.default.join(bundlesDir, `${(0, import_node_crypto13.createHash)("sha256").update(combined).digest("hex").slice(0, BUNDLE_NAME_HEX_DIGITS)}.pem`);
|
|
68211
|
+
if (!fs19.exists(bundle)) {
|
|
68212
|
+
fs19.mkdirp(bundlesDir);
|
|
68213
|
+
fs19.writeFileAtomic(bundle, combined);
|
|
68214
|
+
}
|
|
68215
|
+
return { path: bundle };
|
|
68216
|
+
}
|
|
68217
|
+
|
|
68218
|
+
// src/frontdoor/realFrontDoorPort.ts
|
|
68219
|
+
var realTrustBundleFs = {
|
|
68220
|
+
readFileUtf8: (file2) => import_node_fs15.default.readFileSync(file2, "utf8"),
|
|
68221
|
+
exists: (file2) => import_node_fs15.default.existsSync(file2),
|
|
68222
|
+
mkdirp: (dir) => {
|
|
68223
|
+
import_node_fs15.default.mkdirSync(dir, { recursive: true });
|
|
68224
|
+
},
|
|
68225
|
+
writeFileAtomic: (file2, contents) => {
|
|
68226
|
+
realFarmFs.writeFilePrivate(file2, contents);
|
|
68227
|
+
}
|
|
68228
|
+
};
|
|
68229
|
+
function realFrontDoorPort(paths, spawnDaemon) {
|
|
68230
|
+
return {
|
|
68231
|
+
ensure: (inheritedExtraCaCerts) => {
|
|
68232
|
+
const up = ensureFrontDoor({
|
|
68233
|
+
paths,
|
|
68234
|
+
launcherPid: process.pid,
|
|
68235
|
+
ports: {
|
|
68236
|
+
fs: realFarmFs,
|
|
68237
|
+
isRunning: realIsProcessRunning,
|
|
68238
|
+
now: () => Date.now(),
|
|
68239
|
+
sleep: realSleepSync,
|
|
68240
|
+
spawnSupervisor: (layout) => spawnDaemon(layout, "__frontdoor-supervisor", layout.frontdoorLogPath),
|
|
68241
|
+
stopSupervisor: (pid) => {
|
|
68242
|
+
process.kill(pid, "SIGTERM");
|
|
68243
|
+
},
|
|
68244
|
+
// Read fresh for each probe: a replacement supervisor may have regenerated an unparseable CA, and the probe must trust exactly what the serving door's leaf chains to.
|
|
68245
|
+
verifyListener: (port) => probeFrontDoorSync(port, import_node_fs15.default.readFileSync(paths.frontdoorCaCertFile, "utf8"))
|
|
68246
|
+
}
|
|
68247
|
+
});
|
|
68248
|
+
const trust = resolveTrustBundle({ caCertFile: paths.frontdoorCaCertFile, bundlesDir: paths.frontdoorCaBundlesDir, variable: "NODE_EXTRA_CA_CERTS", inherited: inheritedExtraCaCerts, fs: realTrustBundleFs });
|
|
68249
|
+
return {
|
|
68250
|
+
port: up.port,
|
|
68251
|
+
connectPort: up.connectPort,
|
|
68252
|
+
trustBundlePath: trust.path,
|
|
68253
|
+
...trust.warning === void 0 ? {} : { trustWarning: trust.warning },
|
|
68254
|
+
sessionToken: up.token
|
|
68255
|
+
};
|
|
68256
|
+
},
|
|
68257
|
+
release: () => {
|
|
68258
|
+
removeFrontDoorSession(realFarmFs, paths.frontdoorSessionsDir, process.pid);
|
|
68259
|
+
}
|
|
68260
|
+
};
|
|
68261
|
+
}
|
|
68262
|
+
|
|
68263
|
+
// src/headroom/settings.ts
|
|
68264
|
+
var import_node_crypto14 = require("node:crypto");
|
|
68047
68265
|
function settingsOf(config2) {
|
|
68048
68266
|
return {
|
|
68049
68267
|
...config2.mode === void 0 ? {} : { mode: config2.mode },
|
|
@@ -68068,7 +68286,7 @@ function settingsEnv(settings2) {
|
|
|
68068
68286
|
return settings2.rolloutChannel === void 0 ? {} : { HEADROOM_ROLLOUT_CHANNEL: settings2.rolloutChannel };
|
|
68069
68287
|
}
|
|
68070
68288
|
function hashSettings(settings2) {
|
|
68071
|
-
return (0,
|
|
68289
|
+
return (0, import_node_crypto14.createHash)("sha256").update(JSON.stringify([...settingsArgs(settings2), JSON.stringify(settingsEnv(settings2))])).digest("hex");
|
|
68072
68290
|
}
|
|
68073
68291
|
|
|
68074
68292
|
// src/headroom/supervisor.ts
|
|
@@ -68413,7 +68631,14 @@ var READY_FETCH_TIMEOUT_MS = 2e3;
|
|
|
68413
68631
|
function headroomPidRunning(pid) {
|
|
68414
68632
|
return !exitedHeadroom.has(pid) && realIsProcessRunning(pid);
|
|
68415
68633
|
}
|
|
68416
|
-
|
|
68634
|
+
var HEADROOM_CA_BUNDLE = "HEADROOM_CA_BUNDLE";
|
|
68635
|
+
function resolveHeadroomTrustBundle(params) {
|
|
68636
|
+
if (!params.fs.exists(params.caCertFile)) {
|
|
68637
|
+
return void 0;
|
|
68638
|
+
}
|
|
68639
|
+
return resolveTrustBundle({ ...params, variable: HEADROOM_CA_BUNDLE });
|
|
68640
|
+
}
|
|
68641
|
+
function headroomSpawnEnv(parentEnv, allowlist, settings2, trustBundlePath) {
|
|
68417
68642
|
const inherited = { ...parentEnv };
|
|
68418
68643
|
delete inherited.HEADROOM_HOST;
|
|
68419
68644
|
delete inherited.HEADROOM_PORT;
|
|
@@ -68421,8 +68646,8 @@ function headroomSpawnEnv(parentEnv, allowlist, settings2, caBundle) {
|
|
|
68421
68646
|
...inherited,
|
|
68422
68647
|
HEADROOM_ALLOWED_BASE_URLS: allowlist.join(","),
|
|
68423
68648
|
HEADROOM_HTTP2: parentEnv.HEADROOM_HTTP2 ?? "0",
|
|
68424
|
-
//
|
|
68425
|
-
...
|
|
68649
|
+
// The bundle already holds any inherited HEADROOM_CA_BUNDLE's certificates, so replacing the variable loses nothing. An inherited SSL_CERT_FILE or REQUESTS_CA_BUNDLE passes through untouched and, by headroom's own precedence, still replaces everything: an explicit choice in the parent environment wins.
|
|
68650
|
+
...trustBundlePath === void 0 ? {} : { [HEADROOM_CA_BUNDLE]: trustBundlePath },
|
|
68426
68651
|
...settingsEnv(settings2)
|
|
68427
68652
|
};
|
|
68428
68653
|
}
|
|
@@ -68449,12 +68674,12 @@ function readInstalledHeadroomCommit() {
|
|
|
68449
68674
|
if (toolDir.status !== 0) {
|
|
68450
68675
|
return void 0;
|
|
68451
68676
|
}
|
|
68452
|
-
const libDir =
|
|
68677
|
+
const libDir = import_node_path36.default.join(toolDir.stdout.trim(), HEADROOM_TOOL_NAME, "lib");
|
|
68453
68678
|
for (const python of realFarmFs.readdir(libDir)) {
|
|
68454
|
-
const sitePackages =
|
|
68679
|
+
const sitePackages = import_node_path36.default.join(libDir, python, "site-packages");
|
|
68455
68680
|
for (const entry of realFarmFs.readdir(sitePackages)) {
|
|
68456
68681
|
if (entry.startsWith("headroom_ai-") && entry.endsWith(".dist-info")) {
|
|
68457
|
-
const directUrl = realFarmFs.readFileUtf8(
|
|
68682
|
+
const directUrl = realFarmFs.readFileUtf8(import_node_path36.default.join(sitePackages, entry, "direct_url.json"));
|
|
68458
68683
|
return directUrl === void 0 ? void 0 : parseInstalledCommit(directUrl);
|
|
68459
68684
|
}
|
|
68460
68685
|
}
|
|
@@ -68477,14 +68702,18 @@ function realSupervisorPorts(paths) {
|
|
|
68477
68702
|
socketTrust: realHeadroomSocketTrust,
|
|
68478
68703
|
readConfig: () => resolveSupervisorConfig(readGlobalConfig(paths)?.headroom ?? {}),
|
|
68479
68704
|
spawnHeadroom: (socketPath, allowlist, settings2) => {
|
|
68480
|
-
const
|
|
68481
|
-
|
|
68482
|
-
|
|
68705
|
+
const trust = resolveHeadroomTrustBundle({ caCertFile: paths.frontdoorCaCertFile, bundlesDir: paths.frontdoorCaBundlesDir, inherited: process.env[HEADROOM_CA_BUNDLE], fs: realTrustBundleFs });
|
|
68706
|
+
import_node_fs16.default.mkdirSync(paths.logsDir, { recursive: true });
|
|
68707
|
+
if (trust?.warning !== void 0) {
|
|
68708
|
+
import_node_fs16.default.appendFileSync(paths.headroomLogPath, `${(/* @__PURE__ */ new Date()).toISOString()} ${trust.warning}
|
|
68709
|
+
`);
|
|
68710
|
+
}
|
|
68711
|
+
const logFd = import_node_fs16.default.openSync(paths.headroomLogPath, "a");
|
|
68483
68712
|
try {
|
|
68484
68713
|
const child = (0, import_node_child_process5.spawn)("headroom", headroomProxyArgs(socketPath, settings2), {
|
|
68485
68714
|
detached: true,
|
|
68486
68715
|
stdio: ["ignore", logFd, logFd],
|
|
68487
|
-
env: headroomSpawnEnv(process.env, allowlist, settings2,
|
|
68716
|
+
env: headroomSpawnEnv(process.env, allowlist, settings2, trust?.path)
|
|
68488
68717
|
});
|
|
68489
68718
|
if (child.pid === void 0) {
|
|
68490
68719
|
throw new Error("spawning headroom returned no pid");
|
|
@@ -68494,12 +68723,12 @@ function realSupervisorPorts(paths) {
|
|
|
68494
68723
|
child.once("exit", (code, signal) => {
|
|
68495
68724
|
ownedHeadroom.delete(pid);
|
|
68496
68725
|
exitedHeadroom.add(pid);
|
|
68497
|
-
|
|
68726
|
+
import_node_fs16.default.appendFileSync(paths.headroomLogPath, `${(/* @__PURE__ */ new Date()).toISOString()} agent-shim headroom supervisor: headroom exited (${signal ?? `code ${String(code)}`})
|
|
68498
68727
|
`);
|
|
68499
68728
|
});
|
|
68500
68729
|
return pid;
|
|
68501
68730
|
} finally {
|
|
68502
|
-
|
|
68731
|
+
import_node_fs16.default.closeSync(logFd);
|
|
68503
68732
|
}
|
|
68504
68733
|
},
|
|
68505
68734
|
stopProcess: (pid) => {
|
|
@@ -68512,7 +68741,7 @@ function realSupervisorPorts(paths) {
|
|
|
68512
68741
|
now: () => Date.now()
|
|
68513
68742
|
});
|
|
68514
68743
|
if (outcome === "still-running") {
|
|
68515
|
-
|
|
68744
|
+
import_node_fs16.default.appendFileSync(
|
|
68516
68745
|
paths.headroomLogPath,
|
|
68517
68746
|
`${(/* @__PURE__ */ new Date()).toISOString()} agent-shim headroom supervisor: pid ${String(pid)} survived SIGKILL within its grace; it is stuck uninterruptibly
|
|
68518
68747
|
`
|
|
@@ -68526,10 +68755,10 @@ function realSupervisorPorts(paths) {
|
|
|
68526
68755
|
return { ok: false, error: `uv is not installed or not on PATH (${result.error.message})` };
|
|
68527
68756
|
}
|
|
68528
68757
|
if (result.stdout !== "") {
|
|
68529
|
-
|
|
68758
|
+
import_node_fs16.default.appendFileSync(paths.headroomLogPath, result.stdout);
|
|
68530
68759
|
}
|
|
68531
68760
|
if (result.stderr !== "") {
|
|
68532
|
-
|
|
68761
|
+
import_node_fs16.default.appendFileSync(paths.headroomLogPath, result.stderr);
|
|
68533
68762
|
}
|
|
68534
68763
|
return result.status === 0 ? { ok: true } : { ok: false, error: `uv tool install exited ${String(result.status)}` };
|
|
68535
68764
|
},
|
|
@@ -68539,8 +68768,8 @@ function realSupervisorPorts(paths) {
|
|
|
68539
68768
|
},
|
|
68540
68769
|
installedCommit: readInstalledHeadroomCommit,
|
|
68541
68770
|
log: (line) => {
|
|
68542
|
-
|
|
68543
|
-
|
|
68771
|
+
import_node_fs16.default.mkdirSync(paths.logsDir, { recursive: true });
|
|
68772
|
+
import_node_fs16.default.appendFileSync(paths.headroomLogPath, `${(/* @__PURE__ */ new Date()).toISOString()} ${line}
|
|
68544
68773
|
`);
|
|
68545
68774
|
}
|
|
68546
68775
|
};
|
|
@@ -69253,224 +69482,6 @@ function buildProgram(deps) {
|
|
|
69253
69482
|
var import_node_os8 = __toESM(require("node:os"), 1);
|
|
69254
69483
|
var import_node_crypto16 = require("node:crypto");
|
|
69255
69484
|
|
|
69256
|
-
// src/frontdoor/realFrontDoorPort.ts
|
|
69257
|
-
var import_node_fs16 = __toESM(require("node:fs"), 1);
|
|
69258
|
-
|
|
69259
|
-
// src/frontdoor/ensure.ts
|
|
69260
|
-
var import_node_crypto13 = require("node:crypto");
|
|
69261
|
-
var FRONTDOOR_START_TIMEOUT_MS = 3e4;
|
|
69262
|
-
var FRONTDOOR_LAUNCHER_POLL_MS = 100;
|
|
69263
|
-
var FrontDoorStartError = class extends CliError {
|
|
69264
|
-
constructor(message) {
|
|
69265
|
-
super(message);
|
|
69266
|
-
this.name = "FrontDoorStartError";
|
|
69267
|
-
}
|
|
69268
|
-
};
|
|
69269
|
-
function ensureFrontDoor(params) {
|
|
69270
|
-
const { paths, ports } = params;
|
|
69271
|
-
const deadline = ports.now() + FRONTDOOR_START_TIMEOUT_MS;
|
|
69272
|
-
let spawned = false;
|
|
69273
|
-
let replaced = false;
|
|
69274
|
-
const distrusted = /* @__PURE__ */ new Set();
|
|
69275
|
-
let lastRejection;
|
|
69276
|
-
for (; ; ) {
|
|
69277
|
-
const state = readFrontDoorState(ports.fs, paths.frontdoorStateFile);
|
|
69278
|
-
const supervisorPid = state?.supervisorPid;
|
|
69279
|
-
if (supervisorPid !== void 0 && !distrusted.has(supervisorPid) && ports.isRunning(supervisorPid)) {
|
|
69280
|
-
if (state?.port !== void 0 && state.connectPort !== void 0) {
|
|
69281
|
-
const verdict = ports.verifyListener(state.port);
|
|
69282
|
-
if (verdict.ok && (state.protocol ?? 0) < FRONT_DOOR_PROTOCOL && !replaced) {
|
|
69283
|
-
ports.stopSupervisor(supervisorPid);
|
|
69284
|
-
while (ports.isRunning(supervisorPid)) {
|
|
69285
|
-
if (ports.now() >= deadline) {
|
|
69286
|
-
throw new FrontDoorStartError(`agent-shim: the front door (pid ${String(supervisorPid)}, protocol ${String(state.protocol ?? 0)}) is older than this launcher (protocol ${String(FRONT_DOOR_PROTOCOL)}) and did not exit when asked. Daemon log: ${paths.frontdoorLogPath}`);
|
|
69287
|
-
}
|
|
69288
|
-
ports.sleep(FRONTDOOR_LAUNCHER_POLL_MS);
|
|
69289
|
-
}
|
|
69290
|
-
replaced = true;
|
|
69291
|
-
continue;
|
|
69292
|
-
}
|
|
69293
|
-
if (verdict.ok) {
|
|
69294
|
-
const token = (0, import_node_crypto13.randomUUID)();
|
|
69295
|
-
writeFrontDoorSession(ports.fs, paths.frontdoorSessionsDir, { pid: params.launcherPid, startedAt: ports.now(), token });
|
|
69296
|
-
return { port: state.port, connectPort: state.connectPort, token };
|
|
69297
|
-
}
|
|
69298
|
-
lastRejection = `the listener on 127.0.0.1:${String(state.port)} (recorded for pid ${String(supervisorPid)}) failed authentication: ${verdict.reason}`;
|
|
69299
|
-
if (spawned) {
|
|
69300
|
-
throw new FrontDoorStartError(`agent-shim: ${lastRejection}; refusing to send this session's credentials to it. Daemon log: ${paths.frontdoorLogPath}`);
|
|
69301
|
-
}
|
|
69302
|
-
distrusted.add(supervisorPid);
|
|
69303
|
-
continue;
|
|
69304
|
-
}
|
|
69305
|
-
if (state?.lastError !== void 0) {
|
|
69306
|
-
throw new FrontDoorStartError(`agent-shim: the front door reported a fatal error and is not serving: ${state.lastError} (daemon log: ${paths.frontdoorLogPath})`);
|
|
69307
|
-
}
|
|
69308
|
-
} else if (!spawned) {
|
|
69309
|
-
ports.fs.mkdirp(paths.frontdoorDir);
|
|
69310
|
-
const created = ports.fs.writeFileExclusive(paths.frontdoorLockFile, `${JSON.stringify({ pid: params.launcherPid, at: ports.now() })}
|
|
69311
|
-
`);
|
|
69312
|
-
if (created) {
|
|
69313
|
-
ports.spawnSupervisor(paths);
|
|
69314
|
-
spawned = true;
|
|
69315
|
-
} else {
|
|
69316
|
-
const lock = readStartLock(ports.fs, paths.frontdoorLockFile);
|
|
69317
|
-
if (lock === void 0 || !ports.isRunning(lock.pid)) {
|
|
69318
|
-
ports.fs.removeRecursive(paths.frontdoorLockFile);
|
|
69319
|
-
continue;
|
|
69320
|
-
}
|
|
69321
|
-
}
|
|
69322
|
-
}
|
|
69323
|
-
if (ports.now() >= deadline) {
|
|
69324
|
-
const lastError = state?.lastError;
|
|
69325
|
-
throw new FrontDoorStartError(
|
|
69326
|
-
`agent-shim: the front door did not become ready within ${String(FRONTDOOR_START_TIMEOUT_MS)}ms` + (lastError === void 0 ? "" : ` (last error: ${lastError})`) + (lastRejection === void 0 ? "" : ` (${lastRejection})`) + `. Daemon log: ${paths.frontdoorLogPath}`
|
|
69327
|
-
);
|
|
69328
|
-
}
|
|
69329
|
-
ports.sleep(FRONTDOOR_LAUNCHER_POLL_MS);
|
|
69330
|
-
}
|
|
69331
|
-
}
|
|
69332
|
-
|
|
69333
|
-
// src/frontdoor/probe.ts
|
|
69334
|
-
var import_node_worker_threads = require("node:worker_threads");
|
|
69335
|
-
var PROBE_TIMEOUT_MS = 2e3;
|
|
69336
|
-
var PROBE_WAIT_MARGIN_MS = 1e3;
|
|
69337
|
-
var REASON_BYTES = 1024;
|
|
69338
|
-
var HEADER_SLOTS = 2;
|
|
69339
|
-
var INT32_BYTES = 4;
|
|
69340
|
-
var VERDICT_PENDING = 0;
|
|
69341
|
-
var VERDICT_OK = 1;
|
|
69342
|
-
var VERDICT_FAILED = 2;
|
|
69343
|
-
var PROBE_SOURCE = `
|
|
69344
|
-
const { workerData } = require("node:worker_threads");
|
|
69345
|
-
const https = require("node:https");
|
|
69346
|
-
const { port, ca, timeoutMs, shared, ok, failed, headerSlots } = workerData;
|
|
69347
|
-
const header = new Int32Array(shared, 0, headerSlots);
|
|
69348
|
-
const reason = new Uint8Array(shared, headerSlots * 4);
|
|
69349
|
-
let done = false;
|
|
69350
|
-
const finish = (verdict, message) => {
|
|
69351
|
-
if (done) return;
|
|
69352
|
-
done = true;
|
|
69353
|
-
const bytes = Buffer.from(String(message), "utf8").subarray(0, reason.length);
|
|
69354
|
-
reason.set(bytes);
|
|
69355
|
-
Atomics.store(header, 1, bytes.length);
|
|
69356
|
-
Atomics.store(header, 0, verdict);
|
|
69357
|
-
Atomics.notify(header, 0);
|
|
69358
|
-
};
|
|
69359
|
-
const request = https.get({ host: "127.0.0.1", port, path: "/healthz", ca: [ca], agent: false }, (response) => {
|
|
69360
|
-
let body = "";
|
|
69361
|
-
response.setEncoding("utf8");
|
|
69362
|
-
response.on("data", (chunk) => { body += chunk; });
|
|
69363
|
-
response.on("end", () => {
|
|
69364
|
-
if (response.statusCode === 200 && body === "ok") finish(ok, "");
|
|
69365
|
-
else finish(failed, "the listener answered its health probe with HTTP " + String(response.statusCode));
|
|
69366
|
-
});
|
|
69367
|
-
response.on("error", (error) => finish(failed, error.message));
|
|
69368
|
-
});
|
|
69369
|
-
// A hard deadline over the whole exchange, handshake included: a listener that accepts the connection and then says nothing must still fail the probe.
|
|
69370
|
-
setTimeout(() => { request.destroy(new Error("no answer within " + String(timeoutMs) + "ms")); }, timeoutMs);
|
|
69371
|
-
request.on("error", (error) => finish(failed, (error.code ? error.code + ": " : "") + error.message));
|
|
69372
|
-
`;
|
|
69373
|
-
function probeFrontDoorSync(port, caPem) {
|
|
69374
|
-
const shared = new SharedArrayBuffer(HEADER_SLOTS * INT32_BYTES + REASON_BYTES);
|
|
69375
|
-
const header = new Int32Array(shared, 0, HEADER_SLOTS);
|
|
69376
|
-
const worker = new import_node_worker_threads.Worker(PROBE_SOURCE, {
|
|
69377
|
-
eval: true,
|
|
69378
|
-
workerData: { port, ca: caPem, timeoutMs: PROBE_TIMEOUT_MS, shared, ok: VERDICT_OK, failed: VERDICT_FAILED, headerSlots: HEADER_SLOTS }
|
|
69379
|
-
});
|
|
69380
|
-
worker.unref();
|
|
69381
|
-
try {
|
|
69382
|
-
const waited = Atomics.wait(header, 0, VERDICT_PENDING, PROBE_TIMEOUT_MS + PROBE_WAIT_MARGIN_MS);
|
|
69383
|
-
const verdict = Atomics.load(header, 0);
|
|
69384
|
-
if (waited === "timed-out" || verdict === VERDICT_PENDING) {
|
|
69385
|
-
return { ok: false, reason: `the probe did not finish within ${String(PROBE_TIMEOUT_MS + PROBE_WAIT_MARGIN_MS)}ms` };
|
|
69386
|
-
}
|
|
69387
|
-
if (verdict === VERDICT_OK) {
|
|
69388
|
-
return { ok: true };
|
|
69389
|
-
}
|
|
69390
|
-
const length = Atomics.load(header, 1);
|
|
69391
|
-
return { ok: false, reason: Buffer.from(new Uint8Array(shared, HEADER_SLOTS * INT32_BYTES, length)).toString("utf8") };
|
|
69392
|
-
} finally {
|
|
69393
|
-
void worker.terminate();
|
|
69394
|
-
}
|
|
69395
|
-
}
|
|
69396
|
-
|
|
69397
|
-
// src/frontdoor/trust.ts
|
|
69398
|
-
var import_node_crypto14 = require("node:crypto");
|
|
69399
|
-
var import_node_path36 = __toESM(require("node:path"), 1);
|
|
69400
|
-
var BUNDLE_NAME_HEX_DIGITS = 16;
|
|
69401
|
-
function resolveTrustBundle(params) {
|
|
69402
|
-
const { caCertFile, bundlesDir, inherited, fs: fs19 } = params;
|
|
69403
|
-
if (inherited === void 0 || inherited === "" || import_node_path36.default.resolve(inherited) === import_node_path36.default.resolve(caCertFile)) {
|
|
69404
|
-
return { path: caCertFile };
|
|
69405
|
-
}
|
|
69406
|
-
const caPem = fs19.readFileUtf8(caCertFile);
|
|
69407
|
-
let inheritedPem;
|
|
69408
|
-
try {
|
|
69409
|
-
inheritedPem = fs19.readFileUtf8(inherited);
|
|
69410
|
-
} catch (error62) {
|
|
69411
|
-
return {
|
|
69412
|
-
path: caCertFile,
|
|
69413
|
-
warning: `agent-shim: NODE_EXTRA_CA_CERTS names ${inherited}, which could not be read (${error62 instanceof Error ? error62.message : String(error62)}); the child trusts agent-shim's front-door CA on top of the system store, and nothing from that file`
|
|
69414
|
-
};
|
|
69415
|
-
}
|
|
69416
|
-
if (inheritedPem.includes(caPem.trim())) {
|
|
69417
|
-
return { path: inherited };
|
|
69418
|
-
}
|
|
69419
|
-
const combined = `${inheritedPem.trimEnd()}
|
|
69420
|
-
${caPem}`;
|
|
69421
|
-
const bundle = import_node_path36.default.join(bundlesDir, `${(0, import_node_crypto14.createHash)("sha256").update(combined).digest("hex").slice(0, BUNDLE_NAME_HEX_DIGITS)}.pem`);
|
|
69422
|
-
if (!fs19.exists(bundle)) {
|
|
69423
|
-
fs19.mkdirp(bundlesDir);
|
|
69424
|
-
fs19.writeFileAtomic(bundle, combined);
|
|
69425
|
-
}
|
|
69426
|
-
return { path: bundle };
|
|
69427
|
-
}
|
|
69428
|
-
|
|
69429
|
-
// src/frontdoor/realFrontDoorPort.ts
|
|
69430
|
-
var realTrustBundleFs = {
|
|
69431
|
-
readFileUtf8: (file2) => import_node_fs16.default.readFileSync(file2, "utf8"),
|
|
69432
|
-
exists: (file2) => import_node_fs16.default.existsSync(file2),
|
|
69433
|
-
mkdirp: (dir) => {
|
|
69434
|
-
import_node_fs16.default.mkdirSync(dir, { recursive: true });
|
|
69435
|
-
},
|
|
69436
|
-
writeFileAtomic: (file2, contents) => {
|
|
69437
|
-
realFarmFs.writeFilePrivate(file2, contents);
|
|
69438
|
-
}
|
|
69439
|
-
};
|
|
69440
|
-
function realFrontDoorPort(paths, spawnDaemon) {
|
|
69441
|
-
return {
|
|
69442
|
-
ensure: (inheritedExtraCaCerts) => {
|
|
69443
|
-
const up = ensureFrontDoor({
|
|
69444
|
-
paths,
|
|
69445
|
-
launcherPid: process.pid,
|
|
69446
|
-
ports: {
|
|
69447
|
-
fs: realFarmFs,
|
|
69448
|
-
isRunning: realIsProcessRunning,
|
|
69449
|
-
now: () => Date.now(),
|
|
69450
|
-
sleep: realSleepSync,
|
|
69451
|
-
spawnSupervisor: (layout) => spawnDaemon(layout, "__frontdoor-supervisor", layout.frontdoorLogPath),
|
|
69452
|
-
stopSupervisor: (pid) => {
|
|
69453
|
-
process.kill(pid, "SIGTERM");
|
|
69454
|
-
},
|
|
69455
|
-
// Read fresh for each probe: a replacement supervisor may have regenerated an unparseable CA, and the probe must trust exactly what the serving door's leaf chains to.
|
|
69456
|
-
verifyListener: (port) => probeFrontDoorSync(port, import_node_fs16.default.readFileSync(paths.frontdoorCaCertFile, "utf8"))
|
|
69457
|
-
}
|
|
69458
|
-
});
|
|
69459
|
-
const trust = resolveTrustBundle({ caCertFile: paths.frontdoorCaCertFile, bundlesDir: paths.frontdoorCaBundlesDir, inherited: inheritedExtraCaCerts, fs: realTrustBundleFs });
|
|
69460
|
-
return {
|
|
69461
|
-
port: up.port,
|
|
69462
|
-
connectPort: up.connectPort,
|
|
69463
|
-
trustBundlePath: trust.path,
|
|
69464
|
-
...trust.warning === void 0 ? {} : { trustWarning: trust.warning },
|
|
69465
|
-
sessionToken: up.token
|
|
69466
|
-
};
|
|
69467
|
-
},
|
|
69468
|
-
release: () => {
|
|
69469
|
-
removeFrontDoorSession(realFarmFs, paths.frontdoorSessionsDir, process.pid);
|
|
69470
|
-
}
|
|
69471
|
-
};
|
|
69472
|
-
}
|
|
69473
|
-
|
|
69474
69485
|
// src/launcher.ts
|
|
69475
69486
|
var import_node_crypto15 = require("node:crypto");
|
|
69476
69487
|
var import_node_path38 = __toESM(require("node:path"), 1);
|
package/dist/index.cjs
CHANGED
|
@@ -8142,7 +8142,7 @@ var import_node_crypto10 = require("node:crypto");
|
|
|
8142
8142
|
var import_node_path28 = __toESM(require("node:path"), 1);
|
|
8143
8143
|
var BUNDLE_NAME_HEX_DIGITS = 16;
|
|
8144
8144
|
function resolveTrustBundle(params) {
|
|
8145
|
-
const { caCertFile, bundlesDir, inherited, fs: fs12 } = params;
|
|
8145
|
+
const { caCertFile, bundlesDir, variable, inherited, fs: fs12 } = params;
|
|
8146
8146
|
if (inherited === void 0 || inherited === "" || import_node_path28.default.resolve(inherited) === import_node_path28.default.resolve(caCertFile)) {
|
|
8147
8147
|
return { path: caCertFile };
|
|
8148
8148
|
}
|
|
@@ -8153,7 +8153,7 @@ function resolveTrustBundle(params) {
|
|
|
8153
8153
|
} catch (error) {
|
|
8154
8154
|
return {
|
|
8155
8155
|
path: caCertFile,
|
|
8156
|
-
warning: `agent-shim:
|
|
8156
|
+
warning: `agent-shim: ${variable} names ${inherited}, which could not be read (${error instanceof Error ? error.message : String(error)}); the child trusts agent-shim's front-door CA on top of the system store, and nothing from that file`
|
|
8157
8157
|
};
|
|
8158
8158
|
}
|
|
8159
8159
|
if (inheritedPem.includes(caPem.trim())) {
|
|
@@ -8199,7 +8199,7 @@ function realFrontDoorPort(paths, spawnDaemon) {
|
|
|
8199
8199
|
verifyListener: (port) => probeFrontDoorSync(port, import_node_fs10.default.readFileSync(paths.frontdoorCaCertFile, "utf8"))
|
|
8200
8200
|
}
|
|
8201
8201
|
});
|
|
8202
|
-
const trust = resolveTrustBundle({ caCertFile: paths.frontdoorCaCertFile, bundlesDir: paths.frontdoorCaBundlesDir, inherited: inheritedExtraCaCerts, fs: realTrustBundleFs });
|
|
8202
|
+
const trust = resolveTrustBundle({ caCertFile: paths.frontdoorCaCertFile, bundlesDir: paths.frontdoorCaBundlesDir, variable: "NODE_EXTRA_CA_CERTS", inherited: inheritedExtraCaCerts, fs: realTrustBundleFs });
|
|
8203
8203
|
return {
|
|
8204
8204
|
port: up.port,
|
|
8205
8205
|
connectPort: up.connectPort,
|
package/dist/index.mjs
CHANGED
|
@@ -7976,7 +7976,7 @@ import { createHash as createHash5 } from "node:crypto";
|
|
|
7976
7976
|
import path28 from "node:path";
|
|
7977
7977
|
var BUNDLE_NAME_HEX_DIGITS = 16;
|
|
7978
7978
|
function resolveTrustBundle(params) {
|
|
7979
|
-
const { caCertFile, bundlesDir, inherited, fs: fs12 } = params;
|
|
7979
|
+
const { caCertFile, bundlesDir, variable, inherited, fs: fs12 } = params;
|
|
7980
7980
|
if (inherited === void 0 || inherited === "" || path28.resolve(inherited) === path28.resolve(caCertFile)) {
|
|
7981
7981
|
return { path: caCertFile };
|
|
7982
7982
|
}
|
|
@@ -7987,7 +7987,7 @@ function resolveTrustBundle(params) {
|
|
|
7987
7987
|
} catch (error) {
|
|
7988
7988
|
return {
|
|
7989
7989
|
path: caCertFile,
|
|
7990
|
-
warning: `agent-shim:
|
|
7990
|
+
warning: `agent-shim: ${variable} names ${inherited}, which could not be read (${error instanceof Error ? error.message : String(error)}); the child trusts agent-shim's front-door CA on top of the system store, and nothing from that file`
|
|
7991
7991
|
};
|
|
7992
7992
|
}
|
|
7993
7993
|
if (inheritedPem.includes(caPem.trim())) {
|
|
@@ -8033,7 +8033,7 @@ function realFrontDoorPort(paths, spawnDaemon) {
|
|
|
8033
8033
|
verifyListener: (port) => probeFrontDoorSync(port, fs11.readFileSync(paths.frontdoorCaCertFile, "utf8"))
|
|
8034
8034
|
}
|
|
8035
8035
|
});
|
|
8036
|
-
const trust = resolveTrustBundle({ caCertFile: paths.frontdoorCaCertFile, bundlesDir: paths.frontdoorCaBundlesDir, inherited: inheritedExtraCaCerts, fs: realTrustBundleFs });
|
|
8036
|
+
const trust = resolveTrustBundle({ caCertFile: paths.frontdoorCaCertFile, bundlesDir: paths.frontdoorCaBundlesDir, variable: "NODE_EXTRA_CA_CERTS", inherited: inheritedExtraCaCerts, fs: realTrustBundleFs });
|
|
8037
8037
|
return {
|
|
8038
8038
|
port: up.port,
|
|
8039
8039
|
connectPort: up.connectPort,
|
package/dist/types/index.d.ts
CHANGED
|
@@ -686,7 +686,7 @@ interface LayoutPaths {
|
|
|
686
686
|
readonly frontdoorCaCertFile: string;
|
|
687
687
|
/** Path to the front door's CA private key, mode 0600: whoever can read it can impersonate the door to every routed child. */
|
|
688
688
|
readonly frontdoorCaKeyFile: string;
|
|
689
|
-
/** Directory of combined CA bundles: a parent environment's own NODE_EXTRA_CA_CERTS file plus the front door's CA, one file per distinct combination, for
|
|
689
|
+
/** Directory of combined CA bundles: a parent environment's own NODE_EXTRA_CA_CERTS (for a routed child) or HEADROOM_CA_BUNDLE (for the headroom daemon) file plus the front door's CA, one file per distinct combination, for processes that must keep trusting both. */
|
|
690
690
|
readonly frontdoorCaBundlesDir: string;
|
|
691
691
|
/** Path to the front door's state.json: its supervisor pid, its port, and the sticky port it last served on. */
|
|
692
692
|
readonly frontdoorStateFile: string;
|
|
@@ -1470,7 +1470,7 @@ declare function mintLeaf(ca: CaMaterial, names: readonly string[], now: Readonl
|
|
|
1470
1470
|
/** Mints each host's leaf once from the CA and reuses it, because generating a 2048-bit RSA keypair costs noticeable time and nothing about the certificate changes between sessions. */
|
|
1471
1471
|
declare function createLeafCache(ca: CaMaterial, now: () => Date): (host: string) => LeafCert;
|
|
1472
1472
|
/**
|
|
1473
|
-
* Persistence for the CA: generated once on the machine's first
|
|
1473
|
+
* Persistence for the CA: generated once on the machine's first front-door start and reused forever after, because regenerating it would invalidate every child's `NODE_EXTRA_CA_CERTS` pointing at the old file. The real implementation writes the key with mode 0600; injected fakes keep it in memory.
|
|
1474
1474
|
*/
|
|
1475
1475
|
interface ConnectCertStore {
|
|
1476
1476
|
/** The persisted CA, or undefined when none exists yet (or only half of it does: a cert without its key can sign nothing, so it counts as absent). */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agent-shim",
|
|
3
|
-
"version": "8.0.
|
|
3
|
+
"version": "8.0.1",
|
|
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>",
|