switchroom 0.13.31 → 0.13.33

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.
@@ -22983,6 +22983,7 @@ function generateCompose(opts) {
22983
22983
  lines.push(` - ${homePrefix}/.switchroom/vault:/state/vault:rw`);
22984
22984
  lines.push(` - ${homePrefix}/.switchroom/vault-auto-unlock:/state/vault-auto-unlock:ro`);
22985
22985
  lines.push(` - ${homePrefix}/.switchroom/vault-audit.log:/root/.switchroom/vault-audit.log`);
22986
+ lines.push(` - ${homePrefix}/.switchroom/vault-grants.db:/root/.switchroom/vault-grants.db`);
22986
22987
  lines.push(` - /etc/machine-id:/etc/machine-id:ro`);
22987
22988
  lines.push(``);
22988
22989
  lines.push(` approval-kernel:`);
@@ -29399,6 +29400,220 @@ var init_doctor_agent_smoke = __esm(() => {
29399
29400
  init_client4();
29400
29401
  });
29401
29402
 
29403
+ // src/cli/doctor-vault-broker-durability.ts
29404
+ import { execFileSync as execFileSync14 } from "node:child_process";
29405
+ import { existsSync as existsSync50, statSync as statSync22 } from "node:fs";
29406
+ import { homedir as homedir27 } from "node:os";
29407
+ import { join as join46 } from "node:path";
29408
+ function probeBindMountInode(hostPath, brokerContainerPath, opts) {
29409
+ const statHost = opts?.statHost ?? defaultStatHost;
29410
+ const statBroker = opts?.statBroker ?? defaultStatBroker;
29411
+ const host = statHost(hostPath);
29412
+ if (host === null)
29413
+ return { kind: "host-missing", hostPath };
29414
+ const broker = statBroker(brokerContainerPath);
29415
+ if (broker.kind !== "ok-with-stat")
29416
+ return broker;
29417
+ if (String(host.ino) === broker.ino && host.size === broker.size) {
29418
+ return { kind: "ok" };
29419
+ }
29420
+ return {
29421
+ kind: "mismatch",
29422
+ hostInode: String(host.ino),
29423
+ brokerInode: broker.ino,
29424
+ hostSize: host.size,
29425
+ brokerSize: broker.size
29426
+ };
29427
+ }
29428
+ function defaultStatHost(p) {
29429
+ if (!existsSync50(p))
29430
+ return null;
29431
+ try {
29432
+ const s = statSync22(p, { bigint: true });
29433
+ return { ino: s.ino, size: Number(s.size) };
29434
+ } catch {
29435
+ return null;
29436
+ }
29437
+ }
29438
+ function defaultStatBroker(p) {
29439
+ const r = spawnDockerStat(p);
29440
+ if (r.error || r.status === null)
29441
+ return { kind: "broker-unreachable" };
29442
+ if (r.status !== 0) {
29443
+ if (r.status >= 125)
29444
+ return { kind: "broker-unreachable" };
29445
+ return {
29446
+ kind: "broker-stat-failed",
29447
+ msg: r.stderr?.trim() || `exit ${r.status}`
29448
+ };
29449
+ }
29450
+ const out = r.stdout.trim();
29451
+ const [inoStr, sizeStr] = out.split(/\s+/);
29452
+ const size = Number(sizeStr);
29453
+ if (!inoStr || !Number.isFinite(size)) {
29454
+ return {
29455
+ kind: "broker-stat-failed",
29456
+ msg: `unparseable stat output: ${out}`
29457
+ };
29458
+ }
29459
+ return { kind: "ok-with-stat", ino: inoStr, size };
29460
+ }
29461
+ function spawnDockerStat(p) {
29462
+ try {
29463
+ const stdout = execFileSync14("docker", ["exec", "switchroom-vault-broker", "stat", "-c", "%i %s", p], { stdio: ["ignore", "pipe", "pipe"], timeout: 3000, encoding: "utf8" });
29464
+ return { status: 0, stdout, stderr: "", error: null };
29465
+ } catch (err) {
29466
+ const e = err;
29467
+ return {
29468
+ status: typeof e.status === "number" ? e.status : null,
29469
+ stdout: e.stdout ?? "",
29470
+ stderr: e.stderr ?? "",
29471
+ error: e.status === undefined ? new Error(e.message ?? "spawn failed") : null
29472
+ };
29473
+ }
29474
+ }
29475
+ function formatBindMountResult(name, hostPath, brokerContainerPath, result) {
29476
+ if (result.kind === "ok") {
29477
+ return {
29478
+ name,
29479
+ status: "ok",
29480
+ detail: `${hostPath} == ${brokerContainerPath} (same inode)`
29481
+ };
29482
+ }
29483
+ if (result.kind === "host-missing") {
29484
+ return {
29485
+ name,
29486
+ status: "warn",
29487
+ detail: `host file ${hostPath} missing \u2014 pre-created by \`switchroom apply\` on greenfield`,
29488
+ fix: "Run `switchroom apply` to pre-create the host file at the correct mode"
29489
+ };
29490
+ }
29491
+ if (result.kind === "broker-unreachable") {
29492
+ return {
29493
+ name,
29494
+ status: "skip",
29495
+ detail: "vault-broker container unreachable \u2014 bind mount unverified"
29496
+ };
29497
+ }
29498
+ if (result.kind === "broker-stat-failed") {
29499
+ return {
29500
+ name,
29501
+ status: "warn",
29502
+ detail: `broker stat failed: ${result.msg}`
29503
+ };
29504
+ }
29505
+ return {
29506
+ name,
29507
+ status: "fail",
29508
+ detail: `inode mismatch \u2014 bind mount is NOT wiring host to broker. ` + `host inode=${result.hostInode} size=${result.hostSize}; ` + `broker inode=${result.brokerInode} size=${result.brokerSize}. ` + `The broker is operating on an ephemeral container-local file; ` + `data written there evaporates on container recreate.`,
29509
+ fix: "Run `switchroom apply` to regenerate compose with the correct " + "bind mount, then `docker compose -p switchroom up -d vault-broker` " + "to recreate the broker container."
29510
+ };
29511
+ }
29512
+ function probeBrokerUnlocked(opts) {
29513
+ const status = (opts?.statusProbe ?? defaultBrokerStatusProbe)();
29514
+ if (status === null) {
29515
+ return {
29516
+ name: "vault-broker unlocked (state)",
29517
+ status: "skip",
29518
+ detail: "vault-broker container unreachable"
29519
+ };
29520
+ }
29521
+ if (!status.unlocked) {
29522
+ return {
29523
+ name: "vault-broker unlocked (state)",
29524
+ status: "fail",
29525
+ detail: `broker reports locked despite config \u2014 auto-unlock failed silently. ` + `Common causes: \`/etc/machine-id\` mount missing or differs from the ` + `host the blob was sealed on; vault-auto-unlock blob corrupted; ` + `vault passphrase was rotated without re-running ` + `\`switchroom vault broker enable-auto-unlock\`.`,
29526
+ fix: "Re-run `switchroom vault broker enable-auto-unlock` on the host " + "to re-seal the blob against the current machine-id + passphrase. " + "Then restart the broker (`docker compose -p switchroom restart vault-broker`)."
29527
+ };
29528
+ }
29529
+ return {
29530
+ name: "vault-broker unlocked (state)",
29531
+ status: "ok",
29532
+ detail: `${status.keyCount} key(s) loaded`
29533
+ };
29534
+ }
29535
+ function defaultBrokerStatusProbe() {
29536
+ try {
29537
+ const out = execFileSync14("switchroom", ["vault", "broker", "status"], { stdio: ["ignore", "pipe", "pipe"], timeout: 3000, encoding: "utf8" });
29538
+ const parsed = JSON.parse(out.trim());
29539
+ if (!parsed.running)
29540
+ return null;
29541
+ return { unlocked: parsed.unlocked, keyCount: parsed.keyCount };
29542
+ } catch {
29543
+ return null;
29544
+ }
29545
+ }
29546
+ function runVaultBrokerDurabilityChecks(_config, opts) {
29547
+ const home2 = homedir27();
29548
+ const probe2 = opts?.inodeProbe ?? probeBindMountInode;
29549
+ return [
29550
+ probeBrokerUnlocked(opts?.statusProbe),
29551
+ probeAutoUnlockBlob(home2),
29552
+ probeMachineIdMount(),
29553
+ formatBindMountResult("vault-broker: vault.enc bind mount", join46(home2, ".switchroom", "vault", "vault.enc"), "/state/vault/vault.enc", probe2(join46(home2, ".switchroom", "vault", "vault.enc"), "/state/vault/vault.enc")),
29554
+ formatBindMountResult("vault-broker: vault-grants.db bind mount (#1737)", join46(home2, ".switchroom", "vault-grants.db"), "/root/.switchroom/vault-grants.db", probe2(join46(home2, ".switchroom", "vault-grants.db"), "/root/.switchroom/vault-grants.db")),
29555
+ formatBindMountResult("vault-broker: vault-audit.log bind mount (#1025)", join46(home2, ".switchroom", "vault-audit.log"), "/root/.switchroom/vault-audit.log", probe2(join46(home2, ".switchroom", "vault-audit.log"), "/root/.switchroom/vault-audit.log"))
29556
+ ];
29557
+ }
29558
+ function probeAutoUnlockBlob(home2) {
29559
+ const blobPath = join46(home2, ".switchroom", "vault-auto-unlock");
29560
+ if (!existsSync50(blobPath)) {
29561
+ return {
29562
+ name: "vault-broker: auto-unlock blob",
29563
+ status: "warn",
29564
+ detail: `${blobPath} not present \u2014 broker will fall back to interactive unlock`,
29565
+ fix: "Run `switchroom vault broker enable-auto-unlock` to seal the blob with the current passphrase + machine-id"
29566
+ };
29567
+ }
29568
+ const sz = statSync22(blobPath).size;
29569
+ if (sz === 0) {
29570
+ return {
29571
+ name: "vault-broker: auto-unlock blob",
29572
+ status: "warn",
29573
+ detail: `${blobPath} is 0 bytes (placeholder) \u2014 broker will fall back to interactive unlock`,
29574
+ fix: "Run `switchroom vault broker enable-auto-unlock` to actually seal the blob"
29575
+ };
29576
+ }
29577
+ return {
29578
+ name: "vault-broker: auto-unlock blob",
29579
+ status: "ok",
29580
+ detail: `${blobPath} present (${sz} bytes, machine-bound)`
29581
+ };
29582
+ }
29583
+ function probeMachineIdMount() {
29584
+ const hostExists = existsSync50("/etc/machine-id");
29585
+ if (!hostExists) {
29586
+ return {
29587
+ name: "vault-broker: machine-id passthrough",
29588
+ status: "fail",
29589
+ detail: "/etc/machine-id missing on host \u2014 auto-unlock key derivation impossible",
29590
+ fix: "Generate a machine-id (`systemd-machine-id-setup`) and re-seal the auto-unlock blob"
29591
+ };
29592
+ }
29593
+ const r = spawnDockerStat("/etc/machine-id");
29594
+ if (r.error || r.status === null || r.status >= 125) {
29595
+ return {
29596
+ name: "vault-broker: machine-id passthrough",
29597
+ status: "skip",
29598
+ detail: "vault-broker container unreachable"
29599
+ };
29600
+ }
29601
+ if (r.status !== 0) {
29602
+ return {
29603
+ name: "vault-broker: machine-id passthrough",
29604
+ status: "fail",
29605
+ detail: "broker container has no /etc/machine-id \u2014 compose `/etc/machine-id:/etc/machine-id:ro` mount is missing",
29606
+ fix: "Run `switchroom apply` to regenerate compose with the machine-id passthrough"
29607
+ };
29608
+ }
29609
+ return {
29610
+ name: "vault-broker: machine-id passthrough",
29611
+ status: "ok",
29612
+ detail: "broker reads the host machine-id"
29613
+ };
29614
+ }
29615
+ var init_doctor_vault_broker_durability = () => {};
29616
+
29402
29617
  // src/cli/doctor.ts
29403
29618
  var exports_doctor = {};
29404
29619
  __export(exports_doctor, {
@@ -29444,25 +29659,25 @@ import { execSync as execSync3, spawnSync as spawnSync7 } from "node:child_proce
29444
29659
  import {
29445
29660
  accessSync as accessSync2,
29446
29661
  constants as fsConstants5,
29447
- existsSync as existsSync50,
29662
+ existsSync as existsSync51,
29448
29663
  lstatSync as lstatSync5,
29449
29664
  mkdirSync as mkdirSync27,
29450
29665
  readFileSync as readFileSync45,
29451
29666
  readdirSync as readdirSync19,
29452
- statSync as statSync22
29667
+ statSync as statSync23
29453
29668
  } from "node:fs";
29454
- import { dirname as dirname12, join as join46, resolve as resolve30 } from "node:path";
29669
+ import { dirname as dirname12, join as join47, resolve as resolve30 } from "node:path";
29455
29670
  import { createPublicKey, createPrivateKey } from "node:crypto";
29456
29671
  function findInNvm(bin) {
29457
- const nvmRoot = join46(process.env.HOME ?? "", ".nvm", "versions", "node");
29458
- if (!existsSync50(nvmRoot))
29672
+ const nvmRoot = join47(process.env.HOME ?? "", ".nvm", "versions", "node");
29673
+ if (!existsSync51(nvmRoot))
29459
29674
  return null;
29460
29675
  try {
29461
29676
  const versions = readdirSync19(nvmRoot).sort().reverse();
29462
29677
  for (const v of versions) {
29463
- const candidate = join46(nvmRoot, v, "bin", bin);
29678
+ const candidate = join47(nvmRoot, v, "bin", bin);
29464
29679
  try {
29465
- const s = statSync22(candidate);
29680
+ const s = statSync23(candidate);
29466
29681
  if (s.isFile() || s.isSymbolicLink()) {
29467
29682
  return candidate;
29468
29683
  }
@@ -29625,21 +29840,21 @@ function findChromium(homeDir = process.env.HOME ?? "", envBrowsersPath = proces
29625
29840
  if (envBrowsersPath && envBrowsersPath.length > 0) {
29626
29841
  cacheLocations.push(envBrowsersPath);
29627
29842
  }
29628
- cacheLocations.push(join46(homeDir, ".cache", "ms-playwright"));
29843
+ cacheLocations.push(join47(homeDir, ".cache", "ms-playwright"));
29629
29844
  for (const cacheDir of cacheLocations) {
29630
- if (!existsSync50(cacheDir))
29845
+ if (!existsSync51(cacheDir))
29631
29846
  continue;
29632
29847
  try {
29633
29848
  const entries = readdirSync19(cacheDir).filter((e) => e.startsWith("chromium"));
29634
29849
  for (const entry of entries) {
29635
29850
  const candidates2 = [
29636
- join46(cacheDir, entry, "chrome-linux64", "chrome"),
29637
- join46(cacheDir, entry, "chrome-linux", "chrome"),
29638
- join46(cacheDir, entry, "chrome-linux64", "headless_shell"),
29639
- join46(cacheDir, entry, "chrome-linux", "headless_shell")
29851
+ join47(cacheDir, entry, "chrome-linux64", "chrome"),
29852
+ join47(cacheDir, entry, "chrome-linux", "chrome"),
29853
+ join47(cacheDir, entry, "chrome-linux64", "headless_shell"),
29854
+ join47(cacheDir, entry, "chrome-linux", "headless_shell")
29640
29855
  ];
29641
29856
  for (const path4 of candidates2) {
29642
- if (existsSync50(path4))
29857
+ if (existsSync51(path4))
29643
29858
  return path4;
29644
29859
  }
29645
29860
  }
@@ -29719,8 +29934,8 @@ function checkConfig(config, configPath) {
29719
29934
  function checkLegacyState() {
29720
29935
  const results = [];
29721
29936
  const h = process.env.HOME ?? "/root";
29722
- const clerkDir = join46(h, LEGACY_STATE_DIR);
29723
- const clerkPresent = existsSync50(clerkDir);
29937
+ const clerkDir = join47(h, LEGACY_STATE_DIR);
29938
+ const clerkPresent = existsSync51(clerkDir);
29724
29939
  results.push({
29725
29940
  name: "legacy ~/.clerk state",
29726
29941
  status: clerkPresent ? "warn" : "ok",
@@ -29729,7 +29944,7 @@ function checkLegacyState() {
29729
29944
  fix: "Legacy state detected. Run `mv ~/.clerk ~/.switchroom` and rename " + "any top-level `clerk:` key in switchroom.yaml to `switchroom:`. " + "This back-compat shim is REMOVED in v0.13.0 \u2014 no automatic " + "migration exists."
29730
29945
  } : {}
29731
29946
  });
29732
- const legacySock = join46(h, ".switchroom", "vault-broker.sock");
29947
+ const legacySock = join47(h, ".switchroom", "vault-broker.sock");
29733
29948
  let sockStat = null;
29734
29949
  try {
29735
29950
  sockStat = lstatSync5(legacySock);
@@ -29850,7 +30065,7 @@ function checkVault(config) {
29850
30065
  detail: "Approval auth: passphrase (two-factor)"
29851
30066
  };
29852
30067
  const pairsResult = checkVaultBrokerSocketPairs(config);
29853
- if (!existsSync50(vaultPath)) {
30068
+ if (!existsSync51(vaultPath)) {
29854
30069
  return [
29855
30070
  postureResult,
29856
30071
  {
@@ -30025,8 +30240,8 @@ async function checkHindsight(config) {
30025
30240
  }
30026
30241
  function checkPendingRetainsQueue(dir) {
30027
30242
  const home2 = process.env.HOME ?? "";
30028
- const pendingDir = dir ?? process.env.HINDSIGHT_PENDING_DIR ?? join46(home2, ".hindsight", "pending-retains");
30029
- if (!existsSync50(pendingDir)) {
30243
+ const pendingDir = dir ?? process.env.HINDSIGHT_PENDING_DIR ?? join47(home2, ".hindsight", "pending-retains");
30244
+ if (!existsSync51(pendingDir)) {
30030
30245
  return {
30031
30246
  name: "pending-retains queue",
30032
30247
  status: "ok",
@@ -30097,7 +30312,7 @@ function tryReadHostFile(path4) {
30097
30312
  }
30098
30313
  }
30099
30314
  function parseEnvFile(path4) {
30100
- if (!existsSync50(path4))
30315
+ if (!existsSync51(path4))
30101
30316
  return {};
30102
30317
  let content;
30103
30318
  try {
@@ -30156,7 +30371,7 @@ async function checkTelegram(config) {
30156
30371
  const plugin = agentConfig.channels?.telegram?.plugin ?? "switchroom";
30157
30372
  if (plugin !== "switchroom")
30158
30373
  continue;
30159
- const envPath = join46(agentsDir, name, "telegram", ".env");
30374
+ const envPath = join47(agentsDir, name, "telegram", ".env");
30160
30375
  const read = tryReadHostFile(envPath);
30161
30376
  if (read.kind === "eacces") {
30162
30377
  results.push({
@@ -30208,7 +30423,7 @@ async function checkTelegram(config) {
30208
30423
  }
30209
30424
  function checkStartShStale(agentName, startShPath) {
30210
30425
  const label = `${agentName}: start.sh scheduler block`;
30211
- if (!existsSync50(startShPath)) {
30426
+ if (!existsSync51(startShPath)) {
30212
30427
  return {
30213
30428
  name: label,
30214
30429
  status: "warn",
@@ -30239,7 +30454,7 @@ function checkStartShStale(agentName, startShPath) {
30239
30454
  }
30240
30455
  function checkLeakedHomeSwitchroom(agentName, agentDir) {
30241
30456
  const label = `${agentName}: $HOME/.switchroom symlink (#910)`;
30242
- const path4 = join46(agentDir, "home", ".switchroom");
30457
+ const path4 = join47(agentDir, "home", ".switchroom");
30243
30458
  let stats;
30244
30459
  try {
30245
30460
  stats = lstatSync5(path4);
@@ -30276,8 +30491,8 @@ function checkLeakedHomeSwitchroom(agentName, agentDir) {
30276
30491
  }
30277
30492
  function checkRepoHygiene(repoRoot) {
30278
30493
  const results = [];
30279
- const exportDir = join46(repoRoot, "clerk-export");
30280
- if (existsSync50(exportDir)) {
30494
+ const exportDir = join47(repoRoot, "clerk-export");
30495
+ if (existsSync51(exportDir)) {
30281
30496
  results.push({
30282
30497
  name: "repo hygiene: clerk-export/ on disk (#1072)",
30283
30498
  status: "warn",
@@ -30285,8 +30500,8 @@ function checkRepoHygiene(repoRoot) {
30285
30500
  fix: `Run scripts/migrate-clerk-export-to-vault.sh to move the bundle ` + `into the vault, then delete the on-disk copy.`
30286
30501
  });
30287
30502
  }
30288
- const knownTarball = join46(repoRoot, "clerk-export-with-secrets.tar.gz");
30289
- if (existsSync50(knownTarball)) {
30503
+ const knownTarball = join47(repoRoot, "clerk-export-with-secrets.tar.gz");
30504
+ if (existsSync51(knownTarball)) {
30290
30505
  results.push({
30291
30506
  name: "repo hygiene: clerk-export-with-secrets.tar.gz on disk (#1072)",
30292
30507
  status: "warn",
@@ -30303,7 +30518,7 @@ function checkRepoHygiene(repoRoot) {
30303
30518
  results.push({
30304
30519
  name: `repo hygiene: ${name} on disk (#1072)`,
30305
30520
  status: "warn",
30306
- detail: `${join46(repoRoot, name)} matches the *-with-secrets*.tar.gz ` + `pattern. Likely contains real credentials.`,
30521
+ detail: `${join47(repoRoot, name)} matches the *-with-secrets*.tar.gz ` + `pattern. Likely contains real credentials.`,
30307
30522
  fix: `Inspect, migrate any secrets into the vault, then delete the ` + `archive.`
30308
30523
  });
30309
30524
  }
@@ -30326,10 +30541,10 @@ function checkRepoHygiene(repoRoot) {
30326
30541
  }
30327
30542
  function isSwitchroomCheckout(dir) {
30328
30543
  try {
30329
- if (!existsSync50(join46(dir, ".git")))
30544
+ if (!existsSync51(join47(dir, ".git")))
30330
30545
  return false;
30331
- const pkgPath = join46(dir, "package.json");
30332
- if (!existsSync50(pkgPath))
30546
+ const pkgPath = join47(dir, "package.json");
30547
+ if (!existsSync51(pkgPath))
30333
30548
  return false;
30334
30549
  const pkg = JSON.parse(readFileSync45(pkgPath, "utf-8"));
30335
30550
  return pkg.name === "switchroom";
@@ -30344,7 +30559,7 @@ function checkAgents(config, configPath) {
30344
30559
  const authStatuses = getAllAuthStatuses(config);
30345
30560
  for (const [name, agentConfig] of Object.entries(config.agents)) {
30346
30561
  const agentDir = resolve30(agentsDir, name);
30347
- if (!existsSync50(agentDir)) {
30562
+ if (!existsSync51(agentDir)) {
30348
30563
  results.push({
30349
30564
  name: `${name}: scaffold`,
30350
30565
  status: "fail",
@@ -30365,7 +30580,7 @@ function checkAgents(config, configPath) {
30365
30580
  fix: `Rotate the bot token (e.g. via \`switchroom vault\`), then run ` + `\`switchroom agent unquarantine ${name}\` and \`switchroom agent restart ${name}\``
30366
30581
  });
30367
30582
  }
30368
- results.push(checkStartShStale(name, join46(agentDir, "start.sh")));
30583
+ results.push(checkStartShStale(name, join47(agentDir, "start.sh")));
30369
30584
  results.push(checkLeakedHomeSwitchroom(name, agentDir));
30370
30585
  const status = statuses[name];
30371
30586
  const active = status?.active ?? "unknown";
@@ -30442,8 +30657,8 @@ function checkAgents(config, configPath) {
30442
30657
  }
30443
30658
  }
30444
30659
  if (agentConfig.channels?.telegram?.plugin === "switchroom") {
30445
- const mcpJsonPath = join46(agentDir, ".mcp.json");
30446
- if (!existsSync50(mcpJsonPath)) {
30660
+ const mcpJsonPath = join47(agentDir, ".mcp.json");
30661
+ if (!existsSync51(mcpJsonPath)) {
30447
30662
  results.push({
30448
30663
  name: `${name}: .mcp.json`,
30449
30664
  status: "fail",
@@ -30528,7 +30743,7 @@ function mffEnvPath(config) {
30528
30743
  return agent ? resolve30(home2, ".switchroom/credentials", agent, "my-family-finance/.env") : resolve30(home2, ".switchroom/credentials/my-family-finance/.env");
30529
30744
  }
30530
30745
  function mffEnvState(envPath) {
30531
- if (!existsSync50(envPath))
30746
+ if (!existsSync51(envPath))
30532
30747
  return "absent";
30533
30748
  try {
30534
30749
  accessSync2(envPath, fsConstants5.R_OK);
@@ -30546,7 +30761,7 @@ function checkMffVaultKeyPresent(passphrase, vaultPath) {
30546
30761
  fix: "Export SWITCHROOM_VAULT_PASSPHRASE to enable MFF vault probes"
30547
30762
  };
30548
30763
  }
30549
- if (!existsSync50(vaultPath)) {
30764
+ if (!existsSync51(vaultPath)) {
30550
30765
  return {
30551
30766
  name: "mff: vault key present",
30552
30767
  status: "fail",
@@ -30599,7 +30814,7 @@ function deriveEd25519PublicKeyBytes(keyMaterial) {
30599
30814
  }
30600
30815
  }
30601
30816
  function checkMffVaultKeyFormat(passphrase, vaultPath) {
30602
- if (!passphrase || !existsSync50(vaultPath)) {
30817
+ if (!passphrase || !existsSync51(vaultPath)) {
30603
30818
  return {
30604
30819
  name: "mff: vault key format",
30605
30820
  status: "warn",
@@ -30743,8 +30958,8 @@ async function checkMffAuthFlow(envPath = mffEnvPath(), timeoutMs = 8000) {
30743
30958
  };
30744
30959
  }
30745
30960
  const credDir = dirname12(envPath);
30746
- const authScript = join46(credDir, "claude-auth.py");
30747
- if (!existsSync50(authScript)) {
30961
+ const authScript = join47(credDir, "claude-auth.py");
30962
+ if (!existsSync51(authScript)) {
30748
30963
  return {
30749
30964
  name: "mff: auth flow",
30750
30965
  status: "warn",
@@ -31022,6 +31237,10 @@ function registerDoctorCommand(program3) {
31022
31237
  },
31023
31238
  { title: "Legacy State", results: checkLegacyState() },
31024
31239
  { title: "Vault", results: checkVault(config) },
31240
+ {
31241
+ title: "Vault-broker durability",
31242
+ results: runVaultBrokerDurabilityChecks(config)
31243
+ },
31025
31244
  { title: "Vault access", results: await runSecretAccessChecks(config) },
31026
31245
  { title: "Memory (Hindsight)", results: await checkHindsight(config) },
31027
31246
  { title: "Telegram", results: await checkTelegram(config) },
@@ -31105,6 +31324,7 @@ var init_doctor = __esm(() => {
31105
31324
  init_doctor_inlined_secrets();
31106
31325
  init_doctor_audit_integrity();
31107
31326
  init_doctor_agent_smoke();
31327
+ init_doctor_vault_broker_durability();
31108
31328
  MANIFEST_WARN_ONLY = new Set([
31109
31329
  "@playwright/mcp",
31110
31330
  "hindsight.backend",
@@ -47033,7 +47253,7 @@ __export(exports_server2, {
47033
47253
  TOOLS: () => TOOLS2
47034
47254
  });
47035
47255
  import { randomBytes as randomBytes14 } from "node:crypto";
47036
- import { existsSync as existsSync74, readFileSync as readFileSync60 } from "node:fs";
47256
+ import { existsSync as existsSync75, readFileSync as readFileSync60 } from "node:fs";
47037
47257
  function selfSocketPath() {
47038
47258
  return `/run/switchroom/hostd/${SELF_AGENT}/sock`;
47039
47259
  }
@@ -47048,7 +47268,7 @@ async function dispatchTool2(name, args) {
47048
47268
  return errorText2("hostd MCP: SWITCHROOM_AGENT_NAME env var is not set \u2014 cannot " + "determine which per-agent socket to talk to.");
47049
47269
  }
47050
47270
  const sockPath = selfSocketPath();
47051
- if (!existsSync74(sockPath)) {
47271
+ if (!existsSync75(sockPath)) {
47052
47272
  return errorText2(`hostd MCP: socket not bound at ${sockPath}. The host-control ` + `daemon is either not installed (run \`switchroom hostd install\`) ` + `or this agent isn't admin-flagged in switchroom.yaml. RFC C ` + `bind-mounts the per-agent socket only when host_control.enabled ` + `is true AND the agent has admin: true.`);
47053
47273
  }
47054
47274
  let req;
@@ -47192,13 +47412,13 @@ function resolveAuditLogPath() {
47192
47412
  if (process.env.HOSTD_AUDIT_LOG_PATH)
47193
47413
  return process.env.HOSTD_AUDIT_LOG_PATH;
47194
47414
  const bindMounted = "/host-home/.switchroom/host-control-audit.log";
47195
- if (existsSync74(bindMounted))
47415
+ if (existsSync75(bindMounted))
47196
47416
  return bindMounted;
47197
47417
  return defaultAuditLogPath2();
47198
47418
  }
47199
47419
  function getLastUpdateApplyStatus() {
47200
47420
  const path8 = resolveAuditLogPath();
47201
- if (!existsSync74(path8)) {
47421
+ if (!existsSync75(path8)) {
47202
47422
  return errorText2(`get_status: audit log not found at ${path8}. No update_apply has run yet?`);
47203
47423
  }
47204
47424
  let raw;
@@ -47436,8 +47656,8 @@ var {
47436
47656
  } = import__.default;
47437
47657
 
47438
47658
  // src/build-info.ts
47439
- var VERSION = "0.13.31";
47440
- var COMMIT_SHA = "061eead1";
47659
+ var VERSION = "0.13.33";
47660
+ var COMMIT_SHA = "a8018071";
47441
47661
 
47442
47662
  // src/cli/agent.ts
47443
47663
  init_source();
@@ -69810,17 +70030,17 @@ init_doctor();
69810
70030
  init_source();
69811
70031
  init_loader();
69812
70032
  init_lifecycle();
69813
- import { cpSync as cpSync2, existsSync as existsSync51, mkdirSync as mkdirSync28, readFileSync as readFileSync46, realpathSync as realpathSync5, rmSync as rmSync12, statSync as statSync23 } from "node:fs";
70033
+ import { cpSync as cpSync2, existsSync as existsSync52, mkdirSync as mkdirSync28, readFileSync as readFileSync46, realpathSync as realpathSync5, rmSync as rmSync12, statSync as statSync24 } from "node:fs";
69814
70034
  import { spawnSync as spawnSync8 } from "node:child_process";
69815
- import { join as join47, dirname as dirname13, resolve as resolve31 } from "node:path";
69816
- import { homedir as homedir27 } from "node:os";
69817
- var DEFAULT_COMPOSE_PATH = join47(homedir27(), ".switchroom", "compose", "docker-compose.yml");
70035
+ import { join as join48, dirname as dirname13, resolve as resolve31 } from "node:path";
70036
+ import { homedir as homedir28 } from "node:os";
70037
+ var DEFAULT_COMPOSE_PATH = join48(homedir28(), ".switchroom", "compose", "docker-compose.yml");
69818
70038
  function runningFromSwitchroomCheckout(scriptPath) {
69819
70039
  let dir = dirname13(scriptPath);
69820
70040
  for (let i = 0;i < 12; i++) {
69821
- if (existsSync51(join47(dir, ".git"))) {
70041
+ if (existsSync52(join48(dir, ".git"))) {
69822
70042
  try {
69823
- const pkg = JSON.parse(readFileSync46(join47(dir, "package.json"), "utf-8"));
70043
+ const pkg = JSON.parse(readFileSync46(join48(dir, "package.json"), "utf-8"));
69824
70044
  if (pkg.name === "switchroom")
69825
70045
  return true;
69826
70046
  } catch {}
@@ -69872,7 +70092,7 @@ function planUpdate(opts) {
69872
70092
  steps.push({
69873
70093
  name: "pull-images",
69874
70094
  description: "Pull broker / kernel / agent images from GHCR",
69875
- skipReason: opts.skipImages ? "--skip-images flag set" : !existsSync51(composePath) ? `compose file not found at ${composePath} (run \`switchroom apply --compose-only\` first)` : undefined,
70095
+ skipReason: opts.skipImages ? "--skip-images flag set" : !existsSync52(composePath) ? `compose file not found at ${composePath} (run \`switchroom apply --compose-only\` first)` : undefined,
69876
70096
  run: () => {
69877
70097
  const r = runner("docker", [
69878
70098
  "compose",
@@ -69951,14 +70171,14 @@ function planUpdate(opts) {
69951
70171
  return;
69952
70172
  }
69953
70173
  const source = resolve31(import.meta.dirname, "../../skills");
69954
- const dest = join47(homedir27(), ".switchroom", "skills", "_bundled");
69955
- if (!existsSync51(source)) {
70174
+ const dest = join48(homedir28(), ".switchroom", "skills", "_bundled");
70175
+ if (!existsSync52(source)) {
69956
70176
  process.stderr.write(`switchroom update: sync-bundled-skills \u2014 CLI bundle has no adjacent skills/ at ${source}; skipping.
69957
70177
  `);
69958
70178
  return;
69959
70179
  }
69960
70180
  try {
69961
- if (existsSync51(dest)) {
70181
+ if (existsSync52(dest)) {
69962
70182
  rmSync12(dest, { recursive: true, force: true });
69963
70183
  }
69964
70184
  mkdirSync28(dirname13(dest), { recursive: true });
@@ -70061,12 +70281,12 @@ function defaultStatusProbe(composePath) {
70061
70281
  } catch {}
70062
70282
  if (scriptPath) {
70063
70283
  try {
70064
- cliBuiltAt = new Date(statSync23(scriptPath).mtimeMs).toISOString();
70284
+ cliBuiltAt = new Date(statSync24(scriptPath).mtimeMs).toISOString();
70065
70285
  } catch {}
70066
70286
  let dir = dirname13(scriptPath);
70067
70287
  for (let i = 0;i < 8; i++) {
70068
- const pkgPath = join47(dir, "package.json");
70069
- if (existsSync51(pkgPath)) {
70288
+ const pkgPath = join48(dir, "package.json");
70289
+ if (existsSync52(pkgPath)) {
70070
70290
  try {
70071
70291
  const pkg = JSON.parse(readFileSync46(pkgPath, "utf-8"));
70072
70292
  if (typeof pkg.version === "string")
@@ -70089,7 +70309,7 @@ function defaultStatusProbe(composePath) {
70089
70309
  warnings.push("could not resolve CLI version (no package.json found above the resolved script path)");
70090
70310
  }
70091
70311
  const services = [];
70092
- if (!existsSync51(composePath)) {
70312
+ if (!existsSync52(composePath)) {
70093
70313
  warnings.push(`compose file not found at ${composePath}; service status unknown`);
70094
70314
  return { cliVersion, cliBuiltAt, services, warnings };
70095
70315
  }
@@ -70284,8 +70504,8 @@ init_source();
70284
70504
  init_helpers();
70285
70505
  init_lifecycle();
70286
70506
  import { execSync as execSync4 } from "node:child_process";
70287
- import { existsSync as existsSync52, readFileSync as readFileSync47 } from "node:fs";
70288
- import { dirname as dirname14, join as join48 } from "node:path";
70507
+ import { existsSync as existsSync53, readFileSync as readFileSync47 } from "node:fs";
70508
+ import { dirname as dirname14, join as join49 } from "node:path";
70289
70509
  function getClaudeCodeVersion() {
70290
70510
  try {
70291
70511
  const out = execSync4("claude --version 2>/dev/null", {
@@ -70335,11 +70555,11 @@ function formatUptime3(timestamp) {
70335
70555
  function locateSwitchroomInstallDir() {
70336
70556
  let dir = import.meta.dirname;
70337
70557
  for (let i = 0;i < 10 && dir && dir !== "/"; i++) {
70338
- const pkgPath = join48(dir, "package.json");
70339
- if (existsSync52(pkgPath)) {
70558
+ const pkgPath = join49(dir, "package.json");
70559
+ if (existsSync53(pkgPath)) {
70340
70560
  try {
70341
70561
  const pkg = JSON.parse(readFileSync47(pkgPath, "utf-8"));
70342
- if (pkg.name === "switchroom" && existsSync52(join48(dir, ".git"))) {
70562
+ if (pkg.name === "switchroom" && existsSync53(join49(dir, ".git"))) {
70343
70563
  return dir;
70344
70564
  }
70345
70565
  } catch {}
@@ -70554,18 +70774,18 @@ function registerHandoffCommand(program3) {
70554
70774
  // src/issues/store.ts
70555
70775
  import {
70556
70776
  closeSync as closeSync11,
70557
- existsSync as existsSync53,
70777
+ existsSync as existsSync54,
70558
70778
  mkdirSync as mkdirSync29,
70559
70779
  openSync as openSync11,
70560
70780
  readdirSync as readdirSync20,
70561
70781
  readFileSync as readFileSync48,
70562
70782
  renameSync as renameSync11,
70563
- statSync as statSync24,
70783
+ statSync as statSync25,
70564
70784
  unlinkSync as unlinkSync11,
70565
70785
  writeFileSync as writeFileSync25,
70566
70786
  writeSync as writeSync7
70567
70787
  } from "node:fs";
70568
- import { join as join49 } from "node:path";
70788
+ import { join as join50 } from "node:path";
70569
70789
  import { randomBytes as randomBytes11 } from "node:crypto";
70570
70790
  import { execSync as execSync5 } from "node:child_process";
70571
70791
 
@@ -70885,8 +71105,8 @@ function redactedMarker(ruleId) {
70885
71105
  var ISSUES_FILE = "issues.jsonl";
70886
71106
  var ISSUES_LOCK = "issues.lock";
70887
71107
  function readAll(stateDir) {
70888
- const path4 = join49(stateDir, ISSUES_FILE);
70889
- if (!existsSync53(path4))
71108
+ const path4 = join50(stateDir, ISSUES_FILE);
71109
+ if (!existsSync54(path4))
70890
71110
  return [];
70891
71111
  let raw;
70892
71112
  try {
@@ -70963,7 +71183,7 @@ function record(stateDir, input, nowFn = Date.now) {
70963
71183
  });
70964
71184
  }
70965
71185
  function resolve34(stateDir, fingerprint, nowFn = Date.now) {
70966
- if (!existsSync53(join49(stateDir, ISSUES_FILE)))
71186
+ if (!existsSync54(join50(stateDir, ISSUES_FILE)))
70967
71187
  return 0;
70968
71188
  return withLock(stateDir, () => {
70969
71189
  const all = readAll(stateDir);
@@ -70981,7 +71201,7 @@ function resolve34(stateDir, fingerprint, nowFn = Date.now) {
70981
71201
  });
70982
71202
  }
70983
71203
  function resolveAllBySource(stateDir, source, nowFn = Date.now) {
70984
- if (!existsSync53(join49(stateDir, ISSUES_FILE)))
71204
+ if (!existsSync54(join50(stateDir, ISSUES_FILE)))
70985
71205
  return 0;
70986
71206
  return withLock(stateDir, () => {
70987
71207
  const all = readAll(stateDir);
@@ -70999,7 +71219,7 @@ function resolveAllBySource(stateDir, source, nowFn = Date.now) {
70999
71219
  });
71000
71220
  }
71001
71221
  function prune(stateDir, opts = {}) {
71002
- if (!existsSync53(join49(stateDir, ISSUES_FILE)))
71222
+ if (!existsSync54(join50(stateDir, ISSUES_FILE)))
71003
71223
  return 0;
71004
71224
  return withLock(stateDir, () => {
71005
71225
  const all = readAll(stateDir);
@@ -71032,7 +71252,7 @@ function ensureDir(stateDir) {
71032
71252
  mkdirSync29(stateDir, { recursive: true });
71033
71253
  }
71034
71254
  function writeAll(stateDir, events) {
71035
- const path4 = join49(stateDir, ISSUES_FILE);
71255
+ const path4 = join50(stateDir, ISSUES_FILE);
71036
71256
  sweepOrphanTmpFiles(stateDir);
71037
71257
  const tmp = `${path4}.tmp-${process.pid}-${randomBytes11(4).toString("hex")}`;
71038
71258
  const body = events.length === 0 ? "" : events.map((e) => JSON.stringify(e)).join(`
@@ -71054,9 +71274,9 @@ function sweepOrphanTmpFiles(stateDir) {
71054
71274
  for (const entry of entries) {
71055
71275
  if (!entry.startsWith(TMP_PREFIX))
71056
71276
  continue;
71057
- const tmpPath = join49(stateDir, entry);
71277
+ const tmpPath = join50(stateDir, entry);
71058
71278
  try {
71059
- const stat = statSync24(tmpPath);
71279
+ const stat = statSync25(tmpPath);
71060
71280
  if (stat.mtimeMs < cutoff) {
71061
71281
  unlinkSync11(tmpPath);
71062
71282
  }
@@ -71066,7 +71286,7 @@ function sweepOrphanTmpFiles(stateDir) {
71066
71286
  var LOCK_RETRY_MS = 25;
71067
71287
  var LOCK_TIMEOUT_MS = 1e4;
71068
71288
  function withLock(stateDir, fn) {
71069
- const lockPath = join49(stateDir, ISSUES_LOCK);
71289
+ const lockPath = join50(stateDir, ISSUES_LOCK);
71070
71290
  const startedAt = Date.now();
71071
71291
  let fd = null;
71072
71292
  while (fd === null) {
@@ -71349,22 +71569,22 @@ function relTime(deltaMs) {
71349
71569
 
71350
71570
  // src/cli/deps.ts
71351
71571
  init_source();
71352
- import { existsSync as existsSync56 } from "node:fs";
71353
- import { homedir as homedir30 } from "node:os";
71354
- import { join as join52, resolve as resolve35 } from "node:path";
71572
+ import { existsSync as existsSync57 } from "node:fs";
71573
+ import { homedir as homedir31 } from "node:os";
71574
+ import { join as join53, resolve as resolve35 } from "node:path";
71355
71575
 
71356
71576
  // src/deps/python.ts
71357
71577
  import { createHash as createHash10 } from "node:crypto";
71358
71578
  import {
71359
- existsSync as existsSync54,
71579
+ existsSync as existsSync55,
71360
71580
  mkdirSync as mkdirSync30,
71361
71581
  readFileSync as readFileSync49,
71362
71582
  rmSync as rmSync13,
71363
71583
  writeFileSync as writeFileSync26
71364
71584
  } from "node:fs";
71365
- import { dirname as dirname15, join as join50 } from "node:path";
71366
- import { homedir as homedir28 } from "node:os";
71367
- import { execFileSync as execFileSync14 } from "node:child_process";
71585
+ import { dirname as dirname15, join as join51 } from "node:path";
71586
+ import { homedir as homedir29 } from "node:os";
71587
+ import { execFileSync as execFileSync15 } from "node:child_process";
71368
71588
 
71369
71589
  class PythonEnvError extends Error {
71370
71590
  stderr;
@@ -71375,7 +71595,7 @@ class PythonEnvError extends Error {
71375
71595
  }
71376
71596
  }
71377
71597
  function defaultPythonCacheRoot() {
71378
- return join50(homedir28(), ".switchroom", "deps", "python");
71598
+ return join51(homedir29(), ".switchroom", "deps", "python");
71379
71599
  }
71380
71600
  function hashFile(path4) {
71381
71601
  return createHash10("sha256").update(readFileSync49(path4)).digest("hex");
@@ -71384,16 +71604,16 @@ function ensurePythonEnv(opts) {
71384
71604
  const { skillName, requirementsPath, force = false } = opts;
71385
71605
  const cacheRoot = opts.cacheRoot ?? defaultPythonCacheRoot();
71386
71606
  const hostPython = opts.pythonBin ?? "python3";
71387
- if (!existsSync54(requirementsPath)) {
71607
+ if (!existsSync55(requirementsPath)) {
71388
71608
  throw new PythonEnvError(`requirements file not found: ${requirementsPath}`);
71389
71609
  }
71390
- const venvDir = join50(cacheRoot, skillName);
71391
- const stampPath = join50(venvDir, ".requirements.sha256");
71392
- const binDir = join50(venvDir, "bin");
71393
- const pythonBin = join50(binDir, "python");
71394
- const pipBin = join50(binDir, "pip");
71610
+ const venvDir = join51(cacheRoot, skillName);
71611
+ const stampPath = join51(venvDir, ".requirements.sha256");
71612
+ const binDir = join51(venvDir, "bin");
71613
+ const pythonBin = join51(binDir, "python");
71614
+ const pipBin = join51(binDir, "pip");
71395
71615
  const targetHash = hashFile(requirementsPath);
71396
- if (!force && existsSync54(stampPath) && existsSync54(pythonBin)) {
71616
+ if (!force && existsSync55(stampPath) && existsSync55(pythonBin)) {
71397
71617
  const existingHash = readFileSync49(stampPath, "utf8").trim();
71398
71618
  if (existingHash === targetHash) {
71399
71619
  return {
@@ -71406,12 +71626,12 @@ function ensurePythonEnv(opts) {
71406
71626
  };
71407
71627
  }
71408
71628
  }
71409
- if (existsSync54(venvDir)) {
71629
+ if (existsSync55(venvDir)) {
71410
71630
  rmSync13(venvDir, { recursive: true, force: true });
71411
71631
  }
71412
71632
  mkdirSync30(dirname15(venvDir), { recursive: true });
71413
71633
  try {
71414
- execFileSync14(hostPython, ["-m", "venv", venvDir], { stdio: "pipe" });
71634
+ execFileSync15(hostPython, ["-m", "venv", venvDir], { stdio: "pipe" });
71415
71635
  } catch (err) {
71416
71636
  const e = err;
71417
71637
  throw new PythonEnvError(`Failed to create venv for skill "${skillName}" with ${hostPython}: ${e.message}`, e.stderr?.toString());
@@ -71423,7 +71643,7 @@ function ensurePythonEnv(opts) {
71423
71643
  delete childEnv.PIP_TARGET;
71424
71644
  delete childEnv.PIP_PREFIX;
71425
71645
  delete childEnv.PYTHONUSERBASE;
71426
- execFileSync14(pipBin, ["install", "--disable-pip-version-check", "-r", requirementsPath], { stdio: "pipe", env: childEnv });
71646
+ execFileSync15(pipBin, ["install", "--disable-pip-version-check", "-r", requirementsPath], { stdio: "pipe", env: childEnv });
71427
71647
  } catch (err) {
71428
71648
  const e = err;
71429
71649
  throw new PythonEnvError(`Failed to install requirements for skill "${skillName}": ${e.message}`, e.stderr?.toString());
@@ -71444,15 +71664,15 @@ function ensurePythonEnv(opts) {
71444
71664
  import { createHash as createHash11 } from "node:crypto";
71445
71665
  import {
71446
71666
  copyFileSync as copyFileSync9,
71447
- existsSync as existsSync55,
71667
+ existsSync as existsSync56,
71448
71668
  mkdirSync as mkdirSync31,
71449
71669
  readFileSync as readFileSync50,
71450
71670
  rmSync as rmSync14,
71451
71671
  writeFileSync as writeFileSync27
71452
71672
  } from "node:fs";
71453
- import { dirname as dirname16, join as join51 } from "node:path";
71454
- import { homedir as homedir29 } from "node:os";
71455
- import { execFileSync as execFileSync15 } from "node:child_process";
71673
+ import { dirname as dirname16, join as join52 } from "node:path";
71674
+ import { homedir as homedir30 } from "node:os";
71675
+ import { execFileSync as execFileSync16 } from "node:child_process";
71456
71676
 
71457
71677
  class NodeEnvError extends Error {
71458
71678
  stderr;
@@ -71474,7 +71694,7 @@ var LOCKFILES_FOR = {
71474
71694
  npm: ["package-lock.json"]
71475
71695
  };
71476
71696
  function defaultNodeCacheRoot() {
71477
- return join51(homedir29(), ".switchroom", "deps", "node");
71697
+ return join52(homedir30(), ".switchroom", "deps", "node");
71478
71698
  }
71479
71699
  function hashDepInputs(packageJsonPath) {
71480
71700
  const sourceDir = dirname16(packageJsonPath);
@@ -71483,8 +71703,8 @@ function hashDepInputs(packageJsonPath) {
71483
71703
  `);
71484
71704
  hasher.update(readFileSync50(packageJsonPath));
71485
71705
  for (const lockName of ALL_LOCKFILES) {
71486
- const lockPath = join51(sourceDir, lockName);
71487
- if (existsSync55(lockPath)) {
71706
+ const lockPath = join52(sourceDir, lockName);
71707
+ if (existsSync56(lockPath)) {
71488
71708
  hasher.update(`
71489
71709
  `);
71490
71710
  hasher.update(lockName);
@@ -71499,16 +71719,16 @@ function ensureNodeEnv(opts) {
71499
71719
  const { skillName, packageJsonPath, force = false } = opts;
71500
71720
  const cacheRoot = opts.cacheRoot ?? defaultNodeCacheRoot();
71501
71721
  const installer = opts.installer ?? "bun";
71502
- if (!existsSync55(packageJsonPath)) {
71722
+ if (!existsSync56(packageJsonPath)) {
71503
71723
  throw new NodeEnvError(`package.json not found: ${packageJsonPath}`);
71504
71724
  }
71505
71725
  const sourceDir = dirname16(packageJsonPath);
71506
- const envDir = join51(cacheRoot, skillName);
71507
- const stampPath = join51(envDir, ".package.sha256");
71508
- const nodeModulesDir = join51(envDir, "node_modules");
71509
- const binDir = join51(nodeModulesDir, ".bin");
71726
+ const envDir = join52(cacheRoot, skillName);
71727
+ const stampPath = join52(envDir, ".package.sha256");
71728
+ const nodeModulesDir = join52(envDir, "node_modules");
71729
+ const binDir = join52(nodeModulesDir, ".bin");
71510
71730
  const targetHash = hashDepInputs(packageJsonPath);
71511
- if (!force && existsSync55(stampPath) && existsSync55(nodeModulesDir)) {
71731
+ if (!force && existsSync56(stampPath) && existsSync56(nodeModulesDir)) {
71512
71732
  const existingHash = readFileSync50(stampPath, "utf8").trim();
71513
71733
  if (existingHash === targetHash) {
71514
71734
  return {
@@ -71520,26 +71740,26 @@ function ensureNodeEnv(opts) {
71520
71740
  };
71521
71741
  }
71522
71742
  }
71523
- if (existsSync55(envDir)) {
71743
+ if (existsSync56(envDir)) {
71524
71744
  rmSync14(envDir, { recursive: true, force: true });
71525
71745
  }
71526
71746
  mkdirSync31(envDir, { recursive: true });
71527
- copyFileSync9(packageJsonPath, join51(envDir, "package.json"));
71747
+ copyFileSync9(packageJsonPath, join52(envDir, "package.json"));
71528
71748
  let copiedLockfile = false;
71529
71749
  for (const lockName of LOCKFILES_FOR[installer]) {
71530
- const lockPath = join51(sourceDir, lockName);
71531
- if (existsSync55(lockPath)) {
71532
- copyFileSync9(lockPath, join51(envDir, lockName));
71750
+ const lockPath = join52(sourceDir, lockName);
71751
+ if (existsSync56(lockPath)) {
71752
+ copyFileSync9(lockPath, join52(envDir, lockName));
71533
71753
  copiedLockfile = true;
71534
71754
  }
71535
71755
  }
71536
71756
  try {
71537
71757
  if (installer === "bun") {
71538
71758
  const args = copiedLockfile ? ["install", "--frozen-lockfile"] : ["install"];
71539
- execFileSync15("bun", args, { cwd: envDir, stdio: "pipe" });
71759
+ execFileSync16("bun", args, { cwd: envDir, stdio: "pipe" });
71540
71760
  } else {
71541
71761
  const args = copiedLockfile ? ["ci"] : ["install"];
71542
- execFileSync15("npm", args, { cwd: envDir, stdio: "pipe" });
71762
+ execFileSync16("npm", args, { cwd: envDir, stdio: "pipe" });
71543
71763
  }
71544
71764
  } catch (err) {
71545
71765
  const e = err;
@@ -71558,28 +71778,28 @@ function ensureNodeEnv(opts) {
71558
71778
 
71559
71779
  // src/cli/deps.ts
71560
71780
  function builtinSkillsRoot() {
71561
- return resolve35(homedir30(), ".switchroom/skills/_bundled");
71781
+ return resolve35(homedir31(), ".switchroom/skills/_bundled");
71562
71782
  }
71563
71783
  function registerDepsCommand(program3) {
71564
71784
  const deps = program3.command("deps").description("Manage cached per-skill dependency environments");
71565
71785
  deps.command("rebuild <skill>").description("Rebuild the Python venv and/or Node node_modules cache for a skill").option("-p, --python", "Rebuild only the Python env").option("-n, --node", "Rebuild only the Node env").action(async (skill, opts) => {
71566
71786
  const skillsRoot = builtinSkillsRoot();
71567
- if (!existsSync56(skillsRoot)) {
71787
+ if (!existsSync57(skillsRoot)) {
71568
71788
  console.error(source_default.red(`Bundled skills pool dir not found at ${skillsRoot} \u2014 run \`switchroom update\` to install it.`));
71569
71789
  process.exit(1);
71570
71790
  }
71571
- const skillDir = join52(skillsRoot, skill);
71572
- if (!existsSync56(skillDir)) {
71791
+ const skillDir = join53(skillsRoot, skill);
71792
+ if (!existsSync57(skillDir)) {
71573
71793
  console.error(source_default.red(`Unknown skill: ${skill} (no dir at ${skillDir})`));
71574
71794
  process.exit(1);
71575
71795
  }
71576
- const requirementsPath = join52(skillDir, "requirements.txt");
71577
- const packageJsonPath = join52(skillDir, "package.json");
71578
- const wantPython = opts.python ?? (!opts.python && !opts.node && existsSync56(requirementsPath));
71579
- const wantNode = opts.node ?? (!opts.python && !opts.node && existsSync56(packageJsonPath));
71796
+ const requirementsPath = join53(skillDir, "requirements.txt");
71797
+ const packageJsonPath = join53(skillDir, "package.json");
71798
+ const wantPython = opts.python ?? (!opts.python && !opts.node && existsSync57(requirementsPath));
71799
+ const wantNode = opts.node ?? (!opts.python && !opts.node && existsSync57(packageJsonPath));
71580
71800
  let did = 0;
71581
71801
  if (wantPython) {
71582
- if (!existsSync56(requirementsPath)) {
71802
+ if (!existsSync57(requirementsPath)) {
71583
71803
  console.error(source_default.red(`Skill "${skill}" has no requirements.txt at ${requirementsPath}`));
71584
71804
  process.exit(1);
71585
71805
  }
@@ -71603,7 +71823,7 @@ function registerDepsCommand(program3) {
71603
71823
  }
71604
71824
  }
71605
71825
  if (wantNode) {
71606
- if (!existsSync56(packageJsonPath)) {
71826
+ if (!existsSync57(packageJsonPath)) {
71607
71827
  console.error(source_default.red(`Skill "${skill}" has no package.json at ${packageJsonPath}`));
71608
71828
  process.exit(1);
71609
71829
  }
@@ -71636,7 +71856,7 @@ function registerDepsCommand(program3) {
71636
71856
  // src/cli/workspace.ts
71637
71857
  init_helpers();
71638
71858
  init_loader();
71639
- import { existsSync as existsSync57 } from "node:fs";
71859
+ import { existsSync as existsSync58 } from "node:fs";
71640
71860
  import { resolve as resolve36, sep as sep3 } from "node:path";
71641
71861
  import { spawnSync as spawnSync9 } from "node:child_process";
71642
71862
 
@@ -72413,7 +72633,7 @@ function registerWorkspaceCommand(program3) {
72413
72633
  if (!dir)
72414
72634
  return;
72415
72635
  const gitDir = resolve36(dir, ".git");
72416
- if (!existsSync57(gitDir)) {
72636
+ if (!existsSync58(gitDir)) {
72417
72637
  process.stdout.write(`Workspace is not a git repository. Re-run \`switchroom agent create ${agentName}\` ` + `or manually \`git init\` in ${dir} to enable versioning.
72418
72638
  `);
72419
72639
  return;
@@ -72467,7 +72687,7 @@ function registerWorkspaceCommand(program3) {
72467
72687
  if (!dir)
72468
72688
  return;
72469
72689
  const gitDir = resolve36(dir, ".git");
72470
- if (!existsSync57(gitDir)) {
72690
+ if (!existsSync58(gitDir)) {
72471
72691
  process.stdout.write(`Workspace is not a git repository.
72472
72692
  `);
72473
72693
  return;
@@ -72492,7 +72712,7 @@ function resolveAgentWorkspaceDirOrExit(program3, agentName) {
72492
72712
  const agentsDir = resolveAgentsDir(config);
72493
72713
  const agentDir = resolve36(agentsDir, agentName);
72494
72714
  const dir = resolveAgentWorkspaceDir(agentDir);
72495
- if (!existsSync57(dir)) {
72715
+ if (!existsSync58(dir)) {
72496
72716
  process.stderr.write(`workspace: ${dir} does not exist yet. Run \`switchroom setup\` or \`switchroom agent scaffold ${agentName}\` to seed it.
72497
72717
  `);
72498
72718
  return;
@@ -72528,8 +72748,8 @@ function safeParseInt(value, fallback) {
72528
72748
  init_helpers();
72529
72749
  init_loader();
72530
72750
  init_merge();
72531
- import { copyFileSync as copyFileSync10, existsSync as existsSync58, readFileSync as readFileSync51, writeFileSync as writeFileSync28 } from "node:fs";
72532
- import { join as join53, resolve as resolve37 } from "node:path";
72751
+ import { copyFileSync as copyFileSync10, existsSync as existsSync59, readFileSync as readFileSync51, writeFileSync as writeFileSync28 } from "node:fs";
72752
+ import { join as join54, resolve as resolve37 } from "node:path";
72533
72753
  init_schema();
72534
72754
  function resolveSoulTargetOrExit(program3, agentName) {
72535
72755
  const config = getConfig(program3);
@@ -72544,7 +72764,7 @@ function resolveSoulTargetOrExit(program3, agentName) {
72544
72764
  const agentsDir = resolveAgentsDir(config);
72545
72765
  const agentDir = resolve37(agentsDir, agentName);
72546
72766
  const workspaceDir = resolveAgentWorkspaceDir(agentDir);
72547
- if (!existsSync58(workspaceDir)) {
72767
+ if (!existsSync59(workspaceDir)) {
72548
72768
  console.error(`soul: ${workspaceDir} does not exist yet. Run \`switchroom setup\` ` + `or \`switchroom agent scaffold ${agentName}\` to seed it.`);
72549
72769
  process.exit(1);
72550
72770
  }
@@ -72553,7 +72773,7 @@ function resolveSoulTargetOrExit(program3, agentName) {
72553
72773
  profileName,
72554
72774
  profilePath,
72555
72775
  workspaceDir,
72556
- soulPath: join53(workspaceDir, "SOUL.md"),
72776
+ soulPath: join54(workspaceDir, "SOUL.md"),
72557
72777
  soul: merged.soul
72558
72778
  };
72559
72779
  }
@@ -72570,7 +72790,7 @@ function registerSoulCommand(program3) {
72570
72790
  const t = resolveSoulTargetOrExit(program3, agentName);
72571
72791
  if (!t)
72572
72792
  return;
72573
- if (!existsSync58(t.soulPath)) {
72793
+ if (!existsSync59(t.soulPath)) {
72574
72794
  console.error(`soul: ${t.soulPath} does not exist yet \u2014 run ` + `\`switchroom soul reset ${agentName}\` to seed it.`);
72575
72795
  process.exit(1);
72576
72796
  }
@@ -72585,7 +72805,7 @@ function registerSoulCommand(program3) {
72585
72805
  console.error(`soul: profile "${t.profileName}" ships no SOUL.md.hbs \u2014 ` + `nothing to re-seed from.`);
72586
72806
  process.exit(1);
72587
72807
  }
72588
- const exists = existsSync58(t.soulPath);
72808
+ const exists = existsSync59(t.soulPath);
72589
72809
  if (exists && !opts.yes) {
72590
72810
  if (!isInteractive()) {
72591
72811
  console.error(`soul: ${t.soulPath} already exists. Re-run with --yes to ` + `replace it (the current file is backed up to SOUL.md.bak).`);
@@ -72600,7 +72820,7 @@ function registerSoulCommand(program3) {
72600
72820
  let backupPath;
72601
72821
  if (exists) {
72602
72822
  backupPath = `${t.soulPath}.bak`;
72603
- if (existsSync58(backupPath)) {
72823
+ if (existsSync59(backupPath)) {
72604
72824
  backupPath = `${t.soulPath}.bak.${Date.now()}`;
72605
72825
  }
72606
72826
  copyFileSync10(t.soulPath, backupPath);
@@ -72619,8 +72839,8 @@ function registerSoulCommand(program3) {
72619
72839
  // src/cli/debug.ts
72620
72840
  init_helpers();
72621
72841
  init_loader();
72622
- import { existsSync as existsSync59, readFileSync as readFileSync52, readdirSync as readdirSync21, statSync as statSync25 } from "node:fs";
72623
- import { resolve as resolve38, join as join54 } from "node:path";
72842
+ import { existsSync as existsSync60, readFileSync as readFileSync52, readdirSync as readdirSync21, statSync as statSync26 } from "node:fs";
72843
+ import { resolve as resolve38, join as join55 } from "node:path";
72624
72844
  import { createHash as createHash12 } from "node:crypto";
72625
72845
  init_merge();
72626
72846
  init_hindsight();
@@ -72634,8 +72854,8 @@ function sha256(content) {
72634
72854
  return createHash12("sha256").update(content).digest("hex").slice(0, 16);
72635
72855
  }
72636
72856
  function findLatestTranscriptJsonl(claudeConfigDir) {
72637
- const projectsDir = join54(claudeConfigDir, "projects");
72638
- if (!existsSync59(projectsDir))
72857
+ const projectsDir = join55(claudeConfigDir, "projects");
72858
+ if (!existsSync60(projectsDir))
72639
72859
  return;
72640
72860
  try {
72641
72861
  const entries = readdirSync21(projectsDir, { withFileTypes: true });
@@ -72643,11 +72863,11 @@ function findLatestTranscriptJsonl(claudeConfigDir) {
72643
72863
  for (const entry of entries) {
72644
72864
  if (!entry.isDirectory())
72645
72865
  continue;
72646
- const projectPath = join54(projectsDir, entry.name);
72647
- const transcriptPath = join54(projectPath, "transcript.jsonl");
72648
- if (!existsSync59(transcriptPath))
72866
+ const projectPath = join55(projectsDir, entry.name);
72867
+ const transcriptPath = join55(projectPath, "transcript.jsonl");
72868
+ if (!existsSync60(transcriptPath))
72649
72869
  continue;
72650
- const stat3 = statSync25(transcriptPath);
72870
+ const stat3 = statSync26(transcriptPath);
72651
72871
  if (!latest || stat3.mtimeMs > latest.mtime) {
72652
72872
  latest = { path: transcriptPath, mtime: stat3.mtimeMs };
72653
72873
  }
@@ -72708,16 +72928,16 @@ function registerDebugCommand(program3) {
72708
72928
  }
72709
72929
  const agentsDir = resolveAgentsDir(config);
72710
72930
  const agentDir = resolve38(agentsDir, agentName);
72711
- if (!existsSync59(agentDir)) {
72931
+ if (!existsSync60(agentDir)) {
72712
72932
  console.error(`Agent directory not found: ${agentDir}`);
72713
72933
  process.exit(1);
72714
72934
  }
72715
72935
  const workspaceDir = resolveAgentWorkspaceDir(agentDir);
72716
- const claudeConfigDir = join54(agentDir, ".claude");
72717
- const claudeMdPath = join54(agentDir, "CLAUDE.md");
72718
- const soulMdPath = join54(agentDir, "SOUL.md");
72719
- const workspaceSoulMdPath = join54(workspaceDir, "SOUL.md");
72720
- const handoffPath = join54(agentDir, ".handoff.md");
72936
+ const claudeConfigDir = join55(agentDir, ".claude");
72937
+ const claudeMdPath = join55(agentDir, "CLAUDE.md");
72938
+ const soulMdPath = join55(agentDir, "SOUL.md");
72939
+ const workspaceSoulMdPath = join55(workspaceDir, "SOUL.md");
72940
+ const handoffPath = join55(agentDir, ".handoff.md");
72721
72941
  const lastN = parseInt(opts.last, 10);
72722
72942
  if (isNaN(lastN) || lastN < 1) {
72723
72943
  console.error("--last must be a positive integer");
@@ -72763,7 +72983,7 @@ function registerDebugCommand(program3) {
72763
72983
  }
72764
72984
  console.log(`=== Append System Prompt (per-session) ===
72765
72985
  `);
72766
- const handoffContent = existsSync59(handoffPath) ? readFileSync52(handoffPath, "utf-8") : "";
72986
+ const handoffContent = existsSync60(handoffPath) ? readFileSync52(handoffPath, "utf-8") : "";
72767
72987
  if (handoffContent.trim().length > 0) {
72768
72988
  console.log(`-- Handoff Briefing (${formatBytes(handoffContent.length)}) --`);
72769
72989
  console.log(handoffContent);
@@ -72774,7 +72994,7 @@ function registerDebugCommand(program3) {
72774
72994
  }
72775
72995
  console.log(`=== CLAUDE.md (auto-loaded by Claude Code) ===
72776
72996
  `);
72777
- const claudeMdContent = existsSync59(claudeMdPath) ? readFileSync52(claudeMdPath, "utf-8") : "";
72997
+ const claudeMdContent = existsSync60(claudeMdPath) ? readFileSync52(claudeMdPath, "utf-8") : "";
72778
72998
  if (claudeMdContent.trim().length > 0) {
72779
72999
  console.log(`(${formatBytes(claudeMdContent.length)})`);
72780
73000
  console.log(claudeMdContent);
@@ -72785,7 +73005,7 @@ function registerDebugCommand(program3) {
72785
73005
  }
72786
73006
  console.log(`=== Persona (SOUL.md) ===
72787
73007
  `);
72788
- const soulMdContent = existsSync59(soulMdPath) ? readFileSync52(soulMdPath, "utf-8") : existsSync59(workspaceSoulMdPath) ? readFileSync52(workspaceSoulMdPath, "utf-8") : "";
73008
+ const soulMdContent = existsSync60(soulMdPath) ? readFileSync52(soulMdPath, "utf-8") : existsSync60(workspaceSoulMdPath) ? readFileSync52(workspaceSoulMdPath, "utf-8") : "";
72789
73009
  if (soulMdContent.trim().length > 0) {
72790
73010
  console.log(`(${formatBytes(soulMdContent.length)})`);
72791
73011
  console.log(soulMdContent);
@@ -72865,10 +73085,10 @@ function registerDebugCommand(program3) {
72865
73085
  init_source();
72866
73086
 
72867
73087
  // src/worktree/claim.ts
72868
- import { execFileSync as execFileSync16 } from "node:child_process";
72869
- import { closeSync as closeSync12, mkdirSync as mkdirSync33, openSync as openSync12, existsSync as existsSync61, unlinkSync as unlinkSync13 } from "node:fs";
72870
- import { join as join56, resolve as resolve40 } from "node:path";
72871
- import { homedir as homedir32 } from "node:os";
73088
+ import { execFileSync as execFileSync17 } from "node:child_process";
73089
+ import { closeSync as closeSync12, mkdirSync as mkdirSync33, openSync as openSync12, existsSync as existsSync62, unlinkSync as unlinkSync13 } from "node:fs";
73090
+ import { join as join57, resolve as resolve40 } from "node:path";
73091
+ import { homedir as homedir33 } from "node:os";
72872
73092
  import { randomBytes as randomBytes12 } from "node:crypto";
72873
73093
 
72874
73094
  // src/worktree/registry.ts
@@ -72878,16 +73098,16 @@ import {
72878
73098
  readFileSync as readFileSync53,
72879
73099
  readdirSync as readdirSync22,
72880
73100
  unlinkSync as unlinkSync12,
72881
- existsSync as existsSync60,
73101
+ existsSync as existsSync61,
72882
73102
  renameSync as renameSync12
72883
73103
  } from "node:fs";
72884
- import { join as join55, resolve as resolve39 } from "node:path";
72885
- import { homedir as homedir31 } from "node:os";
73104
+ import { join as join56, resolve as resolve39 } from "node:path";
73105
+ import { homedir as homedir32 } from "node:os";
72886
73106
  function registryDir() {
72887
- return resolve39(process.env.SWITCHROOM_WORKTREE_DIR ?? join55(homedir31(), ".switchroom", "worktrees"));
73107
+ return resolve39(process.env.SWITCHROOM_WORKTREE_DIR ?? join56(homedir32(), ".switchroom", "worktrees"));
72888
73108
  }
72889
73109
  function recordPath(id) {
72890
- return join55(registryDir(), `${id}.json`);
73110
+ return join56(registryDir(), `${id}.json`);
72891
73111
  }
72892
73112
  function ensureDir2() {
72893
73113
  mkdirSync32(registryDir(), { recursive: true });
@@ -72938,7 +73158,7 @@ function acquireRepoLock(repoPath) {
72938
73158
  const lockDir = registryDir();
72939
73159
  mkdirSync33(lockDir, { recursive: true });
72940
73160
  const lockName = repoPath.replace(/[^A-Za-z0-9]/g, "_");
72941
- const lockPath = join56(lockDir, `.lock-${lockName}`);
73161
+ const lockPath = join57(lockDir, `.lock-${lockName}`);
72942
73162
  const deadline = Date.now() + 5000;
72943
73163
  let fd = null;
72944
73164
  while (fd === null) {
@@ -72965,7 +73185,7 @@ function acquireRepoLock(repoPath) {
72965
73185
  }
72966
73186
  var DEFAULT_CONCURRENCY = 5;
72967
73187
  function worktreesBaseDir() {
72968
- return resolve40(process.env.SWITCHROOM_WORKTREE_BASE ?? join56(homedir32(), ".switchroom", "worktree-checkouts"));
73188
+ return resolve40(process.env.SWITCHROOM_WORKTREE_BASE ?? join57(homedir33(), ".switchroom", "worktree-checkouts"));
72969
73189
  }
72970
73190
  function shortId() {
72971
73191
  return randomBytes12(4).toString("hex");
@@ -72987,12 +73207,12 @@ function resolveRepoPath(repo, codeRepos) {
72987
73207
  }
72988
73208
  function expandHome(p) {
72989
73209
  if (p.startsWith("~/"))
72990
- return join56(homedir32(), p.slice(2));
73210
+ return join57(homedir33(), p.slice(2));
72991
73211
  return p;
72992
73212
  }
72993
73213
  async function claimWorktree(input, codeRepos) {
72994
73214
  const repoPath = resolveRepoPath(input.repo, codeRepos);
72995
- if (!existsSync61(repoPath)) {
73215
+ if (!existsSync62(repoPath)) {
72996
73216
  throw new Error(`Repository path does not exist: ${repoPath}`);
72997
73217
  }
72998
73218
  let concurrencyCap = DEFAULT_CONCURRENCY;
@@ -73015,7 +73235,7 @@ async function claimWorktree(input, codeRepos) {
73015
73235
  branch = `task/${taskSuffix}-${id}`;
73016
73236
  const baseDir = worktreesBaseDir();
73017
73237
  mkdirSync33(baseDir, { recursive: true });
73018
- worktreePath = join56(baseDir, `${id}-${taskSuffix}`);
73238
+ worktreePath = join57(baseDir, `${id}-${taskSuffix}`);
73019
73239
  const now = new Date().toISOString();
73020
73240
  const record2 = {
73021
73241
  id,
@@ -73032,7 +73252,7 @@ async function claimWorktree(input, codeRepos) {
73032
73252
  releaseLock();
73033
73253
  }
73034
73254
  try {
73035
- execFileSync16("git", ["worktree", "add", "-b", branch, worktreePath], {
73255
+ execFileSync17("git", ["worktree", "add", "-b", branch, worktreePath], {
73036
73256
  cwd: repoPath,
73037
73257
  stdio: "pipe"
73038
73258
  });
@@ -73045,8 +73265,8 @@ async function claimWorktree(input, codeRepos) {
73045
73265
  }
73046
73266
 
73047
73267
  // src/worktree/release.ts
73048
- import { execFileSync as execFileSync17 } from "node:child_process";
73049
- import { existsSync as existsSync62 } from "node:fs";
73268
+ import { execFileSync as execFileSync18 } from "node:child_process";
73269
+ import { existsSync as existsSync63 } from "node:fs";
73050
73270
  function releaseWorktree(input) {
73051
73271
  const { id } = input;
73052
73272
  const record2 = readRecord(id);
@@ -73054,9 +73274,9 @@ function releaseWorktree(input) {
73054
73274
  return { released: true };
73055
73275
  }
73056
73276
  let gitSuccess = true;
73057
- if (existsSync62(record2.path)) {
73277
+ if (existsSync63(record2.path)) {
73058
73278
  try {
73059
- execFileSync17("git", ["worktree", "remove", "--force", record2.path], {
73279
+ execFileSync18("git", ["worktree", "remove", "--force", record2.path], {
73060
73280
  cwd: record2.repo,
73061
73281
  stdio: "pipe"
73062
73282
  });
@@ -73092,16 +73312,16 @@ function listWorktrees() {
73092
73312
  }
73093
73313
 
73094
73314
  // src/worktree/reaper.ts
73095
- import { execFileSync as execFileSync18 } from "node:child_process";
73096
- import { existsSync as existsSync63 } from "node:fs";
73315
+ import { execFileSync as execFileSync19 } from "node:child_process";
73316
+ import { existsSync as existsSync64 } from "node:fs";
73097
73317
  var STALE_THRESHOLD_MS = 10 * 60 * 1000;
73098
73318
  function isPathInUse(path7) {
73099
73319
  try {
73100
- execFileSync18("fuser", [path7], { stdio: "pipe" });
73320
+ execFileSync19("fuser", [path7], { stdio: "pipe" });
73101
73321
  return true;
73102
73322
  } catch {}
73103
73323
  try {
73104
- const out = execFileSync18("lsof", ["-t", path7], {
73324
+ const out = execFileSync19("lsof", ["-t", path7], {
73105
73325
  stdio: ["ignore", "pipe", "ignore"]
73106
73326
  }).toString().trim();
73107
73327
  if (out.length > 0)
@@ -73111,7 +73331,7 @@ function isPathInUse(path7) {
73111
73331
  }
73112
73332
  function hasUncommittedChanges(repoPath, worktreePath) {
73113
73333
  try {
73114
- const out = execFileSync18("git", ["-C", worktreePath, "status", "--porcelain"], { stdio: "pipe" }).toString();
73334
+ const out = execFileSync19("git", ["-C", worktreePath, "status", "--porcelain"], { stdio: "pipe" }).toString();
73115
73335
  return out.trim().length > 0;
73116
73336
  } catch {
73117
73337
  return false;
@@ -73120,12 +73340,12 @@ function hasUncommittedChanges(repoPath, worktreePath) {
73120
73340
  function reapRecord(record2) {
73121
73341
  const { id, path: path7, repo, branch, ownerAgent } = record2;
73122
73342
  let warning = null;
73123
- if (existsSync63(path7)) {
73343
+ if (existsSync64(path7)) {
73124
73344
  if (hasUncommittedChanges(repo, path7)) {
73125
73345
  warning = `[worktree-reaper] Reaped worktree with uncommitted changes: ` + `id=${id} branch=${branch} agent=${ownerAgent ?? "unknown"} path=${path7}`;
73126
73346
  }
73127
73347
  try {
73128
- execFileSync18("git", ["worktree", "remove", "--force", path7], {
73348
+ execFileSync19("git", ["worktree", "remove", "--force", path7], {
73129
73349
  cwd: repo,
73130
73350
  stdio: "pipe"
73131
73351
  });
@@ -73141,7 +73361,7 @@ function runReaper(nowMs) {
73141
73361
  const warnings = [];
73142
73362
  for (const record2 of records) {
73143
73363
  const heartbeatAge = now - new Date(record2.heartbeatAt).getTime();
73144
- const worktreeExists = existsSync63(record2.path);
73364
+ const worktreeExists = existsSync64(record2.path);
73145
73365
  if (!worktreeExists) {
73146
73366
  deleteRecord(record2.id);
73147
73367
  reaped.push(record2.id);
@@ -73270,7 +73490,7 @@ import {
73270
73490
  rmSync as rmSync15,
73271
73491
  writeFileSync as writeFileSync30
73272
73492
  } from "node:fs";
73273
- import { join as join57 } from "node:path";
73493
+ import { join as join58 } from "node:path";
73274
73494
  function encodeCredentialsFilename(email) {
73275
73495
  const SAFE = new Set([
73276
73496
  ..."ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
@@ -73460,16 +73680,16 @@ function resolveCredentialsDir(env2) {
73460
73680
  if (explicit && explicit.length > 0)
73461
73681
  return explicit;
73462
73682
  const stateBase = env2.SWITCHROOM_CONTAINER === "1" ? "/state/agent" : env2.HOME ?? ".";
73463
- return join57(stateBase, "google-workspace-mcp", "credentials");
73683
+ return join58(stateBase, "google-workspace-mcp", "credentials");
73464
73684
  }
73465
73685
  function writeSeedFile(dir, email, seed) {
73466
73686
  mkdirSync34(dir, { recursive: true, mode: 448 });
73467
73687
  chmodSync9(dir, 448);
73468
73688
  for (const name of readdirSync23(dir)) {
73469
- rmSync15(join57(dir, name), { force: true, recursive: true });
73689
+ rmSync15(join58(dir, name), { force: true, recursive: true });
73470
73690
  }
73471
73691
  const filename = encodeCredentialsFilename(email);
73472
- const filePath = join57(dir, filename);
73692
+ const filePath = join58(dir, filename);
73473
73693
  writeFileSync30(filePath, JSON.stringify(seed), { mode: 384 });
73474
73694
  chmodSync9(filePath, 384);
73475
73695
  return filePath;
@@ -73627,7 +73847,7 @@ function registerDriveMcpLauncherCommand(program3) {
73627
73847
 
73628
73848
  // src/cli/apply.ts
73629
73849
  init_source();
73630
- import { accessSync as accessSync3, constants as fsConstants6, copyFileSync as copyFileSync11, existsSync as existsSync67, mkdirSync as mkdirSync36, readdirSync as readdirSync25, renameSync as renameSync13, writeFileSync as writeFileSync32 } from "node:fs";
73850
+ import { accessSync as accessSync3, constants as fsConstants6, copyFileSync as copyFileSync11, existsSync as existsSync68, mkdirSync as mkdirSync36, readdirSync as readdirSync25, renameSync as renameSync13, writeFileSync as writeFileSync32 } from "node:fs";
73631
73851
  import { mkdir, writeFile } from "node:fs/promises";
73632
73852
  import { spawnSync as childSpawnSync } from "node:child_process";
73633
73853
  import readline from "node:readline";
@@ -73990,16 +74210,16 @@ agents:
73990
74210
 
73991
74211
  // src/cli/apply.ts
73992
74212
  init_resolver();
73993
- import { dirname as dirname19, join as join61, resolve as resolve42 } from "node:path";
73994
- import { homedir as homedir34 } from "node:os";
73995
- import { execFileSync as execFileSync19 } from "node:child_process";
74213
+ import { dirname as dirname19, join as join62, resolve as resolve42 } from "node:path";
74214
+ import { homedir as homedir35 } from "node:os";
74215
+ import { execFileSync as execFileSync20 } from "node:child_process";
73996
74216
  init_vault();
73997
74217
  init_loader();
73998
74218
  init_loader();
73999
74219
 
74000
74220
  // src/cli/update-prompt-hook.ts
74001
- import { existsSync as existsSync64, readFileSync as readFileSync54, writeFileSync as writeFileSync31, chmodSync as chmodSync10, mkdirSync as mkdirSync35 } from "node:fs";
74002
- import { join as join58 } from "node:path";
74221
+ import { existsSync as existsSync65, readFileSync as readFileSync54, writeFileSync as writeFileSync31, chmodSync as chmodSync10, mkdirSync as mkdirSync35 } from "node:fs";
74222
+ import { join as join59 } from "node:path";
74003
74223
  var HOOK_FILENAME = "update-card-on-prompt.sh";
74004
74224
  function updatePromptHookScript() {
74005
74225
  return `#!/bin/bash
@@ -74065,12 +74285,12 @@ exit 0
74065
74285
  `;
74066
74286
  }
74067
74287
  function installUpdatePromptHook(agentDir) {
74068
- const hooksDir = join58(agentDir, ".claude", "hooks");
74288
+ const hooksDir = join59(agentDir, ".claude", "hooks");
74069
74289
  mkdirSync35(hooksDir, { recursive: true });
74070
- const scriptPath = join58(hooksDir, HOOK_FILENAME);
74290
+ const scriptPath = join59(hooksDir, HOOK_FILENAME);
74071
74291
  const desired = updatePromptHookScript();
74072
74292
  let installed = false;
74073
- const existing = existsSync64(scriptPath) ? readFileSync54(scriptPath, "utf-8") : "";
74293
+ const existing = existsSync65(scriptPath) ? readFileSync54(scriptPath, "utf-8") : "";
74074
74294
  if (existing !== desired) {
74075
74295
  writeFileSync31(scriptPath, desired, { mode: 493 });
74076
74296
  chmodSync10(scriptPath, 493);
@@ -74080,8 +74300,8 @@ function installUpdatePromptHook(agentDir) {
74080
74300
  chmodSync10(scriptPath, 493);
74081
74301
  } catch {}
74082
74302
  }
74083
- const settingsPath = join58(agentDir, ".claude", "settings.json");
74084
- if (!existsSync64(settingsPath)) {
74303
+ const settingsPath = join59(agentDir, ".claude", "settings.json");
74304
+ if (!existsSync65(settingsPath)) {
74085
74305
  return { scriptPath, settingsPath, installed };
74086
74306
  }
74087
74307
  const raw = readFileSync54(settingsPath, "utf-8");
@@ -74200,13 +74420,13 @@ function detectInstallType() {
74200
74420
  // src/cli/operator-uid.ts
74201
74421
  import {
74202
74422
  chownSync as chownSync3,
74203
- existsSync as existsSync66,
74423
+ existsSync as existsSync67,
74204
74424
  lstatSync as lstatSync7,
74205
74425
  readdirSync as readdirSync24,
74206
74426
  realpathSync as realpathSync6,
74207
- statSync as statSync26
74427
+ statSync as statSync27
74208
74428
  } from "node:fs";
74209
- import { join as join60 } from "node:path";
74429
+ import { join as join61 } from "node:path";
74210
74430
  function resolveOperatorUid() {
74211
74431
  const sudoUid = process.env.SUDO_UID;
74212
74432
  if (sudoUid !== undefined) {
@@ -74222,19 +74442,19 @@ function resolveOperatorUid() {
74222
74442
  return;
74223
74443
  }
74224
74444
  function operatorOwnedPaths(home2) {
74225
- const root = join60(home2, ".switchroom");
74445
+ const root = join61(home2, ".switchroom");
74226
74446
  return [
74227
- join60(root, "vault"),
74228
- join60(root, "vault-auto-unlock"),
74229
- join60(root, "vault-audit.log"),
74230
- join60(root, "host-control-audit.log"),
74231
- join60(root, "accounts"),
74232
- join60(root, "compose")
74447
+ join61(root, "vault"),
74448
+ join61(root, "vault-auto-unlock"),
74449
+ join61(root, "vault-audit.log"),
74450
+ join61(root, "host-control-audit.log"),
74451
+ join61(root, "accounts"),
74452
+ join61(root, "compose")
74233
74453
  ];
74234
74454
  }
74235
74455
  function restoreOperatorOwnership(home2, operatorUid, deps = {}) {
74236
74456
  const chown = deps.chown ?? ((p, u, g) => chownSync3(p, u, g));
74237
- const exists = deps.exists ?? ((p) => existsSync66(p));
74457
+ const exists = deps.exists ?? ((p) => existsSync67(p));
74238
74458
  const isSymlink = deps.isSymlink ?? ((p) => {
74239
74459
  try {
74240
74460
  return lstatSync7(p).isSymbolicLink();
@@ -74244,7 +74464,7 @@ function restoreOperatorOwnership(home2, operatorUid, deps = {}) {
74244
74464
  });
74245
74465
  const isDir = deps.isDir ?? ((p) => {
74246
74466
  try {
74247
- return statSync26(p).isDirectory();
74467
+ return statSync27(p).isDirectory();
74248
74468
  } catch {
74249
74469
  return false;
74250
74470
  }
@@ -74278,7 +74498,7 @@ function restoreOperatorOwnership(home2, operatorUid, deps = {}) {
74278
74498
  } catch {}
74279
74499
  if (isDir(target)) {
74280
74500
  for (const entry of readdir2(target)) {
74281
- visit(join60(target, entry));
74501
+ visit(join61(target, entry));
74282
74502
  }
74283
74503
  }
74284
74504
  };
@@ -74292,17 +74512,17 @@ var EMBEDDED_EXAMPLES = {
74292
74512
  switchroom: switchroom_default,
74293
74513
  minimal: minimal_default
74294
74514
  };
74295
- var DEFAULT_COMPOSE_PATH2 = join61(homedir34(), ".switchroom", "compose", "docker-compose.yml");
74515
+ var DEFAULT_COMPOSE_PATH2 = join62(homedir35(), ".switchroom", "compose", "docker-compose.yml");
74296
74516
  var COMPOSE_PROJECT2 = "switchroom";
74297
74517
  function resolveVaultBindMountDir(homeDir, ctx) {
74298
74518
  const isCustomPath = ctx.migrationKind === "custom-path-skipped";
74299
74519
  if (isCustomPath && ctx.customVaultPath) {
74300
74520
  return dirname19(ctx.customVaultPath);
74301
74521
  }
74302
- return join61(homeDir, ".switchroom", "vault");
74522
+ return join62(homeDir, ".switchroom", "vault");
74303
74523
  }
74304
74524
  function inspectVaultBindMountDir(vaultDir) {
74305
- if (!existsSync67(vaultDir))
74525
+ if (!existsSync68(vaultDir))
74306
74526
  return { kind: "missing" };
74307
74527
  const entries = readdirSync25(vaultDir);
74308
74528
  const unknown = [];
@@ -74328,38 +74548,42 @@ function hasVaultRefs(value) {
74328
74548
  return false;
74329
74549
  }
74330
74550
  async function ensureHostMountSources(config) {
74331
- const home2 = homedir34();
74551
+ const home2 = homedir35();
74332
74552
  const dirs = [
74333
- join61(home2, ".switchroom", "approvals"),
74334
- join61(home2, ".switchroom", "scheduler"),
74335
- join61(home2, ".switchroom", "logs"),
74336
- join61(home2, ".switchroom", "compose"),
74337
- join61(home2, ".switchroom", "broker-operator")
74553
+ join62(home2, ".switchroom", "approvals"),
74554
+ join62(home2, ".switchroom", "scheduler"),
74555
+ join62(home2, ".switchroom", "logs"),
74556
+ join62(home2, ".switchroom", "compose"),
74557
+ join62(home2, ".switchroom", "broker-operator")
74338
74558
  ];
74339
74559
  for (const name of Object.keys(config.agents)) {
74340
- dirs.push(join61(home2, ".switchroom", "agents", name));
74341
- dirs.push(join61(home2, ".switchroom", "logs", name));
74342
- dirs.push(join61(home2, ".claude", "projects", name));
74560
+ dirs.push(join62(home2, ".switchroom", "agents", name));
74561
+ dirs.push(join62(home2, ".switchroom", "logs", name));
74562
+ dirs.push(join62(home2, ".claude", "projects", name));
74343
74563
  }
74344
74564
  for (const dir of dirs) {
74345
74565
  await mkdir(dir, { recursive: true });
74346
74566
  }
74347
- const autoUnlockPath = join61(home2, ".switchroom", "vault-auto-unlock");
74348
- if (!existsSync67(autoUnlockPath)) {
74567
+ const autoUnlockPath = join62(home2, ".switchroom", "vault-auto-unlock");
74568
+ if (!existsSync68(autoUnlockPath)) {
74349
74569
  writeFileSync32(autoUnlockPath, "", { mode: 384 });
74350
74570
  }
74351
- const auditLogPath = join61(home2, ".switchroom", "vault-audit.log");
74352
- if (!existsSync67(auditLogPath)) {
74571
+ const auditLogPath = join62(home2, ".switchroom", "vault-audit.log");
74572
+ if (!existsSync68(auditLogPath)) {
74353
74573
  writeFileSync32(auditLogPath, "", { mode: 420 });
74354
74574
  }
74355
- const hostdAuditLogPath = join61(home2, ".switchroom", "host-control-audit.log");
74356
- if (!existsSync67(hostdAuditLogPath)) {
74575
+ const grantsDbPath = join62(home2, ".switchroom", "vault-grants.db");
74576
+ if (!existsSync68(grantsDbPath)) {
74577
+ writeFileSync32(grantsDbPath, "", { mode: 384 });
74578
+ }
74579
+ const hostdAuditLogPath = join62(home2, ".switchroom", "host-control-audit.log");
74580
+ if (!existsSync68(hostdAuditLogPath)) {
74357
74581
  writeFileSync32(hostdAuditLogPath, "", { mode: 420 });
74358
74582
  }
74359
74583
  }
74360
74584
  function detectComposeV2() {
74361
74585
  try {
74362
- const out = execFileSync19("docker", ["compose", "version"], {
74586
+ const out = execFileSync20("docker", ["compose", "version"], {
74363
74587
  stdio: ["ignore", "pipe", "pipe"],
74364
74588
  encoding: "utf8"
74365
74589
  });
@@ -74374,7 +74598,7 @@ ${out.trim()}`;
74374
74598
  }
74375
74599
  function runApplyPreflight(config, opts = {}) {
74376
74600
  const vaultPath = resolvePath(config.vault?.path ?? "~/.switchroom/vault.enc");
74377
- if (hasVaultRefs(config) && !existsSync67(vaultPath)) {
74601
+ if (hasVaultRefs(config) && !existsSync68(vaultPath)) {
74378
74602
  throw new Error(`Config references vault keys (vault:<name>) but ${vaultPath} is missing. ` + `Run \`switchroom setup\` first to initialise the vault.`);
74379
74603
  }
74380
74604
  const detect = opts.detectComposeV2 ?? detectComposeV2;
@@ -74385,7 +74609,7 @@ function runApplyPreflight(config, opts = {}) {
74385
74609
  detectAndReportLegacyGdriveSlots(vaultPath);
74386
74610
  }
74387
74611
  function detectAndReportLegacyGdriveSlots(vaultPath) {
74388
- if (!existsSync67(vaultPath))
74612
+ if (!existsSync68(vaultPath))
74389
74613
  return;
74390
74614
  const passphrase = process.env.SWITCHROOM_VAULT_PASSPHRASE;
74391
74615
  if (!passphrase)
@@ -74424,10 +74648,10 @@ function detectAndReportLegacyGdriveSlots(vaultPath) {
74424
74648
  `));
74425
74649
  }
74426
74650
  }
74427
- function writeInstallTypeCache(homeDir = homedir34()) {
74651
+ function writeInstallTypeCache(homeDir = homedir35()) {
74428
74652
  const ctx = detectInstallType();
74429
- const dir = join61(homeDir, ".switchroom");
74430
- const out = join61(dir, "install-type.json");
74653
+ const dir = join62(homeDir, ".switchroom");
74654
+ const out = join62(dir, "install-type.json");
74431
74655
  const tmp = `${out}.tmp`;
74432
74656
  mkdirSync36(dir, { recursive: true });
74433
74657
  const payload = {
@@ -74476,14 +74700,14 @@ Applying switchroom config...
74476
74700
  writeOut(source_default.green(` + ${name}`) + source_default.gray(` (${agentConfig.extends ?? "default"}) \u2014 ${detail}
74477
74701
  `));
74478
74702
  try {
74479
- installUpdatePromptHook(join61(agentsDir, name));
74703
+ installUpdatePromptHook(join62(agentsDir, name));
74480
74704
  } catch (hookErr) {
74481
74705
  writeOut(source_default.gray(` (update-prompt hook install failed for ${name}: ${hookErr.message})
74482
74706
  `));
74483
74707
  }
74484
74708
  try {
74485
74709
  const uid = allocateAgentUid(name);
74486
- alignAgentUid(name, join61(agentsDir, name), uid, {
74710
+ alignAgentUid(name, join62(agentsDir, name), uid, {
74487
74711
  confirm: !options.nonInteractive,
74488
74712
  writeOut
74489
74713
  });
@@ -74520,7 +74744,7 @@ Applying switchroom config...
74520
74744
  for (const name of agentNames) {
74521
74745
  try {
74522
74746
  const uid = allocateAgentUid(name);
74523
- alignAgentUid(name, join61(agentsDir, name), uid, {
74747
+ alignAgentUid(name, join62(agentsDir, name), uid, {
74524
74748
  confirm: !options.nonInteractive,
74525
74749
  writeOut
74526
74750
  });
@@ -74534,7 +74758,7 @@ Applying switchroom config...
74534
74758
  }
74535
74759
  const vaultPathConfigured = config.vault?.path;
74536
74760
  const customVaultPath = vaultPathConfigured ? resolvePath(vaultPathConfigured) : undefined;
74537
- const migrationResult = migrateVaultLayout(homedir34(), {
74761
+ const migrationResult = migrateVaultLayout(homedir35(), {
74538
74762
  customVaultPath
74539
74763
  });
74540
74764
  switch (migrationResult.kind) {
@@ -74560,7 +74784,7 @@ Applying switchroom config...
74560
74784
  writeErr(formatDivergentRecoveryMessage(migrationResult.details));
74561
74785
  process.exit(4);
74562
74786
  }
74563
- const postMigrationInspect = inspectVaultLayout(homedir34());
74787
+ const postMigrationInspect = inspectVaultLayout(homedir35());
74564
74788
  const acceptable = [
74565
74789
  "no-vault",
74566
74790
  "already-migrated",
@@ -74575,7 +74799,7 @@ Applying switchroom config...
74575
74799
  `));
74576
74800
  process.exit(5);
74577
74801
  }
74578
- const vaultDir = resolveVaultBindMountDir(homedir34(), {
74802
+ const vaultDir = resolveVaultBindMountDir(homedir35(), {
74579
74803
  migrationKind: migrationResult.kind,
74580
74804
  customVaultPath
74581
74805
  });
@@ -74605,7 +74829,7 @@ Applying switchroom config...
74605
74829
  imageTag: composeImageTag,
74606
74830
  buildMode: options.buildLocal ? "local" : "pull",
74607
74831
  buildContext: options.buildContext,
74608
- homeDir: homedir34(),
74832
+ homeDir: homedir35(),
74609
74833
  switchroomConfigPath,
74610
74834
  operatorUid
74611
74835
  });
@@ -74625,7 +74849,7 @@ Wrote `) + composePath + source_default.gray(` (${composeBytes} bytes)
74625
74849
  writeOut(source_default.gray(` (If pull returns 401, login to ghcr.io first: see docs/operators/install.md#ghcr-auth)
74626
74850
  `));
74627
74851
  if (process.geteuid?.() === 0 && operatorUid !== undefined) {
74628
- const restored = restoreOperatorOwnership(homedir34(), operatorUid);
74852
+ const restored = restoreOperatorOwnership(homedir35(), operatorUid);
74629
74853
  if (restored.length > 0) {
74630
74854
  writeOut(source_default.gray(` Restored operator ownership of ${restored.length} ~/.switchroom path(s)
74631
74855
  `));
@@ -74673,7 +74897,7 @@ function copyExampleConfig2(name) {
74673
74897
  throw new Error(`Invalid example name: ${name} (must match /^[a-z0-9_-]+$/)`);
74674
74898
  }
74675
74899
  const dest = resolve42(process.cwd(), "switchroom.yaml");
74676
- if (existsSync67(dest)) {
74900
+ if (existsSync68(dest)) {
74677
74901
  console.error(source_default.yellow("switchroom.yaml already exists \u2014 skipping example copy"));
74678
74902
  return;
74679
74903
  }
@@ -74684,7 +74908,7 @@ function copyExampleConfig2(name) {
74684
74908
  return;
74685
74909
  }
74686
74910
  const exampleFile = resolve42(import.meta.dirname, `../../examples/${name}.yaml`);
74687
- if (!existsSync67(exampleFile)) {
74911
+ if (!existsSync68(exampleFile)) {
74688
74912
  throw new Error(`Example config not found: ${name}.yaml (available: ${Object.keys(EMBEDDED_EXAMPLES).join(", ")})`);
74689
74913
  }
74690
74914
  copyFileSync11(exampleFile, dest);
@@ -74695,8 +74919,8 @@ function findUnwritableAgentDirs(config, opts) {
74695
74919
  const targets = opts.only ? [opts.only] : Object.keys(config.agents ?? {});
74696
74920
  const unwritable = [];
74697
74921
  for (const name of targets) {
74698
- const startSh = join61(agentsDir, name, "start.sh");
74699
- if (!existsSync67(startSh))
74922
+ const startSh = join62(agentsDir, name, "start.sh");
74923
+ if (!existsSync68(startSh))
74700
74924
  continue;
74701
74925
  try {
74702
74926
  accessSync3(startSh, fsConstants6.W_OK);
@@ -74874,9 +75098,9 @@ function runRedactStdin() {
74874
75098
  }
74875
75099
 
74876
75100
  // src/cli/status-ask.ts
74877
- import { readFileSync as readFileSync55, existsSync as existsSync68, readdirSync as readdirSync26 } from "node:fs";
74878
- import { join as join62 } from "node:path";
74879
- import { homedir as homedir35 } from "node:os";
75101
+ import { readFileSync as readFileSync55, existsSync as existsSync69, readdirSync as readdirSync26 } from "node:fs";
75102
+ import { join as join63 } from "node:path";
75103
+ import { homedir as homedir36 } from "node:os";
74880
75104
 
74881
75105
  // src/status-ask/report.ts
74882
75106
  function parseJsonl(content) {
@@ -75197,7 +75421,7 @@ function runReport(opts) {
75197
75421
  function resolveSources(explicitPath) {
75198
75422
  if (explicitPath != null && explicitPath.trim() !== "") {
75199
75423
  const trimmed = explicitPath.trim();
75200
- if (!existsSync68(trimmed)) {
75424
+ if (!existsSync69(trimmed)) {
75201
75425
  process.stderr.write(`status-ask report: ${trimmed}: file not found
75202
75426
  `);
75203
75427
  process.exit(1);
@@ -75211,9 +75435,9 @@ function resolveSources(explicitPath) {
75211
75435
  const config = loadConfig();
75212
75436
  agentsDir = resolveAgentsDir(config);
75213
75437
  } catch {
75214
- agentsDir = join62(homedir35(), ".switchroom", "agents");
75438
+ agentsDir = join63(homedir36(), ".switchroom", "agents");
75215
75439
  }
75216
- if (!existsSync68(agentsDir))
75440
+ if (!existsSync69(agentsDir))
75217
75441
  return [];
75218
75442
  const sources = [];
75219
75443
  let entries;
@@ -75223,8 +75447,8 @@ function resolveSources(explicitPath) {
75223
75447
  return [];
75224
75448
  }
75225
75449
  for (const name of entries) {
75226
- const path8 = join62(agentsDir, name, "runtime-metrics.jsonl");
75227
- if (existsSync68(path8)) {
75450
+ const path8 = join63(agentsDir, name, "runtime-metrics.jsonl");
75451
+ if (existsSync69(path8)) {
75228
75452
  sources.push({ path: path8, agent: name });
75229
75453
  }
75230
75454
  }
@@ -75245,17 +75469,17 @@ function inferAgentFromPath(p) {
75245
75469
 
75246
75470
  // src/cli/agent-config.ts
75247
75471
  init_helpers();
75248
- import { join as join63 } from "node:path";
75249
- import { homedir as homedir36 } from "node:os";
75472
+ import { join as join64 } from "node:path";
75473
+ import { homedir as homedir37 } from "node:os";
75250
75474
  import {
75251
- existsSync as existsSync69,
75475
+ existsSync as existsSync70,
75252
75476
  mkdirSync as mkdirSync37,
75253
75477
  appendFileSync as appendFileSync4,
75254
75478
  readFileSync as readFileSync56
75255
75479
  } from "node:fs";
75256
- var AUDIT_ROOT = join63(homedir36(), ".switchroom", "audit");
75480
+ var AUDIT_ROOT = join64(homedir37(), ".switchroom", "audit");
75257
75481
  function auditPathFor(agent) {
75258
- return join63(AUDIT_ROOT, agent, "agent-config.jsonl");
75482
+ return join64(AUDIT_ROOT, agent, "agent-config.jsonl");
75259
75483
  }
75260
75484
  function appendAudit(agent, cmd, args, exit, opts = {}) {
75261
75485
  const row = {
@@ -75269,7 +75493,7 @@ function appendAudit(agent, cmd, args, exit, opts = {}) {
75269
75493
  const path8 = opts.auditPath ?? auditPathFor(agent);
75270
75494
  const dir = path8.slice(0, path8.lastIndexOf("/"));
75271
75495
  try {
75272
- if (!existsSync69(dir)) {
75496
+ if (!existsSync70(dir)) {
75273
75497
  mkdirSync37(dir, { recursive: true });
75274
75498
  }
75275
75499
  appendFileSync4(path8, JSON.stringify(row) + `
@@ -75281,7 +75505,7 @@ function isContainerContext(env2 = process.env, opts = {}) {
75281
75505
  return true;
75282
75506
  const probe2 = opts.dockerEnvPath ?? "/.dockerenv";
75283
75507
  try {
75284
- if (existsSync69(probe2))
75508
+ if (existsSync70(probe2))
75285
75509
  return true;
75286
75510
  } catch {}
75287
75511
  return false;
@@ -75342,7 +75566,7 @@ function getAgentSlice(config, agent) {
75342
75566
  }
75343
75567
  function readAuditTail(agent, limit, opts = {}) {
75344
75568
  const path8 = opts.auditPath ?? auditPathFor(agent);
75345
- if (!existsSync69(path8))
75569
+ if (!existsSync70(path8))
75346
75570
  return [];
75347
75571
  let raw;
75348
75572
  try {
@@ -75502,32 +75726,32 @@ var import_yaml14 = __toESM(require_dist(), 1);
75502
75726
  init_paths();
75503
75727
  import {
75504
75728
  closeSync as closeSync13,
75505
- existsSync as existsSync70,
75729
+ existsSync as existsSync71,
75506
75730
  fsyncSync as fsyncSync6,
75507
75731
  mkdirSync as mkdirSync38,
75508
75732
  openSync as openSync13,
75509
75733
  readdirSync as readdirSync27,
75510
75734
  readFileSync as readFileSync57,
75511
75735
  renameSync as renameSync14,
75512
- statSync as statSync27,
75736
+ statSync as statSync28,
75513
75737
  unlinkSync as unlinkSync14,
75514
75738
  writeSync as writeSync8
75515
75739
  } from "node:fs";
75516
- import { join as join64, resolve as resolve43 } from "node:path";
75740
+ import { join as join65, resolve as resolve43 } from "node:path";
75517
75741
  var STAGING_SUBDIR = ".staging";
75518
75742
  function overlayPathsFor(agent, opts = {}) {
75519
75743
  const base = opts.root ? resolve43(opts.root, agent) : resolve43(resolveDualPath(`~/.switchroom/agents/${agent}`));
75520
- const scheduleDir = join64(base, "schedule.d");
75521
- const scheduleStagingDir = join64(scheduleDir, STAGING_SUBDIR);
75522
- const skillsDir = join64(base, "skills.d");
75523
- const skillsStagingDir = join64(skillsDir, STAGING_SUBDIR);
75744
+ const scheduleDir = join65(base, "schedule.d");
75745
+ const scheduleStagingDir = join65(scheduleDir, STAGING_SUBDIR);
75746
+ const skillsDir = join65(base, "skills.d");
75747
+ const skillsStagingDir = join65(skillsDir, STAGING_SUBDIR);
75524
75748
  return {
75525
75749
  agentRoot: base,
75526
75750
  scheduleDir,
75527
75751
  scheduleStagingDir,
75528
75752
  skillsDir,
75529
75753
  skillsStagingDir,
75530
- lockPath: join64(base, ".lock"),
75754
+ lockPath: join65(base, ".lock"),
75531
75755
  stagingDir: scheduleStagingDir
75532
75756
  };
75533
75757
  }
@@ -75553,7 +75777,7 @@ function withAgentLock(paths, fn) {
75553
75777
  if (e.code !== "EEXIST")
75554
75778
  throw err;
75555
75779
  try {
75556
- const age = Date.now() - statSync27(paths.lockPath).mtimeMs;
75780
+ const age = Date.now() - statSync28(paths.lockPath).mtimeMs;
75557
75781
  if (age > 30000) {
75558
75782
  unlinkSync14(paths.lockPath);
75559
75783
  continue;
@@ -75581,8 +75805,8 @@ function writeOverlayEntry(agent, slug, yamlText, opts = {}) {
75581
75805
  const paths = overlayPathsFor(agent, opts);
75582
75806
  return withAgentLock(paths, () => {
75583
75807
  ensureDirs(paths);
75584
- const stagingPath = join64(paths.scheduleStagingDir, `${slug}.yaml`);
75585
- const finalPath = join64(paths.scheduleDir, `${slug}.yaml`);
75808
+ const stagingPath = join65(paths.scheduleStagingDir, `${slug}.yaml`);
75809
+ const finalPath = join65(paths.scheduleDir, `${slug}.yaml`);
75586
75810
  const fd = openSync13(stagingPath, "w", 384);
75587
75811
  try {
75588
75812
  writeSync8(fd, yamlText);
@@ -75598,8 +75822,8 @@ function writeSkillsOverlayEntry(agent, slug, yamlText, opts = {}) {
75598
75822
  const paths = overlayPathsFor(agent, opts);
75599
75823
  return withAgentLock(paths, () => {
75600
75824
  ensureSkillsDirs(paths);
75601
- const stagingPath = join64(paths.skillsStagingDir, `${slug}.yaml`);
75602
- const finalPath = join64(paths.skillsDir, `${slug}.yaml`);
75825
+ const stagingPath = join65(paths.skillsStagingDir, `${slug}.yaml`);
75826
+ const finalPath = join65(paths.skillsDir, `${slug}.yaml`);
75603
75827
  const fd = openSync13(stagingPath, "w", 384);
75604
75828
  try {
75605
75829
  writeSync8(fd, yamlText);
@@ -75614,8 +75838,8 @@ function writeSkillsOverlayEntry(agent, slug, yamlText, opts = {}) {
75614
75838
  function deleteSkillsOverlayEntry(agent, slug, opts = {}) {
75615
75839
  const paths = overlayPathsFor(agent, opts);
75616
75840
  return withAgentLock(paths, () => {
75617
- const finalPath = join64(paths.skillsDir, `${slug}.yaml`);
75618
- if (!existsSync70(finalPath))
75841
+ const finalPath = join65(paths.skillsDir, `${slug}.yaml`);
75842
+ if (!existsSync71(finalPath))
75619
75843
  return false;
75620
75844
  unlinkSync14(finalPath);
75621
75845
  return true;
@@ -75623,13 +75847,13 @@ function deleteSkillsOverlayEntry(agent, slug, opts = {}) {
75623
75847
  }
75624
75848
  function listSkillsOverlayEntries(agent, opts = {}) {
75625
75849
  const paths = overlayPathsFor(agent, opts);
75626
- if (!existsSync70(paths.skillsDir))
75850
+ if (!existsSync71(paths.skillsDir))
75627
75851
  return [];
75628
75852
  const out = [];
75629
75853
  for (const name of readdirSync27(paths.skillsDir)) {
75630
75854
  if (!/\.ya?ml$/i.test(name))
75631
75855
  continue;
75632
- const full = join64(paths.skillsDir, name);
75856
+ const full = join65(paths.skillsDir, name);
75633
75857
  try {
75634
75858
  const raw = readFileSync57(full, "utf-8");
75635
75859
  const slug = name.replace(/\.ya?ml$/i, "");
@@ -75641,8 +75865,8 @@ function listSkillsOverlayEntries(agent, opts = {}) {
75641
75865
  function deleteOverlayEntry(agent, slug, opts = {}) {
75642
75866
  const paths = overlayPathsFor(agent, opts);
75643
75867
  return withAgentLock(paths, () => {
75644
- const finalPath = join64(paths.scheduleDir, `${slug}.yaml`);
75645
- if (!existsSync70(finalPath))
75868
+ const finalPath = join65(paths.scheduleDir, `${slug}.yaml`);
75869
+ if (!existsSync71(finalPath))
75646
75870
  return false;
75647
75871
  unlinkSync14(finalPath);
75648
75872
  return true;
@@ -75650,13 +75874,13 @@ function deleteOverlayEntry(agent, slug, opts = {}) {
75650
75874
  }
75651
75875
  function listOverlayEntries(agent, opts = {}) {
75652
75876
  const paths = overlayPathsFor(agent, opts);
75653
- if (!existsSync70(paths.scheduleDir))
75877
+ if (!existsSync71(paths.scheduleDir))
75654
75878
  return [];
75655
75879
  const out = [];
75656
75880
  for (const name of readdirSync27(paths.scheduleDir)) {
75657
75881
  if (!/\.ya?ml$/i.test(name))
75658
75882
  continue;
75659
- const full = join64(paths.scheduleDir, name);
75883
+ const full = join65(paths.scheduleDir, name);
75660
75884
  try {
75661
75885
  const raw = readFileSync57(full, "utf-8");
75662
75886
  const slug = name.replace(/\.ya?ml$/i, "");
@@ -75801,7 +76025,7 @@ function reconcileAgentCronOnly(agent) {
75801
76025
  // src/cli/agent-config-pending.ts
75802
76026
  import {
75803
76027
  closeSync as closeSync14,
75804
- existsSync as existsSync71,
76028
+ existsSync as existsSync72,
75805
76029
  fsyncSync as fsyncSync7,
75806
76030
  mkdirSync as mkdirSync39,
75807
76031
  openSync as openSync14,
@@ -75812,12 +76036,12 @@ import {
75812
76036
  writeFileSync as writeFileSync33,
75813
76037
  writeSync as writeSync9
75814
76038
  } from "node:fs";
75815
- import { join as join65 } from "node:path";
76039
+ import { join as join66 } from "node:path";
75816
76040
  import { randomBytes as randomBytes13 } from "node:crypto";
75817
76041
  var STAGE_ID_PREFIX = "cap_";
75818
76042
  function pendingDir(agent, opts = {}) {
75819
76043
  const paths = overlayPathsFor(agent, opts);
75820
- return join65(paths.scheduleDir, ".pending");
76044
+ return join66(paths.scheduleDir, ".pending");
75821
76045
  }
75822
76046
  function ensurePendingDir(agent, opts = {}) {
75823
76047
  const dir = pendingDir(agent, opts);
@@ -75830,8 +76054,8 @@ function newStageId() {
75830
76054
  function stagePendingScheduleEntry(opts) {
75831
76055
  const dir = ensurePendingDir(opts.agent, { root: opts.root });
75832
76056
  const stageId = opts.stageId ?? newStageId();
75833
- const yamlPath = join65(dir, `${stageId}.yaml`);
75834
- const metaPath = join65(dir, `${stageId}.meta.json`);
76057
+ const yamlPath = join66(dir, `${stageId}.yaml`);
76058
+ const metaPath = join66(dir, `${stageId}.meta.json`);
75835
76059
  const meta = {
75836
76060
  v: 1,
75837
76061
  stage_id: stageId,
@@ -75858,16 +76082,16 @@ function stagePendingScheduleEntry(opts) {
75858
76082
  }
75859
76083
  function listPendingScheduleEntries(agent, opts = {}) {
75860
76084
  const dir = pendingDir(agent, opts);
75861
- if (!existsSync71(dir))
76085
+ if (!existsSync72(dir))
75862
76086
  return [];
75863
76087
  const out = [];
75864
76088
  for (const name of readdirSync28(dir).sort()) {
75865
76089
  if (!name.endsWith(".meta.json"))
75866
76090
  continue;
75867
76091
  const stageId = name.slice(0, -".meta.json".length);
75868
- const metaPath = join65(dir, name);
75869
- const yamlPath = join65(dir, `${stageId}.yaml`);
75870
- if (!existsSync71(yamlPath))
76092
+ const metaPath = join66(dir, name);
76093
+ const yamlPath = join66(dir, `${stageId}.yaml`);
76094
+ if (!existsSync72(yamlPath))
75871
76095
  continue;
75872
76096
  try {
75873
76097
  const meta = JSON.parse(readFileSync58(metaPath, "utf-8"));
@@ -75885,8 +76109,8 @@ function commitPendingScheduleEntry(opts) {
75885
76109
  return { committed: false, reason: "not_found" };
75886
76110
  const slug = match.meta.entry.name ?? match.stageId;
75887
76111
  const paths = overlayPathsFor(opts.agent, { root: opts.root });
75888
- const finalPath = join65(paths.scheduleDir, `${slug}.yaml`);
75889
- if (existsSync71(finalPath)) {
76112
+ const finalPath = join66(paths.scheduleDir, `${slug}.yaml`);
76113
+ if (existsSync72(finalPath)) {
75890
76114
  return { committed: false, reason: "slug_collision" };
75891
76115
  }
75892
76116
  renameSync15(match.yamlPath, finalPath);
@@ -75908,7 +76132,7 @@ function denyPendingScheduleEntry(opts) {
75908
76132
  }
75909
76133
 
75910
76134
  // src/cli/agent-config-write.ts
75911
- import { existsSync as existsSync72, readFileSync as readFileSync59 } from "node:fs";
76135
+ import { existsSync as existsSync73, readFileSync as readFileSync59 } from "node:fs";
75912
76136
  var MAX_ENTRIES_PER_AGENT = 20;
75913
76137
  function checkOperatorContext(verb, env2 = process.env) {
75914
76138
  if (env2.SWITCHROOM_OPERATOR === "1")
@@ -76142,7 +76366,7 @@ function scheduleRemove(opts) {
76142
76366
  }
76143
76367
  let priorContent = null;
76144
76368
  try {
76145
- if (existsSync72(match.path))
76369
+ if (existsSync73(match.path))
76146
76370
  priorContent = readFileSync59(match.path, "utf-8");
76147
76371
  } catch {}
76148
76372
  deleteOverlayEntry(agent, match.slug, { root: opts.root });
@@ -76335,10 +76559,10 @@ function registerAgentConfigWriteCommands(program3) {
76335
76559
 
76336
76560
  // src/cli/agent-config-skill-write.ts
76337
76561
  var import_yaml15 = __toESM(require_dist(), 1);
76338
- import { existsSync as existsSync73 } from "node:fs";
76562
+ import { existsSync as existsSync74 } from "node:fs";
76339
76563
  init_reconcile_default_skills();
76340
76564
  var import_yaml16 = __toESM(require_dist(), 1);
76341
- import { join as join66 } from "node:path";
76565
+ import { join as join67 } from "node:path";
76342
76566
  var MAX_SKILLS_PER_AGENT = 20;
76343
76567
  var V1_ALLOWED_SOURCE_PREFIX = "bundled:";
76344
76568
  function exitCodeFor2(code) {
@@ -76413,8 +76637,8 @@ function skillInstall(opts) {
76413
76637
  return err("E_SKILL_QUOTA_EXCEEDED", `agent ${agent} already has ${used} overlay-installed skills (cap ${MAX_SKILLS_PER_AGENT})`);
76414
76638
  }
76415
76639
  const poolDir = opts.bundledSkillsPoolDir ?? getBundledSkillsPoolDir();
76416
- const skillPath = join66(poolDir, skillName);
76417
- if (!existsSync73(skillPath)) {
76640
+ const skillPath = join67(poolDir, skillName);
76641
+ if (!existsSync74(skillPath)) {
76418
76642
  return err("E_SKILL_NOT_FOUND", `bundled skill not found at ${skillPath}. The operator needs to ` + `place the skill at this path before the agent can opt in.`);
76419
76643
  }
76420
76644
  const yamlText = import_yaml15.stringify({ skills: [skillName] });
@@ -76598,23 +76822,23 @@ init_source();
76598
76822
  init_helpers();
76599
76823
  init_loader();
76600
76824
  import {
76601
- existsSync as existsSync75,
76825
+ existsSync as existsSync76,
76602
76826
  readdirSync as readdirSync29,
76603
76827
  readFileSync as readFileSync61,
76604
76828
  renameSync as renameSync16,
76605
- statSync as statSync28,
76829
+ statSync as statSync29,
76606
76830
  unlinkSync as unlinkSync16
76607
76831
  } from "node:fs";
76608
76832
  import { createHash as createHash13 } from "node:crypto";
76609
- import { join as join67 } from "node:path";
76833
+ import { join as join68 } from "node:path";
76610
76834
  function planCronUnitRenames(agentsDir, agents) {
76611
76835
  const plans = [];
76612
76836
  for (const [agentName, agentConfig] of Object.entries(agents)) {
76613
76837
  const schedule = agentConfig.schedule ?? [];
76614
76838
  if (schedule.length === 0)
76615
76839
  continue;
76616
- const telegramDir = join67(agentsDir, agentName, "telegram");
76617
- if (!existsSync75(telegramDir))
76840
+ const telegramDir = join68(agentsDir, agentName, "telegram");
76841
+ if (!existsSync76(telegramDir))
76618
76842
  continue;
76619
76843
  let entries;
76620
76844
  try {
@@ -76635,8 +76859,8 @@ function planCronUnitRenames(agentsDir, agents) {
76635
76859
  continue;
76636
76860
  plans.push({
76637
76861
  agent: agentName,
76638
- from: join67(telegramDir, file),
76639
- to: join67(telegramDir, canonical),
76862
+ from: join68(telegramDir, file),
76863
+ to: join68(telegramDir, canonical),
76640
76864
  scheduleIdx: idx,
76641
76865
  entry
76642
76866
  });
@@ -76648,7 +76872,7 @@ function sha256File2(path8) {
76648
76872
  return createHash13("sha256").update(readFileSync61(path8)).digest("hex");
76649
76873
  }
76650
76874
  function renamePair(from, to, opts = {}) {
76651
- if (existsSync75(to)) {
76875
+ if (existsSync76(to)) {
76652
76876
  let identical = false;
76653
76877
  try {
76654
76878
  identical = sha256File2(from) === sha256File2(to);
@@ -76741,7 +76965,7 @@ function registerMigrateCommand(program3) {
76741
76965
  const fromSidecar = p.from.replace(/\.sh$/, ".source");
76742
76966
  const toSidecar = p.to.replace(/\.sh$/, ".source");
76743
76967
  let sidecarStatus = null;
76744
- if (existsSync75(fromSidecar) && statSync28(fromSidecar).isFile()) {
76968
+ if (existsSync76(fromSidecar) && statSync29(fromSidecar).isFile()) {
76745
76969
  sidecarStatus = renamePair(fromSidecar, toSidecar);
76746
76970
  }
76747
76971
  switch (status.kind) {
@@ -76773,9 +76997,9 @@ function registerMigrateCommand(program3) {
76773
76997
  // src/cli/hostd.ts
76774
76998
  init_source();
76775
76999
  init_helpers();
76776
- import { existsSync as existsSync76, mkdirSync as mkdirSync40, readdirSync as readdirSync30, readFileSync as readFileSync62, writeFileSync as writeFileSync34, statSync as statSync29, copyFileSync as copyFileSync12 } from "node:fs";
76777
- import { homedir as homedir37 } from "node:os";
76778
- import { join as join68 } from "node:path";
77000
+ import { existsSync as existsSync77, mkdirSync as mkdirSync40, readdirSync as readdirSync30, readFileSync as readFileSync62, writeFileSync as writeFileSync34, statSync as statSync30, copyFileSync as copyFileSync12 } from "node:fs";
77001
+ import { homedir as homedir38 } from "node:os";
77002
+ import { join as join69 } from "node:path";
76779
77003
  import { spawnSync as spawnSync11 } from "node:child_process";
76780
77004
  init_audit_reader();
76781
77005
  var DEFAULT_IMAGE_TAG = "latest";
@@ -76866,14 +77090,14 @@ networks:
76866
77090
  `;
76867
77091
  }
76868
77092
  function hostdDir() {
76869
- return join68(homedir37(), ".switchroom", "hostd");
77093
+ return join69(homedir38(), ".switchroom", "hostd");
76870
77094
  }
76871
77095
  function hostdComposePath() {
76872
- return join68(hostdDir(), "docker-compose.yml");
77096
+ return join69(hostdDir(), "docker-compose.yml");
76873
77097
  }
76874
77098
  function backupExistingCompose() {
76875
77099
  const p = hostdComposePath();
76876
- if (!existsSync76(p))
77100
+ if (!existsSync77(p))
76877
77101
  return null;
76878
77102
  const ts = new Date().toISOString().replace(/[:.]/g, "-");
76879
77103
  const bak = `${p}.bak-${ts}`;
@@ -76908,7 +77132,7 @@ async function doInstall(opts, program3) {
76908
77132
  const composePath = hostdComposePath();
76909
77133
  mkdirSync40(dir, { recursive: true });
76910
77134
  const yaml = renderHostdComposeFile({
76911
- hostHome: homedir37(),
77135
+ hostHome: homedir38(),
76912
77136
  imageTag: opts.tag ?? DEFAULT_IMAGE_TAG,
76913
77137
  operatorUid: resolveOperatorUid()
76914
77138
  });
@@ -76950,7 +77174,7 @@ function doStatus() {
76950
77174
  const composeYml = hostdComposePath();
76951
77175
  console.log(source_default.bold("switchroom-hostd"));
76952
77176
  console.log("");
76953
- if (!existsSync76(composeYml)) {
77177
+ if (!existsSync77(composeYml)) {
76954
77178
  console.log(source_default.yellow(" compose: not installed"));
76955
77179
  console.log(source_default.dim(" run `switchroom hostd install` to set up."));
76956
77180
  return;
@@ -76971,15 +77195,15 @@ function doStatus() {
76971
77195
  } else {
76972
77196
  console.log(source_default.green(` container: ${ps.stdout.trim()}`));
76973
77197
  }
76974
- if (existsSync76(dir)) {
77198
+ if (existsSync77(dir)) {
76975
77199
  const entries = [];
76976
77200
  try {
76977
77201
  for (const name of readdirSync30(dir)) {
76978
77202
  if (name === "docker-compose.yml" || name.startsWith("docker-compose.yml."))
76979
77203
  continue;
76980
- const sockPath = join68(dir, name, "sock");
76981
- if (existsSync76(sockPath)) {
76982
- const st = statSync29(sockPath);
77204
+ const sockPath = join69(dir, name, "sock");
77205
+ if (existsSync77(sockPath)) {
77206
+ const st = statSync30(sockPath);
76983
77207
  if ((st.mode & 61440) === 49152) {
76984
77208
  entries.push(`${name} \u2192 ${sockPath}`);
76985
77209
  }
@@ -76997,7 +77221,7 @@ function doStatus() {
76997
77221
  }
76998
77222
  function doUninstall() {
76999
77223
  const composeYml = hostdComposePath();
77000
- if (!existsSync76(composeYml)) {
77224
+ if (!existsSync77(composeYml)) {
77001
77225
  console.log(source_default.yellow(" No hostd install detected (no compose file at this path)."));
77002
77226
  return;
77003
77227
  }
@@ -77021,7 +77245,7 @@ function registerHostdCommand(program3) {
77021
77245
  hostd.command("uninstall").description("Stop the hostd container. Leaves the compose file in place for re-install.").action(() => doUninstall());
77022
77246
  hostd.command("audit").description("Tail and filter the hostd audit log (privileged-verb call history)").option("--tail <n>", "Number of matching entries to show (default: 50)", "50").option("--agent <name>", "Filter to a specific caller agent").option("--op <verb>", "Filter to a specific hostd verb (e.g. update_apply, agent_restart)").option("--error", "Show only failed (error/denied) entries").option("--verbose", "Show the captured stderr / error tail under each failed row").option("--path <file>", "Override audit log path (for debugging)").action((opts) => {
77023
77247
  const logPath = opts.path ?? defaultAuditLogPath2();
77024
- if (!existsSync76(logPath)) {
77248
+ if (!existsSync77(logPath)) {
77025
77249
  console.error(source_default.yellow(`Audit log not found at ${logPath}.`) + source_default.gray(`
77026
77250
  The log is created when hostd handles its first privileged-verb request.`));
77027
77251
  return;