switchroom 0.14.66 → 0.14.68

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.
@@ -14593,6 +14593,35 @@ function shouldEmitNotionMcp(agentName, config) {
14593
14593
  return false;
14594
14594
  return true;
14595
14595
  }
14596
+ function normalizeNotionUuid(uuid) {
14597
+ if (typeof uuid !== "string")
14598
+ return null;
14599
+ const stripped = uuid.replace(/-/g, "").toLowerCase();
14600
+ if (!/^[0-9a-f]{32}$/.test(stripped))
14601
+ return null;
14602
+ return stripped;
14603
+ }
14604
+ function agentCanAccessNotionDB(config, agentName, dbUuid) {
14605
+ if (!shouldEmitNotionMcp(agentName, config))
14606
+ return false;
14607
+ const targetNorm = normalizeNotionUuid(dbUuid);
14608
+ if (targetNorm === null)
14609
+ return false;
14610
+ const agentConfig = config.agents?.[agentName];
14611
+ const allowedNames = agentConfig?.notion_workspace?.databases;
14612
+ if (allowedNames === undefined || allowedNames.length === 0) {
14613
+ return true;
14614
+ }
14615
+ const dbMap = config.notion_workspace?.databases ?? {};
14616
+ for (const name of allowedNames) {
14617
+ const uuid = dbMap[name];
14618
+ if (!uuid)
14619
+ continue;
14620
+ if (normalizeNotionUuid(uuid) === targetNorm)
14621
+ return true;
14622
+ }
14623
+ return false;
14624
+ }
14596
14625
  function validateNotionWorkspaceConfig(config) {
14597
14626
  const issues = [];
14598
14627
  const dbMap = config.notion_workspace?.databases ?? {};
@@ -23623,7 +23652,7 @@ function bringUpAgentService(opts) {
23623
23652
  writeFileSync6(composePath, compose, { mode: 384 });
23624
23653
  const dockerBin = opts.dockerBin ?? "docker";
23625
23654
  const stdio = opts.stdio ?? "inherit";
23626
- for (const svc of ["vault-broker", "approval-kernel"]) {
23655
+ for (const svc of ["vault-broker", "approval-kernel", "switchroom-auth-broker"]) {
23627
23656
  execFileSync6(dockerBin, [
23628
23657
  "compose",
23629
23658
  "-f",
@@ -23651,9 +23680,93 @@ var init_docker_fleet = __esm(() => {
23651
23680
  init_loader();
23652
23681
  });
23653
23682
 
23683
+ // src/agents/singleton-reconcile.ts
23684
+ import { execFileSync as execFileSync7 } from "node:child_process";
23685
+ import { readFileSync as readFileSync13 } from "node:fs";
23686
+ function singletonContainerName(svc) {
23687
+ return svc.startsWith("switchroom-") ? svc : `switchroom-${svc}`;
23688
+ }
23689
+ function readPinnedSingletonImages(composeText) {
23690
+ let doc;
23691
+ try {
23692
+ doc = import_yaml3.parse(composeText);
23693
+ } catch {
23694
+ return {};
23695
+ }
23696
+ const out = {};
23697
+ for (const svc of SINGLETON_SERVICES) {
23698
+ const img = doc?.services?.[svc]?.image;
23699
+ if (typeof img === "string" && img.length > 0)
23700
+ out[svc] = img;
23701
+ }
23702
+ return out;
23703
+ }
23704
+ function defaultInspectImage(dockerBin, container) {
23705
+ try {
23706
+ const out = execFileSync7(dockerBin, ["inspect", "-f", "{{.Config.Image}}", container], { encoding: "utf-8", stdio: ["ignore", "pipe", "pipe"], timeout: 5000 }).trim();
23707
+ return out.length > 0 ? out : null;
23708
+ } catch {
23709
+ return null;
23710
+ }
23711
+ }
23712
+ function detectSingletonDrift(deps) {
23713
+ const dockerBin = deps.dockerBin ?? "docker";
23714
+ const readCompose = deps.readCompose ?? ((p) => readFileSync13(p, "utf-8"));
23715
+ const inspectImage = deps.inspectImage ?? ((c) => defaultInspectImage(dockerBin, c));
23716
+ let pinned = {};
23717
+ try {
23718
+ pinned = readPinnedSingletonImages(readCompose(deps.composeFile));
23719
+ } catch {
23720
+ pinned = {};
23721
+ }
23722
+ return SINGLETON_SERVICES.map((service) => {
23723
+ const container = singletonContainerName(service);
23724
+ const running = inspectImage(container);
23725
+ const pin = pinned[service] ?? null;
23726
+ const needsRecreate = pin !== null && running !== pin;
23727
+ return { service, container, running, pinned: pin, needsRecreate };
23728
+ });
23729
+ }
23730
+ function defaultRecreate(dockerBin, project, composeFile, service) {
23731
+ execFileSync7(dockerBin, ["compose", "-p", project, "-f", composeFile, "up", "-d", "--no-deps", service], { stdio: ["ignore", "pipe", "pipe"], timeout: 120000 });
23732
+ }
23733
+ function reconcileSingletons(deps) {
23734
+ const dockerBin = deps.dockerBin ?? "docker";
23735
+ const project = deps.project ?? "switchroom";
23736
+ const log = deps.log ?? ((m) => process.stderr.write(m + `
23737
+ `));
23738
+ const recreate = deps.recreate ?? ((svc) => defaultRecreate(dockerBin, project, deps.composeFile, svc));
23739
+ const drift = detectSingletonDrift(deps);
23740
+ const recreated = [];
23741
+ const failed = [];
23742
+ for (const d of drift) {
23743
+ if (!d.needsRecreate)
23744
+ continue;
23745
+ log(`singleton-reconcile: ${d.service} drift ${d.running ?? "<absent>"} \u2192 ${d.pinned} \u2014 recreating`);
23746
+ try {
23747
+ recreate(d.service);
23748
+ recreated.push(d.service);
23749
+ } catch (err) {
23750
+ const msg = err instanceof Error ? err.message : String(err);
23751
+ log(`singleton-reconcile: ${d.service} recreate FAILED: ${msg}`);
23752
+ failed.push({ service: d.service, error: msg });
23753
+ }
23754
+ }
23755
+ return { drift, recreated, failed };
23756
+ }
23757
+ var import_yaml3, SINGLETON_SERVICES;
23758
+ var init_singleton_reconcile = __esm(() => {
23759
+ import_yaml3 = __toESM(require_dist(), 1);
23760
+ SINGLETON_SERVICES = [
23761
+ "vault-broker",
23762
+ "approval-kernel",
23763
+ "switchroom-auth-broker"
23764
+ ];
23765
+ });
23766
+
23654
23767
  // src/agents/lifecycle.ts
23655
- import { execFileSync as execFileSync7, spawn, spawnSync } from "node:child_process";
23656
- import { existsSync as existsSync15, mkdirSync as mkdirSync12, writeFileSync as writeFileSync7, renameSync as renameSync4, readFileSync as readFileSync13 } from "node:fs";
23768
+ import { execFileSync as execFileSync8, spawn, spawnSync } from "node:child_process";
23769
+ import { existsSync as existsSync15, mkdirSync as mkdirSync12, writeFileSync as writeFileSync7, renameSync as renameSync4, readFileSync as readFileSync14 } from "node:fs";
23657
23770
  import { resolve as resolve13, join as join10 } from "node:path";
23658
23771
  import { connect } from "node:net";
23659
23772
  function cleanShutdownMarkerPathForAgent(name) {
@@ -23666,7 +23779,7 @@ function writeRestartReasonMarker(name, reason, opts = {}) {
23666
23779
  mkdirSync12(join10(path, ".."), { recursive: true });
23667
23780
  if (opts.preserveExisting && existsSync15(path)) {
23668
23781
  try {
23669
- const prev = JSON.parse(readFileSync13(path, "utf-8"));
23782
+ const prev = JSON.parse(readFileSync14(path, "utf-8"));
23670
23783
  if (prev && typeof prev.ts === "number" && Date.now() - prev.ts < 30000 && prev.reason) {
23671
23784
  return;
23672
23785
  }
@@ -23683,7 +23796,7 @@ function buildCliRestartReason(opts) {
23683
23796
  if (!buildCommit)
23684
23797
  return "cli: restart";
23685
23798
  try {
23686
- const head = execFileSync7("git", ["rev-parse", "HEAD"], {
23799
+ const head = execFileSync8("git", ["rev-parse", "HEAD"], {
23687
23800
  cwd: cwd ?? process.cwd(),
23688
23801
  encoding: "utf-8",
23689
23802
  stdio: ["ignore", "pipe", "ignore"]
@@ -23694,7 +23807,7 @@ function buildCliRestartReason(opts) {
23694
23807
  return "cli: restart";
23695
23808
  let subject = "";
23696
23809
  try {
23697
- subject = execFileSync7("git", ["log", "-1", "--pretty=%s", head], {
23810
+ subject = execFileSync8("git", ["log", "-1", "--pretty=%s", head], {
23698
23811
  cwd: cwd ?? process.cwd(),
23699
23812
  encoding: "utf-8",
23700
23813
  stdio: ["ignore", "pipe", "ignore"]
@@ -23719,9 +23832,12 @@ function composeFilePath() {
23719
23832
  return override;
23720
23833
  return resolve13(resolveSwitchroomHome(), "compose", "docker-compose.yml");
23721
23834
  }
23835
+ function reconcileSingletonImages(log) {
23836
+ return reconcileSingletons({ composeFile: composeFilePath(), log });
23837
+ }
23722
23838
  function dockerSync(args) {
23723
23839
  try {
23724
- return execFileSync7("docker", args, {
23840
+ return execFileSync8("docker", args, {
23725
23841
  encoding: "utf-8",
23726
23842
  stdio: ["ignore", "pipe", "pipe"]
23727
23843
  }).trim();
@@ -24103,15 +24219,16 @@ var init_lifecycle = __esm(() => {
24103
24219
  init_loader();
24104
24220
  init_tmux();
24105
24221
  init_docker_fleet();
24222
+ init_singleton_reconcile();
24106
24223
  });
24107
24224
 
24108
24225
  // src/auth/pane-ready-probe.ts
24109
- import { execFileSync as execFileSync9 } from "node:child_process";
24226
+ import { execFileSync as execFileSync10 } from "node:child_process";
24110
24227
  function defaultPaneReadyDeps() {
24111
24228
  return {
24112
24229
  capturePane(sessionName) {
24113
24230
  try {
24114
- return execFileSync9("tmux", ["capture-pane", "-p", "-t", sessionName, "-S", "-200"], {
24231
+ return execFileSync10("tmux", ["capture-pane", "-p", "-t", sessionName, "-S", "-200"], {
24115
24232
  encoding: "utf-8",
24116
24233
  stdio: ["pipe", "pipe", "pipe"]
24117
24234
  }).trim();
@@ -24151,7 +24268,7 @@ import {
24151
24268
  copyFileSync as copyFileSync5,
24152
24269
  existsSync as existsSync19,
24153
24270
  mkdirSync as mkdirSync14,
24154
- readFileSync as readFileSync17,
24271
+ readFileSync as readFileSync18,
24155
24272
  readdirSync as readdirSync9,
24156
24273
  renameSync as renameSync6,
24157
24274
  rmSync as rmSync4,
@@ -24206,7 +24323,7 @@ function readActiveSlot(agentDir) {
24206
24323
  if (!existsSync19(p))
24207
24324
  return null;
24208
24325
  try {
24209
- const val = readFileSync17(p, "utf-8").trim();
24326
+ const val = readFileSync18(p, "utf-8").trim();
24210
24327
  return val.length > 0 ? val : null;
24211
24328
  } catch {
24212
24329
  return null;
@@ -24242,7 +24359,7 @@ function readSlotMeta(agentDir, slot) {
24242
24359
  if (!existsSync19(p))
24243
24360
  return null;
24244
24361
  try {
24245
- return JSON.parse(readFileSync17(p, "utf-8"));
24362
+ return JSON.parse(readFileSync18(p, "utf-8"));
24246
24363
  } catch {
24247
24364
  return null;
24248
24365
  }
@@ -24291,7 +24408,7 @@ function syncLegacyFromActive(agentDir) {
24291
24408
  }
24292
24409
  }
24293
24410
  function atomicCopy(src, dest, mode) {
24294
- const contents = readFileSync17(src);
24411
+ const contents = readFileSync18(src);
24295
24412
  const tmp = `${dest}.tmp-${process.pid}-${randomBytes2(4).toString("hex")}`;
24296
24413
  try {
24297
24414
  writeFileSync9(tmp, contents, { mode });
@@ -24320,7 +24437,7 @@ function migrateLegacyIfNeeded(agentDir) {
24320
24437
  }
24321
24438
  let token;
24322
24439
  try {
24323
- token = readFileSync17(legacyToken, "utf-8").trim();
24440
+ token = readFileSync18(legacyToken, "utf-8").trim();
24324
24441
  } catch {
24325
24442
  return { migrated: false };
24326
24443
  }
@@ -24392,9 +24509,9 @@ var init_accounts = __esm(() => {
24392
24509
  });
24393
24510
 
24394
24511
  // src/auth/manager.ts
24395
- import { execFileSync as execFileSync10 } from "node:child_process";
24512
+ import { execFileSync as execFileSync11 } from "node:child_process";
24396
24513
  import {
24397
- readFileSync as readFileSync18,
24514
+ readFileSync as readFileSync19,
24398
24515
  readdirSync as readdirSync10,
24399
24516
  existsSync as existsSync20,
24400
24517
  writeFileSync as writeFileSync10,
@@ -24443,14 +24560,14 @@ function authSessionName(name, slot) {
24443
24560
  return `${base}-${slot.replace(/[^a-zA-Z0-9_.-]/g, "-")}`;
24444
24561
  }
24445
24562
  function tmux(args) {
24446
- return execFileSync10("tmux", args, {
24563
+ return execFileSync11("tmux", args, {
24447
24564
  encoding: "utf-8",
24448
24565
  stdio: ["pipe", "pipe", "pipe"]
24449
24566
  }).trim();
24450
24567
  }
24451
24568
  function tmuxSessionExists(sessionName) {
24452
24569
  try {
24453
- execFileSync10("tmux", ["has-session", "-t", sessionName], {
24570
+ execFileSync11("tmux", ["has-session", "-t", sessionName], {
24454
24571
  stdio: ["pipe", "pipe", "pipe"]
24455
24572
  });
24456
24573
  return true;
@@ -24465,7 +24582,7 @@ function readJsonFile(path) {
24465
24582
  if (!existsSync20(path))
24466
24583
  return null;
24467
24584
  try {
24468
- return JSON.parse(readFileSync18(path, "utf-8"));
24585
+ return JSON.parse(readFileSync19(path, "utf-8"));
24469
24586
  } catch {
24470
24587
  return null;
24471
24588
  }
@@ -24475,7 +24592,7 @@ function readOAuthToken(agentDir) {
24475
24592
  if (!existsSync20(path))
24476
24593
  return null;
24477
24594
  try {
24478
- const token = readFileSync18(path, "utf-8").trim();
24595
+ const token = readFileSync19(path, "utf-8").trim();
24479
24596
  return token.length > 0 ? token : null;
24480
24597
  } catch {
24481
24598
  return null;
@@ -24487,7 +24604,7 @@ function authFilesAreInaccessible(agentDir) {
24487
24604
  if (!existsSync20(p))
24488
24605
  continue;
24489
24606
  try {
24490
- readFileSync18(p, "utf-8");
24607
+ readFileSync19(p, "utf-8");
24491
24608
  } catch (err) {
24492
24609
  const code = err?.code;
24493
24610
  if (code === "EACCES" || code === "EPERM")
@@ -24586,7 +24703,7 @@ function readTokenFromCredentialsFile(credentialsFilePath) {
24586
24703
  try {
24587
24704
  if (!existsSync20(credentialsFilePath))
24588
24705
  return null;
24589
- const raw = readFileSync18(credentialsFilePath, "utf-8");
24706
+ const raw = readFileSync19(credentialsFilePath, "utf-8");
24590
24707
  const parsed = JSON.parse(raw);
24591
24708
  const token = parsed?.claudeAiOauth?.accessToken;
24592
24709
  if (typeof token !== "string")
@@ -24610,7 +24727,7 @@ function readCredentials(agentDir) {
24610
24727
  if (!existsSync20(credPath))
24611
24728
  return null;
24612
24729
  try {
24613
- const parsed = JSON.parse(readFileSync18(credPath, "utf-8"));
24730
+ const parsed = JSON.parse(readFileSync19(credPath, "utf-8"));
24614
24731
  return parsed.claudeAiOauth ?? null;
24615
24732
  } catch {
24616
24733
  return null;
@@ -24766,7 +24883,7 @@ function readTokenFromLogFile(logPath) {
24766
24883
  if (!existsSync20(logPath))
24767
24884
  return null;
24768
24885
  try {
24769
- const content = readFileSync18(logPath, "utf-8");
24886
+ const content = readFileSync19(logPath, "utf-8");
24770
24887
  return parseSetupTokenValue(content);
24771
24888
  } catch {
24772
24889
  return null;
@@ -24912,7 +25029,7 @@ var init_manager = __esm(() => {
24912
25029
  import {
24913
25030
  existsSync as existsSync25,
24914
25031
  mkdirSync as mkdirSync16,
24915
- readFileSync as readFileSync20,
25032
+ readFileSync as readFileSync21,
24916
25033
  unlinkSync as unlinkSync6,
24917
25034
  writeFileSync as writeFileSync12
24918
25035
  } from "node:fs";
@@ -24925,7 +25042,7 @@ function readQuarantineMarker(telegramStateDir) {
24925
25042
  if (!existsSync25(path))
24926
25043
  return null;
24927
25044
  try {
24928
- const raw = readFileSync20(path, "utf-8");
25045
+ const raw = readFileSync21(path, "utf-8");
24929
25046
  const parsed = JSON.parse(raw);
24930
25047
  if (!parsed || typeof parsed !== "object")
24931
25048
  return null;
@@ -24981,7 +25098,7 @@ __export(exports_inject, {
24981
25098
  INJECT_BLOCKED: () => INJECT_BLOCKED,
24982
25099
  INJECT_ALLOWLIST: () => INJECT_ALLOWLIST
24983
25100
  });
24984
- import { execFile, execFileSync as execFileSync12 } from "node:child_process";
25101
+ import { execFile, execFileSync as execFileSync13 } from "node:child_process";
24985
25102
  import { promisify } from "node:util";
24986
25103
  function validateInjectCommand(command) {
24987
25104
  if (typeof command !== "string" || command.trim().length === 0) {
@@ -25009,7 +25126,7 @@ function makeTmuxRunner(tmuxBin) {
25009
25126
  return {
25010
25127
  capture(socket, session) {
25011
25128
  try {
25012
- return execFileSync12(tmuxBin, ["-L", socket, "capture-pane", "-p", "-t", session, "-S", "-200"], { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] });
25129
+ return execFileSync13(tmuxBin, ["-L", socket, "capture-pane", "-p", "-t", session, "-S", "-200"], { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] });
25013
25130
  } catch {
25014
25131
  return null;
25015
25132
  }
@@ -25019,11 +25136,11 @@ function makeTmuxRunner(tmuxBin) {
25019
25136
  const flagEnd = rest.findIndex((a) => !a.startsWith("-"));
25020
25137
  const flagsBeforeKeys = flagEnd === -1 ? rest : rest.slice(0, flagEnd);
25021
25138
  const keys = flagEnd === -1 ? [] : rest.slice(flagEnd);
25022
- execFileSync12(tmuxBin, ["-L", socket, subcmd, ...flagsBeforeKeys, "-t", session, ...keys], { stdio: ["pipe", "pipe", "pipe"] });
25139
+ execFileSync13(tmuxBin, ["-L", socket, subcmd, ...flagsBeforeKeys, "-t", session, ...keys], { stdio: ["pipe", "pipe", "pipe"] });
25023
25140
  },
25024
25141
  hasSession(socket, session) {
25025
25142
  try {
25026
- execFileSync12(tmuxBin, ["-L", socket, "has-session", "-t", session], {
25143
+ execFileSync13(tmuxBin, ["-L", socket, "has-session", "-t", session], {
25027
25144
  stdio: ["pipe", "pipe", "pipe"]
25028
25145
  });
25029
25146
  return true;
@@ -25856,7 +25973,7 @@ import {
25856
25973
  chownSync,
25857
25974
  existsSync as existsSync28,
25858
25975
  mkdirSync as mkdirSync17,
25859
- readFileSync as readFileSync22,
25976
+ readFileSync as readFileSync23,
25860
25977
  readdirSync as readdirSync14,
25861
25978
  renameSync as renameSync7,
25862
25979
  rmSync as rmSync10,
@@ -25904,7 +26021,7 @@ function readAccountCredentials(label, home2 = homedir9()) {
25904
26021
  if (!existsSync28(p))
25905
26022
  return null;
25906
26023
  try {
25907
- return JSON.parse(readFileSync22(p, "utf-8"));
26024
+ return JSON.parse(readFileSync23(p, "utf-8"));
25908
26025
  } catch {
25909
26026
  return null;
25910
26027
  }
@@ -25914,7 +26031,7 @@ function readAccountMeta(label, home2 = homedir9()) {
25914
26031
  if (!existsSync28(p))
25915
26032
  return null;
25916
26033
  try {
25917
- return JSON.parse(readFileSync22(p, "utf-8"));
26034
+ return JSON.parse(readFileSync23(p, "utf-8"));
25918
26035
  } catch {
25919
26036
  return null;
25920
26037
  }
@@ -25964,9 +26081,9 @@ function setGoogleWorkspaceBlock(yamlText, block) {
25964
26081
  if (!Array.isArray(block.approvers) || block.approvers.length === 0) {
25965
26082
  throw new Error("setGoogleWorkspaceBlock: at least one approver id is required");
25966
26083
  }
25967
- const doc = import_yaml6.parseDocument(yamlText);
26084
+ const doc = import_yaml7.parseDocument(yamlText);
25968
26085
  const root = doc.contents;
25969
- if (!import_yaml6.isMap(root)) {
26086
+ if (!import_yaml7.isMap(root)) {
25970
26087
  throw new Error("setGoogleWorkspaceBlock: YAML root is not a map");
25971
26088
  }
25972
26089
  if (root.has("google_workspace") || root.has("drive")) {
@@ -25983,9 +26100,9 @@ function setGoogleWorkspaceBlock(yamlText, block) {
25983
26100
  `) ? out : out + `
25984
26101
  `;
25985
26102
  }
25986
- var import_yaml6;
26103
+ var import_yaml7;
25987
26104
  var init_google_workspace_yaml = __esm(() => {
25988
- import_yaml6 = __toESM(require_dist(), 1);
26105
+ import_yaml7 = __toESM(require_dist(), 1);
25989
26106
  });
25990
26107
 
25991
26108
  // src/util/atomic.ts
@@ -27655,13 +27772,13 @@ function setAuthActive(yamlText, label) {
27655
27772
  if (typeof label !== "string" || label.length === 0) {
27656
27773
  throw new Error("setAuthActive: label must be a non-empty string");
27657
27774
  }
27658
- const doc = import_yaml8.parseDocument(yamlText);
27775
+ const doc = import_yaml9.parseDocument(yamlText);
27659
27776
  const root = doc.contents;
27660
- if (!import_yaml8.isMap(root)) {
27777
+ if (!import_yaml9.isMap(root)) {
27661
27778
  throw new Error("setAuthActive: YAML root is not a map");
27662
27779
  }
27663
27780
  const existing = root.get("auth", true);
27664
- if (import_yaml8.isMap(existing)) {
27781
+ if (import_yaml9.isMap(existing)) {
27665
27782
  if (existing.get("active") === label) {
27666
27783
  return yamlText;
27667
27784
  }
@@ -27674,9 +27791,9 @@ function setAuthActive(yamlText, label) {
27674
27791
  `) ? out : out + `
27675
27792
  `;
27676
27793
  }
27677
- var import_yaml8;
27794
+ var import_yaml9;
27678
27795
  var init_auth_active_yaml = __esm(() => {
27679
- import_yaml8 = __toESM(require_dist(), 1);
27796
+ import_yaml9 = __toESM(require_dist(), 1);
27680
27797
  });
27681
27798
 
27682
27799
  // src/auth/via-claude.ts
@@ -27690,8 +27807,8 @@ __export(exports_via_claude, {
27690
27807
  PRE_PASTE_RULES: () => PRE_PASTE_RULES,
27691
27808
  POST_PASTE_RULES: () => POST_PASTE_RULES
27692
27809
  });
27693
- import { execFileSync as execFileSync13, spawnSync as spawnSync2 } from "node:child_process";
27694
- import { existsSync as existsSync30, mkdirSync as mkdirSync18, readFileSync as readFileSync25 } from "node:fs";
27810
+ import { execFileSync as execFileSync14, spawnSync as spawnSync2 } from "node:child_process";
27811
+ import { existsSync as existsSync30, mkdirSync as mkdirSync18, readFileSync as readFileSync26 } from "node:fs";
27695
27812
  import { join as join22, resolve as resolve23 } from "node:path";
27696
27813
  function tmuxHasSession(session) {
27697
27814
  const r = spawnSync2("tmux", ["has-session", "-t", session], {
@@ -27701,7 +27818,7 @@ function tmuxHasSession(session) {
27701
27818
  }
27702
27819
  function tmuxKillSession(session) {
27703
27820
  try {
27704
- execFileSync13("tmux", ["kill-session", "-t", session], {
27821
+ execFileSync14("tmux", ["kill-session", "-t", session], {
27705
27822
  stdio: "ignore",
27706
27823
  timeout: 3000
27707
27824
  });
@@ -27709,7 +27826,7 @@ function tmuxKillSession(session) {
27709
27826
  }
27710
27827
  function tmuxCapturePane(session) {
27711
27828
  try {
27712
- const out = execFileSync13("tmux", ["capture-pane", "-p", "-t", session, "-S", "-200"], { timeout: 3000, stdio: ["ignore", "pipe", "pipe"], maxBuffer: 4 * 1024 * 1024 });
27829
+ const out = execFileSync14("tmux", ["capture-pane", "-p", "-t", session, "-S", "-200"], { timeout: 3000, stdio: ["ignore", "pipe", "pipe"], maxBuffer: 4 * 1024 * 1024 });
27713
27830
  return out.toString("utf8");
27714
27831
  } catch {
27715
27832
  return "";
@@ -27717,7 +27834,7 @@ function tmuxCapturePane(session) {
27717
27834
  }
27718
27835
  function tmuxSendKeys(session, keys, literal = false) {
27719
27836
  try {
27720
- execFileSync13("tmux", ["send-keys", "-t", session, ...literal ? ["-l"] : [], ...keys], { timeout: 3000, stdio: ["ignore", "pipe", "pipe"] });
27837
+ execFileSync14("tmux", ["send-keys", "-t", session, ...literal ? ["-l"] : [], ...keys], { timeout: 3000, stdio: ["ignore", "pipe", "pipe"] });
27721
27838
  } catch {}
27722
27839
  }
27723
27840
  function extractAuthorizeUrl(pane) {
@@ -27746,7 +27863,7 @@ async function runViaClaude(opts) {
27746
27863
  tmuxKillSession(SESSION);
27747
27864
  }
27748
27865
  const spawn4 = opts.spawnClaude ?? (() => {
27749
- execFileSync13("tmux", [
27866
+ execFileSync14("tmux", [
27750
27867
  "new-session",
27751
27868
  "-d",
27752
27869
  "-s",
@@ -27801,7 +27918,7 @@ async function runViaClaude(opts) {
27801
27918
  await sleep3(poll);
27802
27919
  if (existsSync30(credentialsPath2)) {
27803
27920
  await sleep3(200);
27804
- const raw = readFileSync25(credentialsPath2, "utf-8");
27921
+ const raw = readFileSync26(credentialsPath2, "utf-8");
27805
27922
  let parsed;
27806
27923
  try {
27807
27924
  parsed = JSON.parse(raw);
@@ -28563,7 +28680,7 @@ var init_thinking_effort_risk = __esm(() => {
28563
28680
  // src/manifest.ts
28564
28681
  import {
28565
28682
  existsSync as existsSync49,
28566
- readFileSync as readFileSync44,
28683
+ readFileSync as readFileSync45,
28567
28684
  readdirSync as readdirSync18
28568
28685
  } from "node:fs";
28569
28686
  import { dirname as dirname11, join as join42 } from "node:path";
@@ -28585,7 +28702,7 @@ function loadManifest(manifestPath) {
28585
28702
  }
28586
28703
  let raw;
28587
28704
  try {
28588
- raw = readFileSync44(path4, "utf-8");
28705
+ raw = readFileSync45(path4, "utf-8");
28589
28706
  } catch (err) {
28590
28707
  throw new Error(`Failed to read manifest at ${path4}: ${err.message}`);
28591
28708
  }
@@ -28650,7 +28767,7 @@ function probePlaywrightMcpVersion() {
28650
28767
  const pkgPath = join42(npxCache, entry, "node_modules/@playwright/mcp/package.json");
28651
28768
  if (existsSync49(pkgPath)) {
28652
28769
  try {
28653
- const pkg = JSON.parse(readFileSync44(pkgPath, "utf-8"));
28770
+ const pkg = JSON.parse(readFileSync45(pkgPath, "utf-8"));
28654
28771
  if (pkg.version)
28655
28772
  return pkg.version;
28656
28773
  } catch {}
@@ -28742,13 +28859,22 @@ var init_manifest = __esm(() => {
28742
28859
  });
28743
28860
 
28744
28861
  // src/cli/doctor-docker.ts
28745
- import { readFileSync as readFileSync45 } from "node:fs";
28862
+ import { readFileSync as readFileSync46 } from "node:fs";
28863
+ function imageTagOf(ref) {
28864
+ if (!ref)
28865
+ return "<absent>";
28866
+ const at = ref.lastIndexOf("@");
28867
+ const base = at >= 0 ? ref.slice(0, at) : ref;
28868
+ const colon = base.lastIndexOf(":");
28869
+ const slash = base.lastIndexOf("/");
28870
+ return colon > slash ? base.slice(colon + 1) : ref;
28871
+ }
28746
28872
  function isDockerMode(opts) {
28747
28873
  if (process.env.SWITCHROOM_RUNTIME === "docker")
28748
28874
  return true;
28749
28875
  if (opts?.composePath) {
28750
28876
  try {
28751
- readFileSync45(opts.composePath, "utf8");
28877
+ readFileSync46(opts.composePath, "utf8");
28752
28878
  return true;
28753
28879
  } catch {}
28754
28880
  }
@@ -28883,6 +29009,27 @@ function checkDockerfileUserAlignment(composeYaml, dockerfileAgent) {
28883
29009
  fix: "Drop the USER directive from Dockerfile.agent (preferred \u2014 the image is identity-neutral) or align per-agent UIDs by renaming."
28884
29010
  };
28885
29011
  }
29012
+ function checkSingletonImageDrift(composeYaml, deps) {
29013
+ const drift = detectSingletonDrift({
29014
+ composeFile: "(in-memory)",
29015
+ readCompose: () => composeYaml,
29016
+ inspectImage: deps?.inspectImage
29017
+ });
29018
+ const stale = drift.filter((d) => d.needsRecreate && d.running !== null);
29019
+ if (stale.length === 0) {
29020
+ return {
29021
+ name: "singleton image drift",
29022
+ status: "ok",
29023
+ detail: "vault-broker / approval-kernel / auth-broker match the pinned image"
29024
+ };
29025
+ }
29026
+ return {
29027
+ name: "singleton image drift",
29028
+ status: "warn",
29029
+ detail: "singleton(s) running an image older than the pin: " + stale.map((d) => `${d.service} ${imageTagOf(d.running)}\u2260${imageTagOf(d.pinned)}`).join(", "),
29030
+ fix: "Recreate them \u2014 `switchroom agent restart <any-agent>` now self-heals stale singletons, or `switchroom update` (whole-project recreate)."
29031
+ };
29032
+ }
28886
29033
  function runDockerChecks(args) {
28887
29034
  if (!args.active) {
28888
29035
  return [{
@@ -28896,6 +29043,7 @@ function runDockerChecks(args) {
28896
29043
  out.push(checkAgentCaps(args.config));
28897
29044
  if (args.composeYaml) {
28898
29045
  out.push(checkAgentSocketMounts(args.composeYaml));
29046
+ out.push(checkSingletonImageDrift(args.composeYaml));
28899
29047
  if (args.dockerfileAgent) {
28900
29048
  out.push(checkDockerfileUserAlignment(args.composeYaml, args.dockerfileAgent));
28901
29049
  }
@@ -28911,10 +29059,11 @@ function runDockerChecks(args) {
28911
29059
  }
28912
29060
  var init_doctor_docker = __esm(() => {
28913
29061
  init_compose();
29062
+ init_singleton_reconcile();
28914
29063
  });
28915
29064
 
28916
29065
  // src/cli/doctor-auth-broker.ts
28917
- import { existsSync as existsSync50, readFileSync as readFileSync46 } from "node:fs";
29066
+ import { existsSync as existsSync50, readFileSync as readFileSync47 } from "node:fs";
28918
29067
  import { createHash as createHash10 } from "node:crypto";
28919
29068
  import { spawnSync as spawnSync5 } from "node:child_process";
28920
29069
  import { homedir as homedir23 } from "node:os";
@@ -29028,7 +29177,7 @@ function checkAuthBrokerDrift(deps = {}) {
29028
29177
  }
29029
29178
  let index;
29030
29179
  try {
29031
- index = JSON.parse(readFileSync46(indexPath, "utf-8"));
29180
+ index = JSON.parse(readFileSync47(indexPath, "utf-8"));
29032
29181
  } catch (err) {
29033
29182
  return {
29034
29183
  name: "auth-broker: drift",
@@ -29048,7 +29197,7 @@ function checkAuthBrokerDrift(deps = {}) {
29048
29197
  }
29049
29198
  let got;
29050
29199
  try {
29051
- got = sha256Hex(readFileSync46(credsPath, "utf-8"));
29200
+ got = sha256Hex(readFileSync47(credsPath, "utf-8"));
29052
29201
  } catch (err) {
29053
29202
  divergent.push(`${label} (read failed: ${err.message})`);
29054
29203
  continue;
@@ -29089,7 +29238,7 @@ function checkAuthBrokerThresholdViolations(deps = {}) {
29089
29238
  }
29090
29239
  let violations;
29091
29240
  try {
29092
- violations = JSON.parse(readFileSync46(path4, "utf-8"));
29241
+ violations = JSON.parse(readFileSync47(path4, "utf-8"));
29093
29242
  } catch (err) {
29094
29243
  return {
29095
29244
  name: "auth-broker: threshold violations",
@@ -30586,7 +30735,7 @@ function runInlinedSecretChecks(_config, deps = {}) {
30586
30735
  }
30587
30736
  let parsed;
30588
30737
  try {
30589
- parsed = import_yaml14.parse(raw);
30738
+ parsed = import_yaml15.parse(raw);
30590
30739
  } catch {
30591
30740
  return [
30592
30741
  {
@@ -30614,9 +30763,9 @@ function runInlinedSecretChecks(_config, deps = {}) {
30614
30763
  fix: `Move it to the per-agent-ACL'd vault: \`switchroom vault set <name>\` ` + `then replace the literal with \`vault:<name>\`. Rotate the exposed ` + `value if any agent may already have read it.`
30615
30764
  }));
30616
30765
  }
30617
- var import_yaml14, SECRET_KEY_EXACT;
30766
+ var import_yaml15, SECRET_KEY_EXACT;
30618
30767
  var init_doctor_inlined_secrets = __esm(() => {
30619
- import_yaml14 = __toESM(require_dist(), 1);
30768
+ import_yaml15 = __toESM(require_dist(), 1);
30620
30769
  SECRET_KEY_EXACT = new Set([
30621
30770
  "bot_token",
30622
30771
  "client_secret",
@@ -30868,7 +31017,7 @@ var init_doctor_agent_smoke = __esm(() => {
30868
31017
  });
30869
31018
 
30870
31019
  // src/cli/doctor-vault-broker-durability.ts
30871
- import { execFileSync as execFileSync16 } from "node:child_process";
31020
+ import { execFileSync as execFileSync17 } from "node:child_process";
30872
31021
  import { existsSync as existsSync53, statSync as statSync22 } from "node:fs";
30873
31022
  import { homedir as homedir32 } from "node:os";
30874
31023
  import { join as join53 } from "node:path";
@@ -30930,7 +31079,7 @@ function spawnDockerStat(p) {
30930
31079
  }
30931
31080
  function spawnDockerStatForContainer(containerName2, p) {
30932
31081
  try {
30933
- const stdout = execFileSync16("docker", ["exec", containerName2, "stat", "-c", "%i %s", p], { stdio: ["ignore", "pipe", "pipe"], timeout: 3000, encoding: "utf8" });
31082
+ const stdout = execFileSync17("docker", ["exec", containerName2, "stat", "-c", "%i %s", p], { stdio: ["ignore", "pipe", "pipe"], timeout: 3000, encoding: "utf8" });
30934
31083
  return { status: 0, stdout, stderr: "", error: null };
30935
31084
  } catch (err) {
30936
31085
  const e = err;
@@ -31004,7 +31153,7 @@ function probeBrokerUnlocked(opts) {
31004
31153
  }
31005
31154
  function defaultBrokerStatusProbe() {
31006
31155
  try {
31007
- const out = execFileSync16("switchroom", ["vault", "broker", "status"], { stdio: ["ignore", "pipe", "pipe"], timeout: 3000, encoding: "utf8" });
31156
+ const out = execFileSync17("switchroom", ["vault", "broker", "status"], { stdio: ["ignore", "pipe", "pipe"], timeout: 3000, encoding: "utf8" });
31008
31157
  const parsed = JSON.parse(out.trim());
31009
31158
  if (!parsed.running)
31010
31159
  return null;
@@ -31204,7 +31353,7 @@ import {
31204
31353
  existsSync as existsSync54,
31205
31354
  lstatSync as lstatSync5,
31206
31355
  mkdirSync as mkdirSync29,
31207
- readFileSync as readFileSync47,
31356
+ readFileSync as readFileSync48,
31208
31357
  readdirSync as readdirSync20,
31209
31358
  statSync as statSync23
31210
31359
  } from "node:fs";
@@ -31882,7 +32031,7 @@ function classifyReadError(err) {
31882
32031
  }
31883
32032
  function tryReadHostFile(path4) {
31884
32033
  try {
31885
- return { kind: "ok", content: readFileSync47(path4, "utf-8") };
32034
+ return { kind: "ok", content: readFileSync48(path4, "utf-8") };
31886
32035
  } catch (err) {
31887
32036
  const kind = classifyReadError(err);
31888
32037
  const error = err?.message ?? String(err);
@@ -31898,7 +32047,7 @@ function parseEnvFile(path4) {
31898
32047
  return {};
31899
32048
  let content;
31900
32049
  try {
31901
- content = readFileSync47(path4, "utf-8");
32050
+ content = readFileSync48(path4, "utf-8");
31902
32051
  } catch {
31903
32052
  return {};
31904
32053
  }
@@ -32015,7 +32164,7 @@ function checkStartShStale(agentName, startShPath) {
32015
32164
  }
32016
32165
  let content;
32017
32166
  try {
32018
- content = readFileSync47(startShPath, "utf-8");
32167
+ content = readFileSync48(startShPath, "utf-8");
32019
32168
  } catch (err) {
32020
32169
  return {
32021
32170
  name: label,
@@ -32128,7 +32277,7 @@ function isSwitchroomCheckout(dir) {
32128
32277
  const pkgPath = join54(dir, "package.json");
32129
32278
  if (!existsSync54(pkgPath))
32130
32279
  return false;
32131
- const pkg = JSON.parse(readFileSync47(pkgPath, "utf-8"));
32280
+ const pkg = JSON.parse(readFileSync48(pkgPath, "utf-8"));
32132
32281
  return pkg.name === "switchroom";
32133
32282
  } catch {
32134
32283
  return false;
@@ -32249,7 +32398,7 @@ function checkAgents(config, configPath) {
32249
32398
  });
32250
32399
  } else {
32251
32400
  try {
32252
- const mcp = JSON.parse(readFileSync47(mcpJsonPath, "utf-8"));
32401
+ const mcp = JSON.parse(readFileSync48(mcpJsonPath, "utf-8"));
32253
32402
  const hasSwitchroomTelegram = !!mcp.mcpServers?.["switchroom-telegram"];
32254
32403
  const memoryEnabled = isHindsightEnabled(config);
32255
32404
  const hasHindsight = !!mcp.mcpServers?.hindsight;
@@ -32744,11 +32893,11 @@ function runDockerSection(config) {
32744
32893
  let composeYaml;
32745
32894
  let dockerfileAgent;
32746
32895
  try {
32747
- composeYaml = readFileSync47(composePath, "utf8");
32896
+ composeYaml = readFileSync48(composePath, "utf8");
32748
32897
  } catch {}
32749
32898
  const dockerfilePath = resolve32(process.env.HOME ?? "", ".switchroom", "docker", "Dockerfile.agent");
32750
32899
  try {
32751
- dockerfileAgent = readFileSync47(dockerfilePath, "utf8");
32900
+ dockerfileAgent = readFileSync48(dockerfilePath, "utf8");
32752
32901
  } catch {}
32753
32902
  return runDockerChecks({
32754
32903
  config,
@@ -49041,7 +49190,7 @@ __export(exports_server2, {
49041
49190
  TOOLS: () => TOOLS2
49042
49191
  });
49043
49192
  import { randomBytes as randomBytes15 } from "node:crypto";
49044
- import { existsSync as existsSync82, readFileSync as readFileSync66 } from "node:fs";
49193
+ import { existsSync as existsSync82, readFileSync as readFileSync67 } from "node:fs";
49045
49194
  function selfSocketPath() {
49046
49195
  return `/run/switchroom/hostd/${SELF_AGENT}/sock`;
49047
49196
  }
@@ -49219,7 +49368,7 @@ function getLastUpdateApplyStatus() {
49219
49368
  }
49220
49369
  let raw;
49221
49370
  try {
49222
- raw = readFileSync66(path8, "utf-8");
49371
+ raw = readFileSync67(path8, "utf-8");
49223
49372
  } catch (err2) {
49224
49373
  return errorText2(`get_status: failed to read audit log at ${path8}: ${err2.message}`);
49225
49374
  }
@@ -49452,13 +49601,13 @@ var {
49452
49601
  } = import__.default;
49453
49602
 
49454
49603
  // src/build-info.ts
49455
- var VERSION = "0.14.66";
49456
- var COMMIT_SHA = "0f4f029d";
49604
+ var VERSION = "0.14.68";
49605
+ var COMMIT_SHA = "4f371b79";
49457
49606
 
49458
49607
  // src/cli/agent.ts
49459
49608
  init_source();
49460
49609
  import { join as join17, resolve as resolve21 } from "node:path";
49461
- import { rmSync as rmSync9, existsSync as existsSync26, readFileSync as readFileSync21, writeFileSync as writeFileSync13 } from "node:fs";
49610
+ import { rmSync as rmSync9, existsSync as existsSync26, readFileSync as readFileSync22, writeFileSync as writeFileSync13 } from "node:fs";
49462
49611
  import { homedir as homedir6 } from "node:os";
49463
49612
 
49464
49613
  // src/agents/scheduler-state.ts
@@ -49524,7 +49673,7 @@ function formatSchedulerState(state) {
49524
49673
  init_loader();
49525
49674
  init_hindsight();
49526
49675
  init_helpers();
49527
- var import_yaml4 = __toESM(require_dist(), 1);
49676
+ var import_yaml5 = __toESM(require_dist(), 1);
49528
49677
 
49529
49678
  // src/agents/scaffold.ts
49530
49679
  init_source();
@@ -53079,12 +53228,12 @@ function spinner(message) {
53079
53228
  }
53080
53229
 
53081
53230
  // src/agents/status.ts
53082
- import { existsSync as existsSync18, readFileSync as readFileSync16, statSync as statSync10 } from "node:fs";
53231
+ import { existsSync as existsSync18, readFileSync as readFileSync17, statSync as statSync10 } from "node:fs";
53083
53232
  import { join as join12 } from "node:path";
53084
- import { execFileSync as execFileSync8 } from "node:child_process";
53233
+ import { execFileSync as execFileSync9 } from "node:child_process";
53085
53234
 
53086
53235
  // src/agents/handoff-summarizer.ts
53087
- import { readFileSync as readFileSync14, writeFileSync as writeFileSync8, renameSync as renameSync5, mkdirSync as mkdirSync13, existsSync as existsSync16, statSync as statSync9, readdirSync as readdirSync8 } from "node:fs";
53236
+ import { readFileSync as readFileSync15, writeFileSync as writeFileSync8, renameSync as renameSync5, mkdirSync as mkdirSync13, existsSync as existsSync16, statSync as statSync9, readdirSync as readdirSync8 } from "node:fs";
53088
53237
  import { join as join11 } from "node:path";
53089
53238
  var DEFAULT_MAX_TURNS = 50;
53090
53239
  var TOPIC_MAX_CHARS = 117;
@@ -53092,7 +53241,7 @@ var TURN_TEXT_MAX_CHARS = 1200;
53092
53241
  function extractTurnsFromJsonl(path, maxTurns) {
53093
53242
  let raw;
53094
53243
  try {
53095
- raw = readFileSync14(path, "utf-8");
53244
+ raw = readFileSync15(path, "utf-8");
53096
53245
  } catch {
53097
53246
  return [];
53098
53247
  }
@@ -53317,7 +53466,7 @@ function findLatestSessionJsonl(claudeConfigDir) {
53317
53466
  }
53318
53467
 
53319
53468
  // src/agents/perf.ts
53320
- import { existsSync as existsSync17, readFileSync as readFileSync15 } from "node:fs";
53469
+ import { existsSync as existsSync17, readFileSync as readFileSync16 } from "node:fs";
53321
53470
  function readTurnUsages(jsonlPath, lastN) {
53322
53471
  if (!existsSync17(jsonlPath))
53323
53472
  return [];
@@ -53325,7 +53474,7 @@ function readTurnUsages(jsonlPath, lastN) {
53325
53474
  return [];
53326
53475
  let raw;
53327
53476
  try {
53328
- raw = readFileSync15(jsonlPath, "utf-8");
53477
+ raw = readFileSync16(jsonlPath, "utf-8");
53329
53478
  } catch {
53330
53479
  return [];
53331
53480
  }
@@ -53734,7 +53883,7 @@ function readLogFile(logPath) {
53734
53883
  const stat = statSync10(logPath);
53735
53884
  const cap = 256 * 1024;
53736
53885
  if (stat.size <= cap) {
53737
- return readFileSync16(logPath, "utf-8");
53886
+ return readFileSync17(logPath, "utf-8");
53738
53887
  }
53739
53888
  const fs2 = __require("node:fs");
53740
53889
  const fd = fs2.openSync(logPath, "r");
@@ -53758,14 +53907,14 @@ function readLastMessages(historyDbPath) {
53758
53907
  };
53759
53908
  }
53760
53909
  try {
53761
- const out = execFileSync8("bun", [
53910
+ const out = execFileSync9("bun", [
53762
53911
  "-e",
53763
53912
  `const { Database } = require("bun:sqlite"); ` + `const db = new Database(${JSON.stringify(historyDbPath)}, { readonly: true }); ` + `const rows = db.prepare("SELECT role, MAX(ts) as ts FROM messages GROUP BY role").all(); ` + `for (const r of rows) console.log(r.role + "|" + r.ts); ` + `db.close();`
53764
53913
  ], { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] });
53765
53914
  return parseSqliteRoleTsOutput(out);
53766
53915
  } catch {}
53767
53916
  try {
53768
- const out = execFileSync8("sqlite3", [
53917
+ const out = execFileSync9("sqlite3", [
53769
53918
  historyDbPath,
53770
53919
  "SELECT role, MAX(ts) FROM messages GROUP BY role;"
53771
53920
  ], { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] });
@@ -53877,7 +54026,7 @@ function escapeRegex(s) {
53877
54026
  }
53878
54027
  function readDockerContainer(containerName2) {
53879
54028
  try {
53880
- const out = execFileSync8("docker", ["inspect", "--format", "{{json .State}}", containerName2], { encoding: "utf-8", stdio: ["ignore", "pipe", "pipe"] });
54029
+ const out = execFileSync9("docker", ["inspect", "--format", "{{json .State}}", containerName2], { encoding: "utf-8", stdio: ["ignore", "pipe", "pipe"] });
53881
54030
  const state = JSON.parse(out.trim());
53882
54031
  const active = state.Status === "running" ? "active" : state.Status === "restarting" ? "restarting" : "inactive";
53883
54032
  const pid = typeof state.Pid === "number" && state.Pid > 0 ? state.Pid : null;
@@ -54153,7 +54302,7 @@ async function completeCreation(name, code, opts = {}) {
54153
54302
  // src/agents/add-orchestrator.ts
54154
54303
  import { resolve as resolve18, join as join15 } from "node:path";
54155
54304
  import { existsSync as existsSync23, rmSync as rmSync7, statSync as statSync14 } from "node:fs";
54156
- import { execFileSync as execFileSync11 } from "node:child_process";
54305
+ import { execFileSync as execFileSync12 } from "node:child_process";
54157
54306
 
54158
54307
  // src/setup/botfather-walkthrough.ts
54159
54308
  var DEFAULT_MAX_ATTEMPTS = 3;
@@ -54725,7 +54874,7 @@ function pruneBundledSkills(agentDir, keep, scope) {
54725
54874
  }
54726
54875
  function defaultIsUnitActive(unitName) {
54727
54876
  try {
54728
- const out = execFileSync11("systemctl", ["--user", "is-active", unitName], {
54877
+ const out = execFileSync12("systemctl", ["--user", "is-active", unitName], {
54729
54878
  encoding: "utf-8",
54730
54879
  stdio: ["ignore", "pipe", "pipe"]
54731
54880
  }).trim();
@@ -54754,8 +54903,8 @@ import { tmpdir as tmpdir2 } from "node:os";
54754
54903
  init_merge();
54755
54904
  init_timezone();
54756
54905
  init_resolver();
54757
- var import_yaml3 = __toESM(require_dist(), 1);
54758
- import { readFileSync as readFileSync19, writeFileSync as writeFileSync11 } from "node:fs";
54906
+ var import_yaml4 = __toESM(require_dist(), 1);
54907
+ import { readFileSync as readFileSync20, writeFileSync as writeFileSync11 } from "node:fs";
54759
54908
  var AGENT_NAME_RE2 = /^[a-z0-9][a-z0-9_-]{0,50}$/;
54760
54909
  function defaultDeps() {
54761
54910
  return {
@@ -54778,12 +54927,12 @@ function defaultDeps() {
54778
54927
  copyDir: (src, dst) => cpSync(src, dst, { recursive: true }),
54779
54928
  removeDir: (p) => rmSync8(p, { recursive: true, force: true }),
54780
54929
  existsSync: existsSync24,
54781
- readFileSync: (p, enc) => readFileSync19(p, enc)
54930
+ readFileSync: (p, enc) => readFileSync20(p, enc)
54782
54931
  };
54783
54932
  }
54784
54933
  function renameAgentInConfig(configPath, oldName, newName) {
54785
- const raw = readFileSync19(configPath, "utf-8");
54786
- const doc = import_yaml3.default.parseDocument(raw);
54934
+ const raw = readFileSync20(configPath, "utf-8");
54935
+ const doc = import_yaml4.default.parseDocument(raw);
54787
54936
  const agents = doc.get("agents");
54788
54937
  if (!agents || !agents.has(oldName)) {
54789
54938
  throw new Error(`Agent "${oldName}" not found in ${configPath}`);
@@ -54825,7 +54974,7 @@ async function renameAgent(opts, injectedDeps) {
54825
54974
  const deps = { ...defaultDeps(), ...injectedDeps };
54826
54975
  const { oldName, newName, configPath, hindsightMode = "preserve" } = opts;
54827
54976
  const _existsSync = deps.existsSync;
54828
- const _readFileSync = deps.readFileSync ?? ((p, enc) => readFileSync19(p, enc));
54977
+ const _readFileSync = deps.readFileSync ?? ((p, enc) => readFileSync20(p, enc));
54829
54978
  if (!AGENT_NAME_RE2.test(oldName)) {
54830
54979
  throw new Error(`Invalid old agent name: "${oldName}". ` + `Names must match ^[a-z0-9][a-z0-9_-]{0,50}$`);
54831
54980
  }
@@ -55145,16 +55294,16 @@ function parsePorcelainDirty(porcelain) {
55145
55294
  }
55146
55295
  function checkSwitchroomBranch() {
55147
55296
  try {
55148
- const { execFileSync: execFileSync13 } = __require("node:child_process");
55297
+ const { execFileSync: execFileSync14 } = __require("node:child_process");
55149
55298
  const cwd = process.cwd();
55150
- const branch = execFileSync13("git", ["-C", cwd, "rev-parse", "--abbrev-ref", "HEAD"], {
55299
+ const branch = execFileSync14("git", ["-C", cwd, "rev-parse", "--abbrev-ref", "HEAD"], {
55151
55300
  encoding: "utf-8",
55152
55301
  stdio: ["ignore", "pipe", "ignore"]
55153
55302
  }).trim();
55154
55303
  if (branch === "" || branch === "HEAD")
55155
55304
  return null;
55156
55305
  if (branch === "main" || branch === "master") {
55157
- const porcelain = execFileSync13("git", ["-C", cwd, "status", "--porcelain"], {
55306
+ const porcelain = execFileSync14("git", ["-C", cwd, "status", "--porcelain"], {
55158
55307
  encoding: "utf-8",
55159
55308
  stdio: ["ignore", "pipe", "ignore"]
55160
55309
  });
@@ -55199,7 +55348,7 @@ function preflightCheck(name, agentDir, _usesDevChannels) {
55199
55348
  }
55200
55349
  const envPath = resolve21(agentDir, "telegram", ".env");
55201
55350
  if (existsSync26(envPath)) {
55202
- const envContent = readFileSync21(envPath, "utf-8");
55351
+ const envContent = readFileSync22(envPath, "utf-8");
55203
55352
  if (!envContent.includes("TELEGRAM_BOT_TOKEN=") || envContent.includes("# Set your bot token")) {
55204
55353
  errors2.push(`telegram/.env is missing TELEGRAM_BOT_TOKEN. ` + `Set it or run: switchroom setup`);
55205
55354
  }
@@ -55286,25 +55435,25 @@ function writeAgentEntryToConfig(configPath, name, profile) {
55286
55435
  if (!existsSync26(configPath)) {
55287
55436
  throw new Error(`switchroom.yaml not found at ${configPath}`);
55288
55437
  }
55289
- const raw = readFileSync21(configPath, "utf-8");
55290
- const doc = import_yaml4.default.parseDocument(raw);
55438
+ const raw = readFileSync22(configPath, "utf-8");
55439
+ const doc = import_yaml5.default.parseDocument(raw);
55291
55440
  let agents = doc.get("agents");
55292
55441
  if (!agents) {
55293
- agents = new import_yaml4.default.YAMLMap;
55442
+ agents = new import_yaml5.default.YAMLMap;
55294
55443
  doc.set("agents", agents);
55295
55444
  }
55296
55445
  if (agents.has(name)) {
55297
55446
  throw new Error(`Agent "${name}" already exists in ${configPath}. Use updateAgentExtendsInConfig to change its profile.`);
55298
55447
  }
55299
- const entry = new import_yaml4.default.YAMLMap;
55448
+ const entry = new import_yaml5.default.YAMLMap;
55300
55449
  entry.set("extends", profile);
55301
55450
  entry.set("topic_name", synthesizeTopicName2(name));
55302
55451
  agents.set(name, entry);
55303
55452
  writeFileSync13(configPath, doc.toString(), "utf-8");
55304
55453
  }
55305
55454
  function updateAgentExtendsInConfig(configPath, name, profile) {
55306
- const raw = readFileSync21(configPath, "utf-8");
55307
- const doc = import_yaml4.default.parseDocument(raw);
55455
+ const raw = readFileSync22(configPath, "utf-8");
55456
+ const doc = import_yaml5.default.parseDocument(raw);
55308
55457
  const agents = doc.get("agents");
55309
55458
  if (!agents || !agents.has(name)) {
55310
55459
  throw new Error(`Agent "${name}" not found in ${configPath}; cannot update extends.`);
@@ -55316,8 +55465,8 @@ function updateAgentExtendsInConfig(configPath, name, profile) {
55316
55465
  function removeAgentFromConfig(configPath, name) {
55317
55466
  if (!existsSync26(configPath))
55318
55467
  return;
55319
- const raw = readFileSync21(configPath, "utf-8");
55320
- const doc = import_yaml4.default.parseDocument(raw);
55468
+ const raw = readFileSync22(configPath, "utf-8");
55469
+ const doc = import_yaml5.default.parseDocument(raw);
55321
55470
  const agents = doc.get("agents");
55322
55471
  if (!agents || !agents.has(name))
55323
55472
  return;
@@ -55362,7 +55511,7 @@ async function reconcileAndRestartAgent(name, config, agentsDir, configPath, opt
55362
55511
  if (!opts.force) {
55363
55512
  const envPath = resolve21(agentsDir, name, "telegram", ".env");
55364
55513
  if (existsSync26(envPath)) {
55365
- const envContent = readFileSync21(envPath, "utf-8");
55514
+ const envContent = readFileSync22(envPath, "utf-8");
55366
55515
  const match = envContent.match(/^TELEGRAM_BOT_TOKEN=(.+)$/m);
55367
55516
  if (match) {
55368
55517
  const token = match[1].trim();
@@ -55637,6 +55786,14 @@ Scaffolding agent: ${name}
55637
55786
  }
55638
55787
  }
55639
55788
  let sawAbort = false;
55789
+ try {
55790
+ const recon = reconcileSingletonImages((m) => console.error(source_default.gray(` ${m}`)));
55791
+ if (recon.recreated.length > 0) {
55792
+ console.error(source_default.cyan(` \u21bb Recreated stale singleton(s) to the pinned image: ${recon.recreated.join(", ")}`));
55793
+ }
55794
+ } catch (err) {
55795
+ console.error(source_default.yellow(` \u26a0 singleton reconcile skipped: ${err instanceof Error ? err.message : String(err)}`));
55796
+ }
55640
55797
  for (const n of names) {
55641
55798
  if (!config.agents[n]) {
55642
55799
  console.error(source_default.red(`Agent "${n}" is not defined in switchroom.yaml`));
@@ -55836,7 +55993,7 @@ Scaffolding agent: ${name}
55836
55993
  let actual = {};
55837
55994
  if (existsSync26(settingsPath)) {
55838
55995
  try {
55839
- const raw = JSON.parse(readFileSync21(settingsPath, "utf-8"));
55996
+ const raw = JSON.parse(readFileSync22(settingsPath, "utf-8"));
55840
55997
  actual = raw.hooks ?? {};
55841
55998
  } catch {
55842
55999
  console.error(source_default.red(` ${n}: could not parse settings.json`));
@@ -55978,8 +56135,8 @@ Reconciled ${agentsTouched} agent(s), ${totalChanges} file(s) changed.`));
55978
56135
  console.error(source_default.red(`switchroom.yaml not found at ${configPath}`));
55979
56136
  process.exit(1);
55980
56137
  }
55981
- const raw = readFileSync21(configPath, "utf-8");
55982
- const doc = import_yaml4.default.parseDocument(raw);
56138
+ const raw = readFileSync22(configPath, "utf-8");
56139
+ const doc = import_yaml5.default.parseDocument(raw);
55983
56140
  const agents = doc.get("agents");
55984
56141
  if (!agents || !agents.has(name)) {
55985
56142
  console.error(source_default.red(`Agent "${name}" is not defined in switchroom.yaml`));
@@ -55988,12 +56145,12 @@ Reconciled ${agentsTouched} agent(s), ${totalChanges} file(s) changed.`));
55988
56145
  const agentNode = agents.get(name);
55989
56146
  let tools = agentNode.get("tools");
55990
56147
  if (!tools) {
55991
- tools = new import_yaml4.default.YAMLMap;
56148
+ tools = new import_yaml5.default.YAMLMap;
55992
56149
  agentNode.set("tools", tools);
55993
56150
  }
55994
56151
  let allow = tools.get("allow");
55995
56152
  if (!allow) {
55996
- allow = new import_yaml4.default.YAMLSeq;
56153
+ allow = new import_yaml5.default.YAMLSeq;
55997
56154
  tools.set("allow", allow);
55998
56155
  }
55999
56156
  const existingAllow = allow.toJSON() ?? [];
@@ -56027,8 +56184,8 @@ Reconciled ${agentsTouched} agent(s), ${totalChanges} file(s) changed.`));
56027
56184
  console.error(source_default.red(`switchroom.yaml not found at ${configPath}`));
56028
56185
  process.exit(1);
56029
56186
  }
56030
- const raw = readFileSync21(configPath, "utf-8");
56031
- const doc = import_yaml4.default.parseDocument(raw);
56187
+ const raw = readFileSync22(configPath, "utf-8");
56188
+ const doc = import_yaml5.default.parseDocument(raw);
56032
56189
  const agents = doc.get("agents");
56033
56190
  if (!agents || !agents.has(name)) {
56034
56191
  console.error(source_default.red(`Agent "${name}" is not defined in switchroom.yaml`));
@@ -56038,7 +56195,7 @@ Reconciled ${agentsTouched} agent(s), ${totalChanges} file(s) changed.`));
56038
56195
  if (opts.off) {
56039
56196
  const tools = agentNode.get("tools");
56040
56197
  if (tools && tools.has("allow")) {
56041
- tools.set("allow", new import_yaml4.default.YAMLSeq);
56198
+ tools.set("allow", new import_yaml5.default.YAMLSeq);
56042
56199
  writeFileSync13(configPath, doc.toString(), "utf-8");
56043
56200
  console.log(source_default.yellow(` ${name}: dangerous mode OFF (tools.allow cleared)`));
56044
56201
  } else {
@@ -56047,10 +56204,10 @@ Reconciled ${agentsTouched} agent(s), ${totalChanges} file(s) changed.`));
56047
56204
  } else {
56048
56205
  let tools = agentNode.get("tools");
56049
56206
  if (!tools) {
56050
- tools = new import_yaml4.default.YAMLMap;
56207
+ tools = new import_yaml5.default.YAMLMap;
56051
56208
  agentNode.set("tools", tools);
56052
56209
  }
56053
- const allowSeq = new import_yaml4.default.YAMLSeq;
56210
+ const allowSeq = new import_yaml5.default.YAMLSeq;
56054
56211
  allowSeq.add("all");
56055
56212
  tools.set("allow", allowSeq);
56056
56213
  writeFileSync13(configPath, doc.toString(), "utf-8");
@@ -56082,7 +56239,7 @@ Reconciled ${agentsTouched} agent(s), ${totalChanges} file(s) changed.`));
56082
56239
  console.error(source_default.red(`Agent "${name}" not found at ${settingsPath}`));
56083
56240
  process.exit(1);
56084
56241
  }
56085
- const settings = JSON.parse(readFileSync21(settingsPath, "utf-8"));
56242
+ const settings = JSON.parse(readFileSync22(settingsPath, "utf-8"));
56086
56243
  const allow = settings.permissions?.allow ?? [];
56087
56244
  const deny = settings.permissions?.deny ?? [];
56088
56245
  const defaultMode = settings.permissions?.defaultMode;
@@ -56922,24 +57079,24 @@ init_account_store();
56922
57079
  init_loader();
56923
57080
  init_manager();
56924
57081
  init_helpers();
56925
- import { existsSync as existsSync31, readFileSync as readFileSync26 } from "node:fs";
57082
+ import { existsSync as existsSync31, readFileSync as readFileSync27 } from "node:fs";
56926
57083
  import { join as join23, resolve as resolve24 } from "node:path";
56927
57084
 
56928
57085
  // src/cli/auth-google.ts
56929
57086
  init_source();
56930
- import { readFileSync as readFileSync23, writeFileSync as writeFileSync15 } from "node:fs";
57087
+ import { readFileSync as readFileSync24, writeFileSync as writeFileSync15 } from "node:fs";
56931
57088
 
56932
57089
  // src/cli/google-accounts-yaml.ts
56933
- var import_yaml5 = __toESM(require_dist(), 1);
57090
+ var import_yaml6 = __toESM(require_dist(), 1);
56934
57091
  function enableAgentsOnGoogleAccount(yamlText, account, agentsToEnable) {
56935
- const doc = import_yaml5.parseDocument(yamlText);
57092
+ const doc = import_yaml6.parseDocument(yamlText);
56936
57093
  ensureGoogleAccountEntry(doc, account);
56937
57094
  const existing = doc.getIn(["google_accounts", account, "enabled_for"]);
56938
57095
  const currentAgents = readEnabledFor(existing);
56939
57096
  const additions = agentsToEnable.filter((a) => !currentAgents.includes(a));
56940
57097
  if (additions.length === 0)
56941
57098
  return yamlText;
56942
- if (import_yaml5.isSeq(existing)) {
57099
+ if (import_yaml6.isSeq(existing)) {
56943
57100
  const seq = existing;
56944
57101
  for (const a of additions)
56945
57102
  seq.add(a);
@@ -56949,11 +57106,11 @@ function enableAgentsOnGoogleAccount(yamlText, account, agentsToEnable) {
56949
57106
  return String(doc);
56950
57107
  }
56951
57108
  function disableAgentsOnGoogleAccount(yamlText, account, agentsToDisable) {
56952
- const doc = import_yaml5.parseDocument(yamlText);
57109
+ const doc = import_yaml6.parseDocument(yamlText);
56953
57110
  if (!hasGoogleAccountEntry(doc, account))
56954
57111
  return yamlText;
56955
57112
  const existing = doc.getIn(["google_accounts", account, "enabled_for"]);
56956
- if (!import_yaml5.isSeq(existing))
57113
+ if (!import_yaml6.isSeq(existing))
56957
57114
  return yamlText;
56958
57115
  const seq = existing;
56959
57116
  const beforeLen = seq.items.length;
@@ -56969,16 +57126,16 @@ function disableAgentsOnGoogleAccount(yamlText, account, agentsToDisable) {
56969
57126
  return String(doc);
56970
57127
  }
56971
57128
  function getEnabledAgentsForGoogleAccount(yamlText, account) {
56972
- const doc = import_yaml5.parseDocument(yamlText);
57129
+ const doc = import_yaml6.parseDocument(yamlText);
56973
57130
  if (!hasGoogleAccountEntry(doc, account))
56974
57131
  return null;
56975
57132
  const existing = doc.getIn(["google_accounts", account, "enabled_for"]);
56976
57133
  return readEnabledFor(existing);
56977
57134
  }
56978
57135
  function listGoogleAccounts(yamlText) {
56979
- const doc = import_yaml5.parseDocument(yamlText);
57136
+ const doc = import_yaml6.parseDocument(yamlText);
56980
57137
  const accounts = doc.get("google_accounts");
56981
- if (!import_yaml5.isMap(accounts))
57138
+ if (!import_yaml6.isMap(accounts))
56982
57139
  return [];
56983
57140
  const out = [];
56984
57141
  for (const item of accounts.items) {
@@ -56993,7 +57150,7 @@ function listGoogleAccounts(yamlText) {
56993
57150
  return out;
56994
57151
  }
56995
57152
  function readEnabledFor(node) {
56996
- if (!import_yaml5.isSeq(node))
57153
+ if (!import_yaml6.isSeq(node))
56997
57154
  return [];
56998
57155
  const seq = node;
56999
57156
  return seq.items.map((item) => item.value ?? item).filter((v) => typeof v === "string");
@@ -57005,7 +57162,7 @@ function ensureGoogleAccountEntry(doc, account) {
57005
57162
  }
57006
57163
  function hasGoogleAccountEntry(doc, account) {
57007
57164
  const accounts = doc.get("google_accounts");
57008
- if (!import_yaml5.isMap(accounts))
57165
+ if (!import_yaml6.isMap(accounts))
57009
57166
  return false;
57010
57167
  return accounts.has(account);
57011
57168
  }
@@ -57122,7 +57279,7 @@ function registerConnect(googleParent, program3) {
57122
57279
  ` tier: ${tier}`
57123
57280
  ].join(`
57124
57281
  `);
57125
- const raw = readFileSync23(configPath, "utf-8");
57282
+ const raw = readFileSync24(configPath, "utf-8");
57126
57283
  const patched = setGoogleWorkspaceBlock2(raw, {
57127
57284
  clientIdRef: "vault:google-oauth-client-id",
57128
57285
  clientSecretRef: "vault:google-oauth-client-secret",
@@ -57168,7 +57325,7 @@ function registerEnable(googleParent, program3) {
57168
57325
  }
57169
57326
  }
57170
57327
  const yamlPath = getConfigPath(program3);
57171
- const before = readFileSync23(yamlPath, "utf-8");
57328
+ const before = readFileSync24(yamlPath, "utf-8");
57172
57329
  const after = enableAgentsOnGoogleAccount(before, normalizedAccount, agents);
57173
57330
  const noop = after === before;
57174
57331
  if (!noop) {
@@ -57196,7 +57353,7 @@ function registerDisable(googleParent, program3) {
57196
57353
  const config = getConfig(program3);
57197
57354
  agents = expandAllAgents(agents, config);
57198
57355
  const yamlPath = getConfigPath(program3);
57199
- const before = readFileSync23(yamlPath, "utf-8");
57356
+ const before = readFileSync24(yamlPath, "utf-8");
57200
57357
  const enabledBefore = getEnabledAgentsBefore(before, normalizedAccount);
57201
57358
  if (enabledBefore.length === 0) {
57202
57359
  console.log();
@@ -57233,7 +57390,7 @@ function registerDisable(googleParent, program3) {
57233
57390
  function registerList(googleParent, program3) {
57234
57391
  googleParent.command("list").description("List every Google account configured in switchroom.yaml with its enabled_for[] agents. Matrix view of accounts \u00d7 agents.").option("--json", "Emit raw JSON instead of a table").action(withConfigError(async (opts) => {
57235
57392
  const yamlPath = getConfigPath(program3);
57236
- const yaml = readFileSync23(yamlPath, "utf-8");
57393
+ const yaml = readFileSync24(yamlPath, "utf-8");
57237
57394
  const accounts = listGoogleAccounts(yaml);
57238
57395
  if (opts.json) {
57239
57396
  console.log(JSON.stringify(accounts, null, 2));
@@ -57619,19 +57776,19 @@ function buildGoogleCredentials(args) {
57619
57776
 
57620
57777
  // src/cli/auth-microsoft.ts
57621
57778
  init_source();
57622
- import { readFileSync as readFileSync24, writeFileSync as writeFileSync16 } from "node:fs";
57779
+ import { readFileSync as readFileSync25, writeFileSync as writeFileSync16 } from "node:fs";
57623
57780
 
57624
57781
  // src/cli/microsoft-accounts-yaml.ts
57625
- var import_yaml7 = __toESM(require_dist(), 1);
57782
+ var import_yaml8 = __toESM(require_dist(), 1);
57626
57783
  function enableAgentsOnMicrosoftAccount(yamlText, account, agentsToEnable) {
57627
- const doc = import_yaml7.parseDocument(yamlText);
57784
+ const doc = import_yaml8.parseDocument(yamlText);
57628
57785
  ensureMicrosoftAccountEntry(doc, account);
57629
57786
  const existing = doc.getIn(["microsoft_accounts", account, "enabled_for"]);
57630
57787
  const currentAgents = readEnabledFor2(existing);
57631
57788
  const additions = agentsToEnable.filter((a) => !currentAgents.includes(a));
57632
57789
  if (additions.length === 0)
57633
57790
  return yamlText;
57634
- if (import_yaml7.isSeq(existing)) {
57791
+ if (import_yaml8.isSeq(existing)) {
57635
57792
  const seq = existing;
57636
57793
  for (const a of additions)
57637
57794
  seq.add(a);
@@ -57641,11 +57798,11 @@ function enableAgentsOnMicrosoftAccount(yamlText, account, agentsToEnable) {
57641
57798
  return String(doc);
57642
57799
  }
57643
57800
  function disableAgentsOnMicrosoftAccount(yamlText, account, agentsToDisable) {
57644
- const doc = import_yaml7.parseDocument(yamlText);
57801
+ const doc = import_yaml8.parseDocument(yamlText);
57645
57802
  if (!hasMicrosoftAccountEntry(doc, account))
57646
57803
  return yamlText;
57647
57804
  const existing = doc.getIn(["microsoft_accounts", account, "enabled_for"]);
57648
- if (!import_yaml7.isSeq(existing))
57805
+ if (!import_yaml8.isSeq(existing))
57649
57806
  return yamlText;
57650
57807
  const seq = existing;
57651
57808
  const beforeLen = seq.items.length;
@@ -57661,16 +57818,16 @@ function disableAgentsOnMicrosoftAccount(yamlText, account, agentsToDisable) {
57661
57818
  return String(doc);
57662
57819
  }
57663
57820
  function getEnabledAgentsForMicrosoftAccount(yamlText, account) {
57664
- const doc = import_yaml7.parseDocument(yamlText);
57821
+ const doc = import_yaml8.parseDocument(yamlText);
57665
57822
  if (!hasMicrosoftAccountEntry(doc, account))
57666
57823
  return null;
57667
57824
  const existing = doc.getIn(["microsoft_accounts", account, "enabled_for"]);
57668
57825
  return readEnabledFor2(existing);
57669
57826
  }
57670
57827
  function listMicrosoftAccounts(yamlText) {
57671
- const doc = import_yaml7.parseDocument(yamlText);
57828
+ const doc = import_yaml8.parseDocument(yamlText);
57672
57829
  const accounts = doc.get("microsoft_accounts");
57673
- if (!import_yaml7.isMap(accounts))
57830
+ if (!import_yaml8.isMap(accounts))
57674
57831
  return [];
57675
57832
  const out = [];
57676
57833
  for (const item of accounts.items) {
@@ -57685,7 +57842,7 @@ function listMicrosoftAccounts(yamlText) {
57685
57842
  return out;
57686
57843
  }
57687
57844
  function removeMicrosoftAccountEntry(yamlText, account) {
57688
- const doc = import_yaml7.parseDocument(yamlText);
57845
+ const doc = import_yaml8.parseDocument(yamlText);
57689
57846
  if (!hasMicrosoftAccountEntry(doc, account))
57690
57847
  return yamlText;
57691
57848
  doc.deleteIn(["microsoft_accounts", account]);
@@ -57693,7 +57850,7 @@ function removeMicrosoftAccountEntry(yamlText, account) {
57693
57850
  return String(doc);
57694
57851
  }
57695
57852
  function readEnabledFor2(node) {
57696
- if (!import_yaml7.isSeq(node))
57853
+ if (!import_yaml8.isSeq(node))
57697
57854
  return [];
57698
57855
  const seq = node;
57699
57856
  return seq.items.map((item) => item.value ?? item).filter((v) => typeof v === "string");
@@ -57705,13 +57862,13 @@ function ensureMicrosoftAccountEntry(doc, account) {
57705
57862
  }
57706
57863
  function hasMicrosoftAccountEntry(doc, account) {
57707
57864
  const accounts = doc.get("microsoft_accounts");
57708
- if (!import_yaml7.isMap(accounts))
57865
+ if (!import_yaml8.isMap(accounts))
57709
57866
  return false;
57710
57867
  return accounts.has(account);
57711
57868
  }
57712
57869
  function pruneEmptyMap(doc, path) {
57713
57870
  const node = doc.getIn(path);
57714
- if (import_yaml7.isMap(node) && node.items.length === 0) {
57871
+ if (import_yaml8.isMap(node) && node.items.length === 0) {
57715
57872
  doc.deleteIn(path);
57716
57873
  }
57717
57874
  }
@@ -57813,7 +57970,7 @@ function registerEnable2(microsoftParent, program3) {
57813
57970
  agents = expandAllAgents2(agents, config);
57814
57971
  validateAgentSlugs(agents, config);
57815
57972
  const yamlPath = getConfigPath(program3);
57816
- const before = readFileSync24(yamlPath, "utf-8");
57973
+ const before = readFileSync25(yamlPath, "utf-8");
57817
57974
  const enabledBefore = getEnabledAgentsBefore2(before, normalizedAccount);
57818
57975
  const after = enableAgentsOnMicrosoftAccount(before, normalizedAccount, agents);
57819
57976
  if (after !== before)
@@ -57843,7 +58000,7 @@ function registerDisable2(microsoftParent, program3) {
57843
58000
  const config = getConfig(program3);
57844
58001
  agents = expandAllAgents2(agents, config);
57845
58002
  const yamlPath = getConfigPath(program3);
57846
- const before = readFileSync24(yamlPath, "utf-8");
58003
+ const before = readFileSync25(yamlPath, "utf-8");
57847
58004
  const enabledBefore = getEnabledAgentsBefore2(before, normalizedAccount);
57848
58005
  if (enabledBefore.length === 0) {
57849
58006
  console.log();
@@ -57877,7 +58034,7 @@ function registerDisable2(microsoftParent, program3) {
57877
58034
  function registerList2(microsoftParent, program3) {
57878
58035
  microsoftParent.command("list").description("List every Microsoft account configured in switchroom.yaml with its enabled_for[] agents.").option("--json", "Emit raw JSON instead of a table").action(withConfigError(async (opts) => {
57879
58036
  const yamlPath = getConfigPath(program3);
57880
- const yaml = readFileSync24(yamlPath, "utf-8");
58037
+ const yaml = readFileSync25(yamlPath, "utf-8");
57881
58038
  const accounts = listMicrosoftAccounts(yaml);
57882
58039
  if (opts.json) {
57883
58040
  console.log(JSON.stringify(accounts, null, 2));
@@ -58052,7 +58209,7 @@ function registerAccountRemove2(accountParent) {
58052
58209
  const { brokerCall: brokerCall2 } = await Promise.resolve().then(() => (init_broker_call(), exports_broker_call));
58053
58210
  const program3 = command.parent?.parent?.parent ?? command;
58054
58211
  const yamlPath = getConfigPath(program3);
58055
- const before = readFileSync24(yamlPath, "utf-8");
58212
+ const before = readFileSync25(yamlPath, "utf-8");
58056
58213
  const enabled = getEnabledAgentsForMicrosoftAccount(before, normalizedAccount);
58057
58214
  if (enabled && enabled.length > 0) {
58058
58215
  throw new Error(`Account ${normalizedAccount} is still enabled on agents: ${enabled.join(", ")}. Run 'switchroom auth microsoft disable ${normalizedAccount} all' first.`);
@@ -58236,7 +58393,7 @@ function diagnoseAuthState(claudeConfigDir) {
58236
58393
  } else if (hasCreds) {
58237
58394
  let parsed;
58238
58395
  try {
58239
- parsed = JSON.parse(readFileSync26(credsPath, "utf-8"));
58396
+ parsed = JSON.parse(readFileSync27(credsPath, "utf-8"));
58240
58397
  } catch (err) {
58241
58398
  const code = err?.code;
58242
58399
  if (code === "EACCES" || code === "EPERM") {
@@ -58404,7 +58561,7 @@ function loadCredentialsFromAgent(agentName) {
58404
58561
  }
58405
58562
  let parsed;
58406
58563
  try {
58407
- parsed = JSON.parse(readFileSync26(credsPath, "utf-8"));
58564
+ parsed = JSON.parse(readFileSync27(credsPath, "utf-8"));
58408
58565
  } catch (err) {
58409
58566
  console.error(source_default.red(` Failed to parse credentials.json: ${err.message}`));
58410
58567
  process.exit(1);
@@ -58422,7 +58579,7 @@ function loadCredentialsFromFile(path) {
58422
58579
  }
58423
58580
  let parsed;
58424
58581
  try {
58425
- parsed = JSON.parse(readFileSync26(path, "utf-8"));
58582
+ parsed = JSON.parse(readFileSync27(path, "utf-8"));
58426
58583
  } catch (err) {
58427
58584
  console.error(source_default.red(` Failed to parse ${path}: ${err.message}`));
58428
58585
  process.exit(1);
@@ -58555,7 +58712,7 @@ function registerAuthCommand(program3) {
58555
58712
  function pinAuthActiveInYaml(label, quiet = false) {
58556
58713
  try {
58557
58714
  const yamlPath = getConfigPath(program3);
58558
- const before = readFileSync26(yamlPath, "utf-8");
58715
+ const before = readFileSync27(yamlPath, "utf-8");
58559
58716
  const after = setAuthActive(before, label);
58560
58717
  if (after !== before) {
58561
58718
  let mode = 420;
@@ -58703,15 +58860,15 @@ init_loader();
58703
58860
  init_loader();
58704
58861
  init_vault();
58705
58862
  import { createInterface as createInterface3 } from "node:readline";
58706
- import { readFileSync as readFileSync35 } from "node:fs";
58863
+ import { readFileSync as readFileSync36 } from "node:fs";
58707
58864
 
58708
58865
  // src/cli/vault-sweep.ts
58709
58866
  init_source();
58710
58867
  init_loader();
58711
58868
  init_vault();
58712
58869
  init_hindsight();
58713
- import { readFileSync as readFileSync27, writeFileSync as writeFileSync17, copyFileSync as copyFileSync6, existsSync as existsSync32, readdirSync as readdirSync15, statSync as statSync17 } from "node:fs";
58714
- import { execFileSync as execFileSync14 } from "node:child_process";
58870
+ import { readFileSync as readFileSync28, writeFileSync as writeFileSync17, copyFileSync as copyFileSync6, existsSync as existsSync32, readdirSync as readdirSync15, statSync as statSync17 } from "node:fs";
58871
+ import { execFileSync as execFileSync15 } from "node:child_process";
58715
58872
  import { join as join24 } from "node:path";
58716
58873
  import { homedir as homedir11 } from "node:os";
58717
58874
  function getVaultPath2(configPath) {
@@ -58771,7 +58928,7 @@ function findTelegramHistoryDb() {
58771
58928
  function scrubJsonl(path, values, dryRun) {
58772
58929
  let content;
58773
58930
  try {
58774
- content = readFileSync27(path, "utf8");
58931
+ content = readFileSync28(path, "utf8");
58775
58932
  } catch {
58776
58933
  return { target: path, matches: 0, modified: false };
58777
58934
  }
@@ -59049,7 +59206,7 @@ function registerVaultSweep(vault, program3) {
59049
59206
  function scrubSqlite(path, values, dryRun) {
59050
59207
  let hasSqlite = true;
59051
59208
  try {
59052
- execFileSync14("sqlite3", ["-version"], { timeout: 2000, stdio: "ignore" });
59209
+ execFileSync15("sqlite3", ["-version"], { timeout: 2000, stdio: "ignore" });
59053
59210
  } catch {
59054
59211
  hasSqlite = false;
59055
59212
  }
@@ -59061,7 +59218,7 @@ function scrubSqlite(path, values, dryRun) {
59061
59218
  for (const { value } of values) {
59062
59219
  const esc = value.replace(/'/g, "''");
59063
59220
  try {
59064
- const out = execFileSync14("sqlite3", [path, `SELECT COUNT(*) FROM messages WHERE text LIKE '%${esc}%'`], { encoding: "utf8", timeout: 1e4 });
59221
+ const out = execFileSync15("sqlite3", [path, `SELECT COUNT(*) FROM messages WHERE text LIKE '%${esc}%'`], { encoding: "utf8", timeout: 1e4 });
59065
59222
  const n = parseInt(out.trim(), 10);
59066
59223
  if (!Number.isNaN(n))
59067
59224
  matches += n;
@@ -59075,7 +59232,7 @@ function scrubSqlite(path, values, dryRun) {
59075
59232
  for (const { key, value } of values) {
59076
59233
  const esc = value.replace(/'/g, "''");
59077
59234
  const replacement = `vault:${key}`.replace(/'/g, "''");
59078
- execFileSync14("sqlite3", [path, `UPDATE messages SET text = replace(text, '${esc}', '${replacement}')`], { timeout: 15000 });
59235
+ execFileSync15("sqlite3", [path, `UPDATE messages SET text = replace(text, '${esc}', '${replacement}')`], { timeout: 15000 });
59079
59236
  }
59080
59237
  return { target: path, matches, modified: true };
59081
59238
  } catch (err) {
@@ -59113,14 +59270,14 @@ function suggestVaultKeys(requested, available, max = 3) {
59113
59270
  init_loader();
59114
59271
  init_loader();
59115
59272
  init_client();
59116
- import { readFileSync as readFileSync32, existsSync as existsSync36, unlinkSync as unlinkSync9 } from "node:fs";
59273
+ import { readFileSync as readFileSync33, existsSync as existsSync36, unlinkSync as unlinkSync9 } from "node:fs";
59117
59274
  import { spawn as spawn4 } from "node:child_process";
59118
59275
 
59119
59276
  // src/vault/broker/server.ts
59120
59277
  init_compose();
59121
59278
  init_vault();
59122
59279
  import * as net3 from "node:net";
59123
- import { mkdirSync as mkdirSync22, chmodSync as chmodSync7, chownSync as chownSync2, existsSync as existsSync35, readFileSync as readFileSync30, readdirSync as readdirSync16, statSync as statSync19, unlinkSync as unlinkSync8, writeFileSync as writeFileSync19, renameSync as renameSync10 } from "node:fs";
59280
+ import { mkdirSync as mkdirSync22, chmodSync as chmodSync7, chownSync as chownSync2, existsSync as existsSync35, readFileSync as readFileSync31, readdirSync as readdirSync16, statSync as statSync19, unlinkSync as unlinkSync8, writeFileSync as writeFileSync19, renameSync as renameSync10 } from "node:fs";
59124
59281
  import { dirname as dirname6, resolve as resolve26, basename as basename4 } from "node:path";
59125
59282
  import * as os4 from "node:os";
59126
59283
  import * as path3 from "node:path";
@@ -59136,7 +59293,7 @@ import {
59136
59293
  mkdirSync as mkdirSync19,
59137
59294
  openSync as openSync6,
59138
59295
  closeSync as closeSync6,
59139
- readFileSync as readFileSync28,
59296
+ readFileSync as readFileSync29,
59140
59297
  renameSync as renameSync9,
59141
59298
  statSync as statSync18,
59142
59299
  symlinkSync as symlinkSync3,
@@ -59292,7 +59449,7 @@ function lstatSyncOrNull(path) {
59292
59449
  }
59293
59450
  }
59294
59451
  function sha256File(path) {
59295
- const data = readFileSync28(path);
59452
+ const data = readFileSync29(path);
59296
59453
  return createHash5("sha256").update(data).digest("hex");
59297
59454
  }
59298
59455
  function atomicReplaceWithSymlink(target, linkTarget) {
@@ -59327,7 +59484,7 @@ init_loader();
59327
59484
 
59328
59485
  // src/vault/auto-unlock.ts
59329
59486
  import { createHmac, randomBytes as randomBytes6, createCipheriv as createCipheriv2, createDecipheriv as createDecipheriv2 } from "node:crypto";
59330
- import { chmodSync as chmodSync5, existsSync as existsSync34, mkdirSync as mkdirSync20, readFileSync as readFileSync29, writeFileSync as writeFileSync18 } from "node:fs";
59487
+ import { chmodSync as chmodSync5, existsSync as existsSync34, mkdirSync as mkdirSync20, readFileSync as readFileSync30, writeFileSync as writeFileSync18 } from "node:fs";
59331
59488
  import { dirname as dirname4 } from "node:path";
59332
59489
  var FORMAT_VERSION = 1;
59333
59490
  var SALT_LEN = 16;
@@ -59363,7 +59520,7 @@ function readMachineId() {
59363
59520
  }
59364
59521
  for (const path of [MACHINE_ID_PRIMARY, MACHINE_ID_FALLBACK]) {
59365
59522
  try {
59366
- const id = readFileSync29(path, "utf8").trim();
59523
+ const id = readFileSync30(path, "utf8").trim();
59367
59524
  if (id.length > 0)
59368
59525
  return id;
59369
59526
  } catch {}
@@ -59427,7 +59584,7 @@ function readAutoUnlockFile(filePath) {
59427
59584
  }
59428
59585
  let blob;
59429
59586
  try {
59430
- blob = readFileSync29(filePath);
59587
+ blob = readFileSync30(filePath);
59431
59588
  } catch {
59432
59589
  throw new AutoUnlockDecryptError("io");
59433
59590
  }
@@ -63284,7 +63441,7 @@ class VaultBroker {
63284
63441
  const credPath = `${dir}/vault-passphrase`;
63285
63442
  let passphrase;
63286
63443
  try {
63287
- passphrase = readFileSync30(credPath, "utf8").replace(/\n+$/, "");
63444
+ passphrase = readFileSync31(credPath, "utf8").replace(/\n+$/, "");
63288
63445
  } catch (err) {
63289
63446
  const code = err.code;
63290
63447
  if (code === "ENOENT") {
@@ -63435,9 +63592,9 @@ init_vault();
63435
63592
  // src/cli/vault-auto-unlock.ts
63436
63593
  init_loader();
63437
63594
  init_client();
63438
- var import_yaml9 = __toESM(require_dist(), 1);
63595
+ var import_yaml10 = __toESM(require_dist(), 1);
63439
63596
  import { spawnSync as spawnSync3 } from "node:child_process";
63440
- import { readFileSync as readFileSync31, writeFileSync as writeFileSync20 } from "node:fs";
63597
+ import { readFileSync as readFileSync32, writeFileSync as writeFileSync20 } from "node:fs";
63441
63598
  import { homedir as homedir16 } from "node:os";
63442
63599
  import { join as join31 } from "node:path";
63443
63600
  class EncryptFailedError extends Error {
@@ -63467,8 +63624,8 @@ function encryptCredential(passphrase, credPath) {
63467
63624
  }
63468
63625
  }
63469
63626
  function setVaultBrokerAutoUnlock(configPath, value) {
63470
- const raw = readFileSync31(configPath, "utf-8");
63471
- const doc = import_yaml9.default.parseDocument(raw);
63627
+ const raw = readFileSync32(configPath, "utf-8");
63628
+ const doc = import_yaml10.default.parseDocument(raw);
63472
63629
  doc.setIn(["vault", "broker", "autoUnlock"], value);
63473
63630
  writeFileSync20(configPath, doc.toString(), "utf-8");
63474
63631
  }
@@ -63662,7 +63819,7 @@ function registerVaultBrokerCommand(vaultCmd, program3) {
63662
63819
  console.error("vault-broker PID file not found \u2014 is the daemon running?");
63663
63820
  process.exit(1);
63664
63821
  }
63665
- const pid = parseInt(readFileSync32(pidPath, "utf8").trim(), 10);
63822
+ const pid = parseInt(readFileSync33(pidPath, "utf8").trim(), 10);
63666
63823
  if (isNaN(pid) || pid <= 0) {
63667
63824
  console.error("Invalid PID file contents");
63668
63825
  process.exit(1);
@@ -64035,7 +64192,7 @@ Vault Doctor`));
64035
64192
 
64036
64193
  // src/cli/vault-audit.ts
64037
64194
  init_source();
64038
- import { existsSync as existsSync38, readFileSync as readFileSync33 } from "node:fs";
64195
+ import { existsSync as existsSync38, readFileSync as readFileSync34 } from "node:fs";
64039
64196
 
64040
64197
  // src/vault/audit-reader.ts
64041
64198
  function parseAuditLine(line) {
@@ -64114,7 +64271,7 @@ function registerVaultAuditCommand(vault, _program) {
64114
64271
  The log is created when the vault broker handles its first request.`));
64115
64272
  process.exit(0);
64116
64273
  }
64117
- const raw = readFileSync33(logPath, "utf-8");
64274
+ const raw = readFileSync34(logPath, "utf-8");
64118
64275
  const rawLines = raw.split(`
64119
64276
  `);
64120
64277
  const limit = Math.max(1, parseInt(opts.tail ?? "50", 10) || 50);
@@ -64324,7 +64481,7 @@ import {
64324
64481
  mkdirSync as mkdirSync23,
64325
64482
  openSync as openSync9,
64326
64483
  readdirSync as readdirSync17,
64327
- readFileSync as readFileSync34,
64484
+ readFileSync as readFileSync35,
64328
64485
  renameSync as renameSync11,
64329
64486
  statSync as statSync20,
64330
64487
  symlinkSync as symlinkSync4,
@@ -64371,7 +64528,7 @@ function parseBackupFilename(name) {
64371
64528
  function validateVaultEnvelopeFile(path4) {
64372
64529
  let buf;
64373
64530
  try {
64374
- buf = readFileSync34(path4);
64531
+ buf = readFileSync35(path4);
64375
64532
  } catch (err) {
64376
64533
  return `cannot read ${path4}: ${err.message}`;
64377
64534
  }
@@ -64443,7 +64600,7 @@ function listBackupFiles(dir) {
64443
64600
  }
64444
64601
  function sha256OfFile(path4) {
64445
64602
  const h = createHash8("sha256");
64446
- h.update(readFileSync34(path4));
64603
+ h.update(readFileSync35(path4));
64447
64604
  return h.digest("hex");
64448
64605
  }
64449
64606
  function backupVault(opts) {
@@ -64463,7 +64620,7 @@ function backupVault(opts) {
64463
64620
  const fullPath = join33(opts.destDir, filename);
64464
64621
  const tmpName = `.tmp.${process.pid}.${randomBytes10(4).toString("hex")}`;
64465
64622
  const tmpPath = join33(opts.destDir, tmpName);
64466
- const src = readFileSync34(opts.vaultPath);
64623
+ const src = readFileSync35(opts.vaultPath);
64467
64624
  const fd = openSync9(tmpPath, "wx", 384);
64468
64625
  try {
64469
64626
  writeSync5(fd, src);
@@ -64838,7 +64995,7 @@ function registerVaultCommand(program3) {
64838
64995
  let isBinaryFile = false;
64839
64996
  if (opts.file) {
64840
64997
  try {
64841
- const buf = readFileSync35(resolvePath(opts.file));
64998
+ const buf = readFileSync36(resolvePath(opts.file));
64842
64999
  const asUtf8 = buf.toString("utf8");
64843
65000
  if (Buffer.compare(buf, Buffer.from(asUtf8, "utf8")) === 0) {
64844
65001
  value = asUtf8;
@@ -65182,7 +65339,7 @@ Push passphrase to broker for future requests? [Y/n]: `);
65182
65339
 
65183
65340
  // src/cli/telegram.ts
65184
65341
  init_source();
65185
- import { existsSync as existsSync41, readFileSync as readFileSync36, writeFileSync as writeFileSync21 } from "node:fs";
65342
+ import { existsSync as existsSync41, readFileSync as readFileSync37, writeFileSync as writeFileSync21 } from "node:fs";
65186
65343
  import { join as join35 } from "node:path";
65187
65344
 
65188
65345
  // src/web/webhook-dispatch.ts
@@ -65286,15 +65443,15 @@ init_paths();
65286
65443
  import { createInterface as createInterface4 } from "node:readline";
65287
65444
 
65288
65445
  // src/cli/telegram-yaml.ts
65289
- var import_yaml10 = __toESM(require_dist(), 1);
65446
+ var import_yaml11 = __toESM(require_dist(), 1);
65290
65447
  function setTelegramFeature(yamlText, agentName, feature, value) {
65291
- const doc = import_yaml10.parseDocument(yamlText);
65448
+ const doc = import_yaml11.parseDocument(yamlText);
65292
65449
  ensureAgent(doc, agentName);
65293
65450
  doc.setIn(["agents", agentName, "channels", "telegram", feature], value);
65294
65451
  return String(doc);
65295
65452
  }
65296
65453
  function removeTelegramFeature(yamlText, agentName, feature) {
65297
- const doc = import_yaml10.parseDocument(yamlText);
65454
+ const doc = import_yaml11.parseDocument(yamlText);
65298
65455
  if (!hasAgent(doc, agentName))
65299
65456
  return yamlText;
65300
65457
  if (!doc.hasIn(["agents", agentName, "channels", "telegram", feature])) {
@@ -65312,21 +65469,21 @@ function ensureAgent(doc, agentName) {
65312
65469
  }
65313
65470
  function hasAgent(doc, agentName) {
65314
65471
  const agents = doc.get("agents");
65315
- if (!import_yaml10.isMap(agents))
65472
+ if (!import_yaml11.isMap(agents))
65316
65473
  return false;
65317
65474
  return agents.has(agentName);
65318
65475
  }
65319
65476
  function pruneEmptyMap2(doc, path4) {
65320
65477
  const node = doc.getIn(path4);
65321
- if (import_yaml10.isMap(node) && node.items.length === 0) {
65478
+ if (import_yaml11.isMap(node) && node.items.length === 0) {
65322
65479
  doc.deleteIn(path4);
65323
65480
  }
65324
65481
  }
65325
65482
  function addWebhookSource(yamlText, agentName, source) {
65326
- const doc = import_yaml10.parseDocument(yamlText);
65483
+ const doc = import_yaml11.parseDocument(yamlText);
65327
65484
  ensureAgent(doc, agentName);
65328
65485
  const existing = doc.getIn(["agents", agentName, "channels", "telegram", "webhook_sources"]);
65329
- if (import_yaml10.isSeq(existing)) {
65486
+ if (import_yaml11.isSeq(existing)) {
65330
65487
  const seq = existing;
65331
65488
  for (const item of seq.items) {
65332
65489
  const v = item.value ?? item;
@@ -65340,11 +65497,11 @@ function addWebhookSource(yamlText, agentName, source) {
65340
65497
  return String(doc);
65341
65498
  }
65342
65499
  function removeWebhookSource(yamlText, agentName, source) {
65343
- const doc = import_yaml10.parseDocument(yamlText);
65500
+ const doc = import_yaml11.parseDocument(yamlText);
65344
65501
  if (!hasAgent(doc, agentName))
65345
65502
  return yamlText;
65346
65503
  const existing = doc.getIn(["agents", agentName, "channels", "telegram", "webhook_sources"]);
65347
- if (!import_yaml10.isSeq(existing))
65504
+ if (!import_yaml11.isSeq(existing))
65348
65505
  return yamlText;
65349
65506
  const seq = existing;
65350
65507
  const beforeLen = seq.items.length;
@@ -65613,7 +65770,7 @@ function registerDisableVerb(tg, program3) {
65613
65770
  }
65614
65771
  async function applyYamlEdit(program3, agent, feature, value, dryRun) {
65615
65772
  const path4 = getConfigPath(program3);
65616
- const before = readFileSync36(path4, "utf-8");
65773
+ const before = readFileSync37(path4, "utf-8");
65617
65774
  let after;
65618
65775
  try {
65619
65776
  after = setTelegramFeature(before, agent, feature, value);
@@ -65628,7 +65785,7 @@ async function applyYamlEdit(program3, agent, feature, value, dryRun) {
65628
65785
  }
65629
65786
  async function applyYamlRemove(program3, agent, feature, dryRun) {
65630
65787
  const path4 = getConfigPath(program3);
65631
- const before = readFileSync36(path4, "utf-8");
65788
+ const before = readFileSync37(path4, "utf-8");
65632
65789
  const after = removeTelegramFeature(before, agent, feature);
65633
65790
  if (before === after) {
65634
65791
  console.log(source_default.yellow(`No change \u2014 ${feature.replace("_", "-")} is not set for agent '${agent}'.`));
@@ -65677,7 +65834,7 @@ function fail(msg) {
65677
65834
  }
65678
65835
  async function applyYamlAddWebhook(program3, agent, source, dryRun) {
65679
65836
  const path4 = getConfigPath(program3);
65680
- const before = readFileSync36(path4, "utf-8");
65837
+ const before = readFileSync37(path4, "utf-8");
65681
65838
  let after;
65682
65839
  try {
65683
65840
  after = addWebhookSource(before, agent, source);
@@ -65697,7 +65854,7 @@ async function applyYamlAddWebhook(program3, agent, source, dryRun) {
65697
65854
  }
65698
65855
  async function applyYamlRemoveWebhook(program3, agent, source, dryRun) {
65699
65856
  const path4 = getConfigPath(program3);
65700
- const before = readFileSync36(path4, "utf-8");
65857
+ const before = readFileSync37(path4, "utf-8");
65701
65858
  const after = removeWebhookSource(before, agent, source);
65702
65859
  if (before === after) {
65703
65860
  console.log(source_default.yellow(`No change \u2014 webhook source '${source}' is not currently enabled for agent '${agent}'.`));
@@ -65754,7 +65911,7 @@ function registerDispatchVerb(tg, _program) {
65754
65911
  }
65755
65912
  let payload;
65756
65913
  try {
65757
- payload = JSON.parse(readFileSync36(opts.payload, "utf-8"));
65914
+ payload = JSON.parse(readFileSync37(opts.payload, "utf-8"));
65758
65915
  } catch (err) {
65759
65916
  fail(`Could not read payload file '${opts.payload}': ${err.message}`);
65760
65917
  }
@@ -65875,7 +66032,7 @@ function reflectAcrossAgents(config) {
65875
66032
  init_helpers();
65876
66033
 
65877
66034
  // src/setup/hindsight.ts
65878
- import { execFileSync as execFileSync15 } from "node:child_process";
66035
+ import { execFileSync as execFileSync16 } from "node:child_process";
65879
66036
  import { createServer as createServer4 } from "node:net";
65880
66037
  var HINDSIGHT_DEFAULT_API_PORT = 8888;
65881
66038
  var HINDSIGHT_DEFAULT_UI_PORT = 9999;
@@ -65930,7 +66087,7 @@ async function pickHindsightPorts() {
65930
66087
  }
65931
66088
  function isDockerAvailable() {
65932
66089
  try {
65933
- execFileSync15("docker", ["--version"], { stdio: "pipe" });
66090
+ execFileSync16("docker", ["--version"], { stdio: "pipe" });
65934
66091
  return true;
65935
66092
  } catch {
65936
66093
  return false;
@@ -65938,7 +66095,7 @@ function isDockerAvailable() {
65938
66095
  }
65939
66096
  function isHindsightRunning() {
65940
66097
  try {
65941
- const output = execFileSync15("docker", ["ps", "--filter", "name=switchroom-hindsight", "--format", "{{.Status}}"], { stdio: "pipe", encoding: "utf-8" });
66098
+ const output = execFileSync16("docker", ["ps", "--filter", "name=switchroom-hindsight", "--format", "{{.Status}}"], { stdio: "pipe", encoding: "utf-8" });
65942
66099
  return output.trim().length > 0;
65943
66100
  } catch {
65944
66101
  return false;
@@ -65946,7 +66103,7 @@ function isHindsightRunning() {
65946
66103
  }
65947
66104
  function isHindsightContainerExists() {
65948
66105
  try {
65949
- const output = execFileSync15("docker", ["ps", "-a", "--filter", "name=switchroom-hindsight", "--format", "{{.Names}}"], { stdio: "pipe", encoding: "utf-8" });
66106
+ const output = execFileSync16("docker", ["ps", "-a", "--filter", "name=switchroom-hindsight", "--format", "{{.Names}}"], { stdio: "pipe", encoding: "utf-8" });
65950
66107
  return output.trim().length > 0;
65951
66108
  } catch {
65952
66109
  return false;
@@ -65996,19 +66153,19 @@ function startHindsight(ports) {
65996
66153
  ...envArgs,
65997
66154
  HINDSIGHT_IMAGE
65998
66155
  ];
65999
- execFileSync15("docker", args, { stdio: "pipe" });
66156
+ execFileSync16("docker", args, { stdio: "pipe" });
66000
66157
  }
66001
66158
  function stopHindsight() {
66002
66159
  try {
66003
- execFileSync15("docker", ["stop", "switchroom-hindsight"], { stdio: "pipe" });
66160
+ execFileSync16("docker", ["stop", "switchroom-hindsight"], { stdio: "pipe" });
66004
66161
  } catch {}
66005
66162
  try {
66006
- execFileSync15("docker", ["rm", "switchroom-hindsight"], { stdio: "pipe" });
66163
+ execFileSync16("docker", ["rm", "switchroom-hindsight"], { stdio: "pipe" });
66007
66164
  } catch {}
66008
66165
  }
66009
66166
  function getHindsightStatus() {
66010
66167
  try {
66011
- const output = execFileSync15("docker", ["ps", "-a", "--filter", "name=switchroom-hindsight", "--format", "{{.Status}}"], { stdio: "pipe", encoding: "utf-8" });
66168
+ const output = execFileSync16("docker", ["ps", "-a", "--filter", "name=switchroom-hindsight", "--format", "{{.Status}}"], { stdio: "pipe", encoding: "utf-8" });
66012
66169
  const status = output.trim();
66013
66170
  return status.length > 0 ? status : null;
66014
66171
  } catch {
@@ -66106,8 +66263,8 @@ async function ensureHindsightConsumer(configPath, account, uid = HINDSIGHT_DEFA
66106
66263
 
66107
66264
  // src/cli/memory.ts
66108
66265
  init_loader();
66109
- var import_yaml11 = __toESM(require_dist(), 1);
66110
- import { existsSync as existsSync42, readFileSync as readFileSync37, writeFileSync as writeFileSync22 } from "node:fs";
66266
+ var import_yaml12 = __toESM(require_dist(), 1);
66267
+ import { existsSync as existsSync42, readFileSync as readFileSync38, writeFileSync as writeFileSync22 } from "node:fs";
66111
66268
  import { join as join36 } from "node:path";
66112
66269
  function readRecallLog(agentDir, limit) {
66113
66270
  const path4 = join36(agentDir, ".claude", "plugins", "data", "hindsight-memory-inline", "state", "recall_log.jsonl");
@@ -66115,7 +66272,7 @@ function readRecallLog(agentDir, limit) {
66115
66272
  return [];
66116
66273
  let raw;
66117
66274
  try {
66118
- raw = readFileSync37(path4, "utf-8");
66275
+ raw = readFileSync38(path4, "utf-8");
66119
66276
  } catch {
66120
66277
  return [];
66121
66278
  }
@@ -66310,8 +66467,8 @@ Cross-agent reflection plan
66310
66467
  const configPath = getConfigPath(program3);
66311
66468
  try {
66312
66469
  if (existsSync42(configPath)) {
66313
- const raw = readFileSync37(configPath, "utf-8");
66314
- const doc = import_yaml11.default.parseDocument(raw);
66470
+ const raw = readFileSync38(configPath, "utf-8");
66471
+ const doc = import_yaml12.default.parseDocument(raw);
66315
66472
  if (!doc.has("memory")) {
66316
66473
  doc.set("memory", { backend: "hindsight", shared_collection: "shared", config: { provider, url } });
66317
66474
  } else {
@@ -66417,7 +66574,7 @@ init_source();
66417
66574
  init_merge();
66418
66575
  init_lifecycle();
66419
66576
  import {
66420
- readFileSync as readFileSync42,
66577
+ readFileSync as readFileSync43,
66421
66578
  existsSync as existsSync47,
66422
66579
  realpathSync as realpathSync3,
66423
66580
  mkdirSync as mkdirSync27,
@@ -66436,7 +66593,7 @@ init_lifecycle();
66436
66593
  init_manager();
66437
66594
  init_hindsight();
66438
66595
  import { spawnSync as spawnSync4 } from "node:child_process";
66439
- import { existsSync as existsSync44, readFileSync as readFileSync39 } from "node:fs";
66596
+ import { existsSync as existsSync44, readFileSync as readFileSync40 } from "node:fs";
66440
66597
  import { resolve as resolve27 } from "node:path";
66441
66598
  init_audit_reader();
66442
66599
 
@@ -70940,7 +71097,7 @@ init_paths();
70940
71097
  import {
70941
71098
  existsSync as existsSync43,
70942
71099
  mkdirSync as mkdirSync24,
70943
- readFileSync as readFileSync38,
71100
+ readFileSync as readFileSync39,
70944
71101
  writeFileSync as writeFileSync23
70945
71102
  } from "node:fs";
70946
71103
  import { dirname as dirname8 } from "node:path";
@@ -70961,7 +71118,7 @@ function getDistinctId() {
70961
71118
  const path4 = resolveStatePath("analytics-id");
70962
71119
  try {
70963
71120
  if (existsSync43(path4)) {
70964
- const existing = readFileSync38(path4, "utf-8").trim();
71121
+ const existing = readFileSync39(path4, "utf-8").trim();
70965
71122
  if (existing) {
70966
71123
  cachedDistinctId = existing;
70967
71124
  return existing;
@@ -71537,7 +71694,7 @@ async function handleGetSystemHealth(home2) {
71537
71694
  const logPath = defaultAuditLogPath2(home2);
71538
71695
  if (existsSync44(logPath)) {
71539
71696
  hostd.auditLogPresent = true;
71540
- const raw = readFileSync39(logPath, "utf-8");
71697
+ const raw = readFileSync40(logPath, "utf-8");
71541
71698
  hostd.recent = readAndFilter(raw, {}, 10);
71542
71699
  }
71543
71700
  } catch (err) {
@@ -71582,6 +71739,70 @@ async function handleGetGoogleAccounts(config) {
71582
71739
  }
71583
71740
  return out;
71584
71741
  }
71742
+ async function handleGetMicrosoftAccounts(config) {
71743
+ const live = new Map;
71744
+ try {
71745
+ await withAuthBrokerClient(async (client2) => {
71746
+ const data = await client2.listMicrosoftAccounts();
71747
+ for (const a of data.accounts) {
71748
+ live.set(a.account.toLowerCase(), {
71749
+ expiresAt: a.expiresAt,
71750
+ scope: a.scope,
71751
+ clientId: a.clientId,
71752
+ accountType: a.accountType
71753
+ });
71754
+ }
71755
+ });
71756
+ } catch (err) {
71757
+ if (!(err instanceof AuthBrokerUnreachableError))
71758
+ throw err;
71759
+ }
71760
+ const cfgAccounts = config.microsoft_accounts ?? {};
71761
+ const keys = new Set([
71762
+ ...Object.keys(cfgAccounts).map((k) => k.toLowerCase()),
71763
+ ...live.keys()
71764
+ ]);
71765
+ const out = [];
71766
+ for (const key of [...keys].sort()) {
71767
+ const cfg = cfgAccounts[key];
71768
+ const l = live.get(key);
71769
+ out.push({
71770
+ account: key,
71771
+ expiresAt: l?.expiresAt ?? null,
71772
+ scope: l?.scope ?? null,
71773
+ clientId: l?.clientId ?? null,
71774
+ accountType: l?.accountType ?? null,
71775
+ enabledFor: cfg?.enabled_for ? [...cfg.enabled_for].sort() : [],
71776
+ brokerKnown: l != null
71777
+ });
71778
+ }
71779
+ return out;
71780
+ }
71781
+ function handleGetNotionWorkspace(config) {
71782
+ const nw = config.notion_workspace;
71783
+ if (!nw) {
71784
+ return { configured: false, vaultKey: null, databases: [], fullAccessAgents: [] };
71785
+ }
71786
+ const declared = nw.databases ?? {};
71787
+ const agentNames = Object.keys(config.agents ?? {});
71788
+ const databases = Object.entries(declared).map(([name, id]) => {
71789
+ const enabledFor = agentNames.filter((n) => agentCanAccessNotionDB(config, n, id)).sort();
71790
+ return { name, id, enabledFor };
71791
+ }).sort((a, b) => a.name.localeCompare(b.name));
71792
+ const agentsRaw = config.agents ?? {};
71793
+ const fullAccessAgents = agentNames.filter((n) => {
71794
+ if (!shouldEmitNotionMcp(n, config))
71795
+ return false;
71796
+ const dbs = agentsRaw[n]?.notion_workspace?.databases;
71797
+ return dbs === undefined || dbs.length === 0;
71798
+ }).sort();
71799
+ return {
71800
+ configured: true,
71801
+ vaultKey: nw.vault_key ?? null,
71802
+ databases,
71803
+ fullAccessAgents
71804
+ };
71805
+ }
71585
71806
  function handleGetSchedule(config) {
71586
71807
  const entries = collectScheduleEntries(config);
71587
71808
  const agentsDir = resolveAgentsDir(config);
@@ -71616,7 +71837,7 @@ async function handleGetApprovals() {
71616
71837
  }
71617
71838
 
71618
71839
  // src/web/webhook-handler.ts
71619
- import { appendFileSync as appendFileSync3, existsSync as existsSync46, mkdirSync as mkdirSync26, readFileSync as readFileSync41, writeFileSync as writeFileSync24 } from "fs";
71840
+ import { appendFileSync as appendFileSync3, existsSync as existsSync46, mkdirSync as mkdirSync26, readFileSync as readFileSync42, writeFileSync as writeFileSync24 } from "fs";
71620
71841
  import { join as join40 } from "path";
71621
71842
  import { homedir as homedir21 } from "os";
71622
71843
 
@@ -71768,7 +71989,7 @@ function forwardToGateway(socketPath, req, opts = {}) {
71768
71989
  }
71769
71990
 
71770
71991
  // src/web/webhook-edge.ts
71771
- import { existsSync as existsSync45, readFileSync as readFileSync40 } from "fs";
71992
+ import { existsSync as existsSync45, readFileSync as readFileSync41 } from "fs";
71772
71993
  import { join as join39 } from "path";
71773
71994
  import { homedir as homedir20 } from "os";
71774
71995
  import { timingSafeEqual as timingSafeEqual2 } from "crypto";
@@ -71781,7 +72002,7 @@ function loadEdgeSecret(path4) {
71781
72002
  try {
71782
72003
  if (!existsSync45(p))
71783
72004
  return null;
71784
- const raw = readFileSync40(p, "utf-8").trim();
72005
+ const raw = readFileSync41(p, "utf-8").trim();
71785
72006
  return raw.length > 0 ? raw : null;
71786
72007
  } catch {
71787
72008
  return null;
@@ -71815,7 +72036,7 @@ function loadDedupFile(path4) {
71815
72036
  try {
71816
72037
  if (!existsSync46(path4))
71817
72038
  return {};
71818
- const raw = JSON.parse(readFileSync41(path4, "utf-8"));
72039
+ const raw = JSON.parse(readFileSync42(path4, "utf-8"));
71819
72040
  return typeof raw.deliveries === "object" && raw.deliveries !== null ? raw.deliveries : {};
71820
72041
  } catch {
71821
72042
  return {};
@@ -72095,7 +72316,7 @@ function resolveWebToken() {
72095
72316
  const home2 = process.env.HOME ?? homedir22();
72096
72317
  const tokenPath = join41(home2, ".switchroom", "web-token");
72097
72318
  if (existsSync47(tokenPath)) {
72098
- const existing = readFileSync42(tokenPath, "utf8").trim();
72319
+ const existing = readFileSync43(tokenPath, "utf8").trim();
72099
72320
  if (existing.length > 0)
72100
72321
  return existing;
72101
72322
  }
@@ -72112,7 +72333,7 @@ function resolveWebToken() {
72112
72333
  return token;
72113
72334
  } catch (err) {
72114
72335
  if (err.code === "EEXIST") {
72115
- const existing = readFileSync42(tokenPath, "utf8").trim();
72336
+ const existing = readFileSync43(tokenPath, "utf8").trim();
72116
72337
  if (existing.length > 0)
72117
72338
  return existing;
72118
72339
  }
@@ -72182,7 +72403,7 @@ function loadWebhookSecrets() {
72182
72403
  if (!existsSync47(path4))
72183
72404
  return {};
72184
72405
  try {
72185
- const parsed = JSON.parse(readFileSync42(path4, "utf-8"));
72406
+ const parsed = JSON.parse(readFileSync43(path4, "utf-8"));
72186
72407
  return parsed && typeof parsed === "object" ? parsed : {};
72187
72408
  } catch (err) {
72188
72409
  process.stderr.write(`webhook-ingest: failed to parse ${path4}: ${err.message} \u2014 webhooks will return 401 until fixed
@@ -72259,6 +72480,12 @@ function parseRoute(pathname, method) {
72259
72480
  if (method === "GET" && pathname === "/api/google-accounts") {
72260
72481
  return { handler: "getGoogleAccounts", params: {} };
72261
72482
  }
72483
+ if (method === "GET" && pathname === "/api/microsoft-accounts") {
72484
+ return { handler: "getMicrosoftAccounts", params: {} };
72485
+ }
72486
+ if (method === "GET" && pathname === "/api/notion-workspace") {
72487
+ return { handler: "getNotionWorkspace", params: {} };
72488
+ }
72262
72489
  if (method === "GET" && pathname === "/api/schedule") {
72263
72490
  return { handler: "getSchedule", params: {} };
72264
72491
  }
@@ -72384,6 +72611,10 @@ function startWebServer(config, port, hostname = "127.0.0.1", configPath) {
72384
72611
  return (async () => jsonResponse(await handleGetSystemHealth()))();
72385
72612
  case "getGoogleAccounts":
72386
72613
  return (async () => jsonResponse(await handleGetGoogleAccounts(config)))();
72614
+ case "getMicrosoftAccounts":
72615
+ return (async () => jsonResponse(await handleGetMicrosoftAccounts(config)))();
72616
+ case "getNotionWorkspace":
72617
+ return jsonResponse(handleGetNotionWorkspace(config));
72387
72618
  case "getSchedule":
72388
72619
  return jsonResponse(handleGetSchedule(config));
72389
72620
  case "getApprovals":
@@ -72457,7 +72688,7 @@ function startWebServer(config, port, hostname = "127.0.0.1", configPath) {
72457
72688
  }
72458
72689
  const ext = extname(realFullPath);
72459
72690
  const contentType = MIME_TYPES[ext] ?? "application/octet-stream";
72460
- const content = readFileSync42(realFullPath);
72691
+ const content = readFileSync43(realFullPath);
72461
72692
  return new Response(content, {
72462
72693
  headers: { "Content-Type": contentType }
72463
72694
  });
@@ -72591,26 +72822,26 @@ Starting Switchroom dashboard...
72591
72822
  // src/cli/setup.ts
72592
72823
  init_source();
72593
72824
  init_loader();
72594
- import { existsSync as existsSync48, copyFileSync as copyFileSync8, readFileSync as readFileSync43, writeFileSync as writeFileSync25, mkdirSync as mkdirSync28 } from "node:fs";
72825
+ import { existsSync as existsSync48, copyFileSync as copyFileSync8, readFileSync as readFileSync44, writeFileSync as writeFileSync25, mkdirSync as mkdirSync28 } from "node:fs";
72595
72826
  import { resolve as resolve29, dirname as dirname10 } from "node:path";
72596
72827
  init_vault();
72597
72828
  init_manager();
72598
72829
 
72599
72830
  // src/cli/setup-posture-rewrite.ts
72600
- var import_yaml12 = __toESM(require_dist(), 1);
72831
+ var import_yaml13 = __toESM(require_dist(), 1);
72601
72832
  function insertVaultBrokerApprovalAuth(source, value = "telegram-id") {
72602
72833
  let doc;
72603
72834
  try {
72604
- doc = import_yaml12.default.parseDocument(source);
72835
+ doc = import_yaml13.default.parseDocument(source);
72605
72836
  } catch {
72606
72837
  return { kind: "not-found" };
72607
72838
  }
72608
72839
  const vault = doc.get("vault");
72609
- if (!vault || !import_yaml12.default.isMap(vault)) {
72840
+ if (!vault || !import_yaml13.default.isMap(vault)) {
72610
72841
  return { kind: "not-found" };
72611
72842
  }
72612
72843
  const broker = vault.get("broker");
72613
- if (!broker || !import_yaml12.default.isMap(broker)) {
72844
+ if (!broker || !import_yaml13.default.isMap(broker)) {
72614
72845
  return { kind: "not-found" };
72615
72846
  }
72616
72847
  if (broker.has("approvalAuth")) {
@@ -72661,7 +72892,7 @@ ${childIndent}approvalAuth: ${value}`;
72661
72892
  }
72662
72893
 
72663
72894
  // src/cli/supergroup-setup-yaml.ts
72664
- var import_yaml13 = __toESM(require_dist(), 1);
72895
+ var import_yaml14 = __toESM(require_dist(), 1);
72665
72896
  function isValidSupergroupChatId(value) {
72666
72897
  return /^-\d+$/.test(value);
72667
72898
  }
@@ -72669,23 +72900,23 @@ function setAgentSupergroupChatId(yamlText, agentName, chatId) {
72669
72900
  if (!isValidSupergroupChatId(chatId)) {
72670
72901
  throw new Error(`setAgentSupergroupChatId: chat_id must be a negative integer string (got "${chatId}")`);
72671
72902
  }
72672
- const doc = import_yaml13.parseDocument(yamlText);
72903
+ const doc = import_yaml14.parseDocument(yamlText);
72673
72904
  const root = doc.contents;
72674
- if (!import_yaml13.isMap(root)) {
72905
+ if (!import_yaml14.isMap(root)) {
72675
72906
  throw new Error("setAgentSupergroupChatId: YAML root is not a map");
72676
72907
  }
72677
72908
  const agents = root.get("agents", true);
72678
- if (!import_yaml13.isMap(agents)) {
72909
+ if (!import_yaml14.isMap(agents)) {
72679
72910
  throw new Error("setAgentSupergroupChatId: config has no `agents:` map");
72680
72911
  }
72681
72912
  const agent = agents.get(agentName, true);
72682
- if (!import_yaml13.isMap(agent)) {
72913
+ if (!import_yaml14.isMap(agent)) {
72683
72914
  throw new Error(`setAgentSupergroupChatId: agent "${agentName}" not found in config`);
72684
72915
  }
72685
72916
  const channels = agent.get("channels", true);
72686
- if (import_yaml13.isMap(channels)) {
72917
+ if (import_yaml14.isMap(channels)) {
72687
72918
  const telegram = channels.get("telegram", true);
72688
- if (import_yaml13.isMap(telegram)) {
72919
+ if (import_yaml14.isMap(telegram)) {
72689
72920
  if (telegram.get("chat_id") === chatId)
72690
72921
  return yamlText;
72691
72922
  telegram.set("chat_id", chatId);
@@ -73320,7 +73551,7 @@ async function stepAutoUnlock(config, switchroomConfigPath, nonInteractive) {
73320
73551
  try {
73321
73552
  const yamlPath = existsSync48(resolve29(process.cwd(), "switchroom.yaml")) ? resolve29(process.cwd(), "switchroom.yaml") : resolve29(process.cwd(), "switchroom.yml");
73322
73553
  if (existsSync48(yamlPath)) {
73323
- const content = readFileSync43(yamlPath, "utf-8");
73554
+ const content = readFileSync44(yamlPath, "utf-8");
73324
73555
  const result = insertVaultBrokerApprovalAuth(content, "telegram-id");
73325
73556
  if (result.kind === "rewritten") {
73326
73557
  writeFileSync25(yamlPath, result.content, "utf-8");
@@ -73355,7 +73586,7 @@ async function stepDangerousMode(config, nonInteractive) {
73355
73586
  ];
73356
73587
  for (const configPath of configPaths) {
73357
73588
  if (existsSync48(configPath)) {
73358
- let content = readFileSync43(configPath, "utf-8");
73589
+ let content = readFileSync44(configPath, "utf-8");
73359
73590
  const agentNames = Object.keys(config.agents);
73360
73591
  for (const name of agentNames) {
73361
73592
  const agentPattern = new RegExp(`(^ ${name}:\\s*\\n)`, "m");
@@ -73465,9 +73696,9 @@ async function stepVerification(config, nonInteractive) {
73465
73696
  Start ${source_default.cyan(firstName)} now?`, false);
73466
73697
  if (startNow) {
73467
73698
  try {
73468
- const { execFileSync: execFileSync16 } = await import("node:child_process");
73699
+ const { execFileSync: execFileSync17 } = await import("node:child_process");
73469
73700
  console.log(source_default.gray(` Starting ${firstName}...`));
73470
- execFileSync16("switchroom", ["agent", "start", firstName], { stdio: "inherit" });
73701
+ execFileSync17("switchroom", ["agent", "start", firstName], { stdio: "inherit" });
73471
73702
  console.log(source_default.green(` ${STEP_DONE} Agent started`));
73472
73703
  } catch {
73473
73704
  console.log(source_default.yellow(` Could not start automatically. Run: switchroom agent start ${firstName}`));
@@ -73484,7 +73715,7 @@ init_doctor();
73484
73715
  init_source();
73485
73716
  init_loader();
73486
73717
  init_lifecycle();
73487
- import { cpSync as cpSync2, existsSync as existsSync55, mkdirSync as mkdirSync30, readFileSync as readFileSync48, realpathSync as realpathSync5, rmSync as rmSync12, statSync as statSync24 } from "node:fs";
73718
+ import { cpSync as cpSync2, existsSync as existsSync55, mkdirSync as mkdirSync30, readFileSync as readFileSync49, realpathSync as realpathSync5, rmSync as rmSync12, statSync as statSync24 } from "node:fs";
73488
73719
  import { spawnSync as spawnSync8 } from "node:child_process";
73489
73720
  import { join as join55, dirname as dirname13, resolve as resolve33 } from "node:path";
73490
73721
  import { homedir as homedir33 } from "node:os";
@@ -73494,7 +73725,7 @@ function runningFromSwitchroomCheckout(scriptPath) {
73494
73725
  for (let i = 0;i < 12; i++) {
73495
73726
  if (existsSync55(join55(dir, ".git"))) {
73496
73727
  try {
73497
- const pkg = JSON.parse(readFileSync48(join55(dir, "package.json"), "utf-8"));
73728
+ const pkg = JSON.parse(readFileSync49(join55(dir, "package.json"), "utf-8"));
73498
73729
  if (pkg.name === "switchroom")
73499
73730
  return true;
73500
73731
  } catch {}
@@ -73762,7 +73993,7 @@ function defaultStatusProbe(composePath) {
73762
73993
  const pkgPath = join55(dir, "package.json");
73763
73994
  if (existsSync55(pkgPath)) {
73764
73995
  try {
73765
- const pkg = JSON.parse(readFileSync48(pkgPath, "utf-8"));
73996
+ const pkg = JSON.parse(readFileSync49(pkgPath, "utf-8"));
73766
73997
  if (typeof pkg.version === "string")
73767
73998
  cliVersion = pkg.version;
73768
73999
  } catch (err) {
@@ -73978,7 +74209,7 @@ init_source();
73978
74209
  init_helpers();
73979
74210
  init_lifecycle();
73980
74211
  import { execSync as execSync4 } from "node:child_process";
73981
- import { existsSync as existsSync56, readFileSync as readFileSync49 } from "node:fs";
74212
+ import { existsSync as existsSync56, readFileSync as readFileSync50 } from "node:fs";
73982
74213
  import { dirname as dirname14, join as join56 } from "node:path";
73983
74214
  function getClaudeCodeVersion() {
73984
74215
  try {
@@ -74032,7 +74263,7 @@ function locateSwitchroomInstallDir() {
74032
74263
  const pkgPath = join56(dir, "package.json");
74033
74264
  if (existsSync56(pkgPath)) {
74034
74265
  try {
74035
- const pkg = JSON.parse(readFileSync49(pkgPath, "utf-8"));
74266
+ const pkg = JSON.parse(readFileSync50(pkgPath, "utf-8"));
74036
74267
  if (pkg.name === "switchroom" && existsSync56(join56(dir, ".git"))) {
74037
74268
  return dir;
74038
74269
  }
@@ -74263,7 +74494,7 @@ import {
74263
74494
  mkdirSync as mkdirSync31,
74264
74495
  openSync as openSync11,
74265
74496
  readdirSync as readdirSync21,
74266
- readFileSync as readFileSync50,
74497
+ readFileSync as readFileSync51,
74267
74498
  renameSync as renameSync12,
74268
74499
  statSync as statSync25,
74269
74500
  unlinkSync as unlinkSync11,
@@ -74673,7 +74904,7 @@ function readAll(stateDir) {
74673
74904
  return [];
74674
74905
  let raw;
74675
74906
  try {
74676
- raw = readFileSync50(path4, "utf-8");
74907
+ raw = readFileSync51(path4, "utf-8");
74677
74908
  } catch {
74678
74909
  return [];
74679
74910
  }
@@ -74884,7 +75115,7 @@ function withLock(stateDir, fn) {
74884
75115
  function tryStealStaleLock(lockPath) {
74885
75116
  let pidStr;
74886
75117
  try {
74887
- pidStr = readFileSync50(lockPath, "utf-8").trim();
75118
+ pidStr = readFileSync51(lockPath, "utf-8").trim();
74888
75119
  } catch {
74889
75120
  return true;
74890
75121
  }
@@ -75141,13 +75372,13 @@ import { createHash as createHash11 } from "node:crypto";
75141
75372
  import {
75142
75373
  existsSync as existsSync58,
75143
75374
  mkdirSync as mkdirSync32,
75144
- readFileSync as readFileSync51,
75375
+ readFileSync as readFileSync52,
75145
75376
  rmSync as rmSync13,
75146
75377
  writeFileSync as writeFileSync27
75147
75378
  } from "node:fs";
75148
75379
  import { dirname as dirname15, join as join58 } from "node:path";
75149
75380
  import { homedir as homedir34 } from "node:os";
75150
- import { execFileSync as execFileSync17 } from "node:child_process";
75381
+ import { execFileSync as execFileSync18 } from "node:child_process";
75151
75382
 
75152
75383
  class PythonEnvError extends Error {
75153
75384
  stderr;
@@ -75161,7 +75392,7 @@ function defaultPythonCacheRoot() {
75161
75392
  return join58(homedir34(), ".switchroom", "deps", "python");
75162
75393
  }
75163
75394
  function hashFile(path4) {
75164
- return createHash11("sha256").update(readFileSync51(path4)).digest("hex");
75395
+ return createHash11("sha256").update(readFileSync52(path4)).digest("hex");
75165
75396
  }
75166
75397
  function ensurePythonEnv(opts) {
75167
75398
  const { skillName, requirementsPath, force = false } = opts;
@@ -75177,7 +75408,7 @@ function ensurePythonEnv(opts) {
75177
75408
  const pipBin = join58(binDir, "pip");
75178
75409
  const targetHash = hashFile(requirementsPath);
75179
75410
  if (!force && existsSync58(stampPath) && existsSync58(pythonBin)) {
75180
- const existingHash = readFileSync51(stampPath, "utf8").trim();
75411
+ const existingHash = readFileSync52(stampPath, "utf8").trim();
75181
75412
  if (existingHash === targetHash) {
75182
75413
  return {
75183
75414
  skillName,
@@ -75194,7 +75425,7 @@ function ensurePythonEnv(opts) {
75194
75425
  }
75195
75426
  mkdirSync32(dirname15(venvDir), { recursive: true });
75196
75427
  try {
75197
- execFileSync17(hostPython, ["-m", "venv", venvDir], { stdio: "pipe" });
75428
+ execFileSync18(hostPython, ["-m", "venv", venvDir], { stdio: "pipe" });
75198
75429
  } catch (err) {
75199
75430
  const e = err;
75200
75431
  throw new PythonEnvError(`Failed to create venv for skill "${skillName}" with ${hostPython}: ${e.message}`, e.stderr?.toString());
@@ -75206,7 +75437,7 @@ function ensurePythonEnv(opts) {
75206
75437
  delete childEnv.PIP_TARGET;
75207
75438
  delete childEnv.PIP_PREFIX;
75208
75439
  delete childEnv.PYTHONUSERBASE;
75209
- execFileSync17(pipBin, ["install", "--disable-pip-version-check", "-r", requirementsPath], { stdio: "pipe", env: childEnv });
75440
+ execFileSync18(pipBin, ["install", "--disable-pip-version-check", "-r", requirementsPath], { stdio: "pipe", env: childEnv });
75210
75441
  } catch (err) {
75211
75442
  const e = err;
75212
75443
  throw new PythonEnvError(`Failed to install requirements for skill "${skillName}": ${e.message}`, e.stderr?.toString());
@@ -75229,13 +75460,13 @@ import {
75229
75460
  copyFileSync as copyFileSync9,
75230
75461
  existsSync as existsSync59,
75231
75462
  mkdirSync as mkdirSync33,
75232
- readFileSync as readFileSync52,
75463
+ readFileSync as readFileSync53,
75233
75464
  rmSync as rmSync14,
75234
75465
  writeFileSync as writeFileSync28
75235
75466
  } from "node:fs";
75236
75467
  import { dirname as dirname16, join as join59 } from "node:path";
75237
75468
  import { homedir as homedir35 } from "node:os";
75238
- import { execFileSync as execFileSync18 } from "node:child_process";
75469
+ import { execFileSync as execFileSync19 } from "node:child_process";
75239
75470
 
75240
75471
  class NodeEnvError extends Error {
75241
75472
  stderr;
@@ -75264,7 +75495,7 @@ function hashDepInputs(packageJsonPath) {
75264
75495
  const hasher = createHash12("sha256");
75265
75496
  hasher.update(`package.json
75266
75497
  `);
75267
- hasher.update(readFileSync52(packageJsonPath));
75498
+ hasher.update(readFileSync53(packageJsonPath));
75268
75499
  for (const lockName of ALL_LOCKFILES) {
75269
75500
  const lockPath = join59(sourceDir, lockName);
75270
75501
  if (existsSync59(lockPath)) {
@@ -75273,7 +75504,7 @@ function hashDepInputs(packageJsonPath) {
75273
75504
  hasher.update(lockName);
75274
75505
  hasher.update(`
75275
75506
  `);
75276
- hasher.update(readFileSync52(lockPath));
75507
+ hasher.update(readFileSync53(lockPath));
75277
75508
  }
75278
75509
  }
75279
75510
  return hasher.digest("hex");
@@ -75292,7 +75523,7 @@ function ensureNodeEnv(opts) {
75292
75523
  const binDir = join59(nodeModulesDir, ".bin");
75293
75524
  const targetHash = hashDepInputs(packageJsonPath);
75294
75525
  if (!force && existsSync59(stampPath) && existsSync59(nodeModulesDir)) {
75295
- const existingHash = readFileSync52(stampPath, "utf8").trim();
75526
+ const existingHash = readFileSync53(stampPath, "utf8").trim();
75296
75527
  if (existingHash === targetHash) {
75297
75528
  return {
75298
75529
  skillName,
@@ -75319,10 +75550,10 @@ function ensureNodeEnv(opts) {
75319
75550
  try {
75320
75551
  if (installer === "bun") {
75321
75552
  const args = copiedLockfile ? ["install", "--frozen-lockfile"] : ["install"];
75322
- execFileSync18("bun", args, { cwd: envDir, stdio: "pipe" });
75553
+ execFileSync19("bun", args, { cwd: envDir, stdio: "pipe" });
75323
75554
  } else {
75324
75555
  const args = copiedLockfile ? ["ci"] : ["install"];
75325
- execFileSync18("npm", args, { cwd: envDir, stdio: "pipe" });
75556
+ execFileSync19("npm", args, { cwd: envDir, stdio: "pipe" });
75326
75557
  }
75327
75558
  } catch (err) {
75328
75559
  const e = err;
@@ -76311,7 +76542,7 @@ function safeParseInt(value, fallback) {
76311
76542
  init_helpers();
76312
76543
  init_loader();
76313
76544
  init_merge();
76314
- import { copyFileSync as copyFileSync10, existsSync as existsSync62, readFileSync as readFileSync53, writeFileSync as writeFileSync29 } from "node:fs";
76545
+ import { copyFileSync as copyFileSync10, existsSync as existsSync62, readFileSync as readFileSync54, writeFileSync as writeFileSync29 } from "node:fs";
76315
76546
  import { join as join61, resolve as resolve39 } from "node:path";
76316
76547
  init_schema();
76317
76548
  function resolveSoulTargetOrExit(program3, agentName) {
@@ -76357,7 +76588,7 @@ function registerSoulCommand(program3) {
76357
76588
  console.error(`soul: ${t.soulPath} does not exist yet \u2014 run ` + `\`switchroom soul reset ${agentName}\` to seed it.`);
76358
76589
  process.exit(1);
76359
76590
  }
76360
- process.stdout.write(readFileSync53(t.soulPath, "utf-8"));
76591
+ process.stdout.write(readFileSync54(t.soulPath, "utf-8"));
76361
76592
  }));
76362
76593
  cmd.command("reset <agent>").description("Re-seed SOUL.md from the agent's current profile " + "(backs the existing file up to SOUL.md.bak first)").option("-y, --yes", "Skip the confirmation prompt").action(withConfigError(async (agentName, opts) => {
76363
76594
  const t = resolveSoulTargetOrExit(program3, agentName);
@@ -76402,7 +76633,7 @@ function registerSoulCommand(program3) {
76402
76633
  // src/cli/debug.ts
76403
76634
  init_helpers();
76404
76635
  init_loader();
76405
- import { existsSync as existsSync63, readFileSync as readFileSync54, readdirSync as readdirSync22, statSync as statSync26 } from "node:fs";
76636
+ import { existsSync as existsSync63, readFileSync as readFileSync55, readdirSync as readdirSync22, statSync as statSync26 } from "node:fs";
76406
76637
  import { resolve as resolve40, join as join62 } from "node:path";
76407
76638
  import { createHash as createHash13 } from "node:crypto";
76408
76639
  init_merge();
@@ -76442,7 +76673,7 @@ function findLatestTranscriptJsonl(claudeConfigDir) {
76442
76673
  }
76443
76674
  function extractLatestUserMessage(transcriptPath) {
76444
76675
  try {
76445
- const content = readFileSync54(transcriptPath, "utf-8");
76676
+ const content = readFileSync55(transcriptPath, "utf-8");
76446
76677
  const lines = content.trim().split(`
76447
76678
  `).filter(Boolean);
76448
76679
  for (let i = lines.length - 1;i >= 0; i--) {
@@ -76546,7 +76777,7 @@ function registerDebugCommand(program3) {
76546
76777
  }
76547
76778
  console.log(`=== Append System Prompt (per-session) ===
76548
76779
  `);
76549
- const handoffContent = existsSync63(handoffPath) ? readFileSync54(handoffPath, "utf-8") : "";
76780
+ const handoffContent = existsSync63(handoffPath) ? readFileSync55(handoffPath, "utf-8") : "";
76550
76781
  if (handoffContent.trim().length > 0) {
76551
76782
  console.log(`-- Handoff Briefing (${formatBytes(handoffContent.length)}) --`);
76552
76783
  console.log(handoffContent);
@@ -76557,7 +76788,7 @@ function registerDebugCommand(program3) {
76557
76788
  }
76558
76789
  console.log(`=== CLAUDE.md (auto-loaded by Claude Code) ===
76559
76790
  `);
76560
- const claudeMdContent = existsSync63(claudeMdPath) ? readFileSync54(claudeMdPath, "utf-8") : "";
76791
+ const claudeMdContent = existsSync63(claudeMdPath) ? readFileSync55(claudeMdPath, "utf-8") : "";
76561
76792
  if (claudeMdContent.trim().length > 0) {
76562
76793
  console.log(`(${formatBytes(claudeMdContent.length)})`);
76563
76794
  console.log(claudeMdContent);
@@ -76568,7 +76799,7 @@ function registerDebugCommand(program3) {
76568
76799
  }
76569
76800
  console.log(`=== Persona (SOUL.md) ===
76570
76801
  `);
76571
- const soulMdContent = existsSync63(soulMdPath) ? readFileSync54(soulMdPath, "utf-8") : existsSync63(workspaceSoulMdPath) ? readFileSync54(workspaceSoulMdPath, "utf-8") : "";
76802
+ const soulMdContent = existsSync63(soulMdPath) ? readFileSync55(soulMdPath, "utf-8") : existsSync63(workspaceSoulMdPath) ? readFileSync55(workspaceSoulMdPath, "utf-8") : "";
76572
76803
  if (soulMdContent.trim().length > 0) {
76573
76804
  console.log(`(${formatBytes(soulMdContent.length)})`);
76574
76805
  console.log(soulMdContent);
@@ -76648,7 +76879,7 @@ function registerDebugCommand(program3) {
76648
76879
  init_source();
76649
76880
 
76650
76881
  // src/worktree/claim.ts
76651
- import { execFileSync as execFileSync19 } from "node:child_process";
76882
+ import { execFileSync as execFileSync20 } from "node:child_process";
76652
76883
  import { closeSync as closeSync12, mkdirSync as mkdirSync35, openSync as openSync12, existsSync as existsSync65, unlinkSync as unlinkSync13 } from "node:fs";
76653
76884
  import { join as join64, resolve as resolve42 } from "node:path";
76654
76885
  import { homedir as homedir38 } from "node:os";
@@ -76658,7 +76889,7 @@ import { randomBytes as randomBytes13 } from "node:crypto";
76658
76889
  import {
76659
76890
  mkdirSync as mkdirSync34,
76660
76891
  writeFileSync as writeFileSync30,
76661
- readFileSync as readFileSync55,
76892
+ readFileSync as readFileSync56,
76662
76893
  readdirSync as readdirSync23,
76663
76894
  unlinkSync as unlinkSync12,
76664
76895
  existsSync as existsSync64,
@@ -76686,7 +76917,7 @@ function writeRecord(record2) {
76686
76917
  function readRecord(id) {
76687
76918
  const path7 = recordPath(id);
76688
76919
  try {
76689
- const raw = readFileSync55(path7, "utf8");
76920
+ const raw = readFileSync56(path7, "utf8");
76690
76921
  return JSON.parse(raw);
76691
76922
  } catch {
76692
76923
  return null;
@@ -76815,7 +77046,7 @@ async function claimWorktree(input, codeRepos) {
76815
77046
  releaseLock();
76816
77047
  }
76817
77048
  try {
76818
- execFileSync19("git", ["worktree", "add", "-b", branch, worktreePath], {
77049
+ execFileSync20("git", ["worktree", "add", "-b", branch, worktreePath], {
76819
77050
  cwd: repoPath,
76820
77051
  stdio: "pipe"
76821
77052
  });
@@ -76828,7 +77059,7 @@ async function claimWorktree(input, codeRepos) {
76828
77059
  }
76829
77060
 
76830
77061
  // src/worktree/release.ts
76831
- import { execFileSync as execFileSync20 } from "node:child_process";
77062
+ import { execFileSync as execFileSync21 } from "node:child_process";
76832
77063
  import { existsSync as existsSync66 } from "node:fs";
76833
77064
  function releaseWorktree(input) {
76834
77065
  const { id } = input;
@@ -76839,7 +77070,7 @@ function releaseWorktree(input) {
76839
77070
  let gitSuccess = true;
76840
77071
  if (existsSync66(record2.path)) {
76841
77072
  try {
76842
- execFileSync20("git", ["worktree", "remove", "--force", record2.path], {
77073
+ execFileSync21("git", ["worktree", "remove", "--force", record2.path], {
76843
77074
  cwd: record2.repo,
76844
77075
  stdio: "pipe"
76845
77076
  });
@@ -76875,16 +77106,16 @@ function listWorktrees() {
76875
77106
  }
76876
77107
 
76877
77108
  // src/worktree/reaper.ts
76878
- import { execFileSync as execFileSync21 } from "node:child_process";
77109
+ import { execFileSync as execFileSync22 } from "node:child_process";
76879
77110
  import { existsSync as existsSync67 } from "node:fs";
76880
77111
  var STALE_THRESHOLD_MS = 10 * 60 * 1000;
76881
77112
  function isPathInUse(path7) {
76882
77113
  try {
76883
- execFileSync21("fuser", [path7], { stdio: "pipe" });
77114
+ execFileSync22("fuser", [path7], { stdio: "pipe" });
76884
77115
  return true;
76885
77116
  } catch {}
76886
77117
  try {
76887
- const out = execFileSync21("lsof", ["-t", path7], {
77118
+ const out = execFileSync22("lsof", ["-t", path7], {
76888
77119
  stdio: ["ignore", "pipe", "ignore"]
76889
77120
  }).toString().trim();
76890
77121
  if (out.length > 0)
@@ -76894,7 +77125,7 @@ function isPathInUse(path7) {
76894
77125
  }
76895
77126
  function hasUncommittedChanges(repoPath, worktreePath) {
76896
77127
  try {
76897
- const out = execFileSync21("git", ["-C", worktreePath, "status", "--porcelain"], { stdio: "pipe" }).toString();
77128
+ const out = execFileSync22("git", ["-C", worktreePath, "status", "--porcelain"], { stdio: "pipe" }).toString();
76898
77129
  return out.trim().length > 0;
76899
77130
  } catch {
76900
77131
  return false;
@@ -76908,7 +77139,7 @@ function reapRecord(record2) {
76908
77139
  warning = `[worktree-reaper] Reaped worktree with uncommitted changes: ` + `id=${id} branch=${branch} agent=${ownerAgent ?? "unknown"} path=${path7}`;
76909
77140
  }
76910
77141
  try {
76911
- execFileSync21("git", ["worktree", "remove", "--force", path7], {
77142
+ execFileSync22("git", ["worktree", "remove", "--force", path7], {
76912
77143
  cwd: repo,
76913
77144
  stdio: "pipe"
76914
77145
  });
@@ -78000,7 +78231,7 @@ async function fetchToken(vaultKey) {
78000
78231
 
78001
78232
  // src/cli/apply.ts
78002
78233
  init_source();
78003
- import { accessSync as accessSync3, chownSync as chownSync4, constants as fsConstants6, copyFileSync as copyFileSync11, existsSync as existsSync72, mkdirSync as mkdirSync40, readFileSync as readFileSync57, readdirSync as readdirSync26, renameSync as renameSync14, writeFileSync as writeFileSync35 } from "node:fs";
78234
+ import { accessSync as accessSync3, chownSync as chownSync4, constants as fsConstants6, copyFileSync as copyFileSync11, existsSync as existsSync72, mkdirSync as mkdirSync40, readFileSync as readFileSync58, readdirSync as readdirSync26, renameSync as renameSync14, writeFileSync as writeFileSync35 } from "node:fs";
78004
78235
  import { mkdir, writeFile } from "node:fs/promises";
78005
78236
  import { spawnSync as childSpawnSync } from "node:child_process";
78006
78237
  import readline from "node:readline";
@@ -78391,13 +78622,13 @@ agents:
78391
78622
  init_resolver();
78392
78623
  import { dirname as dirname21, join as join70, resolve as resolve44 } from "node:path";
78393
78624
  import { homedir as homedir40 } from "node:os";
78394
- import { execFileSync as execFileSync22 } from "node:child_process";
78625
+ import { execFileSync as execFileSync23 } from "node:child_process";
78395
78626
  init_vault();
78396
78627
  init_loader();
78397
78628
  init_loader();
78398
78629
 
78399
78630
  // src/cli/update-prompt-hook.ts
78400
- import { existsSync as existsSync69, readFileSync as readFileSync56, writeFileSync as writeFileSync34, chmodSync as chmodSync10, mkdirSync as mkdirSync39 } from "node:fs";
78631
+ import { existsSync as existsSync69, readFileSync as readFileSync57, writeFileSync as writeFileSync34, chmodSync as chmodSync10, mkdirSync as mkdirSync39 } from "node:fs";
78401
78632
  import { join as join67 } from "node:path";
78402
78633
  var HOOK_FILENAME = "update-card-on-prompt.sh";
78403
78634
  function updatePromptHookScript() {
@@ -78469,7 +78700,7 @@ function installUpdatePromptHook(agentDir) {
78469
78700
  const scriptPath = join67(hooksDir, HOOK_FILENAME);
78470
78701
  const desired = updatePromptHookScript();
78471
78702
  let installed = false;
78472
- const existing = existsSync69(scriptPath) ? readFileSync56(scriptPath, "utf-8") : "";
78703
+ const existing = existsSync69(scriptPath) ? readFileSync57(scriptPath, "utf-8") : "";
78473
78704
  if (existing !== desired) {
78474
78705
  writeFileSync34(scriptPath, desired, { mode: 493 });
78475
78706
  chmodSync10(scriptPath, 493);
@@ -78483,7 +78714,7 @@ function installUpdatePromptHook(agentDir) {
78483
78714
  if (!existsSync69(settingsPath)) {
78484
78715
  return { scriptPath, settingsPath, installed };
78485
78716
  }
78486
- const raw = readFileSync56(settingsPath, "utf-8");
78717
+ const raw = readFileSync57(settingsPath, "utf-8");
78487
78718
  let parsed;
78488
78719
  try {
78489
78720
  parsed = JSON.parse(raw);
@@ -78777,7 +79008,7 @@ async function ensureHostMountSources(config) {
78777
79008
  await mkdir(fleetDir, { recursive: true });
78778
79009
  const invariantsPath = join70(fleetDir, "switchroom-invariants.md");
78779
79010
  const invariantsCanonical = renderFleetInvariants();
78780
- const invariantsCurrent = existsSync72(invariantsPath) ? readFileSync57(invariantsPath, "utf-8") : null;
79011
+ const invariantsCurrent = existsSync72(invariantsPath) ? readFileSync58(invariantsPath, "utf-8") : null;
78781
79012
  if (invariantsCurrent !== invariantsCanonical) {
78782
79013
  writeFileSync35(invariantsPath, invariantsCanonical, { mode: 420 });
78783
79014
  }
@@ -78799,7 +79030,7 @@ async function ensureHostMountSources(config) {
78799
79030
  }
78800
79031
  function detectComposeV2() {
78801
79032
  try {
78802
- const out = execFileSync22("docker", ["compose", "version"], {
79033
+ const out = execFileSync23("docker", ["compose", "version"], {
78803
79034
  stdio: ["ignore", "pipe", "pipe"],
78804
79035
  encoding: "utf8"
78805
79036
  });
@@ -79314,7 +79545,7 @@ function runRedactStdin() {
79314
79545
  }
79315
79546
 
79316
79547
  // src/cli/status-ask.ts
79317
- import { readFileSync as readFileSync58, existsSync as existsSync73, readdirSync as readdirSync27 } from "node:fs";
79548
+ import { readFileSync as readFileSync59, existsSync as existsSync73, readdirSync as readdirSync27 } from "node:fs";
79318
79549
  import { join as join71 } from "node:path";
79319
79550
  import { homedir as homedir41 } from "node:os";
79320
79551
 
@@ -79590,7 +79821,7 @@ function runReport(opts) {
79590
79821
  for (const src of sources) {
79591
79822
  let content;
79592
79823
  try {
79593
- content = readFileSync58(src.path, "utf-8");
79824
+ content = readFileSync59(src.path, "utf-8");
79594
79825
  } catch (err) {
79595
79826
  process.stderr.write(`status-ask report: cannot read ${src.path}: ${err instanceof Error ? err.message : String(err)}
79596
79827
  `);
@@ -79691,7 +79922,7 @@ import {
79691
79922
  existsSync as existsSync74,
79692
79923
  mkdirSync as mkdirSync41,
79693
79924
  appendFileSync as appendFileSync4,
79694
- readFileSync as readFileSync59
79925
+ readFileSync as readFileSync60
79695
79926
  } from "node:fs";
79696
79927
  var AUDIT_ROOT = join72(homedir42(), ".switchroom", "audit");
79697
79928
  function auditPathFor(agent) {
@@ -79786,7 +80017,7 @@ function readAuditTail(agent, limit, opts = {}) {
79786
80017
  return [];
79787
80018
  let raw;
79788
80019
  try {
79789
- raw = readFileSync59(path8, "utf-8");
80020
+ raw = readFileSync60(path8, "utf-8");
79790
80021
  } catch {
79791
80022
  return [];
79792
80023
  }
@@ -79936,7 +80167,7 @@ function registerAgentConfigCommands(program3) {
79936
80167
  }
79937
80168
 
79938
80169
  // src/cli/agent-config-write.ts
79939
- var import_yaml16 = __toESM(require_dist(), 1);
80170
+ var import_yaml17 = __toESM(require_dist(), 1);
79940
80171
 
79941
80172
  // src/config/overlay-writer.ts
79942
80173
  init_paths();
@@ -79947,7 +80178,7 @@ import {
79947
80178
  mkdirSync as mkdirSync42,
79948
80179
  openSync as openSync13,
79949
80180
  readdirSync as readdirSync28,
79950
- readFileSync as readFileSync60,
80181
+ readFileSync as readFileSync61,
79951
80182
  renameSync as renameSync15,
79952
80183
  statSync as statSync28,
79953
80184
  unlinkSync as unlinkSync14,
@@ -80071,7 +80302,7 @@ function listSkillsOverlayEntries(agent, opts = {}) {
80071
80302
  continue;
80072
80303
  const full = join73(paths.skillsDir, name);
80073
80304
  try {
80074
- const raw = readFileSync60(full, "utf-8");
80305
+ const raw = readFileSync61(full, "utf-8");
80075
80306
  const slug = name.replace(/\.ya?ml$/i, "");
80076
80307
  out.push({ slug, path: full, raw });
80077
80308
  } catch {}
@@ -80098,7 +80329,7 @@ function listOverlayEntries(agent, opts = {}) {
80098
80329
  continue;
80099
80330
  const full = join73(paths.scheduleDir, name);
80100
80331
  try {
80101
- const raw = readFileSync60(full, "utf-8");
80332
+ const raw = readFileSync61(full, "utf-8");
80102
80333
  const slug = name.replace(/\.ya?ml$/i, "");
80103
80334
  out.push({ slug, path: full, raw });
80104
80335
  } catch {}
@@ -80129,7 +80360,7 @@ function filterOverlaySecrets(doc, source) {
80129
80360
  // src/agents/reconcile-dry-run.ts
80130
80361
  init_overlay_schema();
80131
80362
  init_schema();
80132
- var import_yaml15 = __toESM(require_dist(), 1);
80363
+ var import_yaml16 = __toESM(require_dist(), 1);
80133
80364
  init_lifecycle();
80134
80365
  var MIN_CRON_INTERVAL_SECS = 5 * 60;
80135
80366
  function violatesMinInterval(cron) {
@@ -80151,7 +80382,7 @@ function violatesMinInterval(cron) {
80151
80382
  function dryRunReconcile(input) {
80152
80383
  let parsed;
80153
80384
  try {
80154
- parsed = import_yaml15.parse(input.yamlText);
80385
+ parsed = import_yaml16.parse(input.yamlText);
80155
80386
  } catch (err) {
80156
80387
  return {
80157
80388
  ok: false,
@@ -80246,7 +80477,7 @@ import {
80246
80477
  mkdirSync as mkdirSync43,
80247
80478
  openSync as openSync14,
80248
80479
  readdirSync as readdirSync29,
80249
- readFileSync as readFileSync61,
80480
+ readFileSync as readFileSync62,
80250
80481
  renameSync as renameSync16,
80251
80482
  unlinkSync as unlinkSync15,
80252
80483
  writeFileSync as writeFileSync36,
@@ -80310,7 +80541,7 @@ function listPendingScheduleEntries(agent, opts = {}) {
80310
80541
  if (!existsSync76(yamlPath))
80311
80542
  continue;
80312
80543
  try {
80313
- const meta = JSON.parse(readFileSync61(metaPath, "utf-8"));
80544
+ const meta = JSON.parse(readFileSync62(metaPath, "utf-8"));
80314
80545
  if (meta?.v !== 1 || typeof meta.stage_id !== "string")
80315
80546
  continue;
80316
80547
  out.push({ stageId: meta.stage_id, agent: meta.agent, yamlPath, metaPath, meta });
@@ -80349,7 +80580,7 @@ function denyPendingScheduleEntry(opts) {
80349
80580
 
80350
80581
  // src/cli/agent-config-write.ts
80351
80582
  init_protocol3();
80352
- import { existsSync as existsSync77, readFileSync as readFileSync62 } from "node:fs";
80583
+ import { existsSync as existsSync77, readFileSync as readFileSync63 } from "node:fs";
80353
80584
  var MAX_ENTRIES_PER_AGENT = 20;
80354
80585
  var MIN_CRON_INTERVAL_MIN = 5;
80355
80586
  function extractCronSmallestGapMin(expr) {
@@ -80457,7 +80688,7 @@ function scheduleAdd(opts) {
80457
80688
  ]
80458
80689
  };
80459
80690
  const yamlText = (() => {
80460
- const body = import_yaml16.stringify(doc);
80691
+ const body = import_yaml17.stringify(doc);
80461
80692
  const header = opts.name ? `# name: ${opts.name}
80462
80693
  ` : "";
80463
80694
  return header + body;
@@ -80567,7 +80798,7 @@ function scheduleAddOrStage(opts) {
80567
80798
  ]
80568
80799
  };
80569
80800
  const yamlText = (opts.name ? `# name: ${opts.name}
80570
- ` : "") + import_yaml16.stringify(doc);
80801
+ ` : "") + import_yaml17.stringify(doc);
80571
80802
  const summary = (() => {
80572
80803
  const parts = [`cron=${opts.cronExpr}`];
80573
80804
  if (opts.secrets?.length)
@@ -80617,7 +80848,7 @@ function scheduleRemove(opts) {
80617
80848
  break;
80618
80849
  }
80619
80850
  try {
80620
- const parsed = import_yaml16.parse(e.raw);
80851
+ const parsed = import_yaml17.parse(e.raw);
80621
80852
  if (parsed && parsed.name === opts.name) {
80622
80853
  match = e;
80623
80854
  break;
@@ -80636,7 +80867,7 @@ function scheduleRemove(opts) {
80636
80867
  let priorContent = null;
80637
80868
  try {
80638
80869
  if (existsSync77(match.path))
80639
- priorContent = readFileSync62(match.path, "utf-8");
80870
+ priorContent = readFileSync63(match.path, "utf-8");
80640
80871
  } catch {}
80641
80872
  deleteOverlayEntry(agent, match.slug, { root: opts.root });
80642
80873
  const reconcileFn = opts.reconcile === undefined ? opts.root ? null : reconcileAgentCronOnly : opts.reconcile;
@@ -80827,10 +81058,10 @@ function registerAgentConfigWriteCommands(program3) {
80827
81058
  }
80828
81059
 
80829
81060
  // src/cli/agent-config-skill-write.ts
80830
- var import_yaml17 = __toESM(require_dist(), 1);
81061
+ var import_yaml18 = __toESM(require_dist(), 1);
80831
81062
  import { existsSync as existsSync78 } from "node:fs";
80832
81063
  init_reconcile_default_skills();
80833
- var import_yaml18 = __toESM(require_dist(), 1);
81064
+ var import_yaml19 = __toESM(require_dist(), 1);
80834
81065
  import { join as join75 } from "node:path";
80835
81066
  var MAX_SKILLS_PER_AGENT = 20;
80836
81067
  var V1_ALLOWED_SOURCE_PREFIX = "bundled:";
@@ -80880,7 +81111,7 @@ function countCurrentSkills(agent, opts) {
80880
81111
  let total = 0;
80881
81112
  for (const e of entries) {
80882
81113
  try {
80883
- const doc = import_yaml18.parse(e.raw);
81114
+ const doc = import_yaml19.parse(e.raw);
80884
81115
  total += (doc?.skills ?? []).length;
80885
81116
  } catch {}
80886
81117
  }
@@ -80910,7 +81141,7 @@ function skillInstall(opts) {
80910
81141
  if (!existsSync78(skillPath)) {
80911
81142
  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.`);
80912
81143
  }
80913
- const yamlText = import_yaml17.stringify({ skills: [skillName] });
81144
+ const yamlText = import_yaml18.stringify({ skills: [skillName] });
80914
81145
  let path8;
80915
81146
  try {
80916
81147
  path8 = writeSkillsOverlayEntry(agent, slug, yamlText, { root: opts.root });
@@ -81076,7 +81307,7 @@ import {
81076
81307
  mkdirSync as mkdirSync44,
81077
81308
  mkdtempSync as mkdtempSync5,
81078
81309
  openSync as openSync15,
81079
- readFileSync as readFileSync63,
81310
+ readFileSync as readFileSync64,
81080
81311
  readdirSync as readdirSync30,
81081
81312
  realpathSync as realpathSync7,
81082
81313
  renameSync as renameSync17,
@@ -81089,7 +81320,7 @@ import { dirname as dirname22, join as join76, relative as relative2, resolve as
81089
81320
  import { spawnSync as spawnSync10 } from "node:child_process";
81090
81321
 
81091
81322
  // src/cli/skill-common.ts
81092
- var import_yaml19 = __toESM(require_dist(), 1);
81323
+ var import_yaml20 = __toESM(require_dist(), 1);
81093
81324
  var MAX_FILE_BYTES = 256 * 1024;
81094
81325
  var MAX_SKILL_BYTES = 2 * 1024 * 1024;
81095
81326
  var MAX_FILES_PER_SKILL = 50;
@@ -81193,7 +81424,7 @@ function validateSkillMd(content, expectedName) {
81193
81424
  }
81194
81425
  let parsed;
81195
81426
  try {
81196
- parsed = import_yaml19.parse(fmText);
81427
+ parsed = import_yaml20.parse(fmText);
81197
81428
  } catch (e) {
81198
81429
  return authorErr("E_SKILL_INVALID_FRONTMATTER", `frontmatter is not valid YAML: ${e.message}`);
81199
81430
  }
@@ -81328,7 +81559,7 @@ function loadFromDir(dir) {
81328
81559
  continue;
81329
81560
  }
81330
81561
  if (ent.isFile()) {
81331
- const buf = readFileSync63(full);
81562
+ const buf = readFileSync64(full);
81332
81563
  files[rel.replace(/\\/g, "/")] = buf.toString("utf-8");
81333
81564
  }
81334
81565
  }
@@ -81377,7 +81608,7 @@ function loadFromTarball(tarPath) {
81377
81608
  }
81378
81609
  }
81379
81610
  function loadSingleFile(filePath) {
81380
- const content = readFileSync63(filePath, "utf-8");
81611
+ const content = readFileSync64(filePath, "utf-8");
81381
81612
  return { "SKILL.md": content };
81382
81613
  }
81383
81614
  function loadFromStdin() {
@@ -81468,7 +81699,7 @@ function diffSummary(currentDir, files) {
81468
81699
  if (ent.isDirectory()) {
81469
81700
  walk2(full);
81470
81701
  } else if (ent.isFile()) {
81471
- currentFiles[rel.replace(/\\/g, "/")] = readFileSync63(full, "utf-8");
81702
+ currentFiles[rel.replace(/\\/g, "/")] = readFileSync64(full, "utf-8");
81472
81703
  }
81473
81704
  }
81474
81705
  };
@@ -81628,7 +81859,7 @@ import {
81628
81859
  mkdirSync as mkdirSync45,
81629
81860
  mkdtempSync as mkdtempSync6,
81630
81861
  openSync as openSync16,
81631
- readFileSync as readFileSync64,
81862
+ readFileSync as readFileSync65,
81632
81863
  readdirSync as readdirSync31,
81633
81864
  renameSync as renameSync18,
81634
81865
  rmSync as rmSync17,
@@ -81710,7 +81941,7 @@ function mirrorToConfigRepo(agent, name, liveSkillDir) {
81710
81941
  if (ent.isDirectory())
81711
81942
  walk2(s, d);
81712
81943
  else if (ent.isFile()) {
81713
- writeFileSync38(d, readFileSync64(s));
81944
+ writeFileSync38(d, readFileSync65(s));
81714
81945
  }
81715
81946
  }
81716
81947
  };
@@ -81789,7 +82020,7 @@ function loadFromDir2(dir) {
81789
82020
  }
81790
82021
  if (ent.isFile()) {
81791
82022
  const rel = relative3(abs, full).replace(/\\/g, "/");
81792
- files[rel] = readFileSync64(full, "utf-8");
82023
+ files[rel] = readFileSync65(full, "utf-8");
81793
82024
  }
81794
82025
  }
81795
82026
  };
@@ -81975,7 +82206,7 @@ function loadFiles(opts) {
81975
82206
  return loadFromDir2(p);
81976
82207
  }
81977
82208
  if (p.endsWith(".md")) {
81978
- return { "SKILL.md": readFileSync64(p, "utf-8") };
82209
+ return { "SKILL.md": readFileSync65(p, "utf-8") };
81979
82210
  }
81980
82211
  fail3(`--from must be a directory or a .md file. Got: ${opts.from}`);
81981
82212
  }
@@ -82064,7 +82295,7 @@ function readSourceFiles(dir) {
82064
82295
  fail3(`clone source has oversized file ${rel} (${st.size} bytes > ${CLONE_MAX_FILE_BYTES}); ` + `refuse to read`, 3);
82065
82296
  }
82066
82297
  } catch {}
82067
- files[rel] = readFileSync64(full, "utf-8");
82298
+ files[rel] = readFileSync65(full, "utf-8");
82068
82299
  }
82069
82300
  }
82070
82301
  };
@@ -82232,8 +82463,8 @@ function registerSkillPersonalCommands(program3) {
82232
82463
 
82233
82464
  // src/cli/skill-search.ts
82234
82465
  init_helpers();
82235
- var import_yaml20 = __toESM(require_dist(), 1);
82236
- import { existsSync as existsSync81, readdirSync as readdirSync32, readFileSync as readFileSync65, statSync as statSync31 } from "node:fs";
82466
+ var import_yaml21 = __toESM(require_dist(), 1);
82467
+ import { existsSync as existsSync81, readdirSync as readdirSync32, readFileSync as readFileSync66, statSync as statSync31 } from "node:fs";
82237
82468
  import { homedir as homedir45 } from "node:os";
82238
82469
  import { join as join78, resolve as resolve48 } from "node:path";
82239
82470
  var PERSONAL_PREFIX2 = "personal-";
@@ -82254,7 +82485,7 @@ function readSkillFrontmatter(skillDir) {
82254
82485
  return null;
82255
82486
  let content;
82256
82487
  try {
82257
- content = readFileSync65(mdPath, "utf-8");
82488
+ content = readFileSync66(mdPath, "utf-8");
82258
82489
  } catch {
82259
82490
  return null;
82260
82491
  }
@@ -82272,7 +82503,7 @@ function readSkillFrontmatter(skillDir) {
82272
82503
  const fmText = rest.slice(0, endIdx);
82273
82504
  let parsed;
82274
82505
  try {
82275
- parsed = import_yaml20.parse(fmText);
82506
+ parsed = import_yaml21.parse(fmText);
82276
82507
  } catch (e) {
82277
82508
  return { error: `yaml parse: ${e.message}` };
82278
82509
  }
@@ -82526,7 +82757,7 @@ function registerHostdMcpCommand(program3) {
82526
82757
  // src/cli/hostd.ts
82527
82758
  init_source();
82528
82759
  init_helpers();
82529
- import { existsSync as existsSync83, mkdirSync as mkdirSync46, readdirSync as readdirSync33, readFileSync as readFileSync67, writeFileSync as writeFileSync39, statSync as statSync32, copyFileSync as copyFileSync12 } from "node:fs";
82760
+ import { existsSync as existsSync83, mkdirSync as mkdirSync46, readdirSync as readdirSync33, readFileSync as readFileSync68, writeFileSync as writeFileSync39, statSync as statSync32, copyFileSync as copyFileSync12 } from "node:fs";
82530
82761
  import { homedir as homedir46 } from "node:os";
82531
82762
  import { join as join79 } from "node:path";
82532
82763
  import { spawnSync as spawnSync13 } from "node:child_process";
@@ -82781,7 +83012,7 @@ function registerHostdCommand(program3) {
82781
83012
  The log is created when hostd handles its first privileged-verb request.`));
82782
83013
  return;
82783
83014
  }
82784
- const raw = readFileSync67(logPath, "utf-8");
83015
+ const raw = readFileSync68(logPath, "utf-8");
82785
83016
  const limit = Math.max(1, parseInt(opts.tail ?? "50", 10) || 50);
82786
83017
  const filters = {
82787
83018
  agent: opts.agent,