switchroom 0.13.24 → 0.13.26
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/agent-scheduler/index.js +2 -4
- package/dist/auth-broker/index.js +31 -9
- package/dist/cli/switchroom.js +494 -349
- package/dist/host-control/main.js +2 -4
- package/dist/vault/approvals/kernel-server.js +68 -65
- package/dist/vault/broker/server.js +41 -12
- package/package.json +1 -1
- package/profiles/_shared/telegram-style.md.hbs +4 -4
- package/telegram-plugin/dist/gateway/gateway.js +34 -29
- package/telegram-plugin/tests/telegram-format.test.ts +2 -2
- package/telegram-plugin/uat/scenarios/jtbd-rapid-followup-dm.test.ts +1 -1
package/dist/cli/switchroom.js
CHANGED
|
@@ -13598,7 +13598,6 @@ var init_schema = __esm(() => {
|
|
|
13598
13598
|
SessionContinuitySchema = exports_external.object({
|
|
13599
13599
|
enabled: exports_external.boolean().optional().describe("Master switch for the session-handoff briefing (default true)."),
|
|
13600
13600
|
show_handoff_line: exports_external.boolean().optional().describe("Whether the telegram plugin prepends a visible '\u21a9\ufe0f Picked up\u2026' " + "line to the first assistant reply after a restart (default true)."),
|
|
13601
|
-
summarizer_model: exports_external.string().regex(/^[a-zA-Z0-9][a-zA-Z0-9._\-/\[\]:]*$/, "Model name must be alphanumeric with ._-/[]: only").optional().describe("Anthropic model used to produce the handoff briefing."),
|
|
13602
13601
|
max_turns_in_briefing: exports_external.number().int().positive().optional().describe("Cap on recent user/assistant turn pairs fed to the summarizer."),
|
|
13603
13602
|
resume_mode: exports_external.enum(["auto", "continue", "handoff", "none"]).optional().describe("How to resume the next session. 'handoff' (default as of #362) " + "never passes --continue; a fresh Claude starts each restart and " + "reads a briefing assembled from recent Telegram messages, Hindsight " + "recall, and today's daily memory file. 'auto' uses --continue when " + "the latest JSONL is smaller than resume_max_bytes, else falls back " + "to the handoff briefing. 'continue' always passes --continue. " + "'none' starts completely fresh every time."),
|
|
13604
13603
|
resume_max_bytes: exports_external.number().int().positive().optional().describe("Byte threshold above which 'auto' mode falls back to handoff " + "instead of --continue. Default 2_000_000 (~2MB). Large transcripts " + "can blow out the context window even with prefix caching, and " + "--continue replay is known-fragile at scale.")
|
|
@@ -13645,10 +13644,9 @@ var init_schema = __esm(() => {
|
|
|
13645
13644
|
start: exports_external.number().int().min(0).max(23),
|
|
13646
13645
|
end: exports_external.number().int().min(0).max(23),
|
|
13647
13646
|
tz: exports_external.string().optional()
|
|
13648
|
-
}).optional()
|
|
13649
|
-
model: exports_external.string().optional()
|
|
13647
|
+
}).optional()
|
|
13650
13648
|
})).optional()
|
|
13651
|
-
}).optional().describe("Auto-dispatch rules: when a verified webhook event matches a rule, " + "
|
|
13649
|
+
}).optional().describe("Auto-dispatch rules: when a verified webhook event matches a rule, " + "inject the rendered prompt into the agent's live session (#1625). " + "Supports cooldowns, quiet hours, and label/action matchers. " + "Off by default \u2014 opt in per agent. See src/web/webhook-dispatch.ts."),
|
|
13652
13650
|
webhook_rate_limit: exports_external.object({
|
|
13653
13651
|
rpm: exports_external.number().int().positive()
|
|
13654
13652
|
}).optional().describe("Per-source rate limit for the webhook ingest path (#714). " + "Off by default \u2014 when this key is absent the handler skips " + "rate-limit checks entirely. Opt in by setting `rpm` to an " + "integer requests-per-minute (token bucket per (agent, source); " + "burst equal to rpm). When enabled, exceeding the limit returns " + "429 with Retry-After header; first throttle event per " + "(agent, source) per 60s window is written to " + "<agent>/telegram/issues.jsonl. " + "Cascades from defaults.channels.telegram.webhook_rate_limit.")
|
|
@@ -21049,6 +21047,7 @@ __export(exports_vault, {
|
|
|
21049
21047
|
setStringSecret: () => setStringSecret,
|
|
21050
21048
|
setSecret: () => setSecret,
|
|
21051
21049
|
setFilesSecret: () => setFilesSecret,
|
|
21050
|
+
setBinarySecret: () => setBinarySecret,
|
|
21052
21051
|
saveVault: () => saveVault,
|
|
21053
21052
|
removeSecret: () => removeSecret,
|
|
21054
21053
|
openVault: () => openVault,
|
|
@@ -21312,6 +21311,13 @@ function setStringSecret(passphrase, vaultPath, key, value, format, scope) {
|
|
|
21312
21311
|
}
|
|
21313
21312
|
setSecret(passphrase, vaultPath, key, entry);
|
|
21314
21313
|
}
|
|
21314
|
+
function setBinarySecret(passphrase, vaultPath, key, value, format, scope) {
|
|
21315
|
+
const entry = format ? { kind: "binary", value, format } : { kind: "binary", value };
|
|
21316
|
+
if (scope !== undefined) {
|
|
21317
|
+
entry.scope = scope;
|
|
21318
|
+
}
|
|
21319
|
+
setSecret(passphrase, vaultPath, key, entry);
|
|
21320
|
+
}
|
|
21315
21321
|
function getStringSecret(passphrase, vaultPath, key) {
|
|
21316
21322
|
const entry = getSecret(passphrase, vaultPath, key);
|
|
21317
21323
|
if (entry === null)
|
|
@@ -21369,6 +21375,315 @@ var init_vault = __esm(() => {
|
|
|
21369
21375
|
];
|
|
21370
21376
|
});
|
|
21371
21377
|
|
|
21378
|
+
// src/vault/broker/peercred-ffi.ts
|
|
21379
|
+
function getPeerCred(fd) {
|
|
21380
|
+
if (process.platform !== "linux")
|
|
21381
|
+
return null;
|
|
21382
|
+
try {
|
|
21383
|
+
const ffi = __require("bun:ffi");
|
|
21384
|
+
const { dlopen, FFIType, ptr } = ffi;
|
|
21385
|
+
const SOL_SOCKET = 1;
|
|
21386
|
+
const SO_PEERCRED = 17;
|
|
21387
|
+
const UCRED_SIZE = 12;
|
|
21388
|
+
const cache = getPeerCred;
|
|
21389
|
+
const lib = cache._lib ?? (() => {
|
|
21390
|
+
const candidates = ["libc.so.6", "libc.so"];
|
|
21391
|
+
const symbolSpec = {
|
|
21392
|
+
getsockopt: {
|
|
21393
|
+
args: [FFIType.i32, FFIType.i32, FFIType.i32, FFIType.ptr, FFIType.ptr],
|
|
21394
|
+
returns: FFIType.i32
|
|
21395
|
+
}
|
|
21396
|
+
};
|
|
21397
|
+
const errors2 = [];
|
|
21398
|
+
for (const name of candidates) {
|
|
21399
|
+
try {
|
|
21400
|
+
const opened = dlopen(name, symbolSpec);
|
|
21401
|
+
cache._lib = opened;
|
|
21402
|
+
return opened;
|
|
21403
|
+
} catch (e) {
|
|
21404
|
+
errors2.push(`${name}: ${e instanceof Error ? e.message : String(e)}`);
|
|
21405
|
+
}
|
|
21406
|
+
}
|
|
21407
|
+
process.stderr.write(`[vault-broker] peercred-ffi: dlopen failed for all libc candidates ` + `(${errors2.join("; ")}); falling back to ss-parsing.
|
|
21408
|
+
`);
|
|
21409
|
+
throw new Error("no libc candidate could be opened");
|
|
21410
|
+
})();
|
|
21411
|
+
const credBuf = new ArrayBuffer(UCRED_SIZE);
|
|
21412
|
+
const lenBuf = new Uint32Array(1);
|
|
21413
|
+
lenBuf[0] = UCRED_SIZE;
|
|
21414
|
+
const rc = lib.symbols.getsockopt(fd, SOL_SOCKET, SO_PEERCRED, ptr(credBuf), ptr(lenBuf.buffer));
|
|
21415
|
+
if (rc !== 0)
|
|
21416
|
+
return null;
|
|
21417
|
+
if (lenBuf[0] !== UCRED_SIZE)
|
|
21418
|
+
return null;
|
|
21419
|
+
const view = new DataView(credBuf);
|
|
21420
|
+
return {
|
|
21421
|
+
pid: view.getInt32(0, true),
|
|
21422
|
+
uid: view.getInt32(4, true),
|
|
21423
|
+
gid: view.getInt32(8, true)
|
|
21424
|
+
};
|
|
21425
|
+
} catch {
|
|
21426
|
+
return null;
|
|
21427
|
+
}
|
|
21428
|
+
}
|
|
21429
|
+
|
|
21430
|
+
// src/vault/broker/peercred.ts
|
|
21431
|
+
import { execFileSync } from "node:child_process";
|
|
21432
|
+
import { readFileSync as readFileSync8, readlinkSync as readlinkSync3, fstatSync } from "node:fs";
|
|
21433
|
+
function socketPathToIdentity(socketPath) {
|
|
21434
|
+
if (typeof socketPath !== "string" || socketPath.length === 0)
|
|
21435
|
+
return null;
|
|
21436
|
+
const m = socketPath.match(SOCKET_PATH_AGENT_RE) ?? socketPath.match(SOCKET_PATH_AGENT_SUBDIR_RE);
|
|
21437
|
+
if (!m)
|
|
21438
|
+
return null;
|
|
21439
|
+
const name = m[1];
|
|
21440
|
+
if (name === "operator")
|
|
21441
|
+
return { kind: "operator" };
|
|
21442
|
+
if (RESERVED_AGENT_NAMES.has(name))
|
|
21443
|
+
return null;
|
|
21444
|
+
return { kind: "agent", name };
|
|
21445
|
+
}
|
|
21446
|
+
function socketPathToAgent(socketPath) {
|
|
21447
|
+
const identity = socketPathToIdentity(socketPath);
|
|
21448
|
+
return identity?.kind === "agent" ? identity.name : null;
|
|
21449
|
+
}
|
|
21450
|
+
function isReservedAgentName(name) {
|
|
21451
|
+
return RESERVED_AGENT_NAMES.has(name);
|
|
21452
|
+
}
|
|
21453
|
+
function unlockSocketFor(dataSocketPath) {
|
|
21454
|
+
if (dataSocketPath.endsWith("/sock")) {
|
|
21455
|
+
return dataSocketPath.slice(0, -"/sock".length) + "/unlock";
|
|
21456
|
+
}
|
|
21457
|
+
return dataSocketPath.replace(/\.sock$/, ".unlock.sock");
|
|
21458
|
+
}
|
|
21459
|
+
function parseSsRows(output) {
|
|
21460
|
+
const rows = [];
|
|
21461
|
+
const lines = output.split(`
|
|
21462
|
+
`);
|
|
21463
|
+
for (const line of lines) {
|
|
21464
|
+
if (!line.trim() || line.startsWith("Netid"))
|
|
21465
|
+
continue;
|
|
21466
|
+
const tokens = line.split(/\s+/).filter((t) => t.length > 0);
|
|
21467
|
+
if (tokens.length < 8)
|
|
21468
|
+
continue;
|
|
21469
|
+
const localAddr = tokens[4];
|
|
21470
|
+
const localInode = tokens[5];
|
|
21471
|
+
const peerAddr = tokens[6];
|
|
21472
|
+
const peerInode = tokens[7];
|
|
21473
|
+
const usersToken = tokens.slice(8).join(" ");
|
|
21474
|
+
const m = usersToken.match(/users:\(\(".*?",pid=(\d+),fd=\d+\)\)/);
|
|
21475
|
+
const pid = m ? parseInt(m[1], 10) : null;
|
|
21476
|
+
rows.push({ localAddr, localInode, peerAddr, peerInode, pid });
|
|
21477
|
+
}
|
|
21478
|
+
return rows;
|
|
21479
|
+
}
|
|
21480
|
+
function findClientPids(rows, socketPath) {
|
|
21481
|
+
const pids = [];
|
|
21482
|
+
for (const serverRow of rows) {
|
|
21483
|
+
if (serverRow.localAddr !== socketPath)
|
|
21484
|
+
continue;
|
|
21485
|
+
for (const clientRow of rows) {
|
|
21486
|
+
if (clientRow.localAddr !== "*")
|
|
21487
|
+
continue;
|
|
21488
|
+
if (clientRow.localInode !== serverRow.peerInode)
|
|
21489
|
+
continue;
|
|
21490
|
+
if (clientRow.pid === null)
|
|
21491
|
+
continue;
|
|
21492
|
+
pids.push(clientRow.pid);
|
|
21493
|
+
break;
|
|
21494
|
+
}
|
|
21495
|
+
}
|
|
21496
|
+
return pids;
|
|
21497
|
+
}
|
|
21498
|
+
function findClientPidByServerInode(rows, socketPath, serverInode) {
|
|
21499
|
+
const serverInodeStr = String(serverInode);
|
|
21500
|
+
for (const serverRow of rows) {
|
|
21501
|
+
if (serverRow.localAddr !== socketPath)
|
|
21502
|
+
continue;
|
|
21503
|
+
if (serverRow.localInode !== serverInodeStr)
|
|
21504
|
+
continue;
|
|
21505
|
+
for (const clientRow of rows) {
|
|
21506
|
+
if (clientRow.localAddr !== "*")
|
|
21507
|
+
continue;
|
|
21508
|
+
if (clientRow.localInode !== serverRow.peerInode)
|
|
21509
|
+
continue;
|
|
21510
|
+
if (clientRow.pid === null)
|
|
21511
|
+
continue;
|
|
21512
|
+
return clientRow.pid;
|
|
21513
|
+
}
|
|
21514
|
+
return null;
|
|
21515
|
+
}
|
|
21516
|
+
return null;
|
|
21517
|
+
}
|
|
21518
|
+
function readUid(pid) {
|
|
21519
|
+
try {
|
|
21520
|
+
const status = readFileSync8(`/proc/${pid}/status`, "utf8");
|
|
21521
|
+
const m = status.match(/^Uid:\s+(\d+)/m);
|
|
21522
|
+
if (!m)
|
|
21523
|
+
return null;
|
|
21524
|
+
return parseInt(m[1], 10);
|
|
21525
|
+
} catch {
|
|
21526
|
+
return null;
|
|
21527
|
+
}
|
|
21528
|
+
}
|
|
21529
|
+
function readExe(pid) {
|
|
21530
|
+
try {
|
|
21531
|
+
return readlinkSync3(`/proc/${pid}/exe`);
|
|
21532
|
+
} catch {
|
|
21533
|
+
return null;
|
|
21534
|
+
}
|
|
21535
|
+
}
|
|
21536
|
+
function readSystemdUnit(pid) {
|
|
21537
|
+
try {
|
|
21538
|
+
const content = readFileSync8(`/proc/${pid}/cgroup`, "utf8");
|
|
21539
|
+
const lines = content.split(`
|
|
21540
|
+
`);
|
|
21541
|
+
for (const line of lines) {
|
|
21542
|
+
if (!line.trim())
|
|
21543
|
+
continue;
|
|
21544
|
+
const parts = line.split(":");
|
|
21545
|
+
if (parts.length < 3)
|
|
21546
|
+
continue;
|
|
21547
|
+
const controller = parts[1];
|
|
21548
|
+
const isV2 = parts[0] === "0" && controller === "";
|
|
21549
|
+
const isV1Systemd = controller === "name=systemd";
|
|
21550
|
+
if (!isV2 && !isV1Systemd)
|
|
21551
|
+
continue;
|
|
21552
|
+
const cgroupPath = parts.slice(2).join(":");
|
|
21553
|
+
const segments = cgroupPath.split("/");
|
|
21554
|
+
const lastSegment = segments[segments.length - 1];
|
|
21555
|
+
if (!lastSegment)
|
|
21556
|
+
continue;
|
|
21557
|
+
if (/^switchroom-[a-zA-Z0-9_-]+(-cron-\d+)?\.service$/.test(lastSegment)) {
|
|
21558
|
+
return lastSegment;
|
|
21559
|
+
}
|
|
21560
|
+
}
|
|
21561
|
+
return null;
|
|
21562
|
+
} catch {
|
|
21563
|
+
return null;
|
|
21564
|
+
}
|
|
21565
|
+
}
|
|
21566
|
+
function verifySystemdUnit(unitName, runner) {
|
|
21567
|
+
let raw;
|
|
21568
|
+
try {
|
|
21569
|
+
const out = runner("systemctl", [
|
|
21570
|
+
"--user",
|
|
21571
|
+
"show",
|
|
21572
|
+
unitName,
|
|
21573
|
+
"--property=LoadState,ActiveState"
|
|
21574
|
+
], { timeout: 500, encoding: "utf8" });
|
|
21575
|
+
raw = typeof out === "string" ? out : out.toString("utf8");
|
|
21576
|
+
} catch {
|
|
21577
|
+
return false;
|
|
21578
|
+
}
|
|
21579
|
+
const props = {};
|
|
21580
|
+
for (const line of raw.split(`
|
|
21581
|
+
`)) {
|
|
21582
|
+
const m = line.match(/^([A-Za-z]+)=(.*)$/);
|
|
21583
|
+
if (m)
|
|
21584
|
+
props[m[1]] = m[2];
|
|
21585
|
+
}
|
|
21586
|
+
if (props.LoadState !== "loaded")
|
|
21587
|
+
return false;
|
|
21588
|
+
if (props.ActiveState !== "active" && props.ActiveState !== "activating") {
|
|
21589
|
+
return false;
|
|
21590
|
+
}
|
|
21591
|
+
return true;
|
|
21592
|
+
}
|
|
21593
|
+
function readFdInode(fd) {
|
|
21594
|
+
try {
|
|
21595
|
+
const stat = fstatSync(fd);
|
|
21596
|
+
return stat.ino;
|
|
21597
|
+
} catch {
|
|
21598
|
+
return null;
|
|
21599
|
+
}
|
|
21600
|
+
}
|
|
21601
|
+
function fdFromSocket(socket) {
|
|
21602
|
+
const handle = socket._handle;
|
|
21603
|
+
if (!handle || typeof handle.fd !== "number" || handle.fd < 0)
|
|
21604
|
+
return null;
|
|
21605
|
+
return handle.fd;
|
|
21606
|
+
}
|
|
21607
|
+
function identify(socketPath, socket, execFileSyncOverride) {
|
|
21608
|
+
if (process.platform !== "linux") {
|
|
21609
|
+
return null;
|
|
21610
|
+
}
|
|
21611
|
+
const runner = execFileSyncOverride ?? execFileSync;
|
|
21612
|
+
let pid = null;
|
|
21613
|
+
if (socket !== undefined) {
|
|
21614
|
+
const fd = fdFromSocket(socket);
|
|
21615
|
+
if (fd !== null) {
|
|
21616
|
+
const cred = getPeerCred(fd);
|
|
21617
|
+
if (cred !== null)
|
|
21618
|
+
pid = cred.pid;
|
|
21619
|
+
}
|
|
21620
|
+
}
|
|
21621
|
+
if (pid === null) {
|
|
21622
|
+
let ssOutput;
|
|
21623
|
+
try {
|
|
21624
|
+
const raw = runner("ss", ["-xpn"], {
|
|
21625
|
+
timeout: 200,
|
|
21626
|
+
encoding: "utf8"
|
|
21627
|
+
});
|
|
21628
|
+
ssOutput = typeof raw === "string" ? raw : raw.toString("utf8");
|
|
21629
|
+
} catch {
|
|
21630
|
+
return null;
|
|
21631
|
+
}
|
|
21632
|
+
const rows = parseSsRows(ssOutput);
|
|
21633
|
+
let serverInode = null;
|
|
21634
|
+
if (socket !== undefined) {
|
|
21635
|
+
const fd = fdFromSocket(socket);
|
|
21636
|
+
if (fd !== null)
|
|
21637
|
+
serverInode = readFdInode(fd);
|
|
21638
|
+
}
|
|
21639
|
+
if (serverInode !== null) {
|
|
21640
|
+
pid = findClientPidByServerInode(rows, socketPath, serverInode);
|
|
21641
|
+
} else {
|
|
21642
|
+
const clientPids = findClientPids(rows, socketPath);
|
|
21643
|
+
if (clientPids.length === 0)
|
|
21644
|
+
return null;
|
|
21645
|
+
if (clientPids.length > 1) {
|
|
21646
|
+
process.stderr.write(`[vault-broker] peercred: ${clientPids.length} connected peers found for ${socketPath}; ` + `using pid=${clientPids[0]}. ` + `Multiple simultaneous connections reduce identification accuracy. ` + `(This warning means identify() was called without a socket arg \u2014 likely a stale call site.)
|
|
21647
|
+
`);
|
|
21648
|
+
}
|
|
21649
|
+
pid = clientPids[0];
|
|
21650
|
+
}
|
|
21651
|
+
}
|
|
21652
|
+
if (pid === null)
|
|
21653
|
+
return null;
|
|
21654
|
+
const uid = readUid(pid);
|
|
21655
|
+
if (uid === null) {
|
|
21656
|
+
return null;
|
|
21657
|
+
}
|
|
21658
|
+
const brokerUid = typeof process.getuid === "function" ? process.getuid() : null;
|
|
21659
|
+
if (brokerUid !== null && uid !== brokerUid) {
|
|
21660
|
+
process.stderr.write(`[vault-broker] peercred: UID mismatch \u2014 caller uid=${uid}, broker uid=${brokerUid}; denying
|
|
21661
|
+
`);
|
|
21662
|
+
return null;
|
|
21663
|
+
}
|
|
21664
|
+
const exe = readExe(pid);
|
|
21665
|
+
if (exe === null) {
|
|
21666
|
+
return null;
|
|
21667
|
+
}
|
|
21668
|
+
const cgroupClaim = readSystemdUnit(pid);
|
|
21669
|
+
let systemdUnit = null;
|
|
21670
|
+
if (cgroupClaim !== null) {
|
|
21671
|
+
if (verifySystemdUnit(cgroupClaim, runner)) {
|
|
21672
|
+
systemdUnit = cgroupClaim;
|
|
21673
|
+
} else {
|
|
21674
|
+
process.stderr.write(`[vault-broker] peercred: cgroup claims unit=${cgroupClaim} but systemd-user does not report it as loaded+running; treating caller as unidentified
|
|
21675
|
+
`);
|
|
21676
|
+
}
|
|
21677
|
+
}
|
|
21678
|
+
return { uid, pid, exe, systemdUnit };
|
|
21679
|
+
}
|
|
21680
|
+
var SOCKET_PATH_AGENT_RE, SOCKET_PATH_AGENT_SUBDIR_RE, RESERVED_AGENT_NAMES;
|
|
21681
|
+
var init_peercred = __esm(() => {
|
|
21682
|
+
SOCKET_PATH_AGENT_RE = /^\/run\/switchroom\/broker\/([a-zA-Z0-9][a-zA-Z0-9_-]*)\.sock$/;
|
|
21683
|
+
SOCKET_PATH_AGENT_SUBDIR_RE = /^\/run\/switchroom\/broker\/([a-zA-Z0-9][a-zA-Z0-9_-]*)\/sock$/;
|
|
21684
|
+
RESERVED_AGENT_NAMES = new Set(["operator", "hostd"]);
|
|
21685
|
+
});
|
|
21686
|
+
|
|
21372
21687
|
// src/vault/broker/protocol.ts
|
|
21373
21688
|
function encodeRequest(req) {
|
|
21374
21689
|
const json = JSON.stringify(req);
|
|
@@ -21420,10 +21735,14 @@ function stripWireFields(entry) {
|
|
|
21420
21735
|
files: entry.files
|
|
21421
21736
|
};
|
|
21422
21737
|
}
|
|
21423
|
-
var MAX_FRAME_BYTES, GetRequestSchema, PutRequestSchema, ListRequestSchema, MintGrantRequestSchema, ListGrantsRequestSchema, RevokeGrantRequestSchema, StatusRequestSchema, LockRequestSchema, PreflightAccessRequestSchema, OkPreflightAccessResponseSchema, ApprovalRequestRequestSchema, ApprovalLookupRequestSchema, ApprovalConsumeRequestSchema, ApprovalRevokeRequestSchema, ApprovalListRequestSchema, ApprovalDecisionModeSchema, ApprovalRecordRequestSchema, ApprovalConsumeRecordRequestSchema, RequestSchema, VaultEntrySchema, ErrorCode, OkEntryResponseSchema, OkKeysResponseSchema, BrokerStatus, OkStatusResponseSchema, OkLockResponseSchema, OkPutResponseSchema, OkMintGrantResponseSchema, GrantMetaSchema, OkListGrantsResponseSchema, OkRevokeGrantResponseSchema, OkApprovalRequestResponseSchema, ApprovalDecisionMetaSchema, OkApprovalLookupResponseSchema, OkApprovalConsumeResponseSchema, OkApprovalRevokeResponseSchema, OkApprovalListResponseSchema, OkApprovalRecordResponseSchema, OkApprovalConsumeRecordResponseSchema, ErrorResponseSchema, ResponseSchema;
|
|
21738
|
+
var MAX_FRAME_BYTES, AgentNameSchema, GetRequestSchema, PutRequestSchema, ListRequestSchema, MintGrantRequestSchema, ListGrantsRequestSchema, RevokeGrantRequestSchema, StatusRequestSchema, LockRequestSchema, PreflightAccessRequestSchema, OkPreflightAccessResponseSchema, ApprovalRequestRequestSchema, ApprovalLookupRequestSchema, ApprovalConsumeRequestSchema, ApprovalRevokeRequestSchema, ApprovalListRequestSchema, ApprovalDecisionModeSchema, ApprovalRecordRequestSchema, ApprovalConsumeRecordRequestSchema, RequestSchema, VaultEntrySchema, ErrorCode, OkEntryResponseSchema, OkKeysResponseSchema, BrokerStatus, OkStatusResponseSchema, OkLockResponseSchema, OkPutResponseSchema, OkMintGrantResponseSchema, GrantMetaSchema, OkListGrantsResponseSchema, OkRevokeGrantResponseSchema, OkApprovalRequestResponseSchema, ApprovalDecisionMetaSchema, OkApprovalLookupResponseSchema, OkApprovalConsumeResponseSchema, OkApprovalRevokeResponseSchema, OkApprovalListResponseSchema, OkApprovalRecordResponseSchema, OkApprovalConsumeRecordResponseSchema, ErrorResponseSchema, ResponseSchema;
|
|
21424
21739
|
var init_protocol = __esm(() => {
|
|
21425
21740
|
init_zod();
|
|
21741
|
+
init_peercred();
|
|
21426
21742
|
MAX_FRAME_BYTES = 64 * 1024;
|
|
21743
|
+
AgentNameSchema = exports_external.string().min(1).max(64, "agent name max 64 chars").regex(/^[a-zA-Z0-9][a-zA-Z0-9_-]*$/, "agent name must be kebab-case ASCII (alnum + _- only, first char alnum)").refine((s) => !isReservedAgentName(s), {
|
|
21744
|
+
message: "agent name is reserved"
|
|
21745
|
+
});
|
|
21427
21746
|
GetRequestSchema = exports_external.object({
|
|
21428
21747
|
v: exports_external.literal(1),
|
|
21429
21748
|
op: exports_external.literal("get"),
|
|
@@ -21451,7 +21770,7 @@ var init_protocol = __esm(() => {
|
|
|
21451
21770
|
MintGrantRequestSchema = exports_external.object({
|
|
21452
21771
|
v: exports_external.literal(1),
|
|
21453
21772
|
op: exports_external.literal("mint_grant"),
|
|
21454
|
-
agent:
|
|
21773
|
+
agent: AgentNameSchema,
|
|
21455
21774
|
keys: exports_external.array(exports_external.string().min(1)),
|
|
21456
21775
|
ttl_seconds: exports_external.number().int().positive().nullable(),
|
|
21457
21776
|
description: exports_external.string().optional(),
|
|
@@ -21462,7 +21781,7 @@ var init_protocol = __esm(() => {
|
|
|
21462
21781
|
ListGrantsRequestSchema = exports_external.object({
|
|
21463
21782
|
v: exports_external.literal(1),
|
|
21464
21783
|
op: exports_external.literal("list_grants"),
|
|
21465
|
-
agent:
|
|
21784
|
+
agent: AgentNameSchema.optional(),
|
|
21466
21785
|
passphrase: exports_external.string().optional(),
|
|
21467
21786
|
attest_via_posture: exports_external.boolean().optional()
|
|
21468
21787
|
});
|
|
@@ -21482,7 +21801,7 @@ var init_protocol = __esm(() => {
|
|
|
21482
21801
|
PreflightAccessRequestSchema = exports_external.object({
|
|
21483
21802
|
v: exports_external.literal(1),
|
|
21484
21803
|
op: exports_external.literal("preflight_access"),
|
|
21485
|
-
agent:
|
|
21804
|
+
agent: AgentNameSchema,
|
|
21486
21805
|
keys: exports_external.array(exports_external.string().min(1)).min(1).max(128)
|
|
21487
21806
|
});
|
|
21488
21807
|
OkPreflightAccessResponseSchema = exports_external.object({
|
|
@@ -21730,315 +22049,6 @@ var init_protocol = __esm(() => {
|
|
|
21730
22049
|
]);
|
|
21731
22050
|
});
|
|
21732
22051
|
|
|
21733
|
-
// src/vault/broker/peercred-ffi.ts
|
|
21734
|
-
function getPeerCred(fd) {
|
|
21735
|
-
if (process.platform !== "linux")
|
|
21736
|
-
return null;
|
|
21737
|
-
try {
|
|
21738
|
-
const ffi = __require("bun:ffi");
|
|
21739
|
-
const { dlopen, FFIType, ptr } = ffi;
|
|
21740
|
-
const SOL_SOCKET = 1;
|
|
21741
|
-
const SO_PEERCRED = 17;
|
|
21742
|
-
const UCRED_SIZE = 12;
|
|
21743
|
-
const cache = getPeerCred;
|
|
21744
|
-
const lib = cache._lib ?? (() => {
|
|
21745
|
-
const candidates = ["libc.so.6", "libc.so"];
|
|
21746
|
-
const symbolSpec = {
|
|
21747
|
-
getsockopt: {
|
|
21748
|
-
args: [FFIType.i32, FFIType.i32, FFIType.i32, FFIType.ptr, FFIType.ptr],
|
|
21749
|
-
returns: FFIType.i32
|
|
21750
|
-
}
|
|
21751
|
-
};
|
|
21752
|
-
const errors2 = [];
|
|
21753
|
-
for (const name of candidates) {
|
|
21754
|
-
try {
|
|
21755
|
-
const opened = dlopen(name, symbolSpec);
|
|
21756
|
-
cache._lib = opened;
|
|
21757
|
-
return opened;
|
|
21758
|
-
} catch (e) {
|
|
21759
|
-
errors2.push(`${name}: ${e instanceof Error ? e.message : String(e)}`);
|
|
21760
|
-
}
|
|
21761
|
-
}
|
|
21762
|
-
process.stderr.write(`[vault-broker] peercred-ffi: dlopen failed for all libc candidates ` + `(${errors2.join("; ")}); falling back to ss-parsing.
|
|
21763
|
-
`);
|
|
21764
|
-
throw new Error("no libc candidate could be opened");
|
|
21765
|
-
})();
|
|
21766
|
-
const credBuf = new ArrayBuffer(UCRED_SIZE);
|
|
21767
|
-
const lenBuf = new Uint32Array(1);
|
|
21768
|
-
lenBuf[0] = UCRED_SIZE;
|
|
21769
|
-
const rc = lib.symbols.getsockopt(fd, SOL_SOCKET, SO_PEERCRED, ptr(credBuf), ptr(lenBuf.buffer));
|
|
21770
|
-
if (rc !== 0)
|
|
21771
|
-
return null;
|
|
21772
|
-
if (lenBuf[0] !== UCRED_SIZE)
|
|
21773
|
-
return null;
|
|
21774
|
-
const view = new DataView(credBuf);
|
|
21775
|
-
return {
|
|
21776
|
-
pid: view.getInt32(0, true),
|
|
21777
|
-
uid: view.getInt32(4, true),
|
|
21778
|
-
gid: view.getInt32(8, true)
|
|
21779
|
-
};
|
|
21780
|
-
} catch {
|
|
21781
|
-
return null;
|
|
21782
|
-
}
|
|
21783
|
-
}
|
|
21784
|
-
|
|
21785
|
-
// src/vault/broker/peercred.ts
|
|
21786
|
-
import { execFileSync } from "node:child_process";
|
|
21787
|
-
import { readFileSync as readFileSync8, readlinkSync as readlinkSync3, fstatSync } from "node:fs";
|
|
21788
|
-
function socketPathToIdentity(socketPath) {
|
|
21789
|
-
if (typeof socketPath !== "string" || socketPath.length === 0)
|
|
21790
|
-
return null;
|
|
21791
|
-
const m = socketPath.match(SOCKET_PATH_AGENT_RE) ?? socketPath.match(SOCKET_PATH_AGENT_SUBDIR_RE);
|
|
21792
|
-
if (!m)
|
|
21793
|
-
return null;
|
|
21794
|
-
const name = m[1];
|
|
21795
|
-
if (name === "operator")
|
|
21796
|
-
return { kind: "operator" };
|
|
21797
|
-
if (RESERVED_AGENT_NAMES.has(name))
|
|
21798
|
-
return null;
|
|
21799
|
-
return { kind: "agent", name };
|
|
21800
|
-
}
|
|
21801
|
-
function socketPathToAgent(socketPath) {
|
|
21802
|
-
const identity = socketPathToIdentity(socketPath);
|
|
21803
|
-
return identity?.kind === "agent" ? identity.name : null;
|
|
21804
|
-
}
|
|
21805
|
-
function isReservedAgentName(name) {
|
|
21806
|
-
return RESERVED_AGENT_NAMES.has(name);
|
|
21807
|
-
}
|
|
21808
|
-
function unlockSocketFor(dataSocketPath) {
|
|
21809
|
-
if (dataSocketPath.endsWith("/sock")) {
|
|
21810
|
-
return dataSocketPath.slice(0, -"/sock".length) + "/unlock";
|
|
21811
|
-
}
|
|
21812
|
-
return dataSocketPath.replace(/\.sock$/, ".unlock.sock");
|
|
21813
|
-
}
|
|
21814
|
-
function parseSsRows(output) {
|
|
21815
|
-
const rows = [];
|
|
21816
|
-
const lines = output.split(`
|
|
21817
|
-
`);
|
|
21818
|
-
for (const line of lines) {
|
|
21819
|
-
if (!line.trim() || line.startsWith("Netid"))
|
|
21820
|
-
continue;
|
|
21821
|
-
const tokens = line.split(/\s+/).filter((t) => t.length > 0);
|
|
21822
|
-
if (tokens.length < 8)
|
|
21823
|
-
continue;
|
|
21824
|
-
const localAddr = tokens[4];
|
|
21825
|
-
const localInode = tokens[5];
|
|
21826
|
-
const peerAddr = tokens[6];
|
|
21827
|
-
const peerInode = tokens[7];
|
|
21828
|
-
const usersToken = tokens.slice(8).join(" ");
|
|
21829
|
-
const m = usersToken.match(/users:\(\(".*?",pid=(\d+),fd=\d+\)\)/);
|
|
21830
|
-
const pid = m ? parseInt(m[1], 10) : null;
|
|
21831
|
-
rows.push({ localAddr, localInode, peerAddr, peerInode, pid });
|
|
21832
|
-
}
|
|
21833
|
-
return rows;
|
|
21834
|
-
}
|
|
21835
|
-
function findClientPids(rows, socketPath) {
|
|
21836
|
-
const pids = [];
|
|
21837
|
-
for (const serverRow of rows) {
|
|
21838
|
-
if (serverRow.localAddr !== socketPath)
|
|
21839
|
-
continue;
|
|
21840
|
-
for (const clientRow of rows) {
|
|
21841
|
-
if (clientRow.localAddr !== "*")
|
|
21842
|
-
continue;
|
|
21843
|
-
if (clientRow.localInode !== serverRow.peerInode)
|
|
21844
|
-
continue;
|
|
21845
|
-
if (clientRow.pid === null)
|
|
21846
|
-
continue;
|
|
21847
|
-
pids.push(clientRow.pid);
|
|
21848
|
-
break;
|
|
21849
|
-
}
|
|
21850
|
-
}
|
|
21851
|
-
return pids;
|
|
21852
|
-
}
|
|
21853
|
-
function findClientPidByServerInode(rows, socketPath, serverInode) {
|
|
21854
|
-
const serverInodeStr = String(serverInode);
|
|
21855
|
-
for (const serverRow of rows) {
|
|
21856
|
-
if (serverRow.localAddr !== socketPath)
|
|
21857
|
-
continue;
|
|
21858
|
-
if (serverRow.localInode !== serverInodeStr)
|
|
21859
|
-
continue;
|
|
21860
|
-
for (const clientRow of rows) {
|
|
21861
|
-
if (clientRow.localAddr !== "*")
|
|
21862
|
-
continue;
|
|
21863
|
-
if (clientRow.localInode !== serverRow.peerInode)
|
|
21864
|
-
continue;
|
|
21865
|
-
if (clientRow.pid === null)
|
|
21866
|
-
continue;
|
|
21867
|
-
return clientRow.pid;
|
|
21868
|
-
}
|
|
21869
|
-
return null;
|
|
21870
|
-
}
|
|
21871
|
-
return null;
|
|
21872
|
-
}
|
|
21873
|
-
function readUid(pid) {
|
|
21874
|
-
try {
|
|
21875
|
-
const status = readFileSync8(`/proc/${pid}/status`, "utf8");
|
|
21876
|
-
const m = status.match(/^Uid:\s+(\d+)/m);
|
|
21877
|
-
if (!m)
|
|
21878
|
-
return null;
|
|
21879
|
-
return parseInt(m[1], 10);
|
|
21880
|
-
} catch {
|
|
21881
|
-
return null;
|
|
21882
|
-
}
|
|
21883
|
-
}
|
|
21884
|
-
function readExe(pid) {
|
|
21885
|
-
try {
|
|
21886
|
-
return readlinkSync3(`/proc/${pid}/exe`);
|
|
21887
|
-
} catch {
|
|
21888
|
-
return null;
|
|
21889
|
-
}
|
|
21890
|
-
}
|
|
21891
|
-
function readSystemdUnit(pid) {
|
|
21892
|
-
try {
|
|
21893
|
-
const content = readFileSync8(`/proc/${pid}/cgroup`, "utf8");
|
|
21894
|
-
const lines = content.split(`
|
|
21895
|
-
`);
|
|
21896
|
-
for (const line of lines) {
|
|
21897
|
-
if (!line.trim())
|
|
21898
|
-
continue;
|
|
21899
|
-
const parts = line.split(":");
|
|
21900
|
-
if (parts.length < 3)
|
|
21901
|
-
continue;
|
|
21902
|
-
const controller = parts[1];
|
|
21903
|
-
const isV2 = parts[0] === "0" && controller === "";
|
|
21904
|
-
const isV1Systemd = controller === "name=systemd";
|
|
21905
|
-
if (!isV2 && !isV1Systemd)
|
|
21906
|
-
continue;
|
|
21907
|
-
const cgroupPath = parts.slice(2).join(":");
|
|
21908
|
-
const segments = cgroupPath.split("/");
|
|
21909
|
-
const lastSegment = segments[segments.length - 1];
|
|
21910
|
-
if (!lastSegment)
|
|
21911
|
-
continue;
|
|
21912
|
-
if (/^switchroom-[a-zA-Z0-9_-]+(-cron-\d+)?\.service$/.test(lastSegment)) {
|
|
21913
|
-
return lastSegment;
|
|
21914
|
-
}
|
|
21915
|
-
}
|
|
21916
|
-
return null;
|
|
21917
|
-
} catch {
|
|
21918
|
-
return null;
|
|
21919
|
-
}
|
|
21920
|
-
}
|
|
21921
|
-
function verifySystemdUnit(unitName, runner) {
|
|
21922
|
-
let raw;
|
|
21923
|
-
try {
|
|
21924
|
-
const out = runner("systemctl", [
|
|
21925
|
-
"--user",
|
|
21926
|
-
"show",
|
|
21927
|
-
unitName,
|
|
21928
|
-
"--property=LoadState,ActiveState"
|
|
21929
|
-
], { timeout: 500, encoding: "utf8" });
|
|
21930
|
-
raw = typeof out === "string" ? out : out.toString("utf8");
|
|
21931
|
-
} catch {
|
|
21932
|
-
return false;
|
|
21933
|
-
}
|
|
21934
|
-
const props = {};
|
|
21935
|
-
for (const line of raw.split(`
|
|
21936
|
-
`)) {
|
|
21937
|
-
const m = line.match(/^([A-Za-z]+)=(.*)$/);
|
|
21938
|
-
if (m)
|
|
21939
|
-
props[m[1]] = m[2];
|
|
21940
|
-
}
|
|
21941
|
-
if (props.LoadState !== "loaded")
|
|
21942
|
-
return false;
|
|
21943
|
-
if (props.ActiveState !== "active" && props.ActiveState !== "activating") {
|
|
21944
|
-
return false;
|
|
21945
|
-
}
|
|
21946
|
-
return true;
|
|
21947
|
-
}
|
|
21948
|
-
function readFdInode(fd) {
|
|
21949
|
-
try {
|
|
21950
|
-
const stat = fstatSync(fd);
|
|
21951
|
-
return stat.ino;
|
|
21952
|
-
} catch {
|
|
21953
|
-
return null;
|
|
21954
|
-
}
|
|
21955
|
-
}
|
|
21956
|
-
function fdFromSocket(socket) {
|
|
21957
|
-
const handle = socket._handle;
|
|
21958
|
-
if (!handle || typeof handle.fd !== "number" || handle.fd < 0)
|
|
21959
|
-
return null;
|
|
21960
|
-
return handle.fd;
|
|
21961
|
-
}
|
|
21962
|
-
function identify(socketPath, socket, execFileSyncOverride) {
|
|
21963
|
-
if (process.platform !== "linux") {
|
|
21964
|
-
return null;
|
|
21965
|
-
}
|
|
21966
|
-
const runner = execFileSyncOverride ?? execFileSync;
|
|
21967
|
-
let pid = null;
|
|
21968
|
-
if (socket !== undefined) {
|
|
21969
|
-
const fd = fdFromSocket(socket);
|
|
21970
|
-
if (fd !== null) {
|
|
21971
|
-
const cred = getPeerCred(fd);
|
|
21972
|
-
if (cred !== null)
|
|
21973
|
-
pid = cred.pid;
|
|
21974
|
-
}
|
|
21975
|
-
}
|
|
21976
|
-
if (pid === null) {
|
|
21977
|
-
let ssOutput;
|
|
21978
|
-
try {
|
|
21979
|
-
const raw = runner("ss", ["-xpn"], {
|
|
21980
|
-
timeout: 200,
|
|
21981
|
-
encoding: "utf8"
|
|
21982
|
-
});
|
|
21983
|
-
ssOutput = typeof raw === "string" ? raw : raw.toString("utf8");
|
|
21984
|
-
} catch {
|
|
21985
|
-
return null;
|
|
21986
|
-
}
|
|
21987
|
-
const rows = parseSsRows(ssOutput);
|
|
21988
|
-
let serverInode = null;
|
|
21989
|
-
if (socket !== undefined) {
|
|
21990
|
-
const fd = fdFromSocket(socket);
|
|
21991
|
-
if (fd !== null)
|
|
21992
|
-
serverInode = readFdInode(fd);
|
|
21993
|
-
}
|
|
21994
|
-
if (serverInode !== null) {
|
|
21995
|
-
pid = findClientPidByServerInode(rows, socketPath, serverInode);
|
|
21996
|
-
} else {
|
|
21997
|
-
const clientPids = findClientPids(rows, socketPath);
|
|
21998
|
-
if (clientPids.length === 0)
|
|
21999
|
-
return null;
|
|
22000
|
-
if (clientPids.length > 1) {
|
|
22001
|
-
process.stderr.write(`[vault-broker] peercred: ${clientPids.length} connected peers found for ${socketPath}; ` + `using pid=${clientPids[0]}. ` + `Multiple simultaneous connections reduce identification accuracy. ` + `(This warning means identify() was called without a socket arg \u2014 likely a stale call site.)
|
|
22002
|
-
`);
|
|
22003
|
-
}
|
|
22004
|
-
pid = clientPids[0];
|
|
22005
|
-
}
|
|
22006
|
-
}
|
|
22007
|
-
if (pid === null)
|
|
22008
|
-
return null;
|
|
22009
|
-
const uid = readUid(pid);
|
|
22010
|
-
if (uid === null) {
|
|
22011
|
-
return null;
|
|
22012
|
-
}
|
|
22013
|
-
const brokerUid = typeof process.getuid === "function" ? process.getuid() : null;
|
|
22014
|
-
if (brokerUid !== null && uid !== brokerUid) {
|
|
22015
|
-
process.stderr.write(`[vault-broker] peercred: UID mismatch \u2014 caller uid=${uid}, broker uid=${brokerUid}; denying
|
|
22016
|
-
`);
|
|
22017
|
-
return null;
|
|
22018
|
-
}
|
|
22019
|
-
const exe = readExe(pid);
|
|
22020
|
-
if (exe === null) {
|
|
22021
|
-
return null;
|
|
22022
|
-
}
|
|
22023
|
-
const cgroupClaim = readSystemdUnit(pid);
|
|
22024
|
-
let systemdUnit = null;
|
|
22025
|
-
if (cgroupClaim !== null) {
|
|
22026
|
-
if (verifySystemdUnit(cgroupClaim, runner)) {
|
|
22027
|
-
systemdUnit = cgroupClaim;
|
|
22028
|
-
} else {
|
|
22029
|
-
process.stderr.write(`[vault-broker] peercred: cgroup claims unit=${cgroupClaim} but systemd-user does not report it as loaded+running; treating caller as unidentified
|
|
22030
|
-
`);
|
|
22031
|
-
}
|
|
22032
|
-
}
|
|
22033
|
-
return { uid, pid, exe, systemdUnit };
|
|
22034
|
-
}
|
|
22035
|
-
var SOCKET_PATH_AGENT_RE, SOCKET_PATH_AGENT_SUBDIR_RE, RESERVED_AGENT_NAMES;
|
|
22036
|
-
var init_peercred = __esm(() => {
|
|
22037
|
-
SOCKET_PATH_AGENT_RE = /^\/run\/switchroom\/broker\/([a-zA-Z0-9][a-zA-Z0-9_-]*)\.sock$/;
|
|
22038
|
-
SOCKET_PATH_AGENT_SUBDIR_RE = /^\/run\/switchroom\/broker\/([a-zA-Z0-9][a-zA-Z0-9_-]*)\/sock$/;
|
|
22039
|
-
RESERVED_AGENT_NAMES = new Set(["operator", "hostd"]);
|
|
22040
|
-
});
|
|
22041
|
-
|
|
22042
22052
|
// src/runtime-mode.ts
|
|
22043
22053
|
function isDockerRuntime() {
|
|
22044
22054
|
return process.env.SWITCHROOM_RUNTIME === "docker";
|
|
@@ -25539,6 +25549,7 @@ var init_broker_call = __esm(() => {
|
|
|
25539
25549
|
|
|
25540
25550
|
// src/auth/account-store.ts
|
|
25541
25551
|
import {
|
|
25552
|
+
chownSync,
|
|
25542
25553
|
existsSync as existsSync26,
|
|
25543
25554
|
mkdirSync as mkdirSync15,
|
|
25544
25555
|
readFileSync as readFileSync22,
|
|
@@ -29089,7 +29100,7 @@ function decodeResponse3(line) {
|
|
|
29089
29100
|
const obj = JSON.parse(line);
|
|
29090
29101
|
return ResponseSchema3.parse(obj);
|
|
29091
29102
|
}
|
|
29092
|
-
var MAX_FRAME_BYTES3, RequestEnvelope, AgentRestartRequestSchema, UpgradeStatusRequestSchema, GetStatusRequestSchema,
|
|
29103
|
+
var MAX_FRAME_BYTES3, RequestEnvelope, AgentRestartRequestSchema, UpgradeStatusRequestSchema, GetStatusRequestSchema, AgentNameSchema2, UpdateCheckRequestSchema, UpdateApplyRequestSchema, ApplyRequestSchema, AgentStartRequestSchema, AgentStopRequestSchema, AgentLogsRequestSchema, AgentExecRequestSchema, DoctorRequestSchema, AgentSmokeRequestSchema, ConfigProposeEditRequestSchema, RequestSchema3, ResultSchema, ResponseEnvelope, ResponseSchema3;
|
|
29093
29104
|
var init_protocol3 = __esm(() => {
|
|
29094
29105
|
init_zod();
|
|
29095
29106
|
MAX_FRAME_BYTES3 = 64 * 1024;
|
|
@@ -29119,7 +29130,7 @@ var init_protocol3 = __esm(() => {
|
|
|
29119
29130
|
target_request_id: exports_external.string().min(1).max(128)
|
|
29120
29131
|
})
|
|
29121
29132
|
});
|
|
29122
|
-
|
|
29133
|
+
AgentNameSchema2 = exports_external.string().regex(/^[a-zA-Z0-9][a-zA-Z0-9_-]*$/, "agent name must be kebab-case ASCII");
|
|
29123
29134
|
UpdateCheckRequestSchema = exports_external.object({
|
|
29124
29135
|
...RequestEnvelope,
|
|
29125
29136
|
op: exports_external.literal("update_check"),
|
|
@@ -29144,21 +29155,21 @@ var init_protocol3 = __esm(() => {
|
|
|
29144
29155
|
...RequestEnvelope,
|
|
29145
29156
|
op: exports_external.literal("agent_start"),
|
|
29146
29157
|
args: exports_external.object({
|
|
29147
|
-
name:
|
|
29158
|
+
name: AgentNameSchema2
|
|
29148
29159
|
})
|
|
29149
29160
|
});
|
|
29150
29161
|
AgentStopRequestSchema = exports_external.object({
|
|
29151
29162
|
...RequestEnvelope,
|
|
29152
29163
|
op: exports_external.literal("agent_stop"),
|
|
29153
29164
|
args: exports_external.object({
|
|
29154
|
-
name:
|
|
29165
|
+
name: AgentNameSchema2
|
|
29155
29166
|
})
|
|
29156
29167
|
});
|
|
29157
29168
|
AgentLogsRequestSchema = exports_external.object({
|
|
29158
29169
|
...RequestEnvelope,
|
|
29159
29170
|
op: exports_external.literal("agent_logs"),
|
|
29160
29171
|
args: exports_external.object({
|
|
29161
|
-
name:
|
|
29172
|
+
name: AgentNameSchema2,
|
|
29162
29173
|
tail: exports_external.number().int().positive().max(2000).optional()
|
|
29163
29174
|
})
|
|
29164
29175
|
});
|
|
@@ -29166,7 +29177,7 @@ var init_protocol3 = __esm(() => {
|
|
|
29166
29177
|
...RequestEnvelope,
|
|
29167
29178
|
op: exports_external.literal("agent_exec"),
|
|
29168
29179
|
args: exports_external.object({
|
|
29169
|
-
name:
|
|
29180
|
+
name: AgentNameSchema2,
|
|
29170
29181
|
argv: exports_external.array(exports_external.string().min(1)).min(1).max(32)
|
|
29171
29182
|
})
|
|
29172
29183
|
});
|
|
@@ -29179,7 +29190,7 @@ var init_protocol3 = __esm(() => {
|
|
|
29179
29190
|
...RequestEnvelope,
|
|
29180
29191
|
op: exports_external.literal("agent_smoke"),
|
|
29181
29192
|
args: exports_external.object({
|
|
29182
|
-
name:
|
|
29193
|
+
name: AgentNameSchema2,
|
|
29183
29194
|
deep: exports_external.boolean().optional()
|
|
29184
29195
|
})
|
|
29185
29196
|
});
|
|
@@ -29394,6 +29405,7 @@ __export(exports_doctor, {
|
|
|
29394
29405
|
tryReadHostFile: () => tryReadHostFile,
|
|
29395
29406
|
telegramGetMe: () => telegramGetMe,
|
|
29396
29407
|
registerDoctorCommand: () => registerDoctorCommand,
|
|
29408
|
+
probeVaultBrokerSocketPair: () => probeVaultBrokerSocketPair,
|
|
29397
29409
|
printSection: () => printSection,
|
|
29398
29410
|
parseSimpleEnv: () => parseSimpleEnv,
|
|
29399
29411
|
parsePythonVersion: () => parsePythonVersion,
|
|
@@ -29406,6 +29418,7 @@ __export(exports_doctor, {
|
|
|
29406
29418
|
findChromium: () => findChromium,
|
|
29407
29419
|
deriveEd25519PublicKeyBytes: () => deriveEd25519PublicKeyBytes,
|
|
29408
29420
|
classifyReadError: () => classifyReadError,
|
|
29421
|
+
checkVaultBrokerSocketPairs: () => checkVaultBrokerSocketPairs,
|
|
29409
29422
|
checkTelegram: () => checkTelegram,
|
|
29410
29423
|
checkStartShStale: () => checkStartShStale,
|
|
29411
29424
|
checkSkillsPrerequisites: () => checkSkillsPrerequisites,
|
|
@@ -29731,6 +29744,93 @@ function checkLegacyState() {
|
|
|
29731
29744
|
}
|
|
29732
29745
|
return results;
|
|
29733
29746
|
}
|
|
29747
|
+
function probeVaultBrokerSocketPair(agentName) {
|
|
29748
|
+
const dataPath = `/run/switchroom/broker/${agentName}/sock`;
|
|
29749
|
+
const unlockPath = `/run/switchroom/broker/${agentName}/unlock`;
|
|
29750
|
+
const script = `D=0; U=0; ` + `test -S '${dataPath}' && D=1; ` + `test -S '${unlockPath}' && U=1; ` + `echo "D=$D U=$U"`;
|
|
29751
|
+
const r = spawnSync7("docker", ["exec", "switchroom-vault-broker", "sh", "-c", script], { stdio: "pipe", timeout: 3000 });
|
|
29752
|
+
if (r.error || r.status === null)
|
|
29753
|
+
return "unreachable";
|
|
29754
|
+
if (r.status !== 0) {
|
|
29755
|
+
if (r.status >= 125)
|
|
29756
|
+
return "unreachable";
|
|
29757
|
+
return "unreachable";
|
|
29758
|
+
}
|
|
29759
|
+
const out = r.stdout.toString();
|
|
29760
|
+
const dOk = /D=1/.test(out);
|
|
29761
|
+
const uOk = /U=1/.test(out);
|
|
29762
|
+
if (dOk && uOk)
|
|
29763
|
+
return "ok";
|
|
29764
|
+
if (dOk && !uOk)
|
|
29765
|
+
return "missing-unlock";
|
|
29766
|
+
if (!dOk && uOk)
|
|
29767
|
+
return "missing-data";
|
|
29768
|
+
return "missing-both";
|
|
29769
|
+
}
|
|
29770
|
+
function checkVaultBrokerSocketPairs(config, opts) {
|
|
29771
|
+
const agentNames = Object.keys(config.agents ?? {}).sort();
|
|
29772
|
+
if (agentNames.length === 0) {
|
|
29773
|
+
return {
|
|
29774
|
+
name: "vault-broker per-agent socket pairs",
|
|
29775
|
+
status: "ok",
|
|
29776
|
+
detail: "no agents configured"
|
|
29777
|
+
};
|
|
29778
|
+
}
|
|
29779
|
+
const probe2 = opts?.probe ?? probeVaultBrokerSocketPair;
|
|
29780
|
+
const states = new Map;
|
|
29781
|
+
for (const name of agentNames) {
|
|
29782
|
+
states.set(name, probe2(name));
|
|
29783
|
+
}
|
|
29784
|
+
const allUnreachable = [...states.values()].every((s) => s === "unreachable");
|
|
29785
|
+
if (allUnreachable) {
|
|
29786
|
+
return {
|
|
29787
|
+
name: "vault-broker per-agent socket pairs",
|
|
29788
|
+
status: "skip",
|
|
29789
|
+
detail: "vault-broker container unreachable \u2014 couldn't probe per-agent socket pairs",
|
|
29790
|
+
fix: "Check the vault-broker service health row above; `switchroom update` brings it back"
|
|
29791
|
+
};
|
|
29792
|
+
}
|
|
29793
|
+
const groups = {
|
|
29794
|
+
"missing-unlock": [],
|
|
29795
|
+
"missing-data": [],
|
|
29796
|
+
"missing-both": [],
|
|
29797
|
+
unreachable: []
|
|
29798
|
+
};
|
|
29799
|
+
let okCount = 0;
|
|
29800
|
+
for (const [name, state] of states) {
|
|
29801
|
+
if (state === "ok") {
|
|
29802
|
+
okCount++;
|
|
29803
|
+
} else {
|
|
29804
|
+
groups[state].push(name);
|
|
29805
|
+
}
|
|
29806
|
+
}
|
|
29807
|
+
if (okCount === agentNames.length) {
|
|
29808
|
+
return {
|
|
29809
|
+
name: "vault-broker per-agent socket pairs",
|
|
29810
|
+
status: "ok",
|
|
29811
|
+
detail: `${okCount}/${agentNames.length} agents: data + unlock sockets bound`
|
|
29812
|
+
};
|
|
29813
|
+
}
|
|
29814
|
+
const parts = [];
|
|
29815
|
+
if (groups["missing-unlock"].length > 0) {
|
|
29816
|
+
parts.push(`unlock missing: ${groups["missing-unlock"].join(", ")} ` + `(the documented Telegram /vault unlock flow fails ENOENT for these)`);
|
|
29817
|
+
}
|
|
29818
|
+
if (groups["missing-data"].length > 0) {
|
|
29819
|
+
parts.push(`data missing: ${groups["missing-data"].join(", ")}`);
|
|
29820
|
+
}
|
|
29821
|
+
if (groups["missing-both"].length > 0) {
|
|
29822
|
+
parts.push(`both missing: ${groups["missing-both"].join(", ")}`);
|
|
29823
|
+
}
|
|
29824
|
+
if (groups["unreachable"].length > 0) {
|
|
29825
|
+
parts.push(`unreachable: ${groups["unreachable"].join(", ")}`);
|
|
29826
|
+
}
|
|
29827
|
+
return {
|
|
29828
|
+
name: "vault-broker per-agent socket pairs",
|
|
29829
|
+
status: "fail",
|
|
29830
|
+
detail: `${okCount}/${agentNames.length} ok \u2014 ${parts.join("; ")}`,
|
|
29831
|
+
fix: "Run `switchroom update` (or `switchroom apply` then recreate the " + "vault-broker container). If only the unlock half is missing, the " + "broker image predates PR #1721 \u2014 pull the latest image."
|
|
29832
|
+
};
|
|
29833
|
+
}
|
|
29734
29834
|
function checkVault(config) {
|
|
29735
29835
|
const vaultPath = config.vault?.path ? config.vault.path.replace(/^~/, process.env.HOME ?? "") : resolveStatePath("vault.enc");
|
|
29736
29836
|
const broker = config.vault?.broker;
|
|
@@ -29749,6 +29849,7 @@ function checkVault(config) {
|
|
|
29749
29849
|
status: "ok",
|
|
29750
29850
|
detail: "Approval auth: passphrase (two-factor)"
|
|
29751
29851
|
};
|
|
29852
|
+
const pairsResult = checkVaultBrokerSocketPairs(config);
|
|
29752
29853
|
if (!existsSync50(vaultPath)) {
|
|
29753
29854
|
return [
|
|
29754
29855
|
postureResult,
|
|
@@ -29757,7 +29858,8 @@ function checkVault(config) {
|
|
|
29757
29858
|
status: "warn",
|
|
29758
29859
|
detail: `${vaultPath} not found`,
|
|
29759
29860
|
fix: "Run `switchroom vault init` if you plan to store secrets in the vault"
|
|
29760
|
-
}
|
|
29861
|
+
},
|
|
29862
|
+
pairsResult
|
|
29761
29863
|
];
|
|
29762
29864
|
}
|
|
29763
29865
|
const passphrase = process.env.SWITCHROOM_VAULT_PASSPHRASE;
|
|
@@ -29774,7 +29876,8 @@ function checkVault(config) {
|
|
|
29774
29876
|
status: "skip",
|
|
29775
29877
|
detail: "SWITCHROOM_VAULT_PASSPHRASE not set; cannot verify decrypt",
|
|
29776
29878
|
fix: "Export SWITCHROOM_VAULT_PASSPHRASE to verify the vault unlocks"
|
|
29777
|
-
}
|
|
29879
|
+
},
|
|
29880
|
+
pairsResult
|
|
29778
29881
|
];
|
|
29779
29882
|
}
|
|
29780
29883
|
try {
|
|
@@ -29785,7 +29888,8 @@ function checkVault(config) {
|
|
|
29785
29888
|
name: "vault unlock",
|
|
29786
29889
|
status: "ok",
|
|
29787
29890
|
detail: `${keys.length} secret(s)`
|
|
29788
|
-
}
|
|
29891
|
+
},
|
|
29892
|
+
pairsResult
|
|
29789
29893
|
];
|
|
29790
29894
|
} catch (err) {
|
|
29791
29895
|
return [
|
|
@@ -29795,7 +29899,8 @@ function checkVault(config) {
|
|
|
29795
29899
|
status: "fail",
|
|
29796
29900
|
detail: err.message,
|
|
29797
29901
|
fix: "SWITCHROOM_VAULT_PASSPHRASE is wrong, or the vault file is corrupted"
|
|
29798
|
-
}
|
|
29902
|
+
},
|
|
29903
|
+
pairsResult
|
|
29799
29904
|
];
|
|
29800
29905
|
}
|
|
29801
29906
|
}
|
|
@@ -47331,8 +47436,8 @@ var {
|
|
|
47331
47436
|
} = import__.default;
|
|
47332
47437
|
|
|
47333
47438
|
// src/build-info.ts
|
|
47334
|
-
var VERSION = "0.13.
|
|
47335
|
-
var COMMIT_SHA = "
|
|
47439
|
+
var VERSION = "0.13.26";
|
|
47440
|
+
var COMMIT_SHA = "b2767bb7";
|
|
47336
47441
|
|
|
47337
47442
|
// src/cli/agent.ts
|
|
47338
47443
|
init_source();
|
|
@@ -55825,7 +55930,7 @@ import { spawn as spawn3 } from "node:child_process";
|
|
|
55825
55930
|
init_compose();
|
|
55826
55931
|
init_vault();
|
|
55827
55932
|
import * as net3 from "node:net";
|
|
55828
|
-
import { mkdirSync as mkdirSync20, chmodSync as chmodSync7, chownSync, existsSync as existsSync33, readFileSync as readFileSync29, readdirSync as readdirSync15, statSync as statSync19, unlinkSync as unlinkSync8, writeFileSync as writeFileSync18, renameSync as renameSync9 } from "node:fs";
|
|
55933
|
+
import { mkdirSync as mkdirSync20, chmodSync as chmodSync7, chownSync as chownSync2, existsSync as existsSync33, readFileSync as readFileSync29, readdirSync as readdirSync15, statSync as statSync19, unlinkSync as unlinkSync8, writeFileSync as writeFileSync18, renameSync as renameSync9 } from "node:fs";
|
|
55829
55934
|
import { dirname as dirname6, resolve as resolve25, basename as basename5 } from "node:path";
|
|
55830
55935
|
import * as os4 from "node:os";
|
|
55831
55936
|
import * as path3 from "node:path";
|
|
@@ -58622,7 +58727,7 @@ class VaultBroker {
|
|
|
58622
58727
|
const dir = abs.slice(0, -"/sock".length);
|
|
58623
58728
|
if (existsSync33(dir)) {
|
|
58624
58729
|
try {
|
|
58625
|
-
|
|
58730
|
+
chownSync2(dir, 0, 0);
|
|
58626
58731
|
} catch {}
|
|
58627
58732
|
try {
|
|
58628
58733
|
chmodSync7(dir, 448);
|
|
@@ -58646,20 +58751,48 @@ class VaultBroker {
|
|
|
58646
58751
|
try {
|
|
58647
58752
|
chmodSync7(abs, 432);
|
|
58648
58753
|
} catch {}
|
|
58754
|
+
let agentUid = null;
|
|
58649
58755
|
try {
|
|
58650
|
-
|
|
58756
|
+
agentUid = allocateAgentUid(agentName);
|
|
58651
58757
|
try {
|
|
58652
|
-
|
|
58758
|
+
chownSync2(abs, agentUid, agentUid);
|
|
58653
58759
|
} catch {}
|
|
58654
58760
|
if (abs.endsWith("/sock")) {
|
|
58655
58761
|
const dir = abs.slice(0, -"/sock".length);
|
|
58656
58762
|
try {
|
|
58657
|
-
|
|
58763
|
+
chownSync2(dir, agentUid, agentUid);
|
|
58658
58764
|
} catch {}
|
|
58659
58765
|
}
|
|
58660
58766
|
} catch {}
|
|
58661
58767
|
this.agentServers.set(abs, { server, agentName });
|
|
58662
|
-
|
|
58768
|
+
const unlockAbs = unlockSocketFor(abs);
|
|
58769
|
+
if (existsSync33(unlockAbs)) {
|
|
58770
|
+
try {
|
|
58771
|
+
unlinkSync8(unlockAbs);
|
|
58772
|
+
} catch {}
|
|
58773
|
+
}
|
|
58774
|
+
const unlockServer = net3.createServer((sock) => {
|
|
58775
|
+
this._handleUnlockConnection(sock, false);
|
|
58776
|
+
});
|
|
58777
|
+
unlockServer.on("error", (err) => {
|
|
58778
|
+
try {
|
|
58779
|
+
server.close();
|
|
58780
|
+
} catch {}
|
|
58781
|
+
this.agentServers.delete(abs);
|
|
58782
|
+
rejectP(err);
|
|
58783
|
+
});
|
|
58784
|
+
unlockServer.listen(unlockAbs, () => {
|
|
58785
|
+
try {
|
|
58786
|
+
chmodSync7(unlockAbs, 432);
|
|
58787
|
+
} catch {}
|
|
58788
|
+
if (agentUid !== null) {
|
|
58789
|
+
try {
|
|
58790
|
+
chownSync2(unlockAbs, agentUid, agentUid);
|
|
58791
|
+
} catch {}
|
|
58792
|
+
}
|
|
58793
|
+
this.agentServers.set(unlockAbs, { server: unlockServer, agentName });
|
|
58794
|
+
resolveP(agentName);
|
|
58795
|
+
});
|
|
58663
58796
|
});
|
|
58664
58797
|
});
|
|
58665
58798
|
}
|
|
@@ -58689,7 +58822,7 @@ class VaultBroker {
|
|
|
58689
58822
|
return;
|
|
58690
58823
|
try {
|
|
58691
58824
|
if (existsSync33(this.vaultPath))
|
|
58692
|
-
|
|
58825
|
+
chownSync2(this.vaultPath, uid, uid);
|
|
58693
58826
|
} catch {}
|
|
58694
58827
|
}
|
|
58695
58828
|
bindOperatorListener(socketPath, operatorUid) {
|
|
@@ -58703,7 +58836,7 @@ class VaultBroker {
|
|
|
58703
58836
|
const dir = abs.slice(0, -"/sock".length);
|
|
58704
58837
|
if (existsSync33(dir)) {
|
|
58705
58838
|
try {
|
|
58706
|
-
|
|
58839
|
+
chownSync2(dir, 0, 0);
|
|
58707
58840
|
} catch {}
|
|
58708
58841
|
try {
|
|
58709
58842
|
chmodSync7(dir, 448);
|
|
@@ -58727,7 +58860,7 @@ class VaultBroker {
|
|
|
58727
58860
|
chmodSync7(abs, 384);
|
|
58728
58861
|
} catch {}
|
|
58729
58862
|
try {
|
|
58730
|
-
|
|
58863
|
+
chownSync2(abs, operatorUid, operatorUid);
|
|
58731
58864
|
} catch {}
|
|
58732
58865
|
const unlockServer = net3.createServer((sock) => {
|
|
58733
58866
|
this._handleUnlockConnection(sock, true);
|
|
@@ -58738,12 +58871,12 @@ class VaultBroker {
|
|
|
58738
58871
|
chmodSync7(unlockAbs, 384);
|
|
58739
58872
|
} catch {}
|
|
58740
58873
|
try {
|
|
58741
|
-
|
|
58874
|
+
chownSync2(unlockAbs, operatorUid, operatorUid);
|
|
58742
58875
|
} catch {}
|
|
58743
58876
|
if (abs.endsWith("/sock")) {
|
|
58744
58877
|
const dir = abs.slice(0, -"/sock".length);
|
|
58745
58878
|
try {
|
|
58746
|
-
|
|
58879
|
+
chownSync2(dir, operatorUid, operatorUid);
|
|
58747
58880
|
} catch {}
|
|
58748
58881
|
try {
|
|
58749
58882
|
chmodSync7(dir, 448);
|
|
@@ -59586,7 +59719,7 @@ class VaultBroker {
|
|
|
59586
59719
|
const revoked = revokeGrant(this.grantsDb, id);
|
|
59587
59720
|
try {
|
|
59588
59721
|
const row = this.grantsDb.query("SELECT agent_slug FROM vault_grants WHERE id = ?").get(id);
|
|
59589
|
-
if (row) {
|
|
59722
|
+
if (row && AgentNameSchema.safeParse(row.agent_slug).success) {
|
|
59590
59723
|
const tokenPath = path3.join(os4.homedir(), ".switchroom", "agents", row.agent_slug, ".vault-token");
|
|
59591
59724
|
if (existsSync33(tokenPath)) {
|
|
59592
59725
|
try {
|
|
@@ -61405,9 +61538,18 @@ function registerVaultCommand(program3) {
|
|
|
61405
61538
|
}
|
|
61406
61539
|
const passphrase = await getPassphrase();
|
|
61407
61540
|
let value;
|
|
61541
|
+
let isBinaryFile = false;
|
|
61408
61542
|
if (opts.file) {
|
|
61409
61543
|
try {
|
|
61410
|
-
|
|
61544
|
+
const buf = readFileSync34(resolvePath(opts.file));
|
|
61545
|
+
const asUtf8 = buf.toString("utf8");
|
|
61546
|
+
if (Buffer.compare(buf, Buffer.from(asUtf8, "utf8")) === 0) {
|
|
61547
|
+
value = asUtf8;
|
|
61548
|
+
} else {
|
|
61549
|
+
value = buf.toString("base64");
|
|
61550
|
+
isBinaryFile = true;
|
|
61551
|
+
console.error(source_default.yellow(`note: file contains non-UTF-8 bytes; storing as kind="binary" ` + `(base64-encoded). Retrieve with: switchroom vault get ${key} | base64 -d`));
|
|
61552
|
+
}
|
|
61411
61553
|
} catch (err) {
|
|
61412
61554
|
const msg = err instanceof Error ? err.message : String(err);
|
|
61413
61555
|
console.error(source_default.red(`Error reading file: ${msg}`));
|
|
@@ -61422,7 +61564,7 @@ function registerVaultCommand(program3) {
|
|
|
61422
61564
|
console.error(source_default.red("Error: Value cannot be empty"));
|
|
61423
61565
|
process.exit(1);
|
|
61424
61566
|
}
|
|
61425
|
-
if (formatHint) {
|
|
61567
|
+
if (formatHint && !isBinaryFile) {
|
|
61426
61568
|
const validationError = validateFormatHint(value, formatHint);
|
|
61427
61569
|
if (validationError) {
|
|
61428
61570
|
console.error(source_default.red(`Error: format validation failed for --format ${formatHint}: ${validationError}`));
|
|
@@ -61451,7 +61593,11 @@ function registerVaultCommand(program3) {
|
|
|
61451
61593
|
}
|
|
61452
61594
|
} catch {}
|
|
61453
61595
|
}
|
|
61454
|
-
|
|
61596
|
+
if (isBinaryFile) {
|
|
61597
|
+
setBinarySecret(passphrase, vaultPath, key, value, formatHint, scope);
|
|
61598
|
+
} else {
|
|
61599
|
+
setStringSecret(passphrase, vaultPath, key, value, formatHint, scope);
|
|
61600
|
+
}
|
|
61455
61601
|
if (formatHint && scope) {
|
|
61456
61602
|
const scopeDesc = [
|
|
61457
61603
|
scope.allow?.length ? `allow: ${scope.allow.join(", ")}` : "",
|
|
@@ -62193,13 +62339,12 @@ function registerDispatchVerb(tg, _program) {
|
|
|
62193
62339
|
`)) {
|
|
62194
62340
|
console.log(` ${line}`);
|
|
62195
62341
|
}
|
|
62196
|
-
console.log(` model: ${rule.model ?? "claude-sonnet-4-6"}`);
|
|
62197
62342
|
}
|
|
62198
62343
|
console.log();
|
|
62199
62344
|
if (matchCount === 0) {
|
|
62200
62345
|
console.log(source_default.yellow("No rules matched \u2014 no dispatch would fire."));
|
|
62201
62346
|
} else {
|
|
62202
|
-
console.log(source_default.green(`${matchCount} rule(s) matched. ` + `
|
|
62347
|
+
console.log(source_default.green(`${matchCount} rule(s) matched. ` + `The webhook turn injects into the agent's live session \u2014 ` + `agent's configured model wins.`));
|
|
62203
62348
|
}
|
|
62204
62349
|
}));
|
|
62205
62350
|
}
|
|
@@ -74040,7 +74185,7 @@ function detectInstallType() {
|
|
|
74040
74185
|
|
|
74041
74186
|
// src/cli/operator-uid.ts
|
|
74042
74187
|
import {
|
|
74043
|
-
chownSync as
|
|
74188
|
+
chownSync as chownSync3,
|
|
74044
74189
|
existsSync as existsSync66,
|
|
74045
74190
|
lstatSync as lstatSync7,
|
|
74046
74191
|
readdirSync as readdirSync24,
|
|
@@ -74074,7 +74219,7 @@ function operatorOwnedPaths(home2) {
|
|
|
74074
74219
|
];
|
|
74075
74220
|
}
|
|
74076
74221
|
function restoreOperatorOwnership(home2, operatorUid, deps = {}) {
|
|
74077
|
-
const chown = deps.chown ?? ((p, u, g) =>
|
|
74222
|
+
const chown = deps.chown ?? ((p, u, g) => chownSync3(p, u, g));
|
|
74078
74223
|
const exists = deps.exists ?? ((p) => existsSync66(p));
|
|
74079
74224
|
const isSymlink = deps.isSymlink ?? ((p) => {
|
|
74080
74225
|
try {
|