switchroom 0.16.6 → 0.16.8

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.
@@ -29955,17 +29955,17 @@ var init_thinking_effort_risk = __esm(() => {
29955
29955
 
29956
29956
  // src/manifest.ts
29957
29957
  import {
29958
- existsSync as existsSync53,
29959
- readFileSync as readFileSync49,
29958
+ existsSync as existsSync54,
29959
+ readFileSync as readFileSync50,
29960
29960
  readdirSync as readdirSync19
29961
29961
  } from "node:fs";
29962
- import { dirname as dirname14, join as join49 } from "node:path";
29962
+ import { dirname as dirname14, join as join50 } from "node:path";
29963
29963
  import { execSync as execSync2 } from "node:child_process";
29964
29964
  function locateManifestPath() {
29965
29965
  let dir = import.meta.dirname;
29966
29966
  for (let i = 0;i < 10 && dir && dir !== "/"; i++) {
29967
- const candidate = join49(dir, "dependencies.json");
29968
- if (existsSync53(candidate))
29967
+ const candidate = join50(dir, "dependencies.json");
29968
+ if (existsSync54(candidate))
29969
29969
  return candidate;
29970
29970
  dir = dirname14(dir);
29971
29971
  }
@@ -29978,7 +29978,7 @@ function loadManifest(manifestPath) {
29978
29978
  }
29979
29979
  let raw;
29980
29980
  try {
29981
- raw = readFileSync49(path4, "utf-8");
29981
+ raw = readFileSync50(path4, "utf-8");
29982
29982
  } catch (err) {
29983
29983
  throw new Error(`Failed to read manifest at ${path4}: ${err.message}`);
29984
29984
  }
@@ -30034,16 +30034,16 @@ function probeClaudeVersion() {
30034
30034
  }
30035
30035
  function probePlaywrightMcpVersion() {
30036
30036
  const home2 = process.env.HOME ?? "";
30037
- const npxCache = join49(home2, ".npm/_npx");
30038
- if (!existsSync53(npxCache))
30037
+ const npxCache = join50(home2, ".npm/_npx");
30038
+ if (!existsSync54(npxCache))
30039
30039
  return null;
30040
30040
  try {
30041
30041
  const entries = readdirSync19(npxCache);
30042
30042
  for (const entry of entries) {
30043
- const pkgPath = join49(npxCache, entry, "node_modules/@playwright/mcp/package.json");
30044
- if (existsSync53(pkgPath)) {
30043
+ const pkgPath = join50(npxCache, entry, "node_modules/@playwright/mcp/package.json");
30044
+ if (existsSync54(pkgPath)) {
30045
30045
  try {
30046
- const pkg = JSON.parse(readFileSync49(pkgPath, "utf-8"));
30046
+ const pkg = JSON.parse(readFileSync50(pkgPath, "utf-8"));
30047
30047
  if (pkg.version)
30048
30048
  return pkg.version;
30049
30049
  } catch {}
@@ -30278,7 +30278,7 @@ var init_doctor_memory = __esm(() => {
30278
30278
  });
30279
30279
 
30280
30280
  // src/cli/doctor-docker.ts
30281
- import { readFileSync as readFileSync50 } from "node:fs";
30281
+ import { readFileSync as readFileSync51 } from "node:fs";
30282
30282
  import { spawnSync as spawnSync7 } from "node:child_process";
30283
30283
  function imageTagOf(ref) {
30284
30284
  if (!ref)
@@ -30294,7 +30294,7 @@ function isDockerMode(opts) {
30294
30294
  return true;
30295
30295
  if (opts?.composePath) {
30296
30296
  try {
30297
- readFileSync50(opts.composePath, "utf8");
30297
+ readFileSync51(opts.composePath, "utf8");
30298
30298
  return true;
30299
30299
  } catch {}
30300
30300
  }
@@ -30576,11 +30576,11 @@ var init_doctor_docker = __esm(() => {
30576
30576
  });
30577
30577
 
30578
30578
  // src/cli/doctor-auth-broker.ts
30579
- import { existsSync as existsSync54, readFileSync as readFileSync51 } from "node:fs";
30580
- import { createHash as createHash10 } from "node:crypto";
30579
+ import { existsSync as existsSync55, readFileSync as readFileSync52 } from "node:fs";
30580
+ import { createHash as createHash11 } from "node:crypto";
30581
30581
  import { spawnSync as spawnSync8 } from "node:child_process";
30582
30582
  import { homedir as homedir27 } from "node:os";
30583
- import { join as join50 } from "node:path";
30583
+ import { join as join51 } from "node:path";
30584
30584
  function defaultDockerInspect(container, format) {
30585
30585
  try {
30586
30586
  const r = spawnSync8("docker", ["inspect", "-f", format, container], { encoding: "utf-8", timeout: 5000 });
@@ -30603,7 +30603,7 @@ function resolveStateDir(deps) {
30603
30603
  return deps.stateDir ?? resolveStatePath("state/auth-broker");
30604
30604
  }
30605
30605
  function sha256Hex(content) {
30606
- return createHash10("sha256").update(content).digest("hex");
30606
+ return createHash11("sha256").update(content).digest("hex");
30607
30607
  }
30608
30608
  function checkAuthBrokerServiceHealth(deps = {}) {
30609
30609
  const inspect = deps.dockerInspect ?? defaultDockerInspect;
@@ -30680,8 +30680,8 @@ function checkAuthBrokerPerAgentSockets(config, deps = {}) {
30680
30680
  }
30681
30681
  function checkAuthBrokerDrift(deps = {}) {
30682
30682
  const stateDir = resolveStateDir(deps);
30683
- const indexPath = join50(stateDir, "sha-index.json");
30684
- if (!existsSync54(indexPath)) {
30683
+ const indexPath = join51(stateDir, "sha-index.json");
30684
+ if (!existsSync55(indexPath)) {
30685
30685
  return {
30686
30686
  name: "auth-broker: drift",
30687
30687
  status: "ok",
@@ -30690,7 +30690,7 @@ function checkAuthBrokerDrift(deps = {}) {
30690
30690
  }
30691
30691
  let index;
30692
30692
  try {
30693
- index = JSON.parse(readFileSync51(indexPath, "utf-8"));
30693
+ index = JSON.parse(readFileSync52(indexPath, "utf-8"));
30694
30694
  } catch (err) {
30695
30695
  return {
30696
30696
  name: "auth-broker: drift",
@@ -30704,13 +30704,13 @@ function checkAuthBrokerDrift(deps = {}) {
30704
30704
  const missingOnDisk = [];
30705
30705
  for (const [label, expected] of Object.entries(index)) {
30706
30706
  const credsPath = accountCredentialsPath(label, home2);
30707
- if (!existsSync54(credsPath)) {
30707
+ if (!existsSync55(credsPath)) {
30708
30708
  missingOnDisk.push(label);
30709
30709
  continue;
30710
30710
  }
30711
30711
  let got;
30712
30712
  try {
30713
- got = sha256Hex(readFileSync51(credsPath, "utf-8"));
30713
+ got = sha256Hex(readFileSync52(credsPath, "utf-8"));
30714
30714
  } catch (err) {
30715
30715
  divergent.push(`${label} (read failed: ${err.message})`);
30716
30716
  continue;
@@ -30741,8 +30741,8 @@ function checkAuthBrokerDrift(deps = {}) {
30741
30741
  }
30742
30742
  function checkAuthBrokerThresholdViolations(deps = {}) {
30743
30743
  const stateDir = resolveStateDir(deps);
30744
- const path4 = join50(stateDir, "threshold-violations.json");
30745
- if (!existsSync54(path4)) {
30744
+ const path4 = join51(stateDir, "threshold-violations.json");
30745
+ if (!existsSync55(path4)) {
30746
30746
  return {
30747
30747
  name: "auth-broker: threshold violations",
30748
30748
  status: "ok",
@@ -30751,7 +30751,7 @@ function checkAuthBrokerThresholdViolations(deps = {}) {
30751
30751
  }
30752
30752
  let violations;
30753
30753
  try {
30754
- violations = JSON.parse(readFileSync51(path4, "utf-8"));
30754
+ violations = JSON.parse(readFileSync52(path4, "utf-8"));
30755
30755
  } catch (err) {
30756
30756
  return {
30757
30757
  name: "auth-broker: threshold violations",
@@ -30787,7 +30787,7 @@ function checkAuthBrokerActiveAccount(config, deps = {}) {
30787
30787
  }
30788
30788
  const home2 = deps.home ?? homedir27();
30789
30789
  const dir = accountDir(active, home2);
30790
- if (!existsSync54(dir)) {
30790
+ if (!existsSync55(dir)) {
30791
30791
  return {
30792
30792
  name: "auth-broker: fleet active account",
30793
30793
  status: "fail",
@@ -30796,7 +30796,7 @@ function checkAuthBrokerActiveAccount(config, deps = {}) {
30796
30796
  };
30797
30797
  }
30798
30798
  const creds = accountCredentialsPath(active, home2);
30799
- if (!existsSync54(creds)) {
30799
+ if (!existsSync55(creds)) {
30800
30800
  return {
30801
30801
  name: "auth-broker: fleet active account",
30802
30802
  status: "fail",
@@ -30933,17 +30933,17 @@ var init_doctor_hostd = () => {};
30933
30933
  import {
30934
30934
  accessSync,
30935
30935
  constants as fsConstants4,
30936
- existsSync as existsSync55,
30936
+ existsSync as existsSync56,
30937
30937
  realpathSync as realpathSync5,
30938
30938
  statSync as statSync23
30939
30939
  } from "node:fs";
30940
30940
  import { userInfo, homedir as homedir28 } from "node:os";
30941
- import { join as join51 } from "node:path";
30941
+ import { join as join52 } from "node:path";
30942
30942
  function resolveVaultPath2(config) {
30943
30943
  return config.vault?.path ? config.vault.path.replace(/^~/, process.env.HOME ?? "") : resolveStatePath("vault.enc");
30944
30944
  }
30945
30945
  function defaultStatVault(path4) {
30946
- if (!existsSync55(path4)) {
30946
+ if (!existsSync56(path4)) {
30947
30947
  return { exists: false, readable: false, uid: -1, mode: 0, realPath: path4 };
30948
30948
  }
30949
30949
  let real = path4;
@@ -31076,7 +31076,7 @@ async function runSecretAccessChecks(config, deps = {}) {
31076
31076
  };
31077
31077
  const passphrase = deps.passphrase ?? process.env.SWITCHROOM_VAULT_PASSPHRASE;
31078
31078
  if (!passphrase) {
31079
- const sock = deps.brokerOperatorSocket ?? join51(homedir28(), ".switchroom", "broker-operator", "sock");
31079
+ const sock = deps.brokerOperatorSocket ?? join52(homedir28(), ".switchroom", "broker-operator", "sock");
31080
31080
  const preflight = deps.preflight ?? ((a, k) => defaultPreflight(sock, a, k));
31081
31081
  for (const name of Object.keys(config.agents ?? {})) {
31082
31082
  const resolved = resolveAgentConfig(config.defaults, config.profiles, config.agents[name]);
@@ -31161,7 +31161,7 @@ import {
31161
31161
  existsSync as realExistsSync,
31162
31162
  readFileSync as realReadFileSync
31163
31163
  } from "node:fs";
31164
- import { join as join52, resolve as resolve31 } from "node:path";
31164
+ import { join as join53, resolve as resolve32 } from "node:path";
31165
31165
  import { homedir as homedir29 } from "node:os";
31166
31166
  function resolveDeps(config, deps) {
31167
31167
  let agentsDir = deps.agentsDir;
@@ -31276,7 +31276,7 @@ function checkScaffoldWiring(config, driveAgents, d) {
31276
31276
  ];
31277
31277
  }
31278
31278
  for (const name of driveAgents) {
31279
- const agentDir = resolve31(d.agentsDir, name);
31279
+ const agentDir = resolve32(d.agentsDir, name);
31280
31280
  if (!d.existsSync(agentDir)) {
31281
31281
  results.push({
31282
31282
  name: `drive: ${name} scaffold`,
@@ -31285,8 +31285,8 @@ function checkScaffoldWiring(config, driveAgents, d) {
31285
31285
  });
31286
31286
  continue;
31287
31287
  }
31288
- const mcpPath = join52(agentDir, ".mcp.json");
31289
- const claudeJsonPath = join52(agentDir, ".claude", ".claude.json");
31288
+ const mcpPath = join53(agentDir, ".mcp.json");
31289
+ const claudeJsonPath = join53(agentDir, ".claude", ".claude.json");
31290
31290
  const mcpRead = readJson(d, mcpPath);
31291
31291
  const trustRead = readJson(d, claudeJsonPath);
31292
31292
  if (mcpRead.kind === "unreadable" || trustRead.kind === "unreadable") {
@@ -31314,7 +31314,7 @@ function checkScaffoldWiring(config, driveAgents, d) {
31314
31314
  let trustOk = false;
31315
31315
  let trustDetail = "no .claude/.claude.json";
31316
31316
  if (trustRead.kind === "ok") {
31317
- const proj = trustRead.data?.projects?.[resolve31(agentDir)];
31317
+ const proj = trustRead.data?.projects?.[resolve32(agentDir)];
31318
31318
  const enabled = proj?.enabledMcpjsonServers;
31319
31319
  if (Array.isArray(enabled) && enabled.includes("gdrive")) {
31320
31320
  trustOk = true;
@@ -31399,7 +31399,7 @@ async function runDriveBrokerReachabilityChecks(config, deps = {}) {
31399
31399
  }
31400
31400
  ];
31401
31401
  }
31402
- const sock = deps.brokerOperatorSocket ?? join52(homedir29(), ".switchroom", "broker-operator", "sock");
31402
+ const sock = deps.brokerOperatorSocket ?? join53(homedir29(), ".switchroom", "broker-operator", "sock");
31403
31403
  const preflight = deps.preflight ?? ((a, k) => defaultPreflight(sock, a, k));
31404
31404
  const results = [];
31405
31405
  for (const agent of driveAgents) {
@@ -31453,7 +31453,7 @@ import {
31453
31453
  readSync as realReadSync,
31454
31454
  closeSync as realCloseSync
31455
31455
  } from "node:fs";
31456
- import { join as join53 } from "node:path";
31456
+ import { join as join54 } from "node:path";
31457
31457
  import { homedir as homedir30 } from "node:os";
31458
31458
  function defaultReadHead(p, n) {
31459
31459
  let fd;
@@ -31511,7 +31511,7 @@ function runWebkiteChecks(config, deps = {}) {
31511
31511
  return [];
31512
31512
  const d = resolveDeps2(config, deps);
31513
31513
  const results = [];
31514
- const binPath = join53(d.homeDir, ".switchroom", "bin", "webkite");
31514
+ const binPath = join54(d.homeDir, ".switchroom", "bin", "webkite");
31515
31515
  if (!d.existsSync(binPath)) {
31516
31516
  results.push({
31517
31517
  name: "webkite: binary",
@@ -31541,12 +31541,12 @@ function runWebkiteChecks(config, deps = {}) {
31541
31541
  });
31542
31542
  }
31543
31543
  }
31544
- const cloakDir = join53(d.homeDir, ".cloakbrowser");
31544
+ const cloakDir = join54(d.homeDir, ".cloakbrowser");
31545
31545
  let chromeFound = false;
31546
31546
  if (d.existsSync(cloakDir)) {
31547
31547
  try {
31548
31548
  for (const entry of d.readdirSync(cloakDir)) {
31549
- if (entry.startsWith("chromium-") && d.existsSync(join53(cloakDir, entry, "chrome"))) {
31549
+ if (entry.startsWith("chromium-") && d.existsSync(join54(cloakDir, entry, "chrome"))) {
31550
31550
  chromeFound = true;
31551
31551
  break;
31552
31552
  }
@@ -31572,9 +31572,9 @@ function runWebkiteChecks(config, deps = {}) {
31572
31572
  return results;
31573
31573
  }
31574
31574
  for (const agent of enabledAgents) {
31575
- const agentDir = join53(d.agentsDir, agent);
31576
- const settingsPath = join53(agentDir, ".claude", "settings.json");
31577
- const mcpPath = join53(agentDir, ".mcp.json");
31575
+ const agentDir = join54(d.agentsDir, agent);
31576
+ const settingsPath = join54(agentDir, ".claude", "settings.json");
31577
+ const mcpPath = join54(agentDir, ".mcp.json");
31578
31578
  if (!d.existsSync(settingsPath) && !d.existsSync(mcpPath)) {
31579
31579
  continue;
31580
31580
  }
@@ -31639,7 +31639,7 @@ var init_doctor_webkite = __esm(() => {
31639
31639
 
31640
31640
  // src/cli/doctor-cron-session.ts
31641
31641
  import { statSync as realStatSync } from "node:fs";
31642
- import { resolve as resolve32 } from "node:path";
31642
+ import { resolve as resolve33 } from "node:path";
31643
31643
  function agentRunsCronSession(config, agent) {
31644
31644
  const raw = config.agents[agent];
31645
31645
  if (!raw)
@@ -31655,7 +31655,7 @@ function runCronSessionChecks(config, deps = defaultDeps2) {
31655
31655
  if (!agentRunsCronSession(config, agent))
31656
31656
  continue;
31657
31657
  const name = `cron-session: ${agent}`;
31658
- const alivePath = resolve32(agentsDir, agent, "telegram", ".bridge-alive-cron");
31658
+ const alivePath = resolve33(agentsDir, agent, "telegram", ".bridge-alive-cron");
31659
31659
  let mtimeMs;
31660
31660
  try {
31661
31661
  mtimeMs = deps.statMtimeMs(alivePath);
@@ -31704,7 +31704,7 @@ var init_doctor_cron_session = __esm(() => {
31704
31704
  });
31705
31705
 
31706
31706
  // src/cli/doctor-scaffold-wiring.ts
31707
- import { join as join54, resolve as resolve33 } from "node:path";
31707
+ import { join as join55, resolve as resolve34 } from "node:path";
31708
31708
  function readJson2(d, path4) {
31709
31709
  if (!d.existsSync(path4))
31710
31710
  return { kind: "absent" };
@@ -31738,7 +31738,7 @@ function checkIntegrationScaffoldWiring(args) {
31738
31738
  ];
31739
31739
  }
31740
31740
  for (const name of agents) {
31741
- const agentDir = resolve33(agentsDir, name);
31741
+ const agentDir = resolve34(agentsDir, name);
31742
31742
  if (!deps.existsSync(agentDir)) {
31743
31743
  results.push({
31744
31744
  name: `${label}: ${name} scaffold`,
@@ -31747,8 +31747,8 @@ function checkIntegrationScaffoldWiring(args) {
31747
31747
  });
31748
31748
  continue;
31749
31749
  }
31750
- const mcpPath = join54(agentDir, ".mcp.json");
31751
- const claudeJsonPath = join54(agentDir, ".claude", ".claude.json");
31750
+ const mcpPath = join55(agentDir, ".mcp.json");
31751
+ const claudeJsonPath = join55(agentDir, ".claude", ".claude.json");
31752
31752
  const mcpRead = readJson2(deps, mcpPath);
31753
31753
  const trustRead = readJson2(deps, claudeJsonPath);
31754
31754
  if (mcpRead.kind === "unreadable" || trustRead.kind === "unreadable") {
@@ -31778,7 +31778,7 @@ function checkIntegrationScaffoldWiring(args) {
31778
31778
  let trustDetail = "no .claude/.claude.json";
31779
31779
  if (trustRead.kind === "ok") {
31780
31780
  const projects = trustRead.data?.projects ?? {};
31781
- const proj = projects[resolve33(agentDir)];
31781
+ const proj = projects[resolve34(agentDir)];
31782
31782
  const enabled = proj?.enabledMcpjsonServers;
31783
31783
  if (Array.isArray(enabled) && enabled.includes(mcpKey)) {
31784
31784
  trustOk = true;
@@ -31812,14 +31812,14 @@ import {
31812
31812
  existsSync as realExistsSync3,
31813
31813
  readFileSync as realReadFileSync3
31814
31814
  } from "node:fs";
31815
- import { join as join55 } from "node:path";
31815
+ import { join as join56 } from "node:path";
31816
31816
  import { homedir as homedir31 } from "node:os";
31817
31817
  function resolveDeps3(deps) {
31818
31818
  const home2 = deps.homeDir?.() ?? homedir31();
31819
31819
  return {
31820
31820
  existsSync: deps.existsSync ?? realExistsSync3,
31821
31821
  readFileSync: deps.readFileSync ?? realReadFileSync3,
31822
- agentsDir: join55(home2, ".switchroom", "agents"),
31822
+ agentsDir: join56(home2, ".switchroom", "agents"),
31823
31823
  now: deps.now ?? Date.now
31824
31824
  };
31825
31825
  }
@@ -31902,7 +31902,7 @@ function checkOAuthClient2(config, anyAgentEnabled) {
31902
31902
  ];
31903
31903
  }
31904
31904
  function readHeartbeat(d, agentName) {
31905
- const path4 = join55(d.agentsDir, agentName, "m365-launcher.heartbeat.json");
31905
+ const path4 = join56(d.agentsDir, agentName, "m365-launcher.heartbeat.json");
31906
31906
  if (!d.existsSync(path4)) {
31907
31907
  return { error: "heartbeat file missing \u2014 launcher has not yet started" };
31908
31908
  }
@@ -31999,7 +31999,7 @@ import {
31999
31999
  readFileSync as realReadFileSync4,
32000
32000
  statSync as realStatSync2
32001
32001
  } from "node:fs";
32002
- import { join as join56 } from "node:path";
32002
+ import { join as join57 } from "node:path";
32003
32003
  import { homedir as homedir32 } from "node:os";
32004
32004
  function resolveDeps4(deps) {
32005
32005
  const home2 = deps.homeDir?.() ?? homedir32();
@@ -32007,7 +32007,7 @@ function resolveDeps4(deps) {
32007
32007
  existsSync: deps.existsSync ?? realExistsSync4,
32008
32008
  readFileSync: deps.readFileSync ?? realReadFileSync4,
32009
32009
  statSync: deps.statSync ?? realStatSync2,
32010
- agentsDir: join56(home2, ".switchroom", "agents"),
32010
+ agentsDir: join57(home2, ".switchroom", "agents"),
32011
32011
  now: deps.now ?? Date.now,
32012
32012
  vaultAclReader: deps.vaultAclReader ?? (async () => ({ kind: "unreachable", msg: "no default reader wired" }))
32013
32013
  };
@@ -32132,7 +32132,7 @@ function checkLauncherHeartbeat2(notionAgents, d) {
32132
32132
  return [];
32133
32133
  const results = [];
32134
32134
  for (const name of notionAgents) {
32135
- const heartbeatPath = join56(d.agentsDir, name, "notion-launcher.heartbeat.json");
32135
+ const heartbeatPath = join57(d.agentsDir, name, "notion-launcher.heartbeat.json");
32136
32136
  if (!d.existsSync(heartbeatPath)) {
32137
32137
  results.push({
32138
32138
  name: `notion:launcher-heartbeat:${name}`,
@@ -32354,10 +32354,10 @@ import {
32354
32354
  statSync as realStatSync3
32355
32355
  } from "node:fs";
32356
32356
  import { homedir as homedir33 } from "node:os";
32357
- import { join as join57 } from "node:path";
32357
+ import { join as join58 } from "node:path";
32358
32358
  function runCredentialsMigrationChecks(config, deps = {}) {
32359
- const credDir = deps.credentialsDir ?? join57(homedir33(), ".switchroom", "credentials");
32360
- const existsSync56 = deps.existsSync ?? ((p) => realExistsSync5(p));
32359
+ const credDir = deps.credentialsDir ?? join58(homedir33(), ".switchroom", "credentials");
32360
+ const existsSync57 = deps.existsSync ?? ((p) => realExistsSync5(p));
32361
32361
  const readdirSync21 = deps.readdirSync ?? ((p) => realReaddirSync2(p));
32362
32362
  const isDirectory = deps.isDirectory ?? ((p) => {
32363
32363
  try {
@@ -32366,7 +32366,7 @@ function runCredentialsMigrationChecks(config, deps = {}) {
32366
32366
  return false;
32367
32367
  }
32368
32368
  });
32369
- if (!existsSync56(credDir))
32369
+ if (!existsSync57(credDir))
32370
32370
  return [];
32371
32371
  const agentNames = new Set(Object.keys(config.agents ?? {}));
32372
32372
  let entries;
@@ -32384,7 +32384,7 @@ function runCredentialsMigrationChecks(config, deps = {}) {
32384
32384
  const flat = [];
32385
32385
  const perAgentDirs = [];
32386
32386
  for (const e of entries) {
32387
- const full = join57(credDir, e);
32387
+ const full = join58(credDir, e);
32388
32388
  if (isDirectory(full) && agentNames.has(e)) {
32389
32389
  perAgentDirs.push(e);
32390
32390
  } else {
@@ -32508,13 +32508,13 @@ var init_doctor_inlined_secrets = __esm(() => {
32508
32508
  // src/cli/doctor-audit-integrity.ts
32509
32509
  import { readFileSync as fsReadFileSync2 } from "node:fs";
32510
32510
  import { homedir as homedir34 } from "node:os";
32511
- import { join as join58 } from "node:path";
32511
+ import { join as join59 } from "node:path";
32512
32512
  function rootWrittenLogs(home2) {
32513
32513
  return [
32514
- { label: "vault-broker", path: join58(home2, ".switchroom", "vault-audit.log") },
32514
+ { label: "vault-broker", path: join59(home2, ".switchroom", "vault-audit.log") },
32515
32515
  {
32516
32516
  label: "hostd",
32517
- path: join58(home2, ".switchroom", "host-control-audit.log")
32517
+ path: join59(home2, ".switchroom", "host-control-audit.log")
32518
32518
  }
32519
32519
  ];
32520
32520
  }
@@ -32576,16 +32576,16 @@ var init_doctor_audit_integrity = __esm(() => {
32576
32576
  });
32577
32577
 
32578
32578
  // src/cli/doctor-agent-smoke.ts
32579
- import { existsSync as existsSync56 } from "node:fs";
32579
+ import { existsSync as existsSync57 } from "node:fs";
32580
32580
  import { homedir as homedir35 } from "node:os";
32581
- import { join as join59 } from "node:path";
32581
+ import { join as join60 } from "node:path";
32582
32582
  import { randomUUID as randomUUID5 } from "node:crypto";
32583
32583
  async function runAgentSmokeChecks(config, deps = {}) {
32584
32584
  if (deps.fast)
32585
32585
  return [];
32586
32586
  const home2 = deps.homeDir ?? homedir35();
32587
- const sock = deps.operatorSockPath ?? join59(home2, ".switchroom", "hostd", "operator", "sock");
32588
- if (!deps.hostdRequestImpl && !existsSync56(sock)) {
32587
+ const sock = deps.operatorSockPath ?? join60(home2, ".switchroom", "hostd", "operator", "sock");
32588
+ if (!deps.hostdRequestImpl && !existsSync57(sock)) {
32589
32589
  return [
32590
32590
  {
32591
32591
  name: "agent liveness",
@@ -32663,9 +32663,9 @@ var init_doctor_agent_smoke = __esm(() => {
32663
32663
 
32664
32664
  // src/cli/doctor-vault-broker-durability.ts
32665
32665
  import { execFileSync as execFileSync18 } from "node:child_process";
32666
- import { existsSync as existsSync57, statSync as statSync24 } from "node:fs";
32666
+ import { existsSync as existsSync58, statSync as statSync24 } from "node:fs";
32667
32667
  import { homedir as homedir36 } from "node:os";
32668
- import { join as join60 } from "node:path";
32668
+ import { join as join61 } from "node:path";
32669
32669
  function probeBindMountInode(hostPath, brokerContainerPath, opts) {
32670
32670
  const statHost = opts?.statHost ?? defaultStatHost;
32671
32671
  const statBroker = opts?.statBroker ?? defaultStatBroker;
@@ -32687,7 +32687,7 @@ function probeBindMountInode(hostPath, brokerContainerPath, opts) {
32687
32687
  };
32688
32688
  }
32689
32689
  function defaultStatHost(p) {
32690
- if (!existsSync57(p))
32690
+ if (!existsSync58(p))
32691
32691
  return null;
32692
32692
  try {
32693
32693
  const s = statSync24(p, { bigint: true });
@@ -32814,16 +32814,16 @@ function runVaultBrokerDurabilityChecks(_config, opts) {
32814
32814
  probeBrokerUnlocked(opts?.statusProbe),
32815
32815
  probeAutoUnlockBlob(home2),
32816
32816
  probeMachineIdMount(),
32817
- formatBindMountResult("vault-broker: vault.enc bind mount", join60(home2, ".switchroom", "vault", "vault.enc"), "/state/vault/vault.enc", probe2(join60(home2, ".switchroom", "vault", "vault.enc"), "/state/vault/vault.enc")),
32818
- formatBindMountResult("vault-broker: vault-grants.db bind mount (#1737)", join60(home2, ".switchroom", "vault-grants.db"), "/root/.switchroom/vault-grants.db", probe2(join60(home2, ".switchroom", "vault-grants.db"), "/root/.switchroom/vault-grants.db")),
32819
- formatBindMountResult("vault-broker: vault-audit.log bind mount (#1025)", join60(home2, ".switchroom", "vault-audit.log"), "/root/.switchroom/vault-audit.log", probe2(join60(home2, ".switchroom", "vault-audit.log"), "/root/.switchroom/vault-audit.log")),
32817
+ formatBindMountResult("vault-broker: vault.enc bind mount", join61(home2, ".switchroom", "vault", "vault.enc"), "/state/vault/vault.enc", probe2(join61(home2, ".switchroom", "vault", "vault.enc"), "/state/vault/vault.enc")),
32818
+ formatBindMountResult("vault-broker: vault-grants.db bind mount (#1737)", join61(home2, ".switchroom", "vault-grants.db"), "/root/.switchroom/vault-grants.db", probe2(join61(home2, ".switchroom", "vault-grants.db"), "/root/.switchroom/vault-grants.db")),
32819
+ formatBindMountResult("vault-broker: vault-audit.log bind mount (#1025)", join61(home2, ".switchroom", "vault-audit.log"), "/root/.switchroom/vault-audit.log", probe2(join61(home2, ".switchroom", "vault-audit.log"), "/root/.switchroom/vault-audit.log")),
32820
32820
  probeKernelDbDurability(home2, {
32821
32821
  statBroker: opts?.kernelStatBroker
32822
32822
  })
32823
32823
  ];
32824
32824
  }
32825
32825
  function probeKernelDbDurability(home2, opts) {
32826
- const hostDir = join60(home2, ".switchroom", "approvals");
32826
+ const hostDir = join61(home2, ".switchroom", "approvals");
32827
32827
  const containerDir = "/state/approvals";
32828
32828
  const name = "approval-kernel: approvals bind mount (allow_always durability)";
32829
32829
  const kernelStat = opts?.statBroker ?? defaultKernelStatBroker;
@@ -32891,8 +32891,8 @@ function defaultKernelStatBroker(p) {
32891
32891
  return { kind: "ok-with-stat", ino: inoStr, size };
32892
32892
  }
32893
32893
  function probeAutoUnlockBlob(home2) {
32894
- const blobPath = join60(home2, ".switchroom", "vault-auto-unlock");
32895
- if (!existsSync57(blobPath)) {
32894
+ const blobPath = join61(home2, ".switchroom", "vault-auto-unlock");
32895
+ if (!existsSync58(blobPath)) {
32896
32896
  return {
32897
32897
  name: "vault-broker: auto-unlock blob",
32898
32898
  status: "warn",
@@ -32916,7 +32916,7 @@ function probeAutoUnlockBlob(home2) {
32916
32916
  };
32917
32917
  }
32918
32918
  function probeMachineIdMount() {
32919
- const hostExists = existsSync57("/etc/machine-id");
32919
+ const hostExists = existsSync58("/etc/machine-id");
32920
32920
  if (!hostExists) {
32921
32921
  return {
32922
32922
  name: "vault-broker: machine-id passthrough",
@@ -33064,23 +33064,23 @@ import { execSync as execSync3, spawnSync as spawnSync10 } from "node:child_proc
33064
33064
  import {
33065
33065
  accessSync as accessSync2,
33066
33066
  constants as fsConstants5,
33067
- existsSync as existsSync58,
33067
+ existsSync as existsSync59,
33068
33068
  lstatSync as lstatSync7,
33069
33069
  mkdirSync as mkdirSync31,
33070
- readFileSync as readFileSync52,
33070
+ readFileSync as readFileSync53,
33071
33071
  readdirSync as readdirSync21,
33072
33072
  statSync as statSync25
33073
33073
  } from "node:fs";
33074
- import { dirname as dirname15, join as join61, resolve as resolve34 } from "node:path";
33074
+ import { dirname as dirname15, join as join62, resolve as resolve35 } from "node:path";
33075
33075
  import { createPublicKey, createPrivateKey } from "node:crypto";
33076
33076
  function findInNvm(bin) {
33077
- const nvmRoot = join61(process.env.HOME ?? "", ".nvm", "versions", "node");
33078
- if (!existsSync58(nvmRoot))
33077
+ const nvmRoot = join62(process.env.HOME ?? "", ".nvm", "versions", "node");
33078
+ if (!existsSync59(nvmRoot))
33079
33079
  return null;
33080
33080
  try {
33081
33081
  const versions = readdirSync21(nvmRoot).sort().reverse();
33082
33082
  for (const v of versions) {
33083
- const candidate = join61(nvmRoot, v, "bin", bin);
33083
+ const candidate = join62(nvmRoot, v, "bin", bin);
33084
33084
  try {
33085
33085
  const s = statSync25(candidate);
33086
33086
  if (s.isFile() || s.isSymbolicLink()) {
@@ -33245,21 +33245,21 @@ function findChromium(homeDir = process.env.HOME ?? "", envBrowsersPath = proces
33245
33245
  if (envBrowsersPath && envBrowsersPath.length > 0) {
33246
33246
  cacheLocations.push(envBrowsersPath);
33247
33247
  }
33248
- cacheLocations.push(join61(homeDir, ".cache", "ms-playwright"));
33248
+ cacheLocations.push(join62(homeDir, ".cache", "ms-playwright"));
33249
33249
  for (const cacheDir of cacheLocations) {
33250
- if (!existsSync58(cacheDir))
33250
+ if (!existsSync59(cacheDir))
33251
33251
  continue;
33252
33252
  try {
33253
33253
  const entries = readdirSync21(cacheDir).filter((e) => e.startsWith("chromium"));
33254
33254
  for (const entry of entries) {
33255
33255
  const candidates2 = [
33256
- join61(cacheDir, entry, "chrome-linux64", "chrome"),
33257
- join61(cacheDir, entry, "chrome-linux", "chrome"),
33258
- join61(cacheDir, entry, "chrome-linux64", "headless_shell"),
33259
- join61(cacheDir, entry, "chrome-linux", "headless_shell")
33256
+ join62(cacheDir, entry, "chrome-linux64", "chrome"),
33257
+ join62(cacheDir, entry, "chrome-linux", "chrome"),
33258
+ join62(cacheDir, entry, "chrome-linux64", "headless_shell"),
33259
+ join62(cacheDir, entry, "chrome-linux", "headless_shell")
33260
33260
  ];
33261
33261
  for (const path4 of candidates2) {
33262
- if (existsSync58(path4))
33262
+ if (existsSync59(path4))
33263
33263
  return path4;
33264
33264
  }
33265
33265
  }
@@ -33388,7 +33388,7 @@ function checkDeployMounts(opts) {
33388
33388
  const home2 = opts?.home ?? process.env.HOME ?? "/root";
33389
33389
  const { pathKind } = opts?.deps ?? DEFAULT_DEPLOY_MOUNTS_DEPS;
33390
33390
  const results = [];
33391
- const dockerComposePlugin = join61(home2, ".docker", "cli-plugins", "docker-compose");
33391
+ const dockerComposePlugin = join62(home2, ".docker", "cli-plugins", "docker-compose");
33392
33392
  const pluginKind = pathKind(dockerComposePlugin);
33393
33393
  if (pluginKind === "dir") {
33394
33394
  results.push({
@@ -33426,8 +33426,8 @@ function checkDeployMounts(opts) {
33426
33426
  function checkLegacyState() {
33427
33427
  const results = [];
33428
33428
  const h = process.env.HOME ?? "/root";
33429
- const clerkDir = join61(h, LEGACY_STATE_DIR);
33430
- const clerkPresent = existsSync58(clerkDir);
33429
+ const clerkDir = join62(h, LEGACY_STATE_DIR);
33430
+ const clerkPresent = existsSync59(clerkDir);
33431
33431
  results.push({
33432
33432
  name: "legacy ~/.clerk state",
33433
33433
  status: clerkPresent ? "warn" : "ok",
@@ -33436,7 +33436,7 @@ function checkLegacyState() {
33436
33436
  fix: "Legacy state detected. Run `mv ~/.clerk ~/.switchroom` and rename " + "any top-level `clerk:` key in switchroom.yaml to `switchroom:`. " + "This back-compat shim is REMOVED in v0.13.0 \u2014 no automatic " + "migration exists."
33437
33437
  } : {}
33438
33438
  });
33439
- const legacySock = join61(h, ".switchroom", "vault-broker.sock");
33439
+ const legacySock = join62(h, ".switchroom", "vault-broker.sock");
33440
33440
  let sockStat = null;
33441
33441
  try {
33442
33442
  sockStat = lstatSync7(legacySock);
@@ -33557,7 +33557,7 @@ function checkVault(config) {
33557
33557
  detail: "Approval auth: passphrase (two-factor)"
33558
33558
  };
33559
33559
  const pairsResult = checkVaultBrokerSocketPairs(config);
33560
- if (!existsSync58(vaultPath)) {
33560
+ if (!existsSync59(vaultPath)) {
33561
33561
  return [
33562
33562
  postureResult,
33563
33563
  {
@@ -33819,8 +33819,8 @@ async function checkHindsight(config) {
33819
33819
  }
33820
33820
  function checkPendingRetainsQueue(dir) {
33821
33821
  const home2 = process.env.HOME ?? "";
33822
- const pendingDir = dir ?? process.env.HINDSIGHT_PENDING_DIR ?? join61(home2, ".hindsight", "pending-retains");
33823
- if (!existsSync58(pendingDir)) {
33822
+ const pendingDir = dir ?? process.env.HINDSIGHT_PENDING_DIR ?? join62(home2, ".hindsight", "pending-retains");
33823
+ if (!existsSync59(pendingDir)) {
33824
33824
  return {
33825
33825
  name: "pending-retains queue",
33826
33826
  status: "ok",
@@ -33879,7 +33879,7 @@ function classifyReadError(err) {
33879
33879
  }
33880
33880
  function tryReadHostFile(path4) {
33881
33881
  try {
33882
- return { kind: "ok", content: readFileSync52(path4, "utf-8") };
33882
+ return { kind: "ok", content: readFileSync53(path4, "utf-8") };
33883
33883
  } catch (err) {
33884
33884
  const kind = classifyReadError(err);
33885
33885
  const error = err?.message ?? String(err);
@@ -33891,11 +33891,11 @@ function tryReadHostFile(path4) {
33891
33891
  }
33892
33892
  }
33893
33893
  function parseEnvFile(path4) {
33894
- if (!existsSync58(path4))
33894
+ if (!existsSync59(path4))
33895
33895
  return {};
33896
33896
  let content;
33897
33897
  try {
33898
- content = readFileSync52(path4, "utf-8");
33898
+ content = readFileSync53(path4, "utf-8");
33899
33899
  } catch {
33900
33900
  return {};
33901
33901
  }
@@ -33950,7 +33950,7 @@ async function checkTelegram(config) {
33950
33950
  const plugin = agentConfig.channels?.telegram?.plugin ?? "switchroom";
33951
33951
  if (plugin !== "switchroom")
33952
33952
  continue;
33953
- const envPath = join61(agentsDir, name, "telegram", ".env");
33953
+ const envPath = join62(agentsDir, name, "telegram", ".env");
33954
33954
  const read = tryReadHostFile(envPath);
33955
33955
  if (read.kind === "eacces") {
33956
33956
  results.push({
@@ -34002,7 +34002,7 @@ async function checkTelegram(config) {
34002
34002
  }
34003
34003
  function checkStartShStale(agentName, startShPath) {
34004
34004
  const label = `${agentName}: start.sh scheduler block`;
34005
- if (!existsSync58(startShPath)) {
34005
+ if (!existsSync59(startShPath)) {
34006
34006
  return {
34007
34007
  name: label,
34008
34008
  status: "warn",
@@ -34012,7 +34012,7 @@ function checkStartShStale(agentName, startShPath) {
34012
34012
  }
34013
34013
  let content;
34014
34014
  try {
34015
- content = readFileSync52(startShPath, "utf-8");
34015
+ content = readFileSync53(startShPath, "utf-8");
34016
34016
  } catch (err) {
34017
34017
  return {
34018
34018
  name: label,
@@ -34033,7 +34033,7 @@ function checkStartShStale(agentName, startShPath) {
34033
34033
  }
34034
34034
  function checkLeakedHomeSwitchroom(agentName, agentDir) {
34035
34035
  const label = `${agentName}: $HOME/.switchroom symlink (#910)`;
34036
- const path4 = join61(agentDir, "home", ".switchroom");
34036
+ const path4 = join62(agentDir, "home", ".switchroom");
34037
34037
  let stats;
34038
34038
  try {
34039
34039
  stats = lstatSync7(path4);
@@ -34070,8 +34070,8 @@ function checkLeakedHomeSwitchroom(agentName, agentDir) {
34070
34070
  }
34071
34071
  function checkRepoHygiene(repoRoot) {
34072
34072
  const results = [];
34073
- const exportDir = join61(repoRoot, "clerk-export");
34074
- if (existsSync58(exportDir)) {
34073
+ const exportDir = join62(repoRoot, "clerk-export");
34074
+ if (existsSync59(exportDir)) {
34075
34075
  results.push({
34076
34076
  name: "repo hygiene: clerk-export/ on disk (#1072)",
34077
34077
  status: "warn",
@@ -34079,8 +34079,8 @@ function checkRepoHygiene(repoRoot) {
34079
34079
  fix: `Run scripts/migrate-clerk-export-to-vault.sh to move the bundle ` + `into the vault, then delete the on-disk copy.`
34080
34080
  });
34081
34081
  }
34082
- const knownTarball = join61(repoRoot, "clerk-export-with-secrets.tar.gz");
34083
- if (existsSync58(knownTarball)) {
34082
+ const knownTarball = join62(repoRoot, "clerk-export-with-secrets.tar.gz");
34083
+ if (existsSync59(knownTarball)) {
34084
34084
  results.push({
34085
34085
  name: "repo hygiene: clerk-export-with-secrets.tar.gz on disk (#1072)",
34086
34086
  status: "warn",
@@ -34097,7 +34097,7 @@ function checkRepoHygiene(repoRoot) {
34097
34097
  results.push({
34098
34098
  name: `repo hygiene: ${name} on disk (#1072)`,
34099
34099
  status: "warn",
34100
- detail: `${join61(repoRoot, name)} matches the *-with-secrets*.tar.gz ` + `pattern. Likely contains real credentials.`,
34100
+ detail: `${join62(repoRoot, name)} matches the *-with-secrets*.tar.gz ` + `pattern. Likely contains real credentials.`,
34101
34101
  fix: `Inspect, migrate any secrets into the vault, then delete the ` + `archive.`
34102
34102
  });
34103
34103
  }
@@ -34120,12 +34120,12 @@ function checkRepoHygiene(repoRoot) {
34120
34120
  }
34121
34121
  function isSwitchroomCheckout(dir) {
34122
34122
  try {
34123
- if (!existsSync58(join61(dir, ".git")))
34123
+ if (!existsSync59(join62(dir, ".git")))
34124
34124
  return false;
34125
- const pkgPath = join61(dir, "package.json");
34126
- if (!existsSync58(pkgPath))
34125
+ const pkgPath = join62(dir, "package.json");
34126
+ if (!existsSync59(pkgPath))
34127
34127
  return false;
34128
- const pkg = JSON.parse(readFileSync52(pkgPath, "utf-8"));
34128
+ const pkg = JSON.parse(readFileSync53(pkgPath, "utf-8"));
34129
34129
  return pkg.name === "switchroom";
34130
34130
  } catch {
34131
34131
  return false;
@@ -34137,8 +34137,8 @@ function checkAgents(config, configPath) {
34137
34137
  const statuses = getAllAgentStatuses(config);
34138
34138
  const authStatuses = getAllAuthStatuses(config);
34139
34139
  for (const [name, agentConfig] of Object.entries(config.agents)) {
34140
- const agentDir = resolve34(agentsDir, name);
34141
- if (!existsSync58(agentDir)) {
34140
+ const agentDir = resolve35(agentsDir, name);
34141
+ if (!existsSync59(agentDir)) {
34142
34142
  results.push({
34143
34143
  name: `${name}: scaffold`,
34144
34144
  status: "fail",
@@ -34159,7 +34159,7 @@ function checkAgents(config, configPath) {
34159
34159
  fix: `Rotate the bot token (e.g. via \`switchroom vault\`), then run ` + `\`switchroom agent unquarantine ${name}\` and \`switchroom agent restart ${name}\``
34160
34160
  });
34161
34161
  }
34162
- results.push(checkStartShStale(name, join61(agentDir, "start.sh")));
34162
+ results.push(checkStartShStale(name, join62(agentDir, "start.sh")));
34163
34163
  results.push(checkLeakedHomeSwitchroom(name, agentDir));
34164
34164
  const status = statuses[name];
34165
34165
  const active = status?.active ?? "unknown";
@@ -34236,8 +34236,8 @@ function checkAgents(config, configPath) {
34236
34236
  }
34237
34237
  }
34238
34238
  if (agentConfig.channels?.telegram?.plugin === "switchroom") {
34239
- const mcpJsonPath = join61(agentDir, ".mcp.json");
34240
- if (!existsSync58(mcpJsonPath)) {
34239
+ const mcpJsonPath = join62(agentDir, ".mcp.json");
34240
+ if (!existsSync59(mcpJsonPath)) {
34241
34241
  results.push({
34242
34242
  name: `${name}: .mcp.json`,
34243
34243
  status: "fail",
@@ -34246,7 +34246,7 @@ function checkAgents(config, configPath) {
34246
34246
  });
34247
34247
  } else {
34248
34248
  try {
34249
- const mcp = JSON.parse(readFileSync52(mcpJsonPath, "utf-8"));
34249
+ const mcp = JSON.parse(readFileSync53(mcpJsonPath, "utf-8"));
34250
34250
  const hasSwitchroomTelegram = !!mcp.mcpServers?.["switchroom-telegram"];
34251
34251
  const memoryEnabled = isHindsightEnabled(config);
34252
34252
  const hasHindsight = !!mcp.mcpServers?.hindsight;
@@ -34320,10 +34320,10 @@ function mffAgentName(config) {
34320
34320
  function mffEnvPath(config) {
34321
34321
  const home2 = process.env.HOME ?? "/root";
34322
34322
  const agent = mffAgentName(config);
34323
- return agent ? resolve34(home2, ".switchroom/credentials", agent, "my-family-finance/.env") : resolve34(home2, ".switchroom/credentials/my-family-finance/.env");
34323
+ return agent ? resolve35(home2, ".switchroom/credentials", agent, "my-family-finance/.env") : resolve35(home2, ".switchroom/credentials/my-family-finance/.env");
34324
34324
  }
34325
34325
  function mffEnvState(envPath) {
34326
- if (!existsSync58(envPath))
34326
+ if (!existsSync59(envPath))
34327
34327
  return "absent";
34328
34328
  try {
34329
34329
  accessSync2(envPath, fsConstants5.R_OK);
@@ -34341,7 +34341,7 @@ function checkMffVaultKeyPresent(passphrase, vaultPath) {
34341
34341
  fix: "Export SWITCHROOM_VAULT_PASSPHRASE to enable MFF vault probes"
34342
34342
  };
34343
34343
  }
34344
- if (!existsSync58(vaultPath)) {
34344
+ if (!existsSync59(vaultPath)) {
34345
34345
  return {
34346
34346
  name: "mff: vault key present",
34347
34347
  status: "fail",
@@ -34394,7 +34394,7 @@ function deriveEd25519PublicKeyBytes(keyMaterial) {
34394
34394
  }
34395
34395
  }
34396
34396
  function checkMffVaultKeyFormat(passphrase, vaultPath) {
34397
- if (!passphrase || !existsSync58(vaultPath)) {
34397
+ if (!passphrase || !existsSync59(vaultPath)) {
34398
34398
  return {
34399
34399
  name: "mff: vault key format",
34400
34400
  status: "warn",
@@ -34538,8 +34538,8 @@ async function checkMffAuthFlow(envPath = mffEnvPath(), timeoutMs = 8000) {
34538
34538
  };
34539
34539
  }
34540
34540
  const credDir = dirname15(envPath);
34541
- const authScript = join61(credDir, "claude-auth.py");
34542
- if (!existsSync58(authScript)) {
34541
+ const authScript = join62(credDir, "claude-auth.py");
34542
+ if (!existsSync59(authScript)) {
34543
34543
  return {
34544
34544
  name: "mff: auth flow",
34545
34545
  status: "warn",
@@ -34736,16 +34736,16 @@ async function checkManifestDrift(probers) {
34736
34736
  return results;
34737
34737
  }
34738
34738
  function runDockerSection(config) {
34739
- const composePath = resolve34(process.env.HOME ?? "", ".switchroom", "compose", "docker-compose.yml");
34739
+ const composePath = resolve35(process.env.HOME ?? "", ".switchroom", "compose", "docker-compose.yml");
34740
34740
  const active = isDockerMode({ composePath });
34741
34741
  let composeYaml;
34742
34742
  let dockerfileAgent;
34743
34743
  try {
34744
- composeYaml = readFileSync52(composePath, "utf8");
34744
+ composeYaml = readFileSync53(composePath, "utf8");
34745
34745
  } catch {}
34746
- const dockerfilePath = resolve34(process.env.HOME ?? "", ".switchroom", "docker", "Dockerfile.agent");
34746
+ const dockerfilePath = resolve35(process.env.HOME ?? "", ".switchroom", "docker", "Dockerfile.agent");
34747
34747
  try {
34748
- dockerfileAgent = readFileSync52(dockerfilePath, "utf8");
34748
+ dockerfileAgent = readFileSync53(dockerfilePath, "utf8");
34749
34749
  } catch {}
34750
34750
  return runDockerChecks({
34751
34751
  config,
@@ -43244,7 +43244,7 @@ class Protocol {
43244
43244
  return;
43245
43245
  }
43246
43246
  const pollInterval = task2.pollInterval ?? this._options?.defaultTaskPollInterval ?? 1000;
43247
- await new Promise((resolve52) => setTimeout(resolve52, pollInterval));
43247
+ await new Promise((resolve53) => setTimeout(resolve53, pollInterval));
43248
43248
  options?.signal?.throwIfAborted();
43249
43249
  }
43250
43250
  } catch (error2) {
@@ -43256,7 +43256,7 @@ class Protocol {
43256
43256
  }
43257
43257
  request(request, resultSchema, options) {
43258
43258
  const { relatedRequestId, resumptionToken, onresumptiontoken, task, relatedTask } = options ?? {};
43259
- return new Promise((resolve52, reject) => {
43259
+ return new Promise((resolve53, reject) => {
43260
43260
  const earlyReject = (error2) => {
43261
43261
  reject(error2);
43262
43262
  };
@@ -43334,7 +43334,7 @@ class Protocol {
43334
43334
  if (!parseResult.success) {
43335
43335
  reject(parseResult.error);
43336
43336
  } else {
43337
- resolve52(parseResult.data);
43337
+ resolve53(parseResult.data);
43338
43338
  }
43339
43339
  } catch (error2) {
43340
43340
  reject(error2);
@@ -43525,12 +43525,12 @@ class Protocol {
43525
43525
  interval = task.pollInterval;
43526
43526
  }
43527
43527
  } catch {}
43528
- return new Promise((resolve52, reject) => {
43528
+ return new Promise((resolve53, reject) => {
43529
43529
  if (signal.aborted) {
43530
43530
  reject(new McpError(ErrorCode2.InvalidRequest, "Request cancelled"));
43531
43531
  return;
43532
43532
  }
43533
- const timeoutId = setTimeout(resolve52, interval);
43533
+ const timeoutId = setTimeout(resolve53, interval);
43534
43534
  signal.addEventListener("abort", () => {
43535
43535
  clearTimeout(timeoutId);
43536
43536
  reject(new McpError(ErrorCode2.InvalidRequest, "Request cancelled"));
@@ -46515,7 +46515,7 @@ var require_compile = __commonJS((exports2) => {
46515
46515
  const schOrFunc = root.refs[ref];
46516
46516
  if (schOrFunc)
46517
46517
  return schOrFunc;
46518
- let _sch = resolve52.call(this, root, ref);
46518
+ let _sch = resolve53.call(this, root, ref);
46519
46519
  if (_sch === undefined) {
46520
46520
  const schema = (_a = root.localRefs) === null || _a === undefined ? undefined : _a[ref];
46521
46521
  const { schemaId } = this.opts;
@@ -46542,7 +46542,7 @@ var require_compile = __commonJS((exports2) => {
46542
46542
  function sameSchemaEnv(s1, s2) {
46543
46543
  return s1.schema === s2.schema && s1.root === s2.root && s1.baseId === s2.baseId;
46544
46544
  }
46545
- function resolve52(root, ref) {
46545
+ function resolve53(root, ref) {
46546
46546
  let sch;
46547
46547
  while (typeof (sch = this.refs[ref]) == "string")
46548
46548
  ref = sch;
@@ -47072,7 +47072,7 @@ var require_fast_uri = __commonJS((exports2, module) => {
47072
47072
  }
47073
47073
  return uri;
47074
47074
  }
47075
- function resolve52(baseURI, relativeURI, options) {
47075
+ function resolve53(baseURI, relativeURI, options) {
47076
47076
  const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
47077
47077
  const resolved = resolveComponent(parse6(baseURI, schemelessOptions), parse6(relativeURI, schemelessOptions), schemelessOptions, true);
47078
47078
  schemelessOptions.skipEscape = true;
@@ -47300,7 +47300,7 @@ var require_fast_uri = __commonJS((exports2, module) => {
47300
47300
  var fastUri = {
47301
47301
  SCHEMES,
47302
47302
  normalize,
47303
- resolve: resolve52,
47303
+ resolve: resolve53,
47304
47304
  resolveComponent,
47305
47305
  equal,
47306
47306
  serialize,
@@ -50683,12 +50683,12 @@ class StdioServerTransport {
50683
50683
  this.onclose?.();
50684
50684
  }
50685
50685
  send(message) {
50686
- return new Promise((resolve52) => {
50686
+ return new Promise((resolve53) => {
50687
50687
  const json = serializeMessage(message);
50688
50688
  if (this._stdout.write(json)) {
50689
- resolve52();
50689
+ resolve53();
50690
50690
  } else {
50691
- this._stdout.once("drain", resolve52);
50691
+ this._stdout.once("drain", resolve53);
50692
50692
  }
50693
50693
  });
50694
50694
  }
@@ -51200,7 +51200,7 @@ __export(exports_server2, {
51200
51200
  TOOLS: () => TOOLS2
51201
51201
  });
51202
51202
  import { randomBytes as randomBytes15 } from "node:crypto";
51203
- import { existsSync as existsSync85, readFileSync as readFileSync73 } from "node:fs";
51203
+ import { existsSync as existsSync86, readFileSync as readFileSync74 } from "node:fs";
51204
51204
  function selfSocketPath() {
51205
51205
  return `/run/switchroom/hostd/${SELF_AGENT}/sock`;
51206
51206
  }
@@ -51218,7 +51218,7 @@ async function dispatchTool2(name, args) {
51218
51218
  return errorText2("hostd MCP: SWITCHROOM_AGENT_NAME env var is not set \u2014 cannot " + "determine which per-agent socket to talk to.");
51219
51219
  }
51220
51220
  const sockPath = selfSocketPath();
51221
- if (!existsSync85(sockPath)) {
51221
+ if (!existsSync86(sockPath)) {
51222
51222
  return errorText2(`hostd MCP: socket not bound at ${sockPath}. The host-control ` + `daemon is either not installed (run \`switchroom hostd install\`) ` + `or this agent isn't admin-flagged in switchroom.yaml. RFC C ` + `bind-mounts the per-agent socket only when host_control.enabled ` + `is true AND the agent has admin: true.`);
51223
51223
  }
51224
51224
  let req;
@@ -51393,18 +51393,18 @@ function resolveAuditLogPath() {
51393
51393
  if (process.env.HOSTD_AUDIT_LOG_PATH)
51394
51394
  return process.env.HOSTD_AUDIT_LOG_PATH;
51395
51395
  const bindMounted = "/host-home/.switchroom/host-control-audit.log";
51396
- if (existsSync85(bindMounted))
51396
+ if (existsSync86(bindMounted))
51397
51397
  return bindMounted;
51398
51398
  return defaultAuditLogPath2();
51399
51399
  }
51400
51400
  function getLastUpdateApplyStatus() {
51401
51401
  const path8 = resolveAuditLogPath();
51402
- if (!existsSync85(path8)) {
51402
+ if (!existsSync86(path8)) {
51403
51403
  return errorText2(`get_status: audit log not found at ${path8}. No update_apply has run yet?`);
51404
51404
  }
51405
51405
  let raw;
51406
51406
  try {
51407
- raw = readFileSync73(path8, "utf-8");
51407
+ raw = readFileSync74(path8, "utf-8");
51408
51408
  } catch (err2) {
51409
51409
  return errorText2(`get_status: failed to read audit log at ${path8}: ${err2.message}`);
51410
51410
  }
@@ -51674,8 +51674,8 @@ import { existsSync, readFileSync } from "node:fs";
51674
51674
  import { dirname, join } from "node:path";
51675
51675
 
51676
51676
  // src/build-info.ts
51677
- var VERSION = "0.16.6";
51678
- var COMMIT_SHA = "925f5798";
51677
+ var VERSION = "0.16.8";
51678
+ var COMMIT_SHA = "c2668516";
51679
51679
 
51680
51680
  // src/cli/resolve-version.ts
51681
51681
  function readPackageVersion() {
@@ -70449,8 +70449,8 @@ init_merge();
70449
70449
  init_loader();
70450
70450
  init_client();
70451
70451
  import {
70452
- readFileSync as readFileSync47,
70453
- existsSync as existsSync51,
70452
+ readFileSync as readFileSync48,
70453
+ existsSync as existsSync52,
70454
70454
  realpathSync as realpathSync4,
70455
70455
  mkdirSync as mkdirSync29,
70456
70456
  openSync as openSync10,
@@ -70458,7 +70458,7 @@ import {
70458
70458
  writeSync as writeSync6,
70459
70459
  constants as fsConstants3
70460
70460
  } from "node:fs";
70461
- import { resolve as resolve29, extname, join as join48, relative, dirname as dirname12 } from "node:path";
70461
+ import { resolve as resolve30, extname, join as join49, relative, dirname as dirname12 } from "node:path";
70462
70462
  import { homedir as homedir26 } from "node:os";
70463
70463
  import { timingSafeEqual as timingSafeEqual3, randomBytes as randomBytes11 } from "node:crypto";
70464
70464
 
@@ -77286,6 +77286,388 @@ async function handleWebhookIngest(args, deps = {}) {
77286
77286
  return jsonReply(202, { ok: true, recorded: true, ts: now });
77287
77287
  }
77288
77288
 
77289
+ // src/web/hermes-adapter.ts
77290
+ init_loader();
77291
+ import { createConnection as createConnection3 } from "node:net";
77292
+ import { createHash as createHash10 } from "node:crypto";
77293
+ import { join as join48, resolve as resolve29 } from "node:path";
77294
+ import { existsSync as existsSync51, readFileSync as readFileSync47 } from "node:fs";
77295
+
77296
+ // src/agent-scheduler/channel-target.ts
77297
+ init_merge();
77298
+ function resolveChannelTarget(config, agentName) {
77299
+ const agent = config.agents?.[agentName];
77300
+ const tgChannel = agent ? resolveAgentConfig(config.defaults, config.profiles, agent).channels?.telegram : undefined;
77301
+ const supergroupChatId = tgChannel?.chat_id;
77302
+ const supergroupDefaultTopic = tgChannel?.default_topic_id;
77303
+ if (typeof supergroupChatId === "string" && supergroupChatId.length > 0) {
77304
+ return {
77305
+ chatId: supergroupChatId,
77306
+ ...typeof supergroupDefaultTopic === "number" ? { threadId: supergroupDefaultTopic } : {},
77307
+ routerConfig: {
77308
+ ...typeof supergroupDefaultTopic === "number" ? { default_topic_id: supergroupDefaultTopic } : {},
77309
+ ...tgChannel?.topic_aliases ? { topic_aliases: tgChannel.topic_aliases } : {}
77310
+ }
77311
+ };
77312
+ }
77313
+ const forumChatId = config.telegram?.forum_chat_id;
77314
+ if (typeof forumChatId !== "string" || forumChatId.length === 0)
77315
+ return null;
77316
+ const threadId = agent?.topic_id;
77317
+ return {
77318
+ chatId: forumChatId,
77319
+ ...typeof threadId === "number" ? { threadId } : {}
77320
+ };
77321
+ }
77322
+
77323
+ // src/web/hermes-adapter.ts
77324
+ function rpcOk(id, result) {
77325
+ return { jsonrpc: "2.0", id, result };
77326
+ }
77327
+ function rpcErr(id, code, message, data) {
77328
+ return { jsonrpc: "2.0", id, error: { code, message, ...data !== undefined ? { data } : {} } };
77329
+ }
77330
+ function hermesEvent(type, sessionId, payload) {
77331
+ return { jsonrpc: "2.0", method: "event", params: { type, session_id: sessionId, payload } };
77332
+ }
77333
+ function agentLiveness(config, agentName) {
77334
+ const agentsDir = resolveAgentsDir(config);
77335
+ if (agentBridgeAlive(agentsDir, agentName))
77336
+ return "active";
77337
+ const alive = join48(agentsDir, agentName, "telegram", ".bridge-alive");
77338
+ if (existsSync51(alive))
77339
+ return "idle";
77340
+ return "offline";
77341
+ }
77342
+ function toHermesSession(agent, liveness) {
77343
+ return {
77344
+ id: agent.name,
77345
+ name: agent.name,
77346
+ status: liveness,
77347
+ model: "claude",
77348
+ created_at: null,
77349
+ updated_at: null,
77350
+ quota: agent.primaryAccount ? { used_pct: null, slot: agent.primaryAccount } : null
77351
+ };
77352
+ }
77353
+ function resolveAgentChat(config, agentName, agentsDir) {
77354
+ const channel = resolveChannelTarget(config, agentName);
77355
+ if (channel)
77356
+ return { chatId: channel.chatId, threadId: channel.threadId };
77357
+ const accessPath = resolve29(agentsDir, agentName, "telegram", "access.json");
77358
+ if (!existsSync51(accessPath))
77359
+ return null;
77360
+ try {
77361
+ const raw = readFileSync47(accessPath, "utf-8");
77362
+ const access = JSON.parse(raw);
77363
+ const chatId = access.allowFrom?.[0];
77364
+ if (!chatId)
77365
+ return null;
77366
+ return { chatId };
77367
+ } catch {
77368
+ return null;
77369
+ }
77370
+ }
77371
+ async function injectInbound(agentsDir, agentName, chatId, threadId, text, promptKey) {
77372
+ const socketPath = resolve29(agentsDir, agentName, "telegram", "gateway.sock");
77373
+ if (!existsSync51(socketPath)) {
77374
+ return { ok: false, error: `agent ${agentName} gateway socket not found \u2014 is it running?` };
77375
+ }
77376
+ const ts = Date.now();
77377
+ const envelope = JSON.stringify({
77378
+ type: "inject_inbound",
77379
+ agentName,
77380
+ inbound: {
77381
+ type: "inbound",
77382
+ chatId,
77383
+ ...threadId !== undefined ? { threadId } : {},
77384
+ messageId: ts,
77385
+ user: "operator",
77386
+ userId: 0,
77387
+ ts,
77388
+ text,
77389
+ meta: {
77390
+ source: "operator-console",
77391
+ prompt_key: promptKey
77392
+ }
77393
+ }
77394
+ });
77395
+ return new Promise((res) => {
77396
+ const sock = createConnection3(socketPath);
77397
+ let settled = false;
77398
+ const settle = (result) => {
77399
+ if (!settled) {
77400
+ settled = true;
77401
+ sock.destroy();
77402
+ res(result);
77403
+ }
77404
+ };
77405
+ const timeout = setTimeout(() => settle({ ok: false, error: "gateway socket timeout" }), 5000);
77406
+ sock.once("connect", () => {
77407
+ clearTimeout(timeout);
77408
+ sock.write(envelope + `
77409
+ `, (err) => {
77410
+ settle(err ? { ok: false, error: err.message } : { ok: true });
77411
+ });
77412
+ });
77413
+ sock.once("error", (err) => {
77414
+ clearTimeout(timeout);
77415
+ settle({ ok: false, error: err.message });
77416
+ });
77417
+ });
77418
+ }
77419
+ async function handleHermesRest(method, pathname, config) {
77420
+ if (method === "GET" && pathname === "/api/sessions") {
77421
+ const agents = await handleGetAgents(config);
77422
+ const agentsDir = resolveAgentsDir(config);
77423
+ const sessions = agents.map((a) => toHermesSession(a, agentLiveness(config, a.name)));
77424
+ return { status: 200, body: { sessions } };
77425
+ }
77426
+ const sessionMatch = pathname.match(/^\/api\/sessions\/([^/]+)$/);
77427
+ if (method === "GET" && sessionMatch) {
77428
+ const id = decodeURIComponent(sessionMatch[1]);
77429
+ if (!config.agents?.[id])
77430
+ return { status: 404, body: { error: "Unknown session" } };
77431
+ const agents = await handleGetAgents(config);
77432
+ const agent = agents.find((a) => a.name === id);
77433
+ if (!agent)
77434
+ return { status: 404, body: { error: "Unknown session" } };
77435
+ return { status: 200, body: { session: toHermesSession(agent, agentLiveness(config, id)) } };
77436
+ }
77437
+ const historyMatch = pathname.match(/^\/api\/sessions\/([^/]+)\/history$/);
77438
+ if (method === "GET" && historyMatch) {
77439
+ const id = decodeURIComponent(historyMatch[1]);
77440
+ if (!config.agents?.[id])
77441
+ return { status: 404, body: { error: "Unknown session" } };
77442
+ const result = handleGetTurns(config, id, 50);
77443
+ if (!result.ok)
77444
+ return { status: 500, body: { error: result.error } };
77445
+ return { status: 200, body: { history: result.turns ?? [] } };
77446
+ }
77447
+ if (method === "GET" && pathname === "/api/status") {
77448
+ const agents = await handleGetAgents(config);
77449
+ const fleet = agents.map((a) => ({
77450
+ name: a.name,
77451
+ status: agentLiveness(config, a.name)
77452
+ }));
77453
+ return {
77454
+ status: 200,
77455
+ body: {
77456
+ status: "ok",
77457
+ provider: "switchroom",
77458
+ agents: fleet
77459
+ }
77460
+ };
77461
+ }
77462
+ if (method === "GET" && pathname === "/api/config") {
77463
+ const agentNames = Object.keys(config.agents ?? {});
77464
+ return {
77465
+ status: 200,
77466
+ body: {
77467
+ provider: "switchroom",
77468
+ agents: agentNames
77469
+ }
77470
+ };
77471
+ }
77472
+ return null;
77473
+ }
77474
+ function sendEvent(ctx, type, sessionId, payload) {
77475
+ try {
77476
+ ctx.send(JSON.stringify(hermesEvent(type, sessionId, payload)));
77477
+ } catch {}
77478
+ }
77479
+ function sendResponse(ctx, resp) {
77480
+ try {
77481
+ ctx.send(JSON.stringify(resp));
77482
+ } catch {}
77483
+ }
77484
+ function onHermesOpen(ctx) {
77485
+ sendEvent(ctx, "gateway.ready", null, {
77486
+ provider: "switchroom",
77487
+ version: "1.0"
77488
+ });
77489
+ ctx.pollInterval = setInterval(async () => {
77490
+ const agents = await handleGetAgents(ctx.config);
77491
+ for (const agent of agents) {
77492
+ const liveness = agentLiveness(ctx.config, agent.name);
77493
+ sendEvent(ctx, "status.update", agent.name, { status: liveness });
77494
+ }
77495
+ }, 5000);
77496
+ }
77497
+ function onHermesClose(ctx) {
77498
+ if (ctx.pollInterval) {
77499
+ clearInterval(ctx.pollInterval);
77500
+ ctx.pollInterval = undefined;
77501
+ }
77502
+ }
77503
+ async function onHermesMessage(ctx, raw) {
77504
+ let req;
77505
+ try {
77506
+ req = JSON.parse(raw);
77507
+ } catch {
77508
+ sendResponse(ctx, rpcErr(null, -32700, "Parse error"));
77509
+ return;
77510
+ }
77511
+ if (!req.method || typeof req.method !== "string") {
77512
+ sendResponse(ctx, rpcErr(req.id ?? null, -32600, "Invalid request"));
77513
+ return;
77514
+ }
77515
+ const id = req.id ?? null;
77516
+ const params = req.params ?? {};
77517
+ const config = ctx.config;
77518
+ switch (req.method) {
77519
+ case "session.list": {
77520
+ const agents = await handleGetAgents(config);
77521
+ const sessions = agents.map((a) => toHermesSession(a, agentLiveness(config, a.name)));
77522
+ sendResponse(ctx, rpcOk(id, { sessions }));
77523
+ break;
77524
+ }
77525
+ case "session.most_recent": {
77526
+ const agents = await handleGetAgents(config);
77527
+ if (agents.length === 0) {
77528
+ sendResponse(ctx, rpcOk(id, { session: null }));
77529
+ break;
77530
+ }
77531
+ const a = agents[0];
77532
+ sendResponse(ctx, rpcOk(id, { session: toHermesSession(a, agentLiveness(config, a.name)) }));
77533
+ break;
77534
+ }
77535
+ case "session.status": {
77536
+ const sessionId = String(params.session_id ?? "");
77537
+ if (!config.agents?.[sessionId]) {
77538
+ sendResponse(ctx, rpcErr(id, -32602, `Unknown session: ${sessionId}`));
77539
+ break;
77540
+ }
77541
+ const agents = await handleGetAgents(config);
77542
+ const agent = agents.find((a) => a.name === sessionId);
77543
+ if (!agent) {
77544
+ sendResponse(ctx, rpcErr(id, -32602, `Unknown session: ${sessionId}`));
77545
+ break;
77546
+ }
77547
+ sendResponse(ctx, rpcOk(id, { session: toHermesSession(agent, agentLiveness(config, sessionId)) }));
77548
+ break;
77549
+ }
77550
+ case "session.create":
77551
+ case "session.resume":
77552
+ case "session.activate": {
77553
+ const sessionId = String(params.session_id ?? params.name ?? "");
77554
+ if (!config.agents?.[sessionId]) {
77555
+ sendResponse(ctx, rpcErr(id, -32602, `Unknown session: ${sessionId}`));
77556
+ break;
77557
+ }
77558
+ ctx.activeSessionId = sessionId;
77559
+ const agents = await handleGetAgents(config);
77560
+ const agent = agents.find((a) => a.name === sessionId);
77561
+ if (!agent) {
77562
+ sendResponse(ctx, rpcErr(id, -32602, `Unknown session: ${sessionId}`));
77563
+ break;
77564
+ }
77565
+ const session = toHermesSession(agent, agentLiveness(config, sessionId));
77566
+ sendResponse(ctx, rpcOk(id, { session }));
77567
+ sendEvent(ctx, "session.info", sessionId, session);
77568
+ break;
77569
+ }
77570
+ case "session.close": {
77571
+ ctx.activeSessionId = undefined;
77572
+ sendResponse(ctx, rpcOk(id, { ok: true }));
77573
+ break;
77574
+ }
77575
+ case "session.history": {
77576
+ const sessionId = String(params.session_id ?? ctx.activeSessionId ?? "");
77577
+ if (!config.agents?.[sessionId]) {
77578
+ sendResponse(ctx, rpcErr(id, -32602, `Unknown session: ${sessionId}`));
77579
+ break;
77580
+ }
77581
+ const limit = typeof params.limit === "number" ? params.limit : 50;
77582
+ const result = handleGetTurns(config, sessionId, Math.min(limit, 200));
77583
+ if (!result.ok) {
77584
+ sendResponse(ctx, rpcErr(id, -32603, result.error ?? "Failed to read history"));
77585
+ break;
77586
+ }
77587
+ sendResponse(ctx, rpcOk(id, { history: result.turns ?? [] }));
77588
+ break;
77589
+ }
77590
+ case "session.usage": {
77591
+ const sessionId = String(params.session_id ?? ctx.activeSessionId ?? "");
77592
+ if (!config.agents?.[sessionId]) {
77593
+ sendResponse(ctx, rpcErr(id, -32602, `Unknown session: ${sessionId}`));
77594
+ break;
77595
+ }
77596
+ const agents = await handleGetAgents(config);
77597
+ const agent = agents.find((a) => a.name === sessionId);
77598
+ sendResponse(ctx, rpcOk(id, {
77599
+ session_id: sessionId,
77600
+ quota: agent?.primaryAccount ? { slot: agent.primaryAccount, state: agent.auth.subscriptionType ?? null } : null
77601
+ }));
77602
+ break;
77603
+ }
77604
+ case "prompt.submit":
77605
+ case "prompt.background": {
77606
+ const sessionId = String(params.session_id ?? ctx.activeSessionId ?? "");
77607
+ const content = String(params.content ?? params.text ?? "");
77608
+ if (!sessionId || !config.agents?.[sessionId]) {
77609
+ sendResponse(ctx, rpcErr(id, -32602, `Unknown session: ${sessionId}`));
77610
+ break;
77611
+ }
77612
+ if (!content) {
77613
+ sendResponse(ctx, rpcErr(id, -32602, "content is required"));
77614
+ break;
77615
+ }
77616
+ const agentsDir = resolveAgentsDir(config);
77617
+ const chat = resolveAgentChat(config, sessionId, agentsDir);
77618
+ if (!chat) {
77619
+ sendResponse(ctx, rpcErr(id, -32603, `Could not resolve chat for ${sessionId} \u2014 ensure the agent has telegram.forum_chat_id or channels.telegram.chat_id configured.`));
77620
+ break;
77621
+ }
77622
+ const promptKey = createHash10("sha256").update(`${sessionId}:${Date.now()}:${content}`).digest("hex").slice(0, 12);
77623
+ sendEvent(ctx, "message.start", sessionId, { prompt_key: promptKey });
77624
+ const result = await injectInbound(agentsDir, sessionId, chat.chatId, chat.threadId, content, promptKey);
77625
+ if (!result.ok) {
77626
+ sendEvent(ctx, "error", sessionId, { message: result.error, prompt_key: promptKey });
77627
+ sendResponse(ctx, rpcErr(id, -32603, result.error ?? "inject failed"));
77628
+ break;
77629
+ }
77630
+ sendEvent(ctx, "message.complete", sessionId, {
77631
+ prompt_key: promptKey,
77632
+ note: "reply delivered to Telegram thread"
77633
+ });
77634
+ sendResponse(ctx, rpcOk(id, { ok: true, prompt_key: promptKey }));
77635
+ break;
77636
+ }
77637
+ case "session.interrupt": {
77638
+ const sessionId = String(params.session_id ?? ctx.activeSessionId ?? "");
77639
+ if (!sessionId || !config.agents?.[sessionId]) {
77640
+ sendResponse(ctx, rpcErr(id, -32602, `Unknown session: ${sessionId}`));
77641
+ break;
77642
+ }
77643
+ const agentsDir = resolveAgentsDir(config);
77644
+ const chat = resolveAgentChat(config, sessionId, agentsDir);
77645
+ if (!chat) {
77646
+ sendResponse(ctx, rpcErr(id, -32603, `Cannot resolve chat for ${sessionId}`));
77647
+ break;
77648
+ }
77649
+ const promptKey = `interrupt-${Date.now()}`;
77650
+ const intResult = await injectInbound(agentsDir, sessionId, chat.chatId, chat.threadId, "! ", promptKey);
77651
+ if (!intResult.ok) {
77652
+ sendResponse(ctx, rpcErr(id, -32603, intResult.error ?? "interrupt inject failed"));
77653
+ break;
77654
+ }
77655
+ sendResponse(ctx, rpcOk(id, { ok: true }));
77656
+ break;
77657
+ }
77658
+ case "approval.request":
77659
+ case "approval.respond":
77660
+ case "sudo.request":
77661
+ case "sudo.respond":
77662
+ case "secret.get":
77663
+ case "secret.set":
77664
+ sendResponse(ctx, rpcErr(id, -32601, `Method not implemented: ${req.method}`));
77665
+ break;
77666
+ default:
77667
+ sendResponse(ctx, rpcErr(id, -32601, `Unknown method: ${req.method}`));
77668
+ }
77669
+ }
77670
+
77289
77671
  // src/web/server.ts
77290
77672
  var LOG_POLL_INTERVAL_MS = 3000;
77291
77673
  var LOG_POLL_TAIL_LINES = 400;
@@ -77337,9 +77719,9 @@ function resolveWebToken() {
77337
77719
  if (fromEnv && fromEnv.length > 0)
77338
77720
  return fromEnv;
77339
77721
  const home2 = process.env.HOME ?? homedir26();
77340
- const tokenPath = join48(home2, ".switchroom", "web-token");
77341
- if (existsSync51(tokenPath)) {
77342
- const existing = readFileSync47(tokenPath, "utf8").trim();
77722
+ const tokenPath = join49(home2, ".switchroom", "web-token");
77723
+ if (existsSync52(tokenPath)) {
77724
+ const existing = readFileSync48(tokenPath, "utf8").trim();
77343
77725
  if (existing.length > 0)
77344
77726
  return existing;
77345
77727
  }
@@ -77356,7 +77738,7 @@ function resolveWebToken() {
77356
77738
  return token;
77357
77739
  } catch (err) {
77358
77740
  if (err.code === "EEXIST") {
77359
- const existing = readFileSync47(tokenPath, "utf8").trim();
77741
+ const existing = readFileSync48(tokenPath, "utf8").trim();
77360
77742
  if (existing.length > 0)
77361
77743
  return existing;
77362
77744
  }
@@ -77422,11 +77804,11 @@ function checkWsAuth(req, token, server) {
77422
77804
  return presented !== null && constantTimeEqual(presented, token);
77423
77805
  }
77424
77806
  function loadWebhookSecrets() {
77425
- const path4 = join48(homedir26(), ".switchroom", "webhook-secrets.json");
77426
- if (!existsSync51(path4))
77807
+ const path4 = join49(homedir26(), ".switchroom", "webhook-secrets.json");
77808
+ if (!existsSync52(path4))
77427
77809
  return {};
77428
77810
  try {
77429
- const parsed = JSON.parse(readFileSync47(path4, "utf-8"));
77811
+ const parsed = JSON.parse(readFileSync48(path4, "utf-8"));
77430
77812
  return parsed && typeof parsed === "object" ? parsed : {};
77431
77813
  } catch (err) {
77432
77814
  process.stderr.write(`webhook-ingest: failed to parse ${path4}: ${err.message} \u2014 webhooks will return 401 until fixed
@@ -77604,8 +77986,8 @@ function parseRoute(pathname, method) {
77604
77986
  return null;
77605
77987
  }
77606
77988
  function startWebServer(config, port, hostname = "127.0.0.1", configPath) {
77607
- const uiDirRaw = resolve29(import.meta.dirname, "ui");
77608
- const uiDir = existsSync51(uiDirRaw) ? realpathSync4(uiDirRaw) : uiDirRaw;
77989
+ const uiDirRaw = resolve30(import.meta.dirname, "ui");
77990
+ const uiDir = existsSync52(uiDirRaw) ? realpathSync4(uiDirRaw) : uiDirRaw;
77609
77991
  const token = resolveWebToken();
77610
77992
  const freshConfig = () => {
77611
77993
  if (!configPath)
@@ -77653,6 +78035,21 @@ function startWebServer(config, port, hostname = "127.0.0.1", configPath) {
77653
78035
  }
77654
78036
  return;
77655
78037
  }
78038
+ if (pathname === "/api/ws") {
78039
+ if (!checkWsAuth(req, token, server2)) {
78040
+ return new Response("Unauthorized", { status: 401 });
78041
+ }
78042
+ const wsProto = req.headers.get("Sec-WebSocket-Protocol");
78043
+ const echoBearer = wsProto && wsProto.split(",").map((s) => s.trim()).includes("bearer");
78044
+ const upgraded = server2.upgrade(req, {
78045
+ headers: echoBearer ? { "Sec-WebSocket-Protocol": "bearer" } : undefined,
78046
+ data: { hermesWs: true }
78047
+ });
78048
+ if (!upgraded) {
78049
+ return new Response("WebSocket upgrade failed", { status: 400 });
78050
+ }
78051
+ return;
78052
+ }
77656
78053
  const route = parseRoute(pathname, req.method);
77657
78054
  if (route) {
77658
78055
  const authError = checkAuth(req, token, server2);
@@ -77871,9 +78268,21 @@ function startWebServer(config, port, hostname = "127.0.0.1", configPath) {
77871
78268
  }
77872
78269
  }
77873
78270
  }
78271
+ if (pathname.startsWith("/api/")) {
78272
+ const authError = checkAuth(req, token, server2);
78273
+ if (authError)
78274
+ return authError;
78275
+ return (async () => {
78276
+ const hermesResult = await handleHermesRest(req.method, pathname, config);
78277
+ if (hermesResult !== null) {
78278
+ return jsonResponse(hermesResult.body, hermesResult.status);
78279
+ }
78280
+ return new Response("Not Found", { status: 404 });
78281
+ })();
78282
+ }
77874
78283
  const filePath = resolveDashboardFilePath(pathname);
77875
- const fullPath = join48(uiDir, filePath);
77876
- if (!existsSync51(fullPath)) {
78284
+ const fullPath = join49(uiDir, filePath);
78285
+ if (!existsSync52(fullPath)) {
77877
78286
  return new Response("Not Found", { status: 404 });
77878
78287
  }
77879
78288
  let realFullPath;
@@ -77883,12 +78292,12 @@ function startWebServer(config, port, hostname = "127.0.0.1", configPath) {
77883
78292
  return new Response("Not Found", { status: 404 });
77884
78293
  }
77885
78294
  const rel = relative(uiDir, realFullPath);
77886
- if (rel.startsWith("..") || resolve29(uiDir, rel) !== realFullPath) {
78295
+ if (rel.startsWith("..") || resolve30(uiDir, rel) !== realFullPath) {
77887
78296
  return new Response("Forbidden", { status: 403 });
77888
78297
  }
77889
78298
  const ext = extname(realFullPath);
77890
78299
  const contentType = MIME_TYPES[ext] ?? "application/octet-stream";
77891
- const content = readFileSync47(realFullPath);
78300
+ const content = readFileSync48(realFullPath);
77892
78301
  const headers = { "Content-Type": contentType };
77893
78302
  const cacheControl = dashboardCacheControl(ext);
77894
78303
  if (cacheControl)
@@ -77896,8 +78305,26 @@ function startWebServer(config, port, hostname = "127.0.0.1", configPath) {
77896
78305
  return new Response(content, { headers });
77897
78306
  },
77898
78307
  websocket: {
77899
- open(_ws) {},
78308
+ open(ws) {
78309
+ if (ws.data?.hermesWs) {
78310
+ const ctx = {
78311
+ config,
78312
+ send: (msg) => {
78313
+ try {
78314
+ ws.send(msg);
78315
+ } catch {}
78316
+ }
78317
+ };
78318
+ ws._hermesCtx = ctx;
78319
+ onHermesOpen(ctx);
78320
+ }
78321
+ },
77900
78322
  close(ws) {
78323
+ if (ws._hermesCtx) {
78324
+ onHermesClose(ws._hermesCtx);
78325
+ delete ws._hermesCtx;
78326
+ return;
78327
+ }
77901
78328
  const interval = ws._logInterval;
77902
78329
  if (interval) {
77903
78330
  clearInterval(interval);
@@ -77905,6 +78332,10 @@ function startWebServer(config, port, hostname = "127.0.0.1", configPath) {
77905
78332
  }
77906
78333
  },
77907
78334
  message(ws, message) {
78335
+ if (ws._hermesCtx) {
78336
+ onHermesMessage(ws._hermesCtx, String(message));
78337
+ return;
78338
+ }
77908
78339
  let data;
77909
78340
  try {
77910
78341
  data = JSON.parse(String(message));
@@ -78039,8 +78470,8 @@ Starting Switchroom dashboard...
78039
78470
  // src/cli/setup.ts
78040
78471
  init_source();
78041
78472
  init_loader();
78042
- import { existsSync as existsSync52, copyFileSync as copyFileSync8, readFileSync as readFileSync48, writeFileSync as writeFileSync27, mkdirSync as mkdirSync30 } from "node:fs";
78043
- import { resolve as resolve30, dirname as dirname13 } from "node:path";
78473
+ import { existsSync as existsSync53, copyFileSync as copyFileSync8, readFileSync as readFileSync49, writeFileSync as writeFileSync27, mkdirSync as mkdirSync30 } from "node:fs";
78474
+ import { resolve as resolve31, dirname as dirname13 } from "node:path";
78044
78475
  init_vault();
78045
78476
  init_manager();
78046
78477
  init_client();
@@ -78257,7 +78688,7 @@ async function stepConfigFile(configPath, nonInteractive) {
78257
78688
  existingConfig = null;
78258
78689
  }
78259
78690
  }
78260
- if (existingConfig && existsSync52(existingConfig)) {
78691
+ if (existingConfig && existsSync53(existingConfig)) {
78261
78692
  if (!nonInteractive) {
78262
78693
  const useExisting = await askYesNo(` Found ${source_default.cyan(existingConfig)}. Use it?`, true);
78263
78694
  if (!useExisting) {
@@ -78269,14 +78700,14 @@ async function stepConfigFile(configPath, nonInteractive) {
78269
78700
  console.log(source_default.green(` ${STEP_DONE} Config loaded`) + source_default.gray(` (${Object.keys(config.agents).length} agents)`));
78270
78701
  const hasExplicitTimezone = config.switchroom?.timezone !== undefined || config.defaults?.timezone !== undefined;
78271
78702
  if (!hasExplicitTimezone) {
78272
- await writeDetectedTimezone(resolve30(existingConfig), nonInteractive);
78703
+ await writeDetectedTimezone(resolve31(existingConfig), nonInteractive);
78273
78704
  }
78274
- return { config, configPath: resolve30(existingConfig) };
78705
+ return { config, configPath: resolve31(existingConfig) };
78275
78706
  }
78276
78707
  return await copyExampleConfig(nonInteractive);
78277
78708
  }
78278
78709
  async function copyExampleConfig(nonInteractive) {
78279
- const examplesDir = resolve30(import.meta.dirname, "../../examples");
78710
+ const examplesDir = resolve31(import.meta.dirname, "../../examples");
78280
78711
  let choice;
78281
78712
  if (nonInteractive) {
78282
78713
  choice = "switchroom";
@@ -78287,9 +78718,9 @@ async function copyExampleConfig(nonInteractive) {
78287
78718
  ]);
78288
78719
  choice = choice.split(" ")[0];
78289
78720
  }
78290
- const srcFile = resolve30(examplesDir, `${choice}.yaml`);
78721
+ const srcFile = resolve31(examplesDir, `${choice}.yaml`);
78291
78722
  const destFile = resolvePath("~/.switchroom/switchroom.yaml");
78292
- if (!existsSync52(srcFile)) {
78723
+ if (!existsSync53(srcFile)) {
78293
78724
  throw new ConfigError(`Example config not found: ${choice}.yaml`);
78294
78725
  }
78295
78726
  mkdirSync30(dirname13(destFile), { recursive: true });
@@ -78299,12 +78730,12 @@ async function copyExampleConfig(nonInteractive) {
78299
78730
  await writeDetectedTimezone(destFile, nonInteractive);
78300
78731
  const config = loadConfig(destFile);
78301
78732
  console.log(source_default.green(` ${STEP_DONE} Config loaded`) + source_default.gray(` (${Object.keys(config.agents).length} agents)`));
78302
- return { config, configPath: resolve30(destFile) };
78733
+ return { config, configPath: resolve31(destFile) };
78303
78734
  }
78304
78735
  async function writeDetectedTimezone(destFile, nonInteractive, detect = detectServerTimezone, prompt = ask) {
78305
78736
  const detected = detect();
78306
78737
  if (detected !== undefined && detected !== "UTC" && isValidTimezone(detected)) {
78307
- const before2 = readFileSync48(destFile, "utf-8");
78738
+ const before2 = readFileSync49(destFile, "utf-8");
78308
78739
  const after2 = setSwitchroomTimezone(before2, detected);
78309
78740
  if (after2 !== before2)
78310
78741
  writeFileSync27(destFile, after2);
@@ -78325,7 +78756,7 @@ async function writeDetectedTimezone(destFile, nonInteractive, detect = detectSe
78325
78756
  console.error(source_default.yellow(` \u26a0 "${zone}" is not a valid IANA zone (expected Region/City like ` + '"Australia/Melbourne"). Skipping \u2014 agents will use UTC. ' + "Edit switchroom.timezone in switchroom.yaml by hand."));
78326
78757
  return;
78327
78758
  }
78328
- const before = readFileSync48(destFile, "utf-8");
78759
+ const before = readFileSync49(destFile, "utf-8");
78329
78760
  const after = setSwitchroomTimezone(before, zone);
78330
78761
  if (after !== before)
78331
78762
  writeFileSync27(destFile, after);
@@ -78404,7 +78835,7 @@ async function resolveOrPromptToken(rawToken, label, config, nonInteractive) {
78404
78835
  try {
78405
78836
  const { openVault: openVault2 } = await Promise.resolve().then(() => (init_vault(), exports_vault));
78406
78837
  const vaultPath = resolvePath(config.vault?.path ?? "~/.switchroom/vault.enc");
78407
- if (existsSync52(vaultPath)) {
78838
+ if (existsSync53(vaultPath)) {
78408
78839
  const secrets = openVault2(passphrase, vaultPath);
78409
78840
  const key = rawToken.replace("vault:", "");
78410
78841
  const entry = secrets[key];
@@ -78432,7 +78863,7 @@ async function resolveOrPromptToken(rawToken, label, config, nonInteractive) {
78432
78863
  async function storeTokenInVault(config, vaultRef, token) {
78433
78864
  const vaultPath = resolvePath(config.vault?.path ?? "~/.switchroom/vault.enc");
78434
78865
  const key = vaultRef.replace("vault:", "");
78435
- if (!existsSync52(vaultPath)) {
78866
+ if (!existsSync53(vaultPath)) {
78436
78867
  console.log(source_default.gray(" Creating encrypted vault..."));
78437
78868
  let passphrase = process.env.SWITCHROOM_VAULT_PASSPHRASE;
78438
78869
  if (!passphrase) {
@@ -78614,7 +79045,7 @@ async function stepMemoryBackend(config, nonInteractive, switchroomConfigPath) {
78614
79045
  try {
78615
79046
  const vaultPath = resolvePath(config.vault?.path ?? "~/.switchroom/vault.enc");
78616
79047
  const passphrase = process.env.SWITCHROOM_VAULT_PASSPHRASE;
78617
- if (passphrase && existsSync52(vaultPath)) {
79048
+ if (passphrase && existsSync53(vaultPath)) {
78618
79049
  const existing = getStringSecret(passphrase, vaultPath, "hindsight-api-key");
78619
79050
  if (existing) {
78620
79051
  console.log(source_default.gray(" Note: legacy 'hindsight-api-key' is in your vault but is no longer used. You can remove it with `switchroom vault rm hindsight-api-key`."));
@@ -78778,13 +79209,13 @@ async function stepAutoUnlock(config, switchroomConfigPath, nonInteractive) {
78778
79209
  return;
78779
79210
  }
78780
79211
  const vaultPath = resolvePath(config.vault?.path ?? "~/.switchroom/vault.enc");
78781
- if (!existsSync52(vaultPath)) {
79212
+ if (!existsSync53(vaultPath)) {
78782
79213
  console.log(source_default.gray(" Skipping (vault not created yet)."));
78783
79214
  return;
78784
79215
  }
78785
79216
  const credPathRaw = config.vault?.broker?.autoUnlockCredentialPath ?? "~/.switchroom/vault-auto-unlock";
78786
79217
  const credPath = resolvePath(credPathRaw);
78787
- if (config.vault?.broker?.autoUnlock === true && existsSync52(credPath)) {
79218
+ if (config.vault?.broker?.autoUnlock === true && existsSync53(credPath)) {
78788
79219
  console.log(source_default.green(` ${STEP_DONE} Already configured (${credPath})`));
78789
79220
  return;
78790
79221
  }
@@ -78850,9 +79281,9 @@ async function stepAutoUnlock(config, switchroomConfigPath, nonInteractive) {
78850
79281
  const choice = await askChoice(" Approval posture", [PASSPHRASE_CHOICE, TELEGRAM_ID_CHOICE]);
78851
79282
  if (choice === TELEGRAM_ID_CHOICE) {
78852
79283
  try {
78853
- const yamlPath = existsSync52(resolve30(process.cwd(), "switchroom.yaml")) ? resolve30(process.cwd(), "switchroom.yaml") : resolve30(process.cwd(), "switchroom.yml");
78854
- if (existsSync52(yamlPath)) {
78855
- const content = readFileSync48(yamlPath, "utf-8");
79284
+ const yamlPath = existsSync53(resolve31(process.cwd(), "switchroom.yaml")) ? resolve31(process.cwd(), "switchroom.yaml") : resolve31(process.cwd(), "switchroom.yml");
79285
+ if (existsSync53(yamlPath)) {
79286
+ const content = readFileSync49(yamlPath, "utf-8");
78856
79287
  const result = insertVaultBrokerApprovalAuth(content, "telegram-id");
78857
79288
  if (result.kind === "rewritten") {
78858
79289
  writeFileSync27(yamlPath, result.content, "utf-8");
@@ -78882,12 +79313,12 @@ async function stepDangerousMode(config, nonInteractive) {
78882
79313
  }
78883
79314
  if (enableDangerous) {
78884
79315
  const configPaths = [
78885
- resolve30(process.cwd(), "switchroom.yaml"),
78886
- resolve30(process.cwd(), "switchroom.yml")
79316
+ resolve31(process.cwd(), "switchroom.yaml"),
79317
+ resolve31(process.cwd(), "switchroom.yml")
78887
79318
  ];
78888
79319
  for (const configPath of configPaths) {
78889
- if (existsSync52(configPath)) {
78890
- let content = readFileSync48(configPath, "utf-8");
79320
+ if (existsSync53(configPath)) {
79321
+ let content = readFileSync49(configPath, "utf-8");
78891
79322
  const agentNames = Object.keys(config.agents);
78892
79323
  for (const name of agentNames) {
78893
79324
  const agentPattern = new RegExp(`(^ ${name}:\\s*\\n)`, "m");
@@ -78917,7 +79348,7 @@ async function stepOnboardingGuidance(config, nonInteractive) {
78917
79348
  const agentNames = Object.keys(config.agents);
78918
79349
  let allAuthenticated = true;
78919
79350
  for (const name of agentNames) {
78920
- const agentDir = resolve30(agentsDir, name);
79351
+ const agentDir = resolve31(agentsDir, name);
78921
79352
  const status = getAuthStatus(name, agentDir);
78922
79353
  if (status.authenticated) {
78923
79354
  console.log(` ${source_default.green("OK")} ${source_default.bold(name)}` + source_default.gray(` - authenticated (expires: ${status.timeUntilExpiry ?? "unknown"})`));
@@ -79015,9 +79446,9 @@ init_doctor();
79015
79446
  init_source();
79016
79447
  init_loader();
79017
79448
  init_lifecycle();
79018
- import { cpSync as cpSync2, existsSync as existsSync59, mkdirSync as mkdirSync32, readFileSync as readFileSync53, realpathSync as realpathSync6, rmSync as rmSync12, statSync as statSync27, chownSync as chownSync5 } from "node:fs";
79449
+ import { cpSync as cpSync2, existsSync as existsSync60, mkdirSync as mkdirSync32, readFileSync as readFileSync54, realpathSync as realpathSync6, rmSync as rmSync12, statSync as statSync27, chownSync as chownSync5 } from "node:fs";
79019
79450
  import { spawnSync as spawnSync11 } from "node:child_process";
79020
- import { join as join62, dirname as dirname16, resolve as resolve35 } from "node:path";
79451
+ import { join as join63, dirname as dirname16, resolve as resolve36 } from "node:path";
79021
79452
  import { homedir as homedir37 } from "node:os";
79022
79453
 
79023
79454
  // src/cli/release-yaml.ts
@@ -79109,7 +79540,7 @@ ${lines.join(`
79109
79540
  function defaultPersistPin(configPath) {
79110
79541
  return (pin) => {
79111
79542
  const path4 = configPath ?? findConfigFile();
79112
- const before = readFileSync53(path4, "utf8");
79543
+ const before = readFileSync54(path4, "utf8");
79113
79544
  const after = setReleasePinInConfig(before, pin);
79114
79545
  if (after === before)
79115
79546
  return;
@@ -79123,13 +79554,13 @@ function defaultPersistPin(configPath) {
79123
79554
  } catch {}
79124
79555
  };
79125
79556
  }
79126
- var DEFAULT_COMPOSE_PATH = join62(homedir37(), ".switchroom", "compose", "docker-compose.yml");
79557
+ var DEFAULT_COMPOSE_PATH = join63(homedir37(), ".switchroom", "compose", "docker-compose.yml");
79127
79558
  function runningFromSwitchroomCheckout(scriptPath) {
79128
79559
  let dir = dirname16(scriptPath);
79129
79560
  for (let i = 0;i < 12; i++) {
79130
- if (existsSync59(join62(dir, ".git"))) {
79561
+ if (existsSync60(join63(dir, ".git"))) {
79131
79562
  try {
79132
- const pkg = JSON.parse(readFileSync53(join62(dir, "package.json"), "utf-8"));
79563
+ const pkg = JSON.parse(readFileSync54(join63(dir, "package.json"), "utf-8"));
79133
79564
  if (pkg.name === "switchroom")
79134
79565
  return true;
79135
79566
  } catch {}
@@ -79198,7 +79629,7 @@ function planUpdate(opts) {
79198
79629
  steps.push({
79199
79630
  name: "pull-images",
79200
79631
  description: "Pull broker / kernel / agent images from GHCR",
79201
- skipReason: opts.skipImages ? "--skip-images flag set" : !existsSync59(composePath) ? `compose file not found at ${composePath} (run \`switchroom apply --compose-only\` first)` : undefined,
79632
+ skipReason: opts.skipImages ? "--skip-images flag set" : !existsSync60(composePath) ? `compose file not found at ${composePath} (run \`switchroom apply --compose-only\` first)` : undefined,
79202
79633
  run: () => {
79203
79634
  const r = runner("docker", [
79204
79635
  "compose",
@@ -79318,15 +79749,15 @@ function planUpdate(opts) {
79318
79749
  opts.syncBundledSkillsFn();
79319
79750
  return;
79320
79751
  }
79321
- const source = resolve35(import.meta.dirname, "../../skills");
79322
- const dest = join62(homedir37(), ".switchroom", "skills", "_bundled");
79323
- if (!existsSync59(source)) {
79752
+ const source = resolve36(import.meta.dirname, "../../skills");
79753
+ const dest = join63(homedir37(), ".switchroom", "skills", "_bundled");
79754
+ if (!existsSync60(source)) {
79324
79755
  process.stderr.write(`switchroom update: sync-bundled-skills \u2014 CLI bundle has no adjacent skills/ at ${source}; skipping.
79325
79756
  `);
79326
79757
  return;
79327
79758
  }
79328
79759
  try {
79329
- if (existsSync59(dest)) {
79760
+ if (existsSync60(dest)) {
79330
79761
  rmSync12(dest, { recursive: true, force: true });
79331
79762
  }
79332
79763
  mkdirSync32(dirname16(dest), { recursive: true });
@@ -79365,7 +79796,7 @@ function planUpdate(opts) {
79365
79796
  description: "docker compose up -d --remove-orphans (recreates services with new images / compose)",
79366
79797
  run: () => {
79367
79798
  try {
79368
- const composeText = readFileSync53(composePath, "utf8");
79799
+ const composeText = readFileSync54(composePath, "utf8");
79369
79800
  const pf = validateBindSources(composeText);
79370
79801
  if (!pf.ok)
79371
79802
  throw new Error(formatPreflightError(pf));
@@ -79443,10 +79874,10 @@ function defaultStatusProbe(composePath) {
79443
79874
  } catch {}
79444
79875
  let dir = dirname16(scriptPath);
79445
79876
  for (let i = 0;i < 8; i++) {
79446
- const pkgPath = join62(dir, "package.json");
79447
- if (existsSync59(pkgPath)) {
79877
+ const pkgPath = join63(dir, "package.json");
79878
+ if (existsSync60(pkgPath)) {
79448
79879
  try {
79449
- const pkg = JSON.parse(readFileSync53(pkgPath, "utf-8"));
79880
+ const pkg = JSON.parse(readFileSync54(pkgPath, "utf-8"));
79450
79881
  if (typeof pkg.version === "string")
79451
79882
  cliVersion = pkg.version;
79452
79883
  } catch (err) {
@@ -79467,7 +79898,7 @@ function defaultStatusProbe(composePath) {
79467
79898
  warnings.push("could not resolve CLI version (no package.json found above the resolved script path)");
79468
79899
  }
79469
79900
  const services = [];
79470
- if (!existsSync59(composePath)) {
79901
+ if (!existsSync60(composePath)) {
79471
79902
  warnings.push(`compose file not found at ${composePath}; service status unknown`);
79472
79903
  return { cliVersion, cliBuiltAt, services, warnings };
79473
79904
  }
@@ -79663,7 +80094,7 @@ function registerUpdateCommand(program3) {
79663
80094
  // src/cli/rollout.ts
79664
80095
  init_helpers();
79665
80096
  import { spawnSync as spawnSync12 } from "node:child_process";
79666
- import { readFileSync as readFileSync54, chownSync as chownSync6, statSync as statSync28 } from "node:fs";
80097
+ import { readFileSync as readFileSync55, chownSync as chownSync6, statSync as statSync28 } from "node:fs";
79667
80098
  import { homedir as homedir38 } from "node:os";
79668
80099
  init_atomic();
79669
80100
  init_audit_reader();
@@ -79847,7 +80278,7 @@ function resolveRollbackTarget(auditLogPath) {
79847
80278
  const logPath = auditLogPath ?? defaultAuditLogPath2(homedir38());
79848
80279
  let raw;
79849
80280
  try {
79850
- raw = readFileSync54(logPath, "utf8");
80281
+ raw = readFileSync55(logPath, "utf8");
79851
80282
  } catch {
79852
80283
  return null;
79853
80284
  }
@@ -79959,7 +80390,7 @@ function registerRolloutCommand(program3) {
79959
80390
  log: (line) => process.stdout.write(line + `
79960
80391
  `),
79961
80392
  persistPin: (pin) => {
79962
- const before = readFileSync54(configPath, "utf8");
80393
+ const before = readFileSync55(configPath, "utf8");
79963
80394
  const after = setReleasePinInConfig(before, pin);
79964
80395
  if (after === before)
79965
80396
  return;
@@ -80024,15 +80455,15 @@ init_source();
80024
80455
  init_helpers();
80025
80456
  init_loader();
80026
80457
  init_lifecycle();
80027
- import { resolve as resolve36 } from "node:path";
80458
+ import { resolve as resolve37 } from "node:path";
80028
80459
 
80029
80460
  // src/cli/version.ts
80030
80461
  init_source();
80031
80462
  init_helpers();
80032
80463
  init_lifecycle();
80033
80464
  import { execSync as execSync4 } from "node:child_process";
80034
- import { existsSync as existsSync60, readFileSync as readFileSync55 } from "node:fs";
80035
- import { dirname as dirname17, join as join63 } from "node:path";
80465
+ import { existsSync as existsSync61, readFileSync as readFileSync56 } from "node:fs";
80466
+ import { dirname as dirname17, join as join64 } from "node:path";
80036
80467
  function getClaudeCodeVersion() {
80037
80468
  try {
80038
80469
  const out = execSync4("claude --version 2>/dev/null", {
@@ -80082,11 +80513,11 @@ function formatUptime3(timestamp) {
80082
80513
  function locateSwitchroomInstallDir() {
80083
80514
  let dir = import.meta.dirname;
80084
80515
  for (let i = 0;i < 10 && dir && dir !== "/"; i++) {
80085
- const pkgPath = join63(dir, "package.json");
80086
- if (existsSync60(pkgPath)) {
80516
+ const pkgPath = join64(dir, "package.json");
80517
+ if (existsSync61(pkgPath)) {
80087
80518
  try {
80088
- const pkg = JSON.parse(readFileSync55(pkgPath, "utf-8"));
80089
- if (pkg.name === "switchroom" && existsSync60(join63(dir, ".git"))) {
80519
+ const pkg = JSON.parse(readFileSync56(pkgPath, "utf-8"));
80520
+ if (pkg.name === "switchroom" && existsSync61(join64(dir, ".git"))) {
80090
80521
  return dir;
80091
80522
  }
80092
80523
  } catch {}
@@ -80179,7 +80610,7 @@ function registerRestartCommand(program3) {
80179
80610
  }
80180
80611
  const didRestart = res.restarted || !graceful;
80181
80612
  if (didRestart) {
80182
- const agentDir = resolve36(agentsDir, name);
80613
+ const agentDir = resolve37(agentsDir, name);
80183
80614
  const converged = waitForAuthConverge(name, agentDir);
80184
80615
  if (!converged) {
80185
80616
  console.log(source_default.yellow(` ${name}: agent is up but auth status didn't converge in 30s \u2014 check logs`));
@@ -80260,7 +80691,7 @@ Dependency manifest`));
80260
80691
  // src/cli/handoff.ts
80261
80692
  init_helpers();
80262
80693
  init_loader();
80263
- import { resolve as resolve37 } from "node:path";
80694
+ import { resolve as resolve38 } from "node:path";
80264
80695
  function registerHandoffCommand(program3) {
80265
80696
  program3.command("handoff <agent>", { hidden: true }).description("Build the agent's session handoff sidecars \u2014 a transcript-tail " + "briefing (.handoff.md) and topic line (.handoff-topic). " + "[internal \u2014 used by the Stop hook]").option("--max-turns <n>", "Max turns kept in the handoff transcript tail", String(DEFAULT_MAX_TURNS)).action(withConfigError(async (agentName, opts) => {
80266
80697
  let agentConfig;
@@ -80274,7 +80705,7 @@ function registerHandoffCommand(program3) {
80274
80705
  return;
80275
80706
  }
80276
80707
  const agentsDir = resolveAgentsDir(config);
80277
- agentDir = resolve37(agentsDir, agentName);
80708
+ agentDir = resolve38(agentsDir, agentName);
80278
80709
  } catch (err) {
80279
80710
  if (!(err instanceof ConfigError))
80280
80711
  throw err;
@@ -80289,7 +80720,7 @@ function registerHandoffCommand(program3) {
80289
80720
  `);
80290
80721
  return;
80291
80722
  }
80292
- const claudeConfigDir = resolve37(agentDir, ".claude");
80723
+ const claudeConfigDir = resolve38(agentDir, ".claude");
80293
80724
  const jsonl = findLatestSessionJsonl(claudeConfigDir);
80294
80725
  if (!jsonl) {
80295
80726
  process.stderr.write(`handoff: no session JSONL under ${claudeConfigDir}/projects; skipping
@@ -80312,18 +80743,18 @@ function registerHandoffCommand(program3) {
80312
80743
  // src/issues/store.ts
80313
80744
  import {
80314
80745
  closeSync as closeSync11,
80315
- existsSync as existsSync61,
80746
+ existsSync as existsSync62,
80316
80747
  mkdirSync as mkdirSync33,
80317
80748
  openSync as openSync11,
80318
80749
  readdirSync as readdirSync22,
80319
- readFileSync as readFileSync56,
80750
+ readFileSync as readFileSync57,
80320
80751
  renameSync as renameSync12,
80321
80752
  statSync as statSync29,
80322
80753
  unlinkSync as unlinkSync11,
80323
80754
  writeFileSync as writeFileSync28,
80324
80755
  writeSync as writeSync7
80325
80756
  } from "node:fs";
80326
- import { join as join64 } from "node:path";
80757
+ import { join as join65 } from "node:path";
80327
80758
  import { randomBytes as randomBytes12 } from "node:crypto";
80328
80759
  import { execSync as execSync5 } from "node:child_process";
80329
80760
 
@@ -80721,12 +81152,12 @@ function redactedMarker(ruleId) {
80721
81152
  var ISSUES_FILE = "issues.jsonl";
80722
81153
  var ISSUES_LOCK = "issues.lock";
80723
81154
  function readAll(stateDir) {
80724
- const path4 = join64(stateDir, ISSUES_FILE);
80725
- if (!existsSync61(path4))
81155
+ const path4 = join65(stateDir, ISSUES_FILE);
81156
+ if (!existsSync62(path4))
80726
81157
  return [];
80727
81158
  let raw;
80728
81159
  try {
80729
- raw = readFileSync56(path4, "utf-8");
81160
+ raw = readFileSync57(path4, "utf-8");
80730
81161
  } catch {
80731
81162
  return [];
80732
81163
  }
@@ -80798,8 +81229,8 @@ function record(stateDir, input, nowFn = Date.now) {
80798
81229
  return result;
80799
81230
  });
80800
81231
  }
80801
- function resolve38(stateDir, fingerprint, nowFn = Date.now) {
80802
- if (!existsSync61(join64(stateDir, ISSUES_FILE)))
81232
+ function resolve39(stateDir, fingerprint, nowFn = Date.now) {
81233
+ if (!existsSync62(join65(stateDir, ISSUES_FILE)))
80803
81234
  return 0;
80804
81235
  return withLock(stateDir, () => {
80805
81236
  const all = readAll(stateDir);
@@ -80817,7 +81248,7 @@ function resolve38(stateDir, fingerprint, nowFn = Date.now) {
80817
81248
  });
80818
81249
  }
80819
81250
  function resolveAllBySource(stateDir, source, nowFn = Date.now) {
80820
- if (!existsSync61(join64(stateDir, ISSUES_FILE)))
81251
+ if (!existsSync62(join65(stateDir, ISSUES_FILE)))
80821
81252
  return 0;
80822
81253
  return withLock(stateDir, () => {
80823
81254
  const all = readAll(stateDir);
@@ -80835,7 +81266,7 @@ function resolveAllBySource(stateDir, source, nowFn = Date.now) {
80835
81266
  });
80836
81267
  }
80837
81268
  function prune(stateDir, opts = {}) {
80838
- if (!existsSync61(join64(stateDir, ISSUES_FILE)))
81269
+ if (!existsSync62(join65(stateDir, ISSUES_FILE)))
80839
81270
  return 0;
80840
81271
  return withLock(stateDir, () => {
80841
81272
  const all = readAll(stateDir);
@@ -80868,7 +81299,7 @@ function ensureDir(stateDir) {
80868
81299
  mkdirSync33(stateDir, { recursive: true });
80869
81300
  }
80870
81301
  function writeAll(stateDir, events) {
80871
- const path4 = join64(stateDir, ISSUES_FILE);
81302
+ const path4 = join65(stateDir, ISSUES_FILE);
80872
81303
  sweepOrphanTmpFiles(stateDir);
80873
81304
  const tmp = `${path4}.tmp-${process.pid}-${randomBytes12(4).toString("hex")}`;
80874
81305
  const body = events.length === 0 ? "" : events.map((e) => JSON.stringify(e)).join(`
@@ -80890,7 +81321,7 @@ function sweepOrphanTmpFiles(stateDir) {
80890
81321
  for (const entry of entries) {
80891
81322
  if (!entry.startsWith(TMP_PREFIX))
80892
81323
  continue;
80893
- const tmpPath = join64(stateDir, entry);
81324
+ const tmpPath = join65(stateDir, entry);
80894
81325
  try {
80895
81326
  const stat = statSync29(tmpPath);
80896
81327
  if (stat.mtimeMs < cutoff) {
@@ -80902,7 +81333,7 @@ function sweepOrphanTmpFiles(stateDir) {
80902
81333
  var LOCK_RETRY_MS = 25;
80903
81334
  var LOCK_TIMEOUT_MS = 1e4;
80904
81335
  function withLock(stateDir, fn) {
80905
- const lockPath = join64(stateDir, ISSUES_LOCK);
81336
+ const lockPath = join65(stateDir, ISSUES_LOCK);
80906
81337
  const startedAt = Date.now();
80907
81338
  let fd = null;
80908
81339
  while (fd === null) {
@@ -80937,7 +81368,7 @@ function withLock(stateDir, fn) {
80937
81368
  function tryStealStaleLock(lockPath) {
80938
81369
  let pidStr;
80939
81370
  try {
80940
- pidStr = readFileSync56(lockPath, "utf-8").trim();
81371
+ pidStr = readFileSync57(lockPath, "utf-8").trim();
80941
81372
  } catch {
80942
81373
  return true;
80943
81374
  }
@@ -81086,11 +81517,11 @@ function registerIssuesCommand(program3) {
81086
81517
  const stateDir = resolveStateDir2(opts);
81087
81518
  let flipped;
81088
81519
  if (opts.source && opts.code) {
81089
- flipped = resolve38(stateDir, computeFingerprint(opts.source, opts.code));
81520
+ flipped = resolve39(stateDir, computeFingerprint(opts.source, opts.code));
81090
81521
  } else if (opts.source && !fingerprint) {
81091
81522
  flipped = resolveAllBySource(stateDir, opts.source);
81092
81523
  } else if (fingerprint) {
81093
- flipped = resolve38(stateDir, fingerprint);
81524
+ flipped = resolve39(stateDir, fingerprint);
81094
81525
  } else {
81095
81526
  process.stderr.write(`issues resolve: need either <fingerprint>, --source, or --source + --code
81096
81527
  `);
@@ -81185,20 +81616,20 @@ function relTime(deltaMs) {
81185
81616
 
81186
81617
  // src/cli/deps.ts
81187
81618
  init_source();
81188
- import { existsSync as existsSync64 } from "node:fs";
81619
+ import { existsSync as existsSync65 } from "node:fs";
81189
81620
  import { homedir as homedir41 } from "node:os";
81190
- import { join as join67, resolve as resolve39 } from "node:path";
81621
+ import { join as join68, resolve as resolve40 } from "node:path";
81191
81622
 
81192
81623
  // src/deps/python.ts
81193
- import { createHash as createHash11 } from "node:crypto";
81624
+ import { createHash as createHash12 } from "node:crypto";
81194
81625
  import {
81195
- existsSync as existsSync62,
81626
+ existsSync as existsSync63,
81196
81627
  mkdirSync as mkdirSync34,
81197
- readFileSync as readFileSync57,
81628
+ readFileSync as readFileSync58,
81198
81629
  rmSync as rmSync13,
81199
81630
  writeFileSync as writeFileSync29
81200
81631
  } from "node:fs";
81201
- import { dirname as dirname18, join as join65 } from "node:path";
81632
+ import { dirname as dirname18, join as join66 } from "node:path";
81202
81633
  import { homedir as homedir39 } from "node:os";
81203
81634
  import { execFileSync as execFileSync19 } from "node:child_process";
81204
81635
 
@@ -81211,26 +81642,26 @@ class PythonEnvError extends Error {
81211
81642
  }
81212
81643
  }
81213
81644
  function defaultPythonCacheRoot() {
81214
- return join65(homedir39(), ".switchroom", "deps", "python");
81645
+ return join66(homedir39(), ".switchroom", "deps", "python");
81215
81646
  }
81216
81647
  function hashFile(path4) {
81217
- return createHash11("sha256").update(readFileSync57(path4)).digest("hex");
81648
+ return createHash12("sha256").update(readFileSync58(path4)).digest("hex");
81218
81649
  }
81219
81650
  function ensurePythonEnv(opts) {
81220
81651
  const { skillName, requirementsPath, force = false } = opts;
81221
81652
  const cacheRoot = opts.cacheRoot ?? defaultPythonCacheRoot();
81222
81653
  const hostPython = opts.pythonBin ?? "python3";
81223
- if (!existsSync62(requirementsPath)) {
81654
+ if (!existsSync63(requirementsPath)) {
81224
81655
  throw new PythonEnvError(`requirements file not found: ${requirementsPath}`);
81225
81656
  }
81226
- const venvDir = join65(cacheRoot, skillName);
81227
- const stampPath = join65(venvDir, ".requirements.sha256");
81228
- const binDir = join65(venvDir, "bin");
81229
- const pythonBin = join65(binDir, "python");
81230
- const pipBin = join65(binDir, "pip");
81657
+ const venvDir = join66(cacheRoot, skillName);
81658
+ const stampPath = join66(venvDir, ".requirements.sha256");
81659
+ const binDir = join66(venvDir, "bin");
81660
+ const pythonBin = join66(binDir, "python");
81661
+ const pipBin = join66(binDir, "pip");
81231
81662
  const targetHash = hashFile(requirementsPath);
81232
- if (!force && existsSync62(stampPath) && existsSync62(pythonBin)) {
81233
- const existingHash = readFileSync57(stampPath, "utf8").trim();
81663
+ if (!force && existsSync63(stampPath) && existsSync63(pythonBin)) {
81664
+ const existingHash = readFileSync58(stampPath, "utf8").trim();
81234
81665
  if (existingHash === targetHash) {
81235
81666
  return {
81236
81667
  skillName,
@@ -81242,7 +81673,7 @@ function ensurePythonEnv(opts) {
81242
81673
  };
81243
81674
  }
81244
81675
  }
81245
- if (existsSync62(venvDir)) {
81676
+ if (existsSync63(venvDir)) {
81246
81677
  rmSync13(venvDir, { recursive: true, force: true });
81247
81678
  }
81248
81679
  mkdirSync34(dirname18(venvDir), { recursive: true });
@@ -81277,16 +81708,16 @@ function ensurePythonEnv(opts) {
81277
81708
  }
81278
81709
 
81279
81710
  // src/deps/node.ts
81280
- import { createHash as createHash12 } from "node:crypto";
81711
+ import { createHash as createHash13 } from "node:crypto";
81281
81712
  import {
81282
81713
  copyFileSync as copyFileSync9,
81283
- existsSync as existsSync63,
81714
+ existsSync as existsSync64,
81284
81715
  mkdirSync as mkdirSync35,
81285
- readFileSync as readFileSync58,
81716
+ readFileSync as readFileSync59,
81286
81717
  rmSync as rmSync14,
81287
81718
  writeFileSync as writeFileSync30
81288
81719
  } from "node:fs";
81289
- import { dirname as dirname19, join as join66 } from "node:path";
81720
+ import { dirname as dirname19, join as join67 } from "node:path";
81290
81721
  import { homedir as homedir40 } from "node:os";
81291
81722
  import { execFileSync as execFileSync20 } from "node:child_process";
81292
81723
 
@@ -81310,23 +81741,23 @@ var LOCKFILES_FOR = {
81310
81741
  npm: ["package-lock.json"]
81311
81742
  };
81312
81743
  function defaultNodeCacheRoot() {
81313
- return join66(homedir40(), ".switchroom", "deps", "node");
81744
+ return join67(homedir40(), ".switchroom", "deps", "node");
81314
81745
  }
81315
81746
  function hashDepInputs(packageJsonPath) {
81316
81747
  const sourceDir = dirname19(packageJsonPath);
81317
- const hasher = createHash12("sha256");
81748
+ const hasher = createHash13("sha256");
81318
81749
  hasher.update(`package.json
81319
81750
  `);
81320
- hasher.update(readFileSync58(packageJsonPath));
81751
+ hasher.update(readFileSync59(packageJsonPath));
81321
81752
  for (const lockName of ALL_LOCKFILES) {
81322
- const lockPath = join66(sourceDir, lockName);
81323
- if (existsSync63(lockPath)) {
81753
+ const lockPath = join67(sourceDir, lockName);
81754
+ if (existsSync64(lockPath)) {
81324
81755
  hasher.update(`
81325
81756
  `);
81326
81757
  hasher.update(lockName);
81327
81758
  hasher.update(`
81328
81759
  `);
81329
- hasher.update(readFileSync58(lockPath));
81760
+ hasher.update(readFileSync59(lockPath));
81330
81761
  }
81331
81762
  }
81332
81763
  return hasher.digest("hex");
@@ -81335,17 +81766,17 @@ function ensureNodeEnv(opts) {
81335
81766
  const { skillName, packageJsonPath, force = false } = opts;
81336
81767
  const cacheRoot = opts.cacheRoot ?? defaultNodeCacheRoot();
81337
81768
  const installer = opts.installer ?? "bun";
81338
- if (!existsSync63(packageJsonPath)) {
81769
+ if (!existsSync64(packageJsonPath)) {
81339
81770
  throw new NodeEnvError(`package.json not found: ${packageJsonPath}`);
81340
81771
  }
81341
81772
  const sourceDir = dirname19(packageJsonPath);
81342
- const envDir = join66(cacheRoot, skillName);
81343
- const stampPath = join66(envDir, ".package.sha256");
81344
- const nodeModulesDir = join66(envDir, "node_modules");
81345
- const binDir = join66(nodeModulesDir, ".bin");
81773
+ const envDir = join67(cacheRoot, skillName);
81774
+ const stampPath = join67(envDir, ".package.sha256");
81775
+ const nodeModulesDir = join67(envDir, "node_modules");
81776
+ const binDir = join67(nodeModulesDir, ".bin");
81346
81777
  const targetHash = hashDepInputs(packageJsonPath);
81347
- if (!force && existsSync63(stampPath) && existsSync63(nodeModulesDir)) {
81348
- const existingHash = readFileSync58(stampPath, "utf8").trim();
81778
+ if (!force && existsSync64(stampPath) && existsSync64(nodeModulesDir)) {
81779
+ const existingHash = readFileSync59(stampPath, "utf8").trim();
81349
81780
  if (existingHash === targetHash) {
81350
81781
  return {
81351
81782
  skillName,
@@ -81356,16 +81787,16 @@ function ensureNodeEnv(opts) {
81356
81787
  };
81357
81788
  }
81358
81789
  }
81359
- if (existsSync63(envDir)) {
81790
+ if (existsSync64(envDir)) {
81360
81791
  rmSync14(envDir, { recursive: true, force: true });
81361
81792
  }
81362
81793
  mkdirSync35(envDir, { recursive: true });
81363
- copyFileSync9(packageJsonPath, join66(envDir, "package.json"));
81794
+ copyFileSync9(packageJsonPath, join67(envDir, "package.json"));
81364
81795
  let copiedLockfile = false;
81365
81796
  for (const lockName of LOCKFILES_FOR[installer]) {
81366
- const lockPath = join66(sourceDir, lockName);
81367
- if (existsSync63(lockPath)) {
81368
- copyFileSync9(lockPath, join66(envDir, lockName));
81797
+ const lockPath = join67(sourceDir, lockName);
81798
+ if (existsSync64(lockPath)) {
81799
+ copyFileSync9(lockPath, join67(envDir, lockName));
81369
81800
  copiedLockfile = true;
81370
81801
  }
81371
81802
  }
@@ -81394,28 +81825,28 @@ function ensureNodeEnv(opts) {
81394
81825
 
81395
81826
  // src/cli/deps.ts
81396
81827
  function builtinSkillsRoot() {
81397
- return resolve39(homedir41(), ".switchroom/skills/_bundled");
81828
+ return resolve40(homedir41(), ".switchroom/skills/_bundled");
81398
81829
  }
81399
81830
  function registerDepsCommand(program3) {
81400
81831
  const deps = program3.command("deps").description("Manage cached per-skill dependency environments");
81401
81832
  deps.command("rebuild <skill>").description("Rebuild the Python venv and/or Node node_modules cache for a skill").option("-p, --python", "Rebuild only the Python env").option("-n, --node", "Rebuild only the Node env").action(async (skill, opts) => {
81402
81833
  const skillsRoot = builtinSkillsRoot();
81403
- if (!existsSync64(skillsRoot)) {
81834
+ if (!existsSync65(skillsRoot)) {
81404
81835
  console.error(source_default.red(`Bundled skills pool dir not found at ${skillsRoot} \u2014 run \`switchroom update\` to install it.`));
81405
81836
  process.exit(1);
81406
81837
  }
81407
- const skillDir = join67(skillsRoot, skill);
81408
- if (!existsSync64(skillDir)) {
81838
+ const skillDir = join68(skillsRoot, skill);
81839
+ if (!existsSync65(skillDir)) {
81409
81840
  console.error(source_default.red(`Unknown skill: ${skill} (no dir at ${skillDir})`));
81410
81841
  process.exit(1);
81411
81842
  }
81412
- const requirementsPath = join67(skillDir, "requirements.txt");
81413
- const packageJsonPath = join67(skillDir, "package.json");
81414
- const wantPython = opts.python ?? (!opts.python && !opts.node && existsSync64(requirementsPath));
81415
- const wantNode = opts.node ?? (!opts.python && !opts.node && existsSync64(packageJsonPath));
81843
+ const requirementsPath = join68(skillDir, "requirements.txt");
81844
+ const packageJsonPath = join68(skillDir, "package.json");
81845
+ const wantPython = opts.python ?? (!opts.python && !opts.node && existsSync65(requirementsPath));
81846
+ const wantNode = opts.node ?? (!opts.python && !opts.node && existsSync65(packageJsonPath));
81416
81847
  let did = 0;
81417
81848
  if (wantPython) {
81418
- if (!existsSync64(requirementsPath)) {
81849
+ if (!existsSync65(requirementsPath)) {
81419
81850
  console.error(source_default.red(`Skill "${skill}" has no requirements.txt at ${requirementsPath}`));
81420
81851
  process.exit(1);
81421
81852
  }
@@ -81439,7 +81870,7 @@ function registerDepsCommand(program3) {
81439
81870
  }
81440
81871
  }
81441
81872
  if (wantNode) {
81442
- if (!existsSync64(packageJsonPath)) {
81873
+ if (!existsSync65(packageJsonPath)) {
81443
81874
  console.error(source_default.red(`Skill "${skill}" has no package.json at ${packageJsonPath}`));
81444
81875
  process.exit(1);
81445
81876
  }
@@ -81472,8 +81903,8 @@ function registerDepsCommand(program3) {
81472
81903
  // src/cli/workspace.ts
81473
81904
  init_helpers();
81474
81905
  init_loader();
81475
- import { existsSync as existsSync65 } from "node:fs";
81476
- import { resolve as resolve40, sep as sep3 } from "node:path";
81906
+ import { existsSync as existsSync66 } from "node:fs";
81907
+ import { resolve as resolve41, sep as sep3 } from "node:path";
81477
81908
  import { spawnSync as spawnSync13 } from "node:child_process";
81478
81909
 
81479
81910
  // src/agents/workspace.ts
@@ -82179,8 +82610,8 @@ function registerWorkspaceCommand(program3) {
82179
82610
  const dir = resolveAgentWorkspaceDirOrExit(program3, agentName);
82180
82611
  if (!dir)
82181
82612
  return;
82182
- const resolvedWorkspace = resolve40(dir);
82183
- const target = resolve40(resolvedWorkspace, file ?? "AGENTS.md");
82613
+ const resolvedWorkspace = resolve41(dir);
82614
+ const target = resolve41(resolvedWorkspace, file ?? "AGENTS.md");
82184
82615
  if (!isInsideWorkspace(resolvedWorkspace, target)) {
82185
82616
  process.stderr.write(`workspace edit: refusing path traversal outside workspace dir (${target})
82186
82617
  `);
@@ -82248,8 +82679,8 @@ function registerWorkspaceCommand(program3) {
82248
82679
  const dir = resolveAgentWorkspaceDirOrExit(program3, agentName);
82249
82680
  if (!dir)
82250
82681
  return;
82251
- const gitDir = resolve40(dir, ".git");
82252
- if (!existsSync65(gitDir)) {
82682
+ const gitDir = resolve41(dir, ".git");
82683
+ if (!existsSync66(gitDir)) {
82253
82684
  process.stdout.write(`Workspace is not a git repository. Re-run \`switchroom agent create ${agentName}\` ` + `or manually \`git init\` in ${dir} to enable versioning.
82254
82685
  `);
82255
82686
  return;
@@ -82302,8 +82733,8 @@ function registerWorkspaceCommand(program3) {
82302
82733
  const dir = resolveAgentWorkspaceDirOrExit(program3, agentName);
82303
82734
  if (!dir)
82304
82735
  return;
82305
- const gitDir = resolve40(dir, ".git");
82306
- if (!existsSync65(gitDir)) {
82736
+ const gitDir = resolve41(dir, ".git");
82737
+ if (!existsSync66(gitDir)) {
82307
82738
  process.stdout.write(`Workspace is not a git repository.
82308
82739
  `);
82309
82740
  return;
@@ -82326,9 +82757,9 @@ function resolveAgentWorkspaceDirOrExit(program3, agentName) {
82326
82757
  return;
82327
82758
  }
82328
82759
  const agentsDir = resolveAgentsDir(config);
82329
- const agentDir = resolve40(agentsDir, agentName);
82760
+ const agentDir = resolve41(agentsDir, agentName);
82330
82761
  const dir = resolveAgentWorkspaceDir(agentDir);
82331
- if (!existsSync65(dir)) {
82762
+ if (!existsSync66(dir)) {
82332
82763
  process.stderr.write(`workspace: ${dir} does not exist yet. Run \`switchroom setup\` or \`switchroom agent scaffold ${agentName}\` to seed it.
82333
82764
  `);
82334
82765
  return;
@@ -82364,8 +82795,8 @@ function safeParseInt(value, fallback) {
82364
82795
  init_helpers();
82365
82796
  init_loader();
82366
82797
  init_merge();
82367
- import { copyFileSync as copyFileSync10, existsSync as existsSync66, readFileSync as readFileSync59, writeFileSync as writeFileSync31 } from "node:fs";
82368
- import { join as join68, resolve as resolve41 } from "node:path";
82798
+ import { copyFileSync as copyFileSync10, existsSync as existsSync67, readFileSync as readFileSync60, writeFileSync as writeFileSync31 } from "node:fs";
82799
+ import { join as join69, resolve as resolve42 } from "node:path";
82369
82800
  init_schema();
82370
82801
  function resolveSoulTargetOrExit(program3, agentName) {
82371
82802
  const config = getConfig(program3);
@@ -82378,9 +82809,9 @@ function resolveSoulTargetOrExit(program3, agentName) {
82378
82809
  const profileName = merged.extends ?? DEFAULT_PROFILE;
82379
82810
  const profilePath = getProfilePath(profileName);
82380
82811
  const agentsDir = resolveAgentsDir(config);
82381
- const agentDir = resolve41(agentsDir, agentName);
82812
+ const agentDir = resolve42(agentsDir, agentName);
82382
82813
  const workspaceDir = resolveAgentWorkspaceDir(agentDir);
82383
- if (!existsSync66(workspaceDir)) {
82814
+ if (!existsSync67(workspaceDir)) {
82384
82815
  console.error(`soul: ${workspaceDir} does not exist yet. Run \`switchroom setup\` ` + `or \`switchroom agent scaffold ${agentName}\` to seed it.`);
82385
82816
  process.exit(1);
82386
82817
  }
@@ -82389,7 +82820,7 @@ function resolveSoulTargetOrExit(program3, agentName) {
82389
82820
  profileName,
82390
82821
  profilePath,
82391
82822
  workspaceDir,
82392
- soulPath: join68(workspaceDir, "SOUL.md"),
82823
+ soulPath: join69(workspaceDir, "SOUL.md"),
82393
82824
  soul: merged.soul
82394
82825
  };
82395
82826
  }
@@ -82406,11 +82837,11 @@ function registerSoulCommand(program3) {
82406
82837
  const t = resolveSoulTargetOrExit(program3, agentName);
82407
82838
  if (!t)
82408
82839
  return;
82409
- if (!existsSync66(t.soulPath)) {
82840
+ if (!existsSync67(t.soulPath)) {
82410
82841
  console.error(`soul: ${t.soulPath} does not exist yet \u2014 run ` + `\`switchroom soul reset ${agentName}\` to seed it.`);
82411
82842
  process.exit(1);
82412
82843
  }
82413
- process.stdout.write(readFileSync59(t.soulPath, "utf-8"));
82844
+ process.stdout.write(readFileSync60(t.soulPath, "utf-8"));
82414
82845
  }));
82415
82846
  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) => {
82416
82847
  const t = resolveSoulTargetOrExit(program3, agentName);
@@ -82421,7 +82852,7 @@ function registerSoulCommand(program3) {
82421
82852
  console.error(`soul: profile "${t.profileName}" ships no SOUL.md.hbs \u2014 ` + `nothing to re-seed from.`);
82422
82853
  process.exit(1);
82423
82854
  }
82424
- const exists = existsSync66(t.soulPath);
82855
+ const exists = existsSync67(t.soulPath);
82425
82856
  if (exists && !opts.yes) {
82426
82857
  if (!isInteractive()) {
82427
82858
  console.error(`soul: ${t.soulPath} already exists. Re-run with --yes to ` + `replace it (the current file is backed up to SOUL.md.bak).`);
@@ -82436,7 +82867,7 @@ function registerSoulCommand(program3) {
82436
82867
  let backupPath;
82437
82868
  if (exists) {
82438
82869
  backupPath = `${t.soulPath}.bak`;
82439
- if (existsSync66(backupPath)) {
82870
+ if (existsSync67(backupPath)) {
82440
82871
  backupPath = `${t.soulPath}.bak.${Date.now()}`;
82441
82872
  }
82442
82873
  copyFileSync10(t.soulPath, backupPath);
@@ -82455,9 +82886,9 @@ function registerSoulCommand(program3) {
82455
82886
  // src/cli/debug.ts
82456
82887
  init_helpers();
82457
82888
  init_loader();
82458
- import { existsSync as existsSync67, readFileSync as readFileSync60, readdirSync as readdirSync23, statSync as statSync30 } from "node:fs";
82459
- import { resolve as resolve42, join as join69 } from "node:path";
82460
- import { createHash as createHash13 } from "node:crypto";
82889
+ import { existsSync as existsSync68, readFileSync as readFileSync61, readdirSync as readdirSync23, statSync as statSync30 } from "node:fs";
82890
+ import { resolve as resolve43, join as join70 } from "node:path";
82891
+ import { createHash as createHash14 } from "node:crypto";
82461
82892
  init_merge();
82462
82893
  init_hindsight();
82463
82894
  function formatBytes(bytes) {
@@ -82467,22 +82898,22 @@ function estimateTokens(bytes) {
82467
82898
  return Math.round(bytes / 3.7);
82468
82899
  }
82469
82900
  function readMcpServerNames(agentDir) {
82470
- const mcpPath = join69(agentDir, ".mcp.json");
82471
- if (!existsSync67(mcpPath))
82901
+ const mcpPath = join70(agentDir, ".mcp.json");
82902
+ if (!existsSync68(mcpPath))
82472
82903
  return [];
82473
82904
  try {
82474
- const parsed = JSON.parse(readFileSync60(mcpPath, "utf-8"));
82905
+ const parsed = JSON.parse(readFileSync61(mcpPath, "utf-8"));
82475
82906
  return Object.keys(parsed.mcpServers ?? {});
82476
82907
  } catch {
82477
82908
  return null;
82478
82909
  }
82479
82910
  }
82480
82911
  function sha256(content) {
82481
- return createHash13("sha256").update(content).digest("hex").slice(0, 16);
82912
+ return createHash14("sha256").update(content).digest("hex").slice(0, 16);
82482
82913
  }
82483
82914
  function findLatestTranscriptJsonl(claudeConfigDir) {
82484
- const projectsDir = join69(claudeConfigDir, "projects");
82485
- if (!existsSync67(projectsDir))
82915
+ const projectsDir = join70(claudeConfigDir, "projects");
82916
+ if (!existsSync68(projectsDir))
82486
82917
  return;
82487
82918
  try {
82488
82919
  const entries = readdirSync23(projectsDir, { withFileTypes: true });
@@ -82490,9 +82921,9 @@ function findLatestTranscriptJsonl(claudeConfigDir) {
82490
82921
  for (const entry of entries) {
82491
82922
  if (!entry.isDirectory())
82492
82923
  continue;
82493
- const projectPath = join69(projectsDir, entry.name);
82494
- const transcriptPath = join69(projectPath, "transcript.jsonl");
82495
- if (!existsSync67(transcriptPath))
82924
+ const projectPath = join70(projectsDir, entry.name);
82925
+ const transcriptPath = join70(projectPath, "transcript.jsonl");
82926
+ if (!existsSync68(transcriptPath))
82496
82927
  continue;
82497
82928
  const stat3 = statSync30(transcriptPath);
82498
82929
  if (!latest || stat3.mtimeMs > latest.mtime) {
@@ -82506,7 +82937,7 @@ function findLatestTranscriptJsonl(claudeConfigDir) {
82506
82937
  }
82507
82938
  function extractLatestUserMessage(transcriptPath) {
82508
82939
  try {
82509
- const content = readFileSync60(transcriptPath, "utf-8");
82940
+ const content = readFileSync61(transcriptPath, "utf-8");
82510
82941
  const lines = content.trim().split(`
82511
82942
  `).filter(Boolean);
82512
82943
  for (let i = lines.length - 1;i >= 0; i--) {
@@ -82554,17 +82985,17 @@ function registerDebugCommand(program3) {
82554
82985
  process.exit(1);
82555
82986
  }
82556
82987
  const agentsDir = resolveAgentsDir(config);
82557
- const agentDir = resolve42(agentsDir, agentName);
82558
- if (!existsSync67(agentDir)) {
82988
+ const agentDir = resolve43(agentsDir, agentName);
82989
+ if (!existsSync68(agentDir)) {
82559
82990
  console.error(`Agent directory not found: ${agentDir}`);
82560
82991
  process.exit(1);
82561
82992
  }
82562
82993
  const workspaceDir = resolveAgentWorkspaceDir(agentDir);
82563
- const claudeConfigDir = join69(agentDir, ".claude");
82564
- const claudeMdPath = join69(agentDir, "CLAUDE.md");
82565
- const soulMdPath = join69(agentDir, "SOUL.md");
82566
- const workspaceSoulMdPath = join69(workspaceDir, "SOUL.md");
82567
- const handoffPath = join69(agentDir, ".handoff.md");
82994
+ const claudeConfigDir = join70(agentDir, ".claude");
82995
+ const claudeMdPath = join70(agentDir, "CLAUDE.md");
82996
+ const soulMdPath = join70(agentDir, "SOUL.md");
82997
+ const workspaceSoulMdPath = join70(workspaceDir, "SOUL.md");
82998
+ const handoffPath = join70(agentDir, ".handoff.md");
82568
82999
  const lastN = parseInt(opts.last, 10);
82569
83000
  if (isNaN(lastN) || lastN < 1) {
82570
83001
  console.error("--last must be a positive integer");
@@ -82610,7 +83041,7 @@ function registerDebugCommand(program3) {
82610
83041
  }
82611
83042
  console.log(`=== Append System Prompt (per-session) ===
82612
83043
  `);
82613
- const handoffContent = existsSync67(handoffPath) ? readFileSync60(handoffPath, "utf-8") : "";
83044
+ const handoffContent = existsSync68(handoffPath) ? readFileSync61(handoffPath, "utf-8") : "";
82614
83045
  if (handoffContent.trim().length > 0) {
82615
83046
  console.log(`-- Handoff Briefing (${formatBytes(handoffContent.length)}) --`);
82616
83047
  console.log(handoffContent);
@@ -82621,7 +83052,7 @@ function registerDebugCommand(program3) {
82621
83052
  }
82622
83053
  console.log(`=== CLAUDE.md (auto-loaded by Claude Code) ===
82623
83054
  `);
82624
- const claudeMdContent = existsSync67(claudeMdPath) ? readFileSync60(claudeMdPath, "utf-8") : "";
83055
+ const claudeMdContent = existsSync68(claudeMdPath) ? readFileSync61(claudeMdPath, "utf-8") : "";
82625
83056
  if (claudeMdContent.trim().length > 0) {
82626
83057
  console.log(`(${formatBytes(claudeMdContent.length)})`);
82627
83058
  console.log(claudeMdContent);
@@ -82632,7 +83063,7 @@ function registerDebugCommand(program3) {
82632
83063
  }
82633
83064
  console.log(`=== Persona (SOUL.md) ===
82634
83065
  `);
82635
- const soulMdContent = existsSync67(soulMdPath) ? readFileSync60(soulMdPath, "utf-8") : existsSync67(workspaceSoulMdPath) ? readFileSync60(workspaceSoulMdPath, "utf-8") : "";
83066
+ const soulMdContent = existsSync68(soulMdPath) ? readFileSync61(soulMdPath, "utf-8") : existsSync68(workspaceSoulMdPath) ? readFileSync61(workspaceSoulMdPath, "utf-8") : "";
82636
83067
  if (soulMdContent.trim().length > 0) {
82637
83068
  console.log(`(${formatBytes(soulMdContent.length)})`);
82638
83069
  console.log(soulMdContent);
@@ -82693,11 +83124,11 @@ function registerDebugCommand(program3) {
82693
83124
  const soulMdBytes = soulMdContent.length;
82694
83125
  const perTurnBytes = dynamicResult.concatenated.length;
82695
83126
  const userBytes = userMessage?.text.length ?? 0;
82696
- const fleetDir = join69(agentsDir, "..", "fleet");
82697
- const fleetInvPath = join69(fleetDir, "switchroom-invariants.md");
82698
- const fleetClaudePath = join69(fleetDir, "CLAUDE.md");
82699
- const fleetInvBytes = existsSync67(fleetInvPath) ? readFileSync60(fleetInvPath, "utf-8").length : 0;
82700
- const fleetClaudeBytes = existsSync67(fleetClaudePath) ? readFileSync60(fleetClaudePath, "utf-8").length : 0;
83127
+ const fleetDir = join70(agentsDir, "..", "fleet");
83128
+ const fleetInvPath = join70(fleetDir, "switchroom-invariants.md");
83129
+ const fleetClaudePath = join70(fleetDir, "CLAUDE.md");
83130
+ const fleetInvBytes = existsSync68(fleetInvPath) ? readFileSync61(fleetInvPath, "utf-8").length : 0;
83131
+ const fleetClaudeBytes = existsSync68(fleetClaudePath) ? readFileSync61(fleetClaudePath, "utf-8").length : 0;
82701
83132
  const fleetBytes = fleetInvBytes + fleetClaudeBytes;
82702
83133
  const totalBytes = stableBytes + perSessionBytes + claudeMdBytes + fleetBytes + perTurnBytes + userBytes;
82703
83134
  console.log(`Stable prefix: ${formatBytes(stableBytes).padEnd(20)} (cache-hot; includes SOUL.md ${soulMdBytes.toLocaleString()}B)`);
@@ -82730,8 +83161,8 @@ init_source();
82730
83161
 
82731
83162
  // src/worktree/claim.ts
82732
83163
  import { execFileSync as execFileSync21 } from "node:child_process";
82733
- import { closeSync as closeSync12, mkdirSync as mkdirSync37, openSync as openSync12, existsSync as existsSync69, unlinkSync as unlinkSync13 } from "node:fs";
82734
- import { join as join71, resolve as resolve44 } from "node:path";
83164
+ import { closeSync as closeSync12, mkdirSync as mkdirSync37, openSync as openSync12, existsSync as existsSync70, unlinkSync as unlinkSync13 } from "node:fs";
83165
+ import { join as join72, resolve as resolve45 } from "node:path";
82735
83166
  import { homedir as homedir43 } from "node:os";
82736
83167
  import { randomBytes as randomBytes13 } from "node:crypto";
82737
83168
 
@@ -82739,19 +83170,19 @@ import { randomBytes as randomBytes13 } from "node:crypto";
82739
83170
  import {
82740
83171
  mkdirSync as mkdirSync36,
82741
83172
  writeFileSync as writeFileSync32,
82742
- readFileSync as readFileSync61,
83173
+ readFileSync as readFileSync62,
82743
83174
  readdirSync as readdirSync24,
82744
83175
  unlinkSync as unlinkSync12,
82745
- existsSync as existsSync68,
83176
+ existsSync as existsSync69,
82746
83177
  renameSync as renameSync13
82747
83178
  } from "node:fs";
82748
- import { join as join70, resolve as resolve43 } from "node:path";
83179
+ import { join as join71, resolve as resolve44 } from "node:path";
82749
83180
  import { homedir as homedir42 } from "node:os";
82750
83181
  function registryDir() {
82751
- return resolve43(process.env.SWITCHROOM_WORKTREE_DIR ?? join70(homedir42(), ".switchroom", "worktrees"));
83182
+ return resolve44(process.env.SWITCHROOM_WORKTREE_DIR ?? join71(homedir42(), ".switchroom", "worktrees"));
82752
83183
  }
82753
83184
  function recordPath(id) {
82754
- return join70(registryDir(), `${id}.json`);
83185
+ return join71(registryDir(), `${id}.json`);
82755
83186
  }
82756
83187
  function ensureDir2() {
82757
83188
  mkdirSync36(registryDir(), { recursive: true });
@@ -82767,7 +83198,7 @@ function writeRecord(record2) {
82767
83198
  function readRecord(id) {
82768
83199
  const path7 = recordPath(id);
82769
83200
  try {
82770
- const raw = readFileSync61(path7, "utf8");
83201
+ const raw = readFileSync62(path7, "utf8");
82771
83202
  return JSON.parse(raw);
82772
83203
  } catch {
82773
83204
  return null;
@@ -82802,7 +83233,7 @@ function acquireRepoLock(repoPath) {
82802
83233
  const lockDir = registryDir();
82803
83234
  mkdirSync37(lockDir, { recursive: true });
82804
83235
  const lockName = repoPath.replace(/[^A-Za-z0-9]/g, "_");
82805
- const lockPath = join71(lockDir, `.lock-${lockName}`);
83236
+ const lockPath = join72(lockDir, `.lock-${lockName}`);
82806
83237
  const deadline = Date.now() + 5000;
82807
83238
  let fd = null;
82808
83239
  while (fd === null) {
@@ -82829,7 +83260,7 @@ function acquireRepoLock(repoPath) {
82829
83260
  }
82830
83261
  var DEFAULT_CONCURRENCY = 5;
82831
83262
  function worktreesBaseDir() {
82832
- return resolve44(process.env.SWITCHROOM_WORKTREE_BASE ?? join71(homedir43(), ".switchroom", "worktree-checkouts"));
83263
+ return resolve45(process.env.SWITCHROOM_WORKTREE_BASE ?? join72(homedir43(), ".switchroom", "worktree-checkouts"));
82833
83264
  }
82834
83265
  function shortId() {
82835
83266
  return randomBytes13(4).toString("hex");
@@ -82851,12 +83282,12 @@ function resolveRepoPath(repo, codeRepos) {
82851
83282
  }
82852
83283
  function expandHome(p) {
82853
83284
  if (p.startsWith("~/"))
82854
- return join71(homedir43(), p.slice(2));
83285
+ return join72(homedir43(), p.slice(2));
82855
83286
  return p;
82856
83287
  }
82857
83288
  async function claimWorktree(input, codeRepos) {
82858
83289
  const repoPath = resolveRepoPath(input.repo, codeRepos);
82859
- if (!existsSync69(repoPath)) {
83290
+ if (!existsSync70(repoPath)) {
82860
83291
  throw new Error(`Repository path does not exist: ${repoPath}`);
82861
83292
  }
82862
83293
  let concurrencyCap = DEFAULT_CONCURRENCY;
@@ -82879,7 +83310,7 @@ async function claimWorktree(input, codeRepos) {
82879
83310
  branch = `task/${taskSuffix}-${id}`;
82880
83311
  const baseDir = worktreesBaseDir();
82881
83312
  mkdirSync37(baseDir, { recursive: true });
82882
- worktreePath = join71(baseDir, `${id}-${taskSuffix}`);
83313
+ worktreePath = join72(baseDir, `${id}-${taskSuffix}`);
82883
83314
  const now = new Date().toISOString();
82884
83315
  const record2 = {
82885
83316
  id,
@@ -82910,7 +83341,7 @@ async function claimWorktree(input, codeRepos) {
82910
83341
 
82911
83342
  // src/worktree/release.ts
82912
83343
  import { execFileSync as execFileSync22 } from "node:child_process";
82913
- import { existsSync as existsSync70 } from "node:fs";
83344
+ import { existsSync as existsSync71 } from "node:fs";
82914
83345
  function releaseWorktree(input) {
82915
83346
  const { id } = input;
82916
83347
  const record2 = readRecord(id);
@@ -82918,7 +83349,7 @@ function releaseWorktree(input) {
82918
83349
  return { released: true };
82919
83350
  }
82920
83351
  let gitSuccess = true;
82921
- if (existsSync70(record2.path)) {
83352
+ if (existsSync71(record2.path)) {
82922
83353
  try {
82923
83354
  execFileSync22("git", ["worktree", "remove", "--force", record2.path], {
82924
83355
  cwd: record2.repo,
@@ -82957,7 +83388,7 @@ function listWorktrees() {
82957
83388
 
82958
83389
  // src/worktree/reaper.ts
82959
83390
  import { execFileSync as execFileSync23 } from "node:child_process";
82960
- import { existsSync as existsSync71 } from "node:fs";
83391
+ import { existsSync as existsSync72 } from "node:fs";
82961
83392
  var STALE_THRESHOLD_MS = 10 * 60 * 1000;
82962
83393
  function isPathInUse(path7) {
82963
83394
  try {
@@ -82984,7 +83415,7 @@ function hasUncommittedChanges(repoPath, worktreePath) {
82984
83415
  function reapRecord(record2) {
82985
83416
  const { id, path: path7, repo, branch, ownerAgent } = record2;
82986
83417
  let warning = null;
82987
- if (existsSync71(path7)) {
83418
+ if (existsSync72(path7)) {
82988
83419
  if (hasUncommittedChanges(repo, path7)) {
82989
83420
  warning = `[worktree-reaper] Reaped worktree with uncommitted changes: ` + `id=${id} branch=${branch} agent=${ownerAgent ?? "unknown"} path=${path7}`;
82990
83421
  }
@@ -83005,7 +83436,7 @@ function runReaper(nowMs) {
83005
83436
  const warnings = [];
83006
83437
  for (const record2 of records) {
83007
83438
  const heartbeatAge = now - new Date(record2.heartbeatAt).getTime();
83008
- const worktreeExists = existsSync71(record2.path);
83439
+ const worktreeExists = existsSync72(record2.path);
83009
83440
  if (!worktreeExists) {
83010
83441
  deleteRecord(record2.id);
83011
83442
  reaped.push(record2.id);
@@ -83025,8 +83456,8 @@ function runReaper(nowMs) {
83025
83456
  // src/worktree/gc.ts
83026
83457
  import { execFileSync as execFileSync24 } from "node:child_process";
83027
83458
  import {
83028
- existsSync as existsSync72,
83029
- readFileSync as readFileSync62,
83459
+ existsSync as existsSync73,
83460
+ readFileSync as readFileSync63,
83030
83461
  readdirSync as readdirSync25,
83031
83462
  statSync as statSync31,
83032
83463
  renameSync as renameSync14,
@@ -83034,7 +83465,7 @@ import {
83034
83465
  rmSync as rmSync15
83035
83466
  } from "node:fs";
83036
83467
  import { homedir as homedir44 } from "node:os";
83037
- import { join as join72, resolve as resolve45 } from "node:path";
83468
+ import { join as join73, resolve as resolve46 } from "node:path";
83038
83469
  function parseGitdirPointer(dotGitFileContents) {
83039
83470
  const m = /^gitdir:\s*(.+?)\s*$/m.exec(dotGitFileContents);
83040
83471
  return m ? m[1] : null;
@@ -83109,7 +83540,7 @@ function looksLikeAgentWorktree(path7, branch) {
83109
83540
  return false;
83110
83541
  }
83111
83542
  function isEphemeralPath(path7) {
83112
- const p = resolve45(path7);
83543
+ const p = resolve46(path7);
83113
83544
  for (const root of ["/tmp", "/host", "/state"]) {
83114
83545
  if (p === root || p.startsWith(root + "/"))
83115
83546
  return true;
@@ -83149,20 +83580,20 @@ function defaultPrSignal(repo, branch, exec) {
83149
83580
  }
83150
83581
  }
83151
83582
  function trashRoot() {
83152
- return resolve45(process.env.SWITCHROOM_WORKTREE_TRASH ?? join72(homedir44(), ".switchroom", "worktree-gc-trash"));
83583
+ return resolve46(process.env.SWITCHROOM_WORKTREE_TRASH ?? join73(homedir44(), ".switchroom", "worktree-gc-trash"));
83153
83584
  }
83154
83585
  function planGc(roots, deps = {}) {
83155
- const exists = deps.existsSync ?? existsSync72;
83586
+ const exists = deps.existsSync ?? existsSync73;
83156
83587
  const readDir = deps.readDir ?? ((p) => readdirSync25(p));
83157
- const readFile4 = deps.readFile ?? ((p) => readFileSync62(p, "utf8"));
83588
+ const readFile4 = deps.readFile ?? ((p) => readFileSync63(p, "utf8"));
83158
83589
  const stat3 = deps.stat ?? ((p) => statSync31(p));
83159
83590
  const exec = deps.exec ?? defaultExec;
83160
83591
  const prSignal = deps.prSignal ?? ((repo, branch) => defaultPrSignal(repo, branch, exec));
83161
83592
  const stamp = deps.dateStamp ?? "undated";
83162
- const trash = join72(trashRoot(), stamp);
83593
+ const trash = join73(trashRoot(), stamp);
83163
83594
  let claimed;
83164
83595
  try {
83165
- claimed = new Set(listRecords().map((r) => resolve45(r.path)));
83596
+ claimed = new Set(listRecords().map((r) => resolve46(r.path)));
83166
83597
  } catch {
83167
83598
  claimed = new Set;
83168
83599
  }
@@ -83195,10 +83626,10 @@ function planGc(roots, deps = {}) {
83195
83626
  continue;
83196
83627
  }
83197
83628
  for (const name of entries) {
83198
- const dir = join72(root, name);
83629
+ const dir = join73(root, name);
83199
83630
  if (isEphemeralPath(dir))
83200
83631
  continue;
83201
- const dotGit = join72(dir, ".git");
83632
+ const dotGit = join73(dir, ".git");
83202
83633
  if (!exists(dotGit))
83203
83634
  continue;
83204
83635
  let st;
@@ -83227,7 +83658,7 @@ function planGc(roots, deps = {}) {
83227
83658
  ownerRepos.add(repoRoot);
83228
83659
  if (exists(ptr))
83229
83660
  continue;
83230
- orphans.push({ dir, owner: repoRoot, dest: join72(trash, name) });
83661
+ orphans.push({ dir, owner: repoRoot, dest: join73(trash, name) });
83231
83662
  }
83232
83663
  }
83233
83664
  const registered = [];
@@ -83240,8 +83671,8 @@ function planGc(roots, deps = {}) {
83240
83671
  continue;
83241
83672
  }
83242
83673
  for (const wt of parseWorktreeList(porcelain)) {
83243
- const wtPath = resolve45(wt.path);
83244
- const isMain = wtPath === resolve45(repo);
83674
+ const wtPath = resolve46(wt.path);
83675
+ const isMain = wtPath === resolve46(repo);
83245
83676
  const claimedWt = claimed.has(wtPath);
83246
83677
  const agentWt = looksLikeAgentWorktree(wt.path, wt.branch);
83247
83678
  const ephemeral = isEphemeralPath(wt.path);
@@ -83331,14 +83762,14 @@ function selectPurgeTargets(entries, olderThanDays) {
83331
83762
  return entries.filter((e) => e.ageDays >= olderThanDays).map((e) => e.path);
83332
83763
  }
83333
83764
  function listTrashEntries(nowMs, deps = {}) {
83334
- const exists = deps.existsSync ?? existsSync72;
83765
+ const exists = deps.existsSync ?? existsSync73;
83335
83766
  const readDir = deps.readDir ?? ((p) => readdirSync25(p));
83336
83767
  const root = trashRoot();
83337
83768
  if (!exists(root))
83338
83769
  return [];
83339
83770
  const out = [];
83340
83771
  for (const stamp of readDir(root)) {
83341
- const stampDir = join72(root, stamp);
83772
+ const stampDir = join73(root, stamp);
83342
83773
  let names;
83343
83774
  try {
83344
83775
  names = readDir(stampDir);
@@ -83346,7 +83777,7 @@ function listTrashEntries(nowMs, deps = {}) {
83346
83777
  continue;
83347
83778
  }
83348
83779
  for (const name of names) {
83349
- const p = join72(stampDir, name);
83780
+ const p = join73(stampDir, name);
83350
83781
  let mtimeMs = nowMs;
83351
83782
  try {
83352
83783
  mtimeMs = statSync31(p).mtimeMs;
@@ -83370,7 +83801,7 @@ function purgeTrash(paths) {
83370
83801
  return { deleted, errors: errors2 };
83371
83802
  }
83372
83803
  function defaultRoots() {
83373
- return [join72(homedir44(), "code")];
83804
+ return [join73(homedir44(), "code")];
83374
83805
  }
83375
83806
 
83376
83807
  // src/cli/worktree.ts
@@ -83564,7 +83995,7 @@ import {
83564
83995
  rmSync as rmSync16,
83565
83996
  writeFileSync as writeFileSync33
83566
83997
  } from "node:fs";
83567
- import { join as join73 } from "node:path";
83998
+ import { join as join74 } from "node:path";
83568
83999
  function encodeCredentialsFilename(email) {
83569
84000
  const SAFE = new Set([
83570
84001
  ..."ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
@@ -83754,16 +84185,16 @@ function resolveCredentialsDir(env2) {
83754
84185
  if (explicit && explicit.length > 0)
83755
84186
  return explicit;
83756
84187
  const stateBase = env2.SWITCHROOM_CONTAINER === "1" ? "/state/agent" : env2.HOME ?? ".";
83757
- return join73(stateBase, "google-workspace-mcp", "credentials");
84188
+ return join74(stateBase, "google-workspace-mcp", "credentials");
83758
84189
  }
83759
84190
  function writeSeedFile(dir, email, seed) {
83760
84191
  mkdirSync39(dir, { recursive: true, mode: 448 });
83761
84192
  chmodSync9(dir, 448);
83762
84193
  for (const name of readdirSync26(dir)) {
83763
- rmSync16(join73(dir, name), { force: true, recursive: true });
84194
+ rmSync16(join74(dir, name), { force: true, recursive: true });
83764
84195
  }
83765
84196
  const filename = encodeCredentialsFilename(email);
83766
- const filePath = join73(dir, filename);
84197
+ const filePath = join74(dir, filename);
83767
84198
  writeFileSync33(filePath, JSON.stringify(seed), { mode: 384 });
83768
84199
  chmodSync9(filePath, 384);
83769
84200
  return filePath;
@@ -83923,7 +84354,7 @@ function registerDriveMcpLauncherCommand(program3) {
83923
84354
  init_scaffold_integration();
83924
84355
  import { spawn as spawn5 } from "node:child_process";
83925
84356
  import { writeFileSync as writeFileSync34, mkdirSync as mkdirSync40 } from "node:fs";
83926
- import { dirname as dirname20, join as join74 } from "node:path";
84357
+ import { dirname as dirname20, join as join75 } from "node:path";
83927
84358
  var SOFTERIA_TOKEN_ENV = "MS365_MCP_OAUTH_TOKEN";
83928
84359
  var DEFAULT_REFRESH_LEAD_MS = 5 * 60 * 1000;
83929
84360
  var MAX_REFRESH_INTERVAL_MS = 60 * 60 * 1000;
@@ -83955,7 +84386,7 @@ function writeRefreshHeartbeat(agentName, data) {
83955
84386
  function heartbeatPath(agentName) {
83956
84387
  const override = process.env.SWITCHROOM_M365_HEARTBEAT_DIR;
83957
84388
  if (override) {
83958
- return join74(override, `m365-launcher-${agentName}.heartbeat.json`);
84389
+ return join75(override, `m365-launcher-${agentName}.heartbeat.json`);
83959
84390
  }
83960
84391
  return "/state/agent/m365-launcher.heartbeat.json";
83961
84392
  }
@@ -83979,20 +84410,20 @@ function wireStdio(child) {
83979
84410
  async function killChild(child, gracefulMs = 3000) {
83980
84411
  if (child.exitCode !== null || child.signalCode !== null)
83981
84412
  return;
83982
- return new Promise((resolve46) => {
84413
+ return new Promise((resolve47) => {
83983
84414
  let killTimer = null;
83984
84415
  const onExit = () => {
83985
84416
  if (killTimer) {
83986
84417
  clearTimeout(killTimer);
83987
84418
  killTimer = null;
83988
84419
  }
83989
- resolve46();
84420
+ resolve47();
83990
84421
  };
83991
84422
  child.once("exit", onExit);
83992
84423
  try {
83993
84424
  child.kill("SIGTERM");
83994
84425
  } catch {
83995
- resolve46();
84426
+ resolve47();
83996
84427
  return;
83997
84428
  }
83998
84429
  killTimer = setTimeout(() => {
@@ -84106,8 +84537,8 @@ async function runMs365McpLauncher(opts, rt) {
84106
84537
  };
84107
84538
  process.on("SIGINT", onSignal);
84108
84539
  process.on("SIGTERM", onSignal);
84109
- return new Promise((resolve46) => {
84110
- resolveLauncher = resolve46;
84540
+ return new Promise((resolve47) => {
84541
+ resolveLauncher = resolve47;
84111
84542
  });
84112
84543
  }
84113
84544
  function registerM365McpLauncherCommand(program3) {
@@ -84140,7 +84571,7 @@ function registerM365McpLauncherCommand(program3) {
84140
84571
  // src/cli/notion-mcp-launcher.ts
84141
84572
  init_scaffold_integration();
84142
84573
  import { spawn as spawn6 } from "node:child_process";
84143
- import { existsSync as existsSync73, mkdirSync as mkdirSync41, writeFileSync as writeFileSync35 } from "node:fs";
84574
+ import { existsSync as existsSync74, mkdirSync as mkdirSync41, writeFileSync as writeFileSync35 } from "node:fs";
84144
84575
  import { dirname as dirname21 } from "node:path";
84145
84576
  var HEARTBEAT_WRITE_INTERVAL_MS = 30 * 1000;
84146
84577
  var DEFAULT_HEARTBEAT_PATH = "/state/agent/notion-launcher.heartbeat.json";
@@ -84152,7 +84583,7 @@ function buildNotionMcpArgs(opts) {
84152
84583
  function defaultWriteHeartbeat(path7, contents) {
84153
84584
  try {
84154
84585
  const dir = dirname21(path7);
84155
- if (!existsSync73(dir))
84586
+ if (!existsSync74(dir))
84156
84587
  mkdirSync41(dir, { recursive: true });
84157
84588
  writeFileSync35(path7, contents);
84158
84589
  } catch {}
@@ -84209,23 +84640,23 @@ async function runNotionMcpLauncher(opts, runtime) {
84209
84640
  };
84210
84641
  process.on("SIGTERM", () => forward("SIGTERM"));
84211
84642
  process.on("SIGINT", () => forward("SIGINT"));
84212
- const exitCode = await new Promise((resolve46) => {
84643
+ const exitCode = await new Promise((resolve47) => {
84213
84644
  child.once("exit", (code, signal) => {
84214
84645
  clearTimer(heartbeatHandle);
84215
84646
  if (typeof code === "number") {
84216
- resolve46(code);
84647
+ resolve47(code);
84217
84648
  } else if (signal) {
84218
84649
  const sigCode = { SIGTERM: 15, SIGINT: 2, SIGKILL: 9 }[signal] ?? 1;
84219
- resolve46(128 + sigCode);
84650
+ resolve47(128 + sigCode);
84220
84651
  } else {
84221
- resolve46(1);
84652
+ resolve47(1);
84222
84653
  }
84223
84654
  });
84224
84655
  child.once("error", (err) => {
84225
84656
  clearTimer(heartbeatHandle);
84226
84657
  process.stderr.write(`notion-mcp-launcher: child spawn error: ${err.message}
84227
84658
  `);
84228
- resolve46(1);
84659
+ resolve47(1);
84229
84660
  });
84230
84661
  });
84231
84662
  return exitCode;
@@ -84264,7 +84695,7 @@ function registerNotionMcpLauncherCommand(program3) {
84264
84695
 
84265
84696
  // src/cli/deliver-file.ts
84266
84697
  init_client2();
84267
- import { readFileSync as readFileSync63, statSync as statSync32 } from "node:fs";
84698
+ import { readFileSync as readFileSync64, statSync as statSync32 } from "node:fs";
84268
84699
  import { basename as basename10 } from "node:path";
84269
84700
 
84270
84701
  // src/delivery/onedrive.ts
@@ -84604,7 +85035,7 @@ async function defaultResolveProvider() {
84604
85035
  async function runDeliverFile(localPath, deps = {}) {
84605
85036
  const agentName = safeAgentName(deps.agentName ?? process.env.SWITCHROOM_AGENT_NAME);
84606
85037
  const sizeOf = deps.fileSize ?? ((p) => statSync32(p).size);
84607
- const read = deps.readFile ?? ((p) => new Uint8Array(readFileSync63(p)));
85038
+ const read = deps.readFile ?? ((p) => new Uint8Array(readFileSync64(p)));
84608
85039
  const resolveProvider = deps.resolveProvider ?? defaultResolveProvider;
84609
85040
  let size;
84610
85041
  try {
@@ -84894,7 +85325,7 @@ async function fetchToken(vaultKey) {
84894
85325
 
84895
85326
  // src/cli/apply.ts
84896
85327
  init_source();
84897
- import { accessSync as accessSync3, chownSync as chownSync7, constants as fsConstants6, copyFileSync as copyFileSync11, existsSync as existsSync76, mkdirSync as mkdirSync44, readFileSync as readFileSync65, readdirSync as readdirSync27, renameSync as renameSync15, writeFileSync as writeFileSync38 } from "node:fs";
85328
+ import { accessSync as accessSync3, chownSync as chownSync7, constants as fsConstants6, copyFileSync as copyFileSync11, existsSync as existsSync77, mkdirSync as mkdirSync44, readFileSync as readFileSync66, readdirSync as readdirSync27, renameSync as renameSync15, writeFileSync as writeFileSync38 } from "node:fs";
84898
85329
  import { mkdir as mkdir2 } from "node:fs/promises";
84899
85330
  import { spawnSync as childSpawnSync } from "node:child_process";
84900
85331
  import readline from "node:readline";
@@ -85286,7 +85717,7 @@ agents:
85286
85717
  // src/cli/apply.ts
85287
85718
  init_resolver();
85288
85719
  init_merge();
85289
- import { dirname as dirname24, join as join78, resolve as resolve47 } from "node:path";
85720
+ import { dirname as dirname24, join as join79, resolve as resolve48 } from "node:path";
85290
85721
  import { homedir as homedir46 } from "node:os";
85291
85722
  import { execFileSync as execFileSync25 } from "node:child_process";
85292
85723
  init_vault();
@@ -85295,7 +85726,7 @@ init_loader();
85295
85726
 
85296
85727
  // src/agents/connection-health.ts
85297
85728
  import { mkdirSync as mkdirSync42, writeFileSync as writeFileSync36 } from "node:fs";
85298
- import { join as join75 } from "node:path";
85729
+ import { join as join76 } from "node:path";
85299
85730
  var CONNECTION_HEALTH_FILENAME = "connection-health.json";
85300
85731
  async function computeAgentConnectionIssues(config, agentName, vaultAclReader) {
85301
85732
  const reqs = computeMcpSecretRequirements(config).filter((r) => r.agent === agentName);
@@ -85353,8 +85784,8 @@ async function computeAgentConnectionIssues(config, agentName, vaultAclReader) {
85353
85784
  return issues;
85354
85785
  }
85355
85786
  function writeConnectionHealthFile(agentDir, health, deps) {
85356
- const dir = join75(agentDir, ".claude");
85357
- const path7 = join75(dir, CONNECTION_HEALTH_FILENAME);
85787
+ const dir = join76(agentDir, ".claude");
85788
+ const path7 = join76(dir, CONNECTION_HEALTH_FILENAME);
85358
85789
  (deps?.mkdir ?? ((p, o) => mkdirSync42(p, o)))(dir, { recursive: true });
85359
85790
  (deps?.writeFile ?? ((p, d) => writeFileSync36(p, d)))(path7, JSON.stringify(health, null, 2) + `
85360
85791
  `);
@@ -85375,12 +85806,12 @@ async function refreshAgentConnectionHealth(config, agentName, agentDir, deps) {
85375
85806
  }
85376
85807
 
85377
85808
  // src/cli/update-prompt-hook.ts
85378
- import { existsSync as existsSync74, readFileSync as readFileSync64, writeFileSync as writeFileSync37, chmodSync as chmodSync10, mkdirSync as mkdirSync43 } from "node:fs";
85379
- import { join as join76 } from "node:path";
85809
+ import { existsSync as existsSync75, readFileSync as readFileSync65, writeFileSync as writeFileSync37, chmodSync as chmodSync10, mkdirSync as mkdirSync43 } from "node:fs";
85810
+ import { join as join77 } from "node:path";
85380
85811
  var HOOK_FILENAME = "update-card-on-prompt.sh";
85381
85812
  var CONTAINER_AGENT_DIR = "/state/agent";
85382
85813
  function containerHookCommand() {
85383
- return join76(CONTAINER_AGENT_DIR, ".claude", "hooks", HOOK_FILENAME);
85814
+ return join77(CONTAINER_AGENT_DIR, ".claude", "hooks", HOOK_FILENAME);
85384
85815
  }
85385
85816
  function updatePromptHookScript() {
85386
85817
  return `#!/bin/bash
@@ -85446,12 +85877,12 @@ exit 0
85446
85877
  `;
85447
85878
  }
85448
85879
  function installUpdatePromptHook(agentDir) {
85449
- const hooksDir = join76(agentDir, ".claude", "hooks");
85880
+ const hooksDir = join77(agentDir, ".claude", "hooks");
85450
85881
  mkdirSync43(hooksDir, { recursive: true });
85451
- const scriptPath = join76(hooksDir, HOOK_FILENAME);
85882
+ const scriptPath = join77(hooksDir, HOOK_FILENAME);
85452
85883
  const desired = updatePromptHookScript();
85453
85884
  let installed = false;
85454
- const existing = existsSync74(scriptPath) ? readFileSync64(scriptPath, "utf-8") : "";
85885
+ const existing = existsSync75(scriptPath) ? readFileSync65(scriptPath, "utf-8") : "";
85455
85886
  if (existing !== desired) {
85456
85887
  writeFileSync37(scriptPath, desired, { mode: 493 });
85457
85888
  chmodSync10(scriptPath, 493);
@@ -85461,11 +85892,11 @@ function installUpdatePromptHook(agentDir) {
85461
85892
  chmodSync10(scriptPath, 493);
85462
85893
  } catch {}
85463
85894
  }
85464
- const settingsPath = join76(agentDir, ".claude", "settings.json");
85465
- if (!existsSync74(settingsPath)) {
85895
+ const settingsPath = join77(agentDir, ".claude", "settings.json");
85896
+ if (!existsSync75(settingsPath)) {
85466
85897
  return { scriptPath, settingsPath, installed };
85467
85898
  }
85468
- const raw = readFileSync64(settingsPath, "utf-8");
85899
+ const raw = readFileSync65(settingsPath, "utf-8");
85469
85900
  let parsed;
85470
85901
  try {
85471
85902
  parsed = JSON.parse(raw);
@@ -85575,7 +86006,7 @@ var EMBEDDED_EXAMPLES = {
85575
86006
  switchroom: switchroom_default,
85576
86007
  minimal: minimal_default
85577
86008
  };
85578
- var DEFAULT_COMPOSE_PATH2 = join78(homedir46(), ".switchroom", "compose", "docker-compose.yml");
86009
+ var DEFAULT_COMPOSE_PATH2 = join79(homedir46(), ".switchroom", "compose", "docker-compose.yml");
85579
86010
  var COMPOSE_PROJECT2 = "switchroom";
85580
86011
  function effectiveLiteLLMEnabled(config, agentResolvedLitellm) {
85581
86012
  return agentResolvedLitellm?.enabled ?? config.litellm?.enabled ?? false;
@@ -85586,7 +86017,7 @@ async function resolveOperatorVaultPassphrase(home2) {
85586
86017
  return envPass;
85587
86018
  try {
85588
86019
  const { readAutoUnlockFile: readAutoUnlockFile2 } = await Promise.resolve().then(() => (init_auto_unlock(), exports_auto_unlock));
85589
- const blobPath = join78(home2, ".switchroom", "vault-auto-unlock");
86020
+ const blobPath = join79(home2, ".switchroom", "vault-auto-unlock");
85590
86021
  const pass = readAutoUnlockFile2(blobPath);
85591
86022
  return pass && pass.length > 0 ? pass : null;
85592
86023
  } catch {
@@ -85633,9 +86064,9 @@ async function provisionLiteLLMKeys(config, agentNames, switchroomConfigPath, ct
85633
86064
  const oauthAccount = config.auth?.active;
85634
86065
  let pendingConfigEdits = false;
85635
86066
  let configText = null;
85636
- if (switchroomConfigPath && existsSync76(switchroomConfigPath)) {
86067
+ if (switchroomConfigPath && existsSync77(switchroomConfigPath)) {
85637
86068
  try {
85638
- configText = readFileSync65(switchroomConfigPath, "utf-8");
86069
+ configText = readFileSync66(switchroomConfigPath, "utf-8");
85639
86070
  } catch (err) {
85640
86071
  ctx.writeErr(source_default.yellow(` ! litellm: could not read config for ACL grants (${err.message}); keys will be provisioned but agents may lack read-ACL.
85641
86072
  `));
@@ -85798,10 +86229,10 @@ function resolveVaultBindMountDir(homeDir, ctx) {
85798
86229
  if (isCustomPath && ctx.customVaultPath) {
85799
86230
  return dirname24(ctx.customVaultPath);
85800
86231
  }
85801
- return join78(homeDir, ".switchroom", "vault");
86232
+ return join79(homeDir, ".switchroom", "vault");
85802
86233
  }
85803
86234
  function inspectVaultBindMountDir(vaultDir) {
85804
- if (!existsSync76(vaultDir))
86235
+ if (!existsSync77(vaultDir))
85805
86236
  return { kind: "missing" };
85806
86237
  const entries = readdirSync27(vaultDir);
85807
86238
  const unknown = [];
@@ -85829,43 +86260,43 @@ function hasVaultRefs(value) {
85829
86260
  async function ensureHostMountSources(config) {
85830
86261
  const home2 = resolveHostHomeForCompose();
85831
86262
  const dirs = [
85832
- join78(home2, ".switchroom", "approvals"),
85833
- join78(home2, ".switchroom", "scheduler"),
85834
- join78(home2, ".switchroom", "logs"),
85835
- join78(home2, ".switchroom", "compose"),
85836
- join78(home2, ".switchroom", "broker-operator")
86263
+ join79(home2, ".switchroom", "approvals"),
86264
+ join79(home2, ".switchroom", "scheduler"),
86265
+ join79(home2, ".switchroom", "logs"),
86266
+ join79(home2, ".switchroom", "compose"),
86267
+ join79(home2, ".switchroom", "broker-operator")
85837
86268
  ];
85838
86269
  for (const name of Object.keys(config.agents)) {
85839
- dirs.push(join78(home2, ".switchroom", "agents", name));
85840
- dirs.push(join78(home2, ".switchroom", "logs", name));
85841
- dirs.push(join78(home2, ".claude", "projects", name));
85842
- dirs.push(join78(home2, ".switchroom", "audit", name));
85843
- if (existsSync76(join78(home2, ".switchroom-config"))) {
85844
- dirs.push(join78(home2, ".switchroom-config", "agents", name, "personal-skills"));
86270
+ dirs.push(join79(home2, ".switchroom", "agents", name));
86271
+ dirs.push(join79(home2, ".switchroom", "logs", name));
86272
+ dirs.push(join79(home2, ".claude", "projects", name));
86273
+ dirs.push(join79(home2, ".switchroom", "audit", name));
86274
+ if (existsSync77(join79(home2, ".switchroom-config"))) {
86275
+ dirs.push(join79(home2, ".switchroom-config", "agents", name, "personal-skills"));
85845
86276
  }
85846
86277
  }
85847
86278
  for (const dir of dirs) {
85848
86279
  await mkdir2(dir, { recursive: true });
85849
86280
  }
85850
- const autoUnlockPath = join78(home2, ".switchroom", "vault-auto-unlock");
85851
- if (!existsSync76(autoUnlockPath)) {
86281
+ const autoUnlockPath = join79(home2, ".switchroom", "vault-auto-unlock");
86282
+ if (!existsSync77(autoUnlockPath)) {
85852
86283
  writeFileSync38(autoUnlockPath, "", { mode: 384 });
85853
86284
  }
85854
- const auditLogPath = join78(home2, ".switchroom", "vault-audit.log");
85855
- if (!existsSync76(auditLogPath)) {
86285
+ const auditLogPath = join79(home2, ".switchroom", "vault-audit.log");
86286
+ if (!existsSync77(auditLogPath)) {
85856
86287
  writeFileSync38(auditLogPath, "", { mode: 420 });
85857
86288
  }
85858
- const grantsDbPath = join78(home2, ".switchroom", "vault-grants.db");
85859
- if (!existsSync76(grantsDbPath)) {
86289
+ const grantsDbPath = join79(home2, ".switchroom", "vault-grants.db");
86290
+ if (!existsSync77(grantsDbPath)) {
85860
86291
  writeFileSync38(grantsDbPath, "", { mode: 384 });
85861
86292
  }
85862
- const hostdAuditLogPath = join78(home2, ".switchroom", "host-control-audit.log");
85863
- if (!existsSync76(hostdAuditLogPath)) {
86293
+ const hostdAuditLogPath = join79(home2, ".switchroom", "host-control-audit.log");
86294
+ if (!existsSync77(hostdAuditLogPath)) {
85864
86295
  writeFileSync38(hostdAuditLogPath, "", { mode: 420 });
85865
86296
  }
85866
86297
  for (const name of Object.keys(config.agents)) {
85867
- const tokenPath = join78(home2, ".switchroom", "agents", name, ".vault-token");
85868
- if (!existsSync76(tokenPath)) {
86298
+ const tokenPath = join79(home2, ".switchroom", "agents", name, ".vault-token");
86299
+ if (!existsSync77(tokenPath)) {
85869
86300
  writeFileSync38(tokenPath, "", { mode: 384 });
85870
86301
  }
85871
86302
  try {
@@ -85873,16 +86304,16 @@ async function ensureHostMountSources(config) {
85873
86304
  chownSync7(tokenPath, uid, uid);
85874
86305
  } catch {}
85875
86306
  }
85876
- const fleetDir = join78(home2, ".switchroom", "fleet");
86307
+ const fleetDir = join79(home2, ".switchroom", "fleet");
85877
86308
  await mkdir2(fleetDir, { recursive: true });
85878
- const invariantsPath = join78(fleetDir, "switchroom-invariants.md");
86309
+ const invariantsPath = join79(fleetDir, "switchroom-invariants.md");
85879
86310
  const invariantsCanonical = renderFleetInvariants();
85880
- const invariantsCurrent = existsSync76(invariantsPath) ? readFileSync65(invariantsPath, "utf-8") : null;
86311
+ const invariantsCurrent = existsSync77(invariantsPath) ? readFileSync66(invariantsPath, "utf-8") : null;
85881
86312
  if (invariantsCurrent !== invariantsCanonical) {
85882
86313
  writeFileSync38(invariantsPath, invariantsCanonical, { mode: 420 });
85883
86314
  }
85884
- const fleetClaudePath = join78(fleetDir, "CLAUDE.md");
85885
- if (!existsSync76(fleetClaudePath)) {
86315
+ const fleetClaudePath = join79(fleetDir, "CLAUDE.md");
86316
+ if (!existsSync77(fleetClaudePath)) {
85886
86317
  writeFileSync38(fleetClaudePath, [
85887
86318
  "# Switchroom fleet defaults",
85888
86319
  "",
@@ -85914,7 +86345,7 @@ ${out.trim()}`;
85914
86345
  }
85915
86346
  function runApplyPreflight(config, opts = {}) {
85916
86347
  const vaultPath = resolvePath(config.vault?.path ?? "~/.switchroom/vault.enc");
85917
- if (hasVaultRefs(config) && !existsSync76(vaultPath)) {
86348
+ if (hasVaultRefs(config) && !existsSync77(vaultPath)) {
85918
86349
  throw new Error(`Config references vault keys (vault:<name>) but ${vaultPath} is missing. Run \`switchroom setup\` first to initialise the vault.`);
85919
86350
  }
85920
86351
  const detect = opts.detectComposeV2 ?? detectComposeV2;
@@ -85925,7 +86356,7 @@ function runApplyPreflight(config, opts = {}) {
85925
86356
  detectAndReportLegacyGdriveSlots(vaultPath);
85926
86357
  }
85927
86358
  function detectAndReportLegacyGdriveSlots(vaultPath) {
85928
- if (!existsSync76(vaultPath))
86359
+ if (!existsSync77(vaultPath))
85929
86360
  return;
85930
86361
  const passphrase = process.env.SWITCHROOM_VAULT_PASSPHRASE;
85931
86362
  if (!passphrase)
@@ -85966,8 +86397,8 @@ function detectAndReportLegacyGdriveSlots(vaultPath) {
85966
86397
  }
85967
86398
  function writeInstallTypeCache(homeDir = homedir46()) {
85968
86399
  const ctx = detectInstallType();
85969
- const dir = join78(homeDir, ".switchroom");
85970
- const out = join78(dir, "install-type.json");
86400
+ const dir = join79(homeDir, ".switchroom");
86401
+ const out = join79(dir, "install-type.json");
85971
86402
  const tmp = `${out}.tmp`;
85972
86403
  mkdirSync44(dir, { recursive: true });
85973
86404
  const payload = {
@@ -86034,17 +86465,17 @@ Applying switchroom config...
86034
86465
  writeOut(source_default.green(` + ${name}`) + source_default.gray(` (${agentConfig.extends ?? "default"}) \u2014 ${detail}
86035
86466
  `));
86036
86467
  try {
86037
- installUpdatePromptHook(join78(agentsDir, name));
86468
+ installUpdatePromptHook(join79(agentsDir, name));
86038
86469
  } catch (hookErr) {
86039
86470
  writeOut(source_default.gray(` (update-prompt hook install failed for ${name}: ${hookErr.message})
86040
86471
  `));
86041
86472
  }
86042
- await refreshAgentConnectionHealth(config, name, join78(agentsDir, name), {
86473
+ await refreshAgentConnectionHealth(config, name, join79(agentsDir, name), {
86043
86474
  vaultAclReader: connHealthVaultAclReader
86044
86475
  });
86045
86476
  try {
86046
86477
  const uid = allocateAgentUid(name);
86047
- alignAgentUid(name, join78(agentsDir, name), uid, {
86478
+ alignAgentUid(name, join79(agentsDir, name), uid, {
86048
86479
  confirm: !options.nonInteractive,
86049
86480
  writeOut
86050
86481
  });
@@ -86089,7 +86520,7 @@ Applying switchroom config...
86089
86520
  for (const name of agentNames) {
86090
86521
  try {
86091
86522
  const uid = allocateAgentUid(name);
86092
- alignAgentUid(name, join78(agentsDir, name), uid, {
86523
+ alignAgentUid(name, join79(agentsDir, name), uid, {
86093
86524
  confirm: !options.nonInteractive,
86094
86525
  writeOut
86095
86526
  });
@@ -86230,8 +86661,8 @@ function copyExampleConfig2(name) {
86230
86661
  if (!/^[a-z0-9_-]+$/.test(name)) {
86231
86662
  throw new Error(`Invalid example name: ${name} (must match /^[a-z0-9_-]+$/)`);
86232
86663
  }
86233
- const dest = resolve47(process.cwd(), "switchroom.yaml");
86234
- if (existsSync76(dest)) {
86664
+ const dest = resolve48(process.cwd(), "switchroom.yaml");
86665
+ if (existsSync77(dest)) {
86235
86666
  console.error(source_default.yellow("switchroom.yaml already exists \u2014 skipping example copy"));
86236
86667
  return;
86237
86668
  }
@@ -86241,8 +86672,8 @@ function copyExampleConfig2(name) {
86241
86672
  console.log(source_default.green(`Copied ${name}.yaml -> switchroom.yaml`));
86242
86673
  return;
86243
86674
  }
86244
- const exampleFile = resolve47(import.meta.dirname, `../../examples/${name}.yaml`);
86245
- if (!existsSync76(exampleFile)) {
86675
+ const exampleFile = resolve48(import.meta.dirname, `../../examples/${name}.yaml`);
86676
+ if (!existsSync77(exampleFile)) {
86246
86677
  throw new Error(`Example config not found: ${name}.yaml (available: ${Object.keys(EMBEDDED_EXAMPLES).join(", ")})`);
86247
86678
  }
86248
86679
  copyFileSync11(exampleFile, dest);
@@ -86253,8 +86684,8 @@ function findUnwritableAgentDirs(config, opts) {
86253
86684
  const targets = opts.only ? [opts.only] : Object.keys(config.agents ?? {});
86254
86685
  const unwritable = [];
86255
86686
  for (const name of targets) {
86256
- const startSh = join78(agentsDir, name, "start.sh");
86257
- if (!existsSync76(startSh))
86687
+ const startSh = join79(agentsDir, name, "start.sh");
86688
+ if (!existsSync77(startSh))
86258
86689
  continue;
86259
86690
  try {
86260
86691
  accessSync3(startSh, fsConstants6.W_OK);
@@ -86450,8 +86881,8 @@ function runRedactStdin() {
86450
86881
  }
86451
86882
 
86452
86883
  // src/cli/status-ask.ts
86453
- import { readFileSync as readFileSync66, existsSync as existsSync77, readdirSync as readdirSync28 } from "node:fs";
86454
- import { join as join79 } from "node:path";
86884
+ import { readFileSync as readFileSync67, existsSync as existsSync78, readdirSync as readdirSync28 } from "node:fs";
86885
+ import { join as join80 } from "node:path";
86455
86886
  import { homedir as homedir47 } from "node:os";
86456
86887
 
86457
86888
  // src/status-ask/report.ts
@@ -86726,7 +87157,7 @@ function runReport(opts) {
86726
87157
  for (const src of sources) {
86727
87158
  let content;
86728
87159
  try {
86729
- content = readFileSync66(src.path, "utf-8");
87160
+ content = readFileSync67(src.path, "utf-8");
86730
87161
  } catch (err) {
86731
87162
  process.stderr.write(`status-ask report: cannot read ${src.path}: ${err instanceof Error ? err.message : String(err)}
86732
87163
  `);
@@ -86773,7 +87204,7 @@ function runReport(opts) {
86773
87204
  function resolveSources(explicitPath) {
86774
87205
  if (explicitPath != null && explicitPath.trim() !== "") {
86775
87206
  const trimmed = explicitPath.trim();
86776
- if (!existsSync77(trimmed)) {
87207
+ if (!existsSync78(trimmed)) {
86777
87208
  process.stderr.write(`status-ask report: ${trimmed}: file not found
86778
87209
  `);
86779
87210
  process.exit(1);
@@ -86787,9 +87218,9 @@ function resolveSources(explicitPath) {
86787
87218
  const config = loadConfig();
86788
87219
  agentsDir = resolveAgentsDir(config);
86789
87220
  } catch {
86790
- agentsDir = join79(homedir47(), ".switchroom", "agents");
87221
+ agentsDir = join80(homedir47(), ".switchroom", "agents");
86791
87222
  }
86792
- if (!existsSync77(agentsDir))
87223
+ if (!existsSync78(agentsDir))
86793
87224
  return [];
86794
87225
  const sources = [];
86795
87226
  let entries;
@@ -86799,8 +87230,8 @@ function resolveSources(explicitPath) {
86799
87230
  return [];
86800
87231
  }
86801
87232
  for (const name of entries) {
86802
- const path8 = join79(agentsDir, name, "runtime-metrics.jsonl");
86803
- if (existsSync77(path8)) {
87233
+ const path8 = join80(agentsDir, name, "runtime-metrics.jsonl");
87234
+ if (existsSync78(path8)) {
86804
87235
  sources.push({ path: path8, agent: name });
86805
87236
  }
86806
87237
  }
@@ -86826,32 +87257,32 @@ var import_yaml21 = __toESM(require_dist(), 1);
86826
87257
  init_paths();
86827
87258
  import {
86828
87259
  closeSync as closeSync13,
86829
- existsSync as existsSync78,
87260
+ existsSync as existsSync79,
86830
87261
  fsyncSync as fsyncSync6,
86831
87262
  mkdirSync as mkdirSync45,
86832
87263
  openSync as openSync13,
86833
87264
  readdirSync as readdirSync29,
86834
- readFileSync as readFileSync67,
87265
+ readFileSync as readFileSync68,
86835
87266
  renameSync as renameSync16,
86836
87267
  statSync as statSync33,
86837
87268
  unlinkSync as unlinkSync14,
86838
87269
  writeSync as writeSync8
86839
87270
  } from "node:fs";
86840
- import { join as join80, resolve as resolve48 } from "node:path";
87271
+ import { join as join81, resolve as resolve49 } from "node:path";
86841
87272
  var STAGING_SUBDIR = ".staging";
86842
87273
  function overlayPathsFor(agent, opts = {}) {
86843
- const base = opts.root ? resolve48(opts.root, agent) : resolve48(resolveDualPath(`~/.switchroom/agents/${agent}`));
86844
- const scheduleDir = join80(base, "schedule.d");
86845
- const scheduleStagingDir = join80(scheduleDir, STAGING_SUBDIR);
86846
- const skillsDir = join80(base, "skills.d");
86847
- const skillsStagingDir = join80(skillsDir, STAGING_SUBDIR);
87274
+ const base = opts.root ? resolve49(opts.root, agent) : resolve49(resolveDualPath(`~/.switchroom/agents/${agent}`));
87275
+ const scheduleDir = join81(base, "schedule.d");
87276
+ const scheduleStagingDir = join81(scheduleDir, STAGING_SUBDIR);
87277
+ const skillsDir = join81(base, "skills.d");
87278
+ const skillsStagingDir = join81(skillsDir, STAGING_SUBDIR);
86848
87279
  return {
86849
87280
  agentRoot: base,
86850
87281
  scheduleDir,
86851
87282
  scheduleStagingDir,
86852
87283
  skillsDir,
86853
87284
  skillsStagingDir,
86854
- lockPath: join80(base, ".lock"),
87285
+ lockPath: join81(base, ".lock"),
86855
87286
  stagingDir: scheduleStagingDir
86856
87287
  };
86857
87288
  }
@@ -86905,8 +87336,8 @@ function writeOverlayEntry(agent, slug, yamlText, opts = {}) {
86905
87336
  const paths = overlayPathsFor(agent, opts);
86906
87337
  return withAgentLock(paths, () => {
86907
87338
  ensureDirs(paths);
86908
- const stagingPath = join80(paths.scheduleStagingDir, `${slug}.yaml`);
86909
- const finalPath = join80(paths.scheduleDir, `${slug}.yaml`);
87339
+ const stagingPath = join81(paths.scheduleStagingDir, `${slug}.yaml`);
87340
+ const finalPath = join81(paths.scheduleDir, `${slug}.yaml`);
86910
87341
  const fd = openSync13(stagingPath, "w", 384);
86911
87342
  try {
86912
87343
  writeSync8(fd, yamlText);
@@ -86922,8 +87353,8 @@ function writeSkillsOverlayEntry(agent, slug, yamlText, opts = {}) {
86922
87353
  const paths = overlayPathsFor(agent, opts);
86923
87354
  return withAgentLock(paths, () => {
86924
87355
  ensureSkillsDirs(paths);
86925
- const stagingPath = join80(paths.skillsStagingDir, `${slug}.yaml`);
86926
- const finalPath = join80(paths.skillsDir, `${slug}.yaml`);
87356
+ const stagingPath = join81(paths.skillsStagingDir, `${slug}.yaml`);
87357
+ const finalPath = join81(paths.skillsDir, `${slug}.yaml`);
86927
87358
  const fd = openSync13(stagingPath, "w", 384);
86928
87359
  try {
86929
87360
  writeSync8(fd, yamlText);
@@ -86938,8 +87369,8 @@ function writeSkillsOverlayEntry(agent, slug, yamlText, opts = {}) {
86938
87369
  function deleteSkillsOverlayEntry(agent, slug, opts = {}) {
86939
87370
  const paths = overlayPathsFor(agent, opts);
86940
87371
  return withAgentLock(paths, () => {
86941
- const finalPath = join80(paths.skillsDir, `${slug}.yaml`);
86942
- if (!existsSync78(finalPath))
87372
+ const finalPath = join81(paths.skillsDir, `${slug}.yaml`);
87373
+ if (!existsSync79(finalPath))
86943
87374
  return false;
86944
87375
  unlinkSync14(finalPath);
86945
87376
  return true;
@@ -86947,15 +87378,15 @@ function deleteSkillsOverlayEntry(agent, slug, opts = {}) {
86947
87378
  }
86948
87379
  function listSkillsOverlayEntries(agent, opts = {}) {
86949
87380
  const paths = overlayPathsFor(agent, opts);
86950
- if (!existsSync78(paths.skillsDir))
87381
+ if (!existsSync79(paths.skillsDir))
86951
87382
  return [];
86952
87383
  const out = [];
86953
87384
  for (const name of readdirSync29(paths.skillsDir)) {
86954
87385
  if (!/\.ya?ml$/i.test(name))
86955
87386
  continue;
86956
- const full = join80(paths.skillsDir, name);
87387
+ const full = join81(paths.skillsDir, name);
86957
87388
  try {
86958
- const raw = readFileSync67(full, "utf-8");
87389
+ const raw = readFileSync68(full, "utf-8");
86959
87390
  const slug = name.replace(/\.ya?ml$/i, "");
86960
87391
  out.push({ slug, path: full, raw });
86961
87392
  } catch {}
@@ -86965,8 +87396,8 @@ function listSkillsOverlayEntries(agent, opts = {}) {
86965
87396
  function deleteOverlayEntry(agent, slug, opts = {}) {
86966
87397
  const paths = overlayPathsFor(agent, opts);
86967
87398
  return withAgentLock(paths, () => {
86968
- const finalPath = join80(paths.scheduleDir, `${slug}.yaml`);
86969
- if (!existsSync78(finalPath))
87399
+ const finalPath = join81(paths.scheduleDir, `${slug}.yaml`);
87400
+ if (!existsSync79(finalPath))
86970
87401
  return false;
86971
87402
  unlinkSync14(finalPath);
86972
87403
  return true;
@@ -86974,15 +87405,15 @@ function deleteOverlayEntry(agent, slug, opts = {}) {
86974
87405
  }
86975
87406
  function listOverlayEntries(agent, opts = {}) {
86976
87407
  const paths = overlayPathsFor(agent, opts);
86977
- if (!existsSync78(paths.scheduleDir))
87408
+ if (!existsSync79(paths.scheduleDir))
86978
87409
  return [];
86979
87410
  const out = [];
86980
87411
  for (const name of readdirSync29(paths.scheduleDir)) {
86981
87412
  if (!/\.ya?ml$/i.test(name))
86982
87413
  continue;
86983
- const full = join80(paths.scheduleDir, name);
87414
+ const full = join81(paths.scheduleDir, name);
86984
87415
  try {
86985
- const raw = readFileSync67(full, "utf-8");
87416
+ const raw = readFileSync68(full, "utf-8");
86986
87417
  const slug = name.replace(/\.ya?ml$/i, "");
86987
87418
  out.push({ slug, path: full, raw });
86988
87419
  } catch {}
@@ -87125,23 +87556,23 @@ function reconcileAgentCronOnly(agent) {
87125
87556
  // src/cli/agent-config-pending.ts
87126
87557
  import {
87127
87558
  closeSync as closeSync14,
87128
- existsSync as existsSync79,
87559
+ existsSync as existsSync80,
87129
87560
  fsyncSync as fsyncSync7,
87130
87561
  mkdirSync as mkdirSync46,
87131
87562
  openSync as openSync14,
87132
87563
  readdirSync as readdirSync30,
87133
- readFileSync as readFileSync68,
87564
+ readFileSync as readFileSync69,
87134
87565
  renameSync as renameSync17,
87135
87566
  unlinkSync as unlinkSync15,
87136
87567
  writeFileSync as writeFileSync39,
87137
87568
  writeSync as writeSync9
87138
87569
  } from "node:fs";
87139
- import { join as join81 } from "node:path";
87570
+ import { join as join82 } from "node:path";
87140
87571
  import { randomBytes as randomBytes14 } from "node:crypto";
87141
87572
  var STAGE_ID_PREFIX = "cap_";
87142
87573
  function pendingDir(agent, opts = {}) {
87143
87574
  const paths = overlayPathsFor(agent, opts);
87144
- return join81(paths.scheduleDir, ".pending");
87575
+ return join82(paths.scheduleDir, ".pending");
87145
87576
  }
87146
87577
  function ensurePendingDir(agent, opts = {}) {
87147
87578
  const dir = pendingDir(agent, opts);
@@ -87154,8 +87585,8 @@ function newStageId() {
87154
87585
  function stagePendingScheduleEntry(opts) {
87155
87586
  const dir = ensurePendingDir(opts.agent, { root: opts.root });
87156
87587
  const stageId = opts.stageId ?? newStageId();
87157
- const yamlPath = join81(dir, `${stageId}.yaml`);
87158
- const metaPath = join81(dir, `${stageId}.meta.json`);
87588
+ const yamlPath = join82(dir, `${stageId}.yaml`);
87589
+ const metaPath = join82(dir, `${stageId}.meta.json`);
87159
87590
  const meta = {
87160
87591
  v: 1,
87161
87592
  stage_id: stageId,
@@ -87182,19 +87613,19 @@ function stagePendingScheduleEntry(opts) {
87182
87613
  }
87183
87614
  function listPendingScheduleEntries(agent, opts = {}) {
87184
87615
  const dir = pendingDir(agent, opts);
87185
- if (!existsSync79(dir))
87616
+ if (!existsSync80(dir))
87186
87617
  return [];
87187
87618
  const out = [];
87188
87619
  for (const name of readdirSync30(dir).sort()) {
87189
87620
  if (!name.endsWith(".meta.json"))
87190
87621
  continue;
87191
87622
  const stageId = name.slice(0, -".meta.json".length);
87192
- const metaPath = join81(dir, name);
87193
- const yamlPath = join81(dir, `${stageId}.yaml`);
87194
- if (!existsSync79(yamlPath))
87623
+ const metaPath = join82(dir, name);
87624
+ const yamlPath = join82(dir, `${stageId}.yaml`);
87625
+ if (!existsSync80(yamlPath))
87195
87626
  continue;
87196
87627
  try {
87197
- const meta = JSON.parse(readFileSync68(metaPath, "utf-8"));
87628
+ const meta = JSON.parse(readFileSync69(metaPath, "utf-8"));
87198
87629
  if (meta?.v !== 1 || typeof meta.stage_id !== "string")
87199
87630
  continue;
87200
87631
  out.push({ stageId: meta.stage_id, agent: meta.agent, yamlPath, metaPath, meta });
@@ -87209,8 +87640,8 @@ function commitPendingScheduleEntry(opts) {
87209
87640
  return { committed: false, reason: "not_found" };
87210
87641
  const slug = match.meta.entry.name ?? match.stageId;
87211
87642
  const paths = overlayPathsFor(opts.agent, { root: opts.root });
87212
- const finalPath = join81(paths.scheduleDir, `${slug}.yaml`);
87213
- if (existsSync79(finalPath)) {
87643
+ const finalPath = join82(paths.scheduleDir, `${slug}.yaml`);
87644
+ if (existsSync80(finalPath)) {
87214
87645
  return { committed: false, reason: "slug_collision" };
87215
87646
  }
87216
87647
  renameSync17(match.yamlPath, finalPath);
@@ -87232,7 +87663,7 @@ function denyPendingScheduleEntry(opts) {
87232
87663
  }
87233
87664
 
87234
87665
  // src/cli/agent-config-write.ts
87235
- import { existsSync as existsSync80, readFileSync as readFileSync69 } from "node:fs";
87666
+ import { existsSync as existsSync81, readFileSync as readFileSync70 } from "node:fs";
87236
87667
  import { execFileSync as execFileSync26 } from "node:child_process";
87237
87668
 
87238
87669
  // src/scheduler/schedule-report.ts
@@ -87603,8 +88034,8 @@ function scheduleRemove(opts) {
87603
88034
  }
87604
88035
  let priorContent = null;
87605
88036
  try {
87606
- if (existsSync80(match.path))
87607
- priorContent = readFileSync69(match.path, "utf-8");
88037
+ if (existsSync81(match.path))
88038
+ priorContent = readFileSync70(match.path, "utf-8");
87608
88039
  } catch {}
87609
88040
  deleteOverlayEntry(agent, match.slug, { root: opts.root });
87610
88041
  const reconcileFn = opts.reconcile === undefined ? opts.root ? null : reconcileAgentCronOnly : opts.reconcile;
@@ -87807,7 +88238,7 @@ function registerAgentConfigWriteCommands(program3) {
87807
88238
  }
87808
88239
  let blob;
87809
88240
  if (opts.jsonl) {
87810
- blob = existsSync80(opts.jsonl) ? readFileSync69(opts.jsonl, "utf-8") : "";
88241
+ blob = existsSync81(opts.jsonl) ? readFileSync70(opts.jsonl, "utf-8") : "";
87811
88242
  } else {
87812
88243
  try {
87813
88244
  blob = execFileSync26("docker", ["exec", `switchroom-${agent}`, "cat", "/state/agent/scheduler.jsonl"], {
@@ -87839,10 +88270,10 @@ function registerAgentConfigWriteCommands(program3) {
87839
88270
 
87840
88271
  // src/cli/agent-config-skill-write.ts
87841
88272
  var import_yaml22 = __toESM(require_dist(), 1);
87842
- import { existsSync as existsSync81 } from "node:fs";
88273
+ import { existsSync as existsSync82 } from "node:fs";
87843
88274
  init_reconcile_default_skills();
87844
88275
  var import_yaml23 = __toESM(require_dist(), 1);
87845
- import { join as join82 } from "node:path";
88276
+ import { join as join83 } from "node:path";
87846
88277
  var MAX_SKILLS_PER_AGENT = 20;
87847
88278
  var V1_ALLOWED_SOURCE_PREFIX = "bundled:";
87848
88279
  function exitCodeFor2(code) {
@@ -87917,8 +88348,8 @@ function skillInstall(opts) {
87917
88348
  return err("E_SKILL_QUOTA_EXCEEDED", `agent ${agent} already has ${used} overlay-installed skills (cap ${MAX_SKILLS_PER_AGENT})`);
87918
88349
  }
87919
88350
  const poolDir = opts.bundledSkillsPoolDir ?? getBundledSkillsPoolDir();
87920
- const skillPath = join82(poolDir, skillName);
87921
- if (!existsSync81(skillPath)) {
88351
+ const skillPath = join83(poolDir, skillName);
88352
+ if (!existsSync82(skillPath)) {
87922
88353
  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.`);
87923
88354
  }
87924
88355
  const yamlText = import_yaml22.stringify({ skills: [skillName] });
@@ -88082,12 +88513,12 @@ function registerAgentConfigSkillWriteCommands(program3) {
88082
88513
  // src/cli/skill.ts
88083
88514
  import {
88084
88515
  closeSync as closeSync15,
88085
- existsSync as existsSync82,
88516
+ existsSync as existsSync83,
88086
88517
  lstatSync as lstatSync9,
88087
88518
  mkdirSync as mkdirSync47,
88088
88519
  mkdtempSync as mkdtempSync5,
88089
88520
  openSync as openSync15,
88090
- readFileSync as readFileSync70,
88521
+ readFileSync as readFileSync71,
88091
88522
  readdirSync as readdirSync31,
88092
88523
  realpathSync as realpathSync7,
88093
88524
  renameSync as renameSync18,
@@ -88096,7 +88527,7 @@ import {
88096
88527
  writeFileSync as writeFileSync40
88097
88528
  } from "node:fs";
88098
88529
  import { tmpdir as tmpdir5, homedir as homedir48 } from "node:os";
88099
- import { dirname as dirname25, join as join83, relative as relative2, resolve as resolve49 } from "node:path";
88530
+ import { dirname as dirname25, join as join84, relative as relative2, resolve as resolve50 } from "node:path";
88100
88531
  import { spawnSync as spawnSync14 } from "node:child_process";
88101
88532
 
88102
88533
  // src/cli/skill-common.ts
@@ -88290,11 +88721,11 @@ function scanForClaudeP2(content) {
88290
88721
  function resolveSkillsPoolDir2(override) {
88291
88722
  const raw = override ?? "~/.switchroom/skills";
88292
88723
  if (raw.startsWith("~/")) {
88293
- return join83(homedir48(), raw.slice(2));
88724
+ return join84(homedir48(), raw.slice(2));
88294
88725
  }
88295
88726
  if (raw === "~")
88296
88727
  return homedir48();
88297
- return resolve49(raw);
88728
+ return resolve50(raw);
88298
88729
  }
88299
88730
  function readStdinSync() {
88300
88731
  const chunks = [];
@@ -88329,7 +88760,7 @@ function loadFromDir(dir) {
88329
88760
  const walk2 = (sub) => {
88330
88761
  const entries = readdirSync31(sub, { withFileTypes: true });
88331
88762
  for (const ent of entries) {
88332
- const full = join83(sub, ent.name);
88763
+ const full = join84(sub, ent.name);
88333
88764
  const rel = relative2(abs, full);
88334
88765
  if (ent.isSymbolicLink()) {
88335
88766
  fail3(`refusing to read symlink inside --from dir: ${rel}`);
@@ -88339,7 +88770,7 @@ function loadFromDir(dir) {
88339
88770
  continue;
88340
88771
  }
88341
88772
  if (ent.isFile()) {
88342
- const buf = readFileSync70(full);
88773
+ const buf = readFileSync71(full);
88343
88774
  files[rel.replace(/\\/g, "/")] = buf.toString("utf-8");
88344
88775
  }
88345
88776
  }
@@ -88364,7 +88795,7 @@ function loadFromTarball(tarPath) {
88364
88795
  fail3(`tarball contains disallowed path: ${JSON.stringify(entry)} \u2014 ` + `refusing to extract before any file is written`);
88365
88796
  }
88366
88797
  }
88367
- const staging = mkdtempSync5(join83(tmpdir5(), "skill-apply-extract-"));
88798
+ const staging = mkdtempSync5(join84(tmpdir5(), "skill-apply-extract-"));
88368
88799
  try {
88369
88800
  const flags = isGz ? ["-xzf"] : ["-xf"];
88370
88801
  const r = spawnSync14("tar", [
@@ -88388,7 +88819,7 @@ function loadFromTarball(tarPath) {
88388
88819
  }
88389
88820
  }
88390
88821
  function loadSingleFile(filePath) {
88391
- const content = readFileSync70(filePath, "utf-8");
88822
+ const content = readFileSync71(filePath, "utf-8");
88392
88823
  return { "SKILL.md": content };
88393
88824
  }
88394
88825
  function loadFromStdin() {
@@ -88450,8 +88881,8 @@ function validatePayload(name, files) {
88450
88881
  errors2.push(`${path8} fails \`bash -n\` syntax check: ${(r.stderr ?? "").trim()}`);
88451
88882
  }
88452
88883
  } else if (PY_SCRIPT_RE2.test(path8)) {
88453
- const tmp = mkdtempSync5(join83(tmpdir5(), "skill-apply-py-"));
88454
- const tmpPy = join83(tmp, "check.py");
88884
+ const tmp = mkdtempSync5(join84(tmpdir5(), "skill-apply-py-"));
88885
+ const tmpPy = join84(tmp, "check.py");
88455
88886
  try {
88456
88887
  writeFileSync40(tmpPy, content);
88457
88888
  const r = spawnSync14("python3", ["-m", "py_compile", tmpPy], {
@@ -88471,15 +88902,15 @@ function validatePayload(name, files) {
88471
88902
  function diffSummary(currentDir, files) {
88472
88903
  const lines = [];
88473
88904
  const currentFiles = {};
88474
- if (existsSync82(currentDir)) {
88905
+ if (existsSync83(currentDir)) {
88475
88906
  const walk2 = (sub) => {
88476
88907
  for (const ent of readdirSync31(sub, { withFileTypes: true })) {
88477
- const full = join83(sub, ent.name);
88908
+ const full = join84(sub, ent.name);
88478
88909
  const rel = relative2(currentDir, full);
88479
88910
  if (ent.isDirectory()) {
88480
88911
  walk2(full);
88481
88912
  } else if (ent.isFile()) {
88482
- currentFiles[rel.replace(/\\/g, "/")] = readFileSync70(full, "utf-8");
88913
+ currentFiles[rel.replace(/\\/g, "/")] = readFileSync71(full, "utf-8");
88483
88914
  }
88484
88915
  }
88485
88916
  };
@@ -88507,10 +88938,10 @@ function diffSummary(currentDir, files) {
88507
88938
  `);
88508
88939
  }
88509
88940
  function writePayload(poolDir, name, files) {
88510
- if (!existsSync82(poolDir)) {
88941
+ if (!existsSync83(poolDir)) {
88511
88942
  mkdirSync47(poolDir, { recursive: true, mode: 493 });
88512
88943
  }
88513
- const target = join83(poolDir, name);
88944
+ const target = join84(poolDir, name);
88514
88945
  let targetIsSymlink = false;
88515
88946
  try {
88516
88947
  const st = lstatSync9(target);
@@ -88521,11 +88952,11 @@ function writePayload(poolDir, name, files) {
88521
88952
  if (targetIsSymlink) {
88522
88953
  fail3(`refusing to overwrite symlink at ${target}; investigate manually`);
88523
88954
  }
88524
- const staging = mkdtempSync5(join83(poolDir, `.skill-apply-stage-${name}-`));
88955
+ const staging = mkdtempSync5(join84(poolDir, `.skill-apply-stage-${name}-`));
88525
88956
  let oldRename = null;
88526
88957
  try {
88527
88958
  for (const [path8, content] of Object.entries(files)) {
88528
- const full = join83(staging, path8);
88959
+ const full = join84(staging, path8);
88529
88960
  mkdirSync47(dirname25(full), { recursive: true, mode: 493 });
88530
88961
  const fd = openSync15(full, "wx");
88531
88962
  try {
@@ -88556,9 +88987,9 @@ function writePayload(poolDir, name, files) {
88556
88987
  try {
88557
88988
  rmSync17(staging, { recursive: true, force: true });
88558
88989
  } catch {}
88559
- if (oldRename && existsSync82(oldRename)) {
88990
+ if (oldRename && existsSync83(oldRename)) {
88560
88991
  try {
88561
- if (existsSync82(target)) {
88992
+ if (existsSync83(target)) {
88562
88993
  rmSync17(target, { recursive: true, force: true });
88563
88994
  }
88564
88995
  renameSync18(oldRename, target);
@@ -88578,8 +89009,8 @@ function registerSkillCommand(program3) {
88578
89009
  if (opts.from === undefined) {
88579
89010
  files = loadFromStdin();
88580
89011
  } else {
88581
- const fromPath = resolve49(opts.from);
88582
- if (!existsSync82(fromPath)) {
89012
+ const fromPath = resolve50(opts.from);
89013
+ if (!existsSync83(fromPath)) {
88583
89014
  fail3(`--from path does not exist: ${opts.from}`);
88584
89015
  }
88585
89016
  const st = statSync34(fromPath);
@@ -88603,7 +89034,7 @@ function registerSkillCommand(program3) {
88603
89034
  }
88604
89035
  const config = loadConfig();
88605
89036
  const poolDir = resolveSkillsPoolDir2(config.switchroom?.skills_dir);
88606
- const currentDir = join83(poolDir, name);
89037
+ const currentDir = join84(poolDir, name);
88607
89038
  console.log(source_default.bold(`Skill: ${name}`) + source_default.gray(` (${Object.keys(files).length} files, ${sumBytes(files)} bytes)`));
88608
89039
  console.log(source_default.bold("Diff vs current pool content:"));
88609
89040
  console.log(diffSummary(currentDir, files));
@@ -88634,12 +89065,12 @@ function sumBytes(files) {
88634
89065
  // src/cli/skill-personal.ts
88635
89066
  import {
88636
89067
  closeSync as closeSync16,
88637
- existsSync as existsSync83,
89068
+ existsSync as existsSync84,
88638
89069
  lstatSync as lstatSync10,
88639
89070
  mkdirSync as mkdirSync48,
88640
89071
  mkdtempSync as mkdtempSync6,
88641
89072
  openSync as openSync16,
88642
- readFileSync as readFileSync71,
89073
+ readFileSync as readFileSync72,
88643
89074
  readdirSync as readdirSync32,
88644
89075
  renameSync as renameSync19,
88645
89076
  rmSync as rmSync18,
@@ -88647,7 +89078,7 @@ import {
88647
89078
  utimesSync,
88648
89079
  writeFileSync as writeFileSync41
88649
89080
  } from "node:fs";
88650
- import { dirname as dirname26, join as join84, relative as relative3, resolve as resolve50 } from "node:path";
89081
+ import { dirname as dirname26, join as join85, relative as relative3, resolve as resolve51 } from "node:path";
88651
89082
  import { homedir as homedir49, tmpdir as tmpdir6 } from "node:os";
88652
89083
  import { spawnSync as spawnSync15 } from "node:child_process";
88653
89084
  init_helpers();
@@ -88658,15 +89089,15 @@ var TRASH_TTL_MS = 24 * 60 * 60 * 1000;
88658
89089
  var PERSONAL_SKILLS_SUBPATH = "personal-skills";
88659
89090
  function resolveConfigSkillsDir(agent) {
88660
89091
  const override = process.env.SWITCHROOM_CONFIG_DIR;
88661
- const candidate = override ? resolve50(override) : join84(homedir49(), ".switchroom-config");
88662
- if (!existsSync83(candidate))
89092
+ const candidate = override ? resolve51(override) : join85(homedir49(), ".switchroom-config");
89093
+ if (!existsSync84(candidate))
88663
89094
  return null;
88664
- return join84(candidate, "agents", agent, PERSONAL_SKILLS_SUBPATH);
89095
+ return join85(candidate, "agents", agent, PERSONAL_SKILLS_SUBPATH);
88665
89096
  }
88666
89097
  var MIRROR_PRIOR_TTL_MS = 24 * 60 * 60 * 1000;
88667
89098
  function sweepMirrorPriors(configSkillsRoot) {
88668
89099
  try {
88669
- if (!existsSync83(configSkillsRoot))
89100
+ if (!existsSync84(configSkillsRoot))
88670
89101
  return;
88671
89102
  const now = Date.now();
88672
89103
  for (const ent of readdirSync32(configSkillsRoot)) {
@@ -88679,7 +89110,7 @@ function sweepMirrorPriors(configSkillsRoot) {
88679
89110
  if (now - ts < MIRROR_PRIOR_TTL_MS)
88680
89111
  continue;
88681
89112
  try {
88682
- rmSync18(join84(configSkillsRoot, ent), { recursive: true, force: true });
89113
+ rmSync18(join85(configSkillsRoot, ent), { recursive: true, force: true });
88683
89114
  } catch {}
88684
89115
  }
88685
89116
  } catch {}
@@ -88688,7 +89119,7 @@ function mirrorToConfigRepo(agent, name, liveSkillDir) {
88688
89119
  const configSkillsRoot = resolveConfigSkillsDir(agent);
88689
89120
  if (!configSkillsRoot)
88690
89121
  return;
88691
- const dest = join84(configSkillsRoot, name);
89122
+ const dest = join85(configSkillsRoot, name);
88692
89123
  try {
88693
89124
  if (liveSkillDir !== null) {
88694
89125
  try {
@@ -88702,32 +89133,32 @@ function mirrorToConfigRepo(agent, name, liveSkillDir) {
88702
89133
  }
88703
89134
  if (liveSkillDir === null) {
88704
89135
  sweepMirrorPriors(configSkillsRoot);
88705
- if (existsSync83(dest)) {
88706
- const trash = join84(configSkillsRoot, `.${name}-trash-${Date.now()}`);
89136
+ if (existsSync84(dest)) {
89137
+ const trash = join85(configSkillsRoot, `.${name}-trash-${Date.now()}`);
88707
89138
  renameSync19(dest, trash);
88708
89139
  }
88709
89140
  return;
88710
89141
  }
88711
89142
  mkdirSync48(configSkillsRoot, { recursive: true, mode: 493 });
88712
89143
  sweepMirrorPriors(configSkillsRoot);
88713
- const staging = mkdtempSync6(join84(configSkillsRoot, `.${name}-staging-`));
89144
+ const staging = mkdtempSync6(join85(configSkillsRoot, `.${name}-staging-`));
88714
89145
  const walk2 = (src, dst) => {
88715
89146
  mkdirSync48(dst, { recursive: true, mode: 493 });
88716
89147
  for (const ent of readdirSync32(src, { withFileTypes: true })) {
88717
- const s = join84(src, ent.name);
88718
- const d = join84(dst, ent.name);
89148
+ const s = join85(src, ent.name);
89149
+ const d = join85(dst, ent.name);
88719
89150
  if (ent.isSymbolicLink())
88720
89151
  continue;
88721
89152
  if (ent.isDirectory())
88722
89153
  walk2(s, d);
88723
89154
  else if (ent.isFile()) {
88724
- writeFileSync41(d, readFileSync71(s));
89155
+ writeFileSync41(d, readFileSync72(s));
88725
89156
  }
88726
89157
  }
88727
89158
  };
88728
89159
  walk2(liveSkillDir, staging);
88729
- if (existsSync83(dest)) {
88730
- const prior = join84(configSkillsRoot, `.${name}-prior-${Date.now()}`);
89160
+ if (existsSync84(dest)) {
89161
+ const prior = join85(configSkillsRoot, `.${name}-prior-${Date.now()}`);
88731
89162
  renameSync19(dest, prior);
88732
89163
  }
88733
89164
  renameSync19(staging, dest);
@@ -88753,14 +89184,14 @@ function resolveAgent(opts) {
88753
89184
  }
88754
89185
  function resolveAgentsRoot(opts) {
88755
89186
  if (opts.root)
88756
- return resolve50(opts.root);
88757
- return join84(homedir49(), ".switchroom", "agents");
89187
+ return resolve51(opts.root);
89188
+ return join85(homedir49(), ".switchroom", "agents");
88758
89189
  }
88759
89190
  function personalSkillDir(agentsRoot, agent, name) {
88760
- return join84(agentsRoot, agent, ".claude", "skills", PERSONAL_PREFIX + name);
89191
+ return join85(agentsRoot, agent, ".claude", "skills", PERSONAL_PREFIX + name);
88761
89192
  }
88762
89193
  function trashDir(agentsRoot, agent) {
88763
- return join84(agentsRoot, agent, ".claude", TRASH_DIRNAME);
89194
+ return join85(agentsRoot, agent, ".claude", TRASH_DIRNAME);
88764
89195
  }
88765
89196
  function readStdinSync2() {
88766
89197
  const chunks = [];
@@ -88783,14 +89214,14 @@ function readStdinSync2() {
88783
89214
  return Buffer.concat(chunks).toString("utf-8");
88784
89215
  }
88785
89216
  function loadFromDir2(dir) {
88786
- const abs = resolve50(dir);
89217
+ const abs = resolve51(dir);
88787
89218
  if (!statSync35(abs).isDirectory()) {
88788
89219
  fail4(`--from path is not a directory: ${dir}`);
88789
89220
  }
88790
89221
  const files = {};
88791
89222
  const walk2 = (sub) => {
88792
89223
  for (const ent of readdirSync32(sub, { withFileTypes: true })) {
88793
- const full = join84(sub, ent.name);
89224
+ const full = join85(sub, ent.name);
88794
89225
  if (ent.isSymbolicLink()) {
88795
89226
  fail4(`refusing to read symlink in --from dir: ${relative3(abs, full)}`);
88796
89227
  }
@@ -88800,7 +89231,7 @@ function loadFromDir2(dir) {
88800
89231
  }
88801
89232
  if (ent.isFile()) {
88802
89233
  const rel = relative3(abs, full).replace(/\\/g, "/");
88803
- files[rel] = readFileSync71(full, "utf-8");
89234
+ files[rel] = readFileSync72(full, "utf-8");
88804
89235
  }
88805
89236
  }
88806
89237
  };
@@ -88843,8 +89274,8 @@ function behavioralValidate(files) {
88843
89274
  errors2.push(`${path8} fails \`bash -n\`: ${(r.stderr ?? "").trim()}`);
88844
89275
  }
88845
89276
  } else if (PY_SCRIPT_RE.test(path8)) {
88846
- const tmp = mkdtempSync6(join84(tmpdir6(), "skill-personal-py-"));
88847
- const tmpPy = join84(tmp, "check.py");
89277
+ const tmp = mkdtempSync6(join85(tmpdir6(), "skill-personal-py-"));
89278
+ const tmpPy = join85(tmp, "check.py");
88848
89279
  try {
88849
89280
  writeFileSync41(tmpPy, content);
88850
89281
  const r = spawnSync15("python3", ["-m", "py_compile", tmpPy], {
@@ -88862,13 +89293,13 @@ function behavioralValidate(files) {
88862
89293
  }
88863
89294
  function sweepTrash(agentsRoot, agent) {
88864
89295
  const trash = trashDir(agentsRoot, agent);
88865
- if (!existsSync83(trash))
89296
+ if (!existsSync84(trash))
88866
89297
  return;
88867
89298
  const now = Date.now();
88868
89299
  for (const ent of readdirSync32(trash, { withFileTypes: true })) {
88869
89300
  if (!ent.isDirectory())
88870
89301
  continue;
88871
- const entPath = join84(trash, ent.name);
89302
+ const entPath = join85(trash, ent.name);
88872
89303
  try {
88873
89304
  const st = statSync35(entPath);
88874
89305
  if (now - st.mtimeMs > TRASH_TTL_MS) {
@@ -88889,11 +89320,11 @@ function writePersonalSkill(targetDir, files) {
88889
89320
  fail4(`refusing to overwrite symlink at ${targetDir}; investigate manually`);
88890
89321
  }
88891
89322
  mkdirSync48(dirname26(targetDir), { recursive: true, mode: 493 });
88892
- const staging = mkdtempSync6(join84(dirname26(targetDir), `.skill-personal-stage-`));
89323
+ const staging = mkdtempSync6(join85(dirname26(targetDir), `.skill-personal-stage-`));
88893
89324
  let oldRename = null;
88894
89325
  try {
88895
89326
  for (const [path8, content] of Object.entries(files)) {
88896
- const full = join84(staging, path8);
89327
+ const full = join85(staging, path8);
88897
89328
  mkdirSync48(dirname26(full), { recursive: true, mode: 493 });
88898
89329
  const fd = openSync16(full, "wx");
88899
89330
  try {
@@ -88924,9 +89355,9 @@ function writePersonalSkill(targetDir, files) {
88924
89355
  try {
88925
89356
  rmSync18(staging, { recursive: true, force: true });
88926
89357
  } catch {}
88927
- if (oldRename && existsSync83(oldRename)) {
89358
+ if (oldRename && existsSync84(oldRename)) {
88928
89359
  try {
88929
- if (existsSync83(targetDir)) {
89360
+ if (existsSync84(targetDir)) {
88930
89361
  rmSync18(targetDir, { recursive: true, force: true });
88931
89362
  }
88932
89363
  renameSync19(oldRename, targetDir);
@@ -88977,8 +89408,8 @@ function loadFiles(opts) {
88977
89408
  if (opts.from === undefined) {
88978
89409
  return loadFromStdin2();
88979
89410
  }
88980
- const p = resolve50(opts.from);
88981
- if (!existsSync83(p)) {
89411
+ const p = resolve51(opts.from);
89412
+ if (!existsSync84(p)) {
88982
89413
  fail4(`--from path does not exist: ${opts.from}`);
88983
89414
  }
88984
89415
  const st = statSync35(p);
@@ -88986,7 +89417,7 @@ function loadFiles(opts) {
88986
89417
  return loadFromDir2(p);
88987
89418
  }
88988
89419
  if (p.endsWith(".md")) {
88989
- return { "SKILL.md": readFileSync71(p, "utf-8") };
89420
+ return { "SKILL.md": readFileSync72(p, "utf-8") };
88990
89421
  }
88991
89422
  fail4(`--from must be a directory or a .md file. Got: ${opts.from}`);
88992
89423
  }
@@ -89026,10 +89457,10 @@ function editPersonalAction(name, opts) {
89026
89457
  }
89027
89458
  var CLONE_SOURCE_RE = /^(shared|bundled):([a-z0-9][a-z0-9_-]{0,62})$/;
89028
89459
  function defaultSharedRoot() {
89029
- return join84(homedir49(), ".switchroom", "skills");
89460
+ return join85(homedir49(), ".switchroom", "skills");
89030
89461
  }
89031
89462
  function defaultBundledRoot() {
89032
- return join84(homedir49(), ".switchroom", "skills", "_bundled");
89463
+ return join85(homedir49(), ".switchroom", "skills", "_bundled");
89033
89464
  }
89034
89465
  function resolveCloneSource(source, opts) {
89035
89466
  const m = CLONE_SOURCE_RE.exec(source);
@@ -89039,8 +89470,8 @@ function resolveCloneSource(source, opts) {
89039
89470
  const tier = m[1];
89040
89471
  const slug = m[2];
89041
89472
  const root = tier === "bundled" ? opts.bundledRoot ?? defaultBundledRoot() : opts.sharedRoot ?? defaultSharedRoot();
89042
- const dir = join84(root, slug);
89043
- if (!existsSync83(dir)) {
89473
+ const dir = join85(root, slug);
89474
+ if (!existsSync84(dir)) {
89044
89475
  fail4(`clone source ${JSON.stringify(source)} not found at ${dir}; ` + `check \`switchroom skill search --tier ${tier}\``, 1);
89045
89476
  }
89046
89477
  const st = lstatSync10(dir);
@@ -89055,7 +89486,7 @@ function readSourceFiles(dir) {
89055
89486
  const skipped = [];
89056
89487
  const walk2 = (sub) => {
89057
89488
  for (const ent of readdirSync32(sub, { withFileTypes: true })) {
89058
- const full = join84(sub, ent.name);
89489
+ const full = join85(sub, ent.name);
89059
89490
  if (ent.isSymbolicLink()) {
89060
89491
  continue;
89061
89492
  }
@@ -89075,7 +89506,7 @@ function readSourceFiles(dir) {
89075
89506
  fail4(`clone source has oversized file ${rel} (${st.size} bytes > ${CLONE_MAX_FILE_BYTES}); ` + `refuse to read`, 3);
89076
89507
  }
89077
89508
  } catch {}
89078
- files[rel] = readFileSync71(full, "utf-8");
89509
+ files[rel] = readFileSync72(full, "utf-8");
89079
89510
  }
89080
89511
  }
89081
89512
  };
@@ -89166,7 +89597,7 @@ function removePersonalAction(name, opts) {
89166
89597
  const trashRoot2 = trashDir(agentsRoot, agent);
89167
89598
  mkdirSync48(trashRoot2, { recursive: true, mode: 493 });
89168
89599
  const ts = Date.now();
89169
- const trashTarget = join84(trashRoot2, `${name}-${ts}`);
89600
+ const trashTarget = join85(trashRoot2, `${name}-${ts}`);
89170
89601
  renameSync19(target, trashTarget);
89171
89602
  const now = new Date(ts);
89172
89603
  utimesSync(trashTarget, now, now);
@@ -89185,16 +89616,16 @@ function listPersonalAction(opts) {
89185
89616
  const agent = resolveAgent(opts);
89186
89617
  const agentsRoot = resolveAgentsRoot(opts);
89187
89618
  sweepTrash(agentsRoot, agent);
89188
- const skillsDir = join84(agentsRoot, agent, ".claude", "skills");
89619
+ const skillsDir = join85(agentsRoot, agent, ".claude", "skills");
89189
89620
  const personal = [];
89190
- if (existsSync83(skillsDir)) {
89621
+ if (existsSync84(skillsDir)) {
89191
89622
  for (const ent of readdirSync32(skillsDir, { withFileTypes: true })) {
89192
89623
  if (!ent.isDirectory())
89193
89624
  continue;
89194
89625
  if (!ent.name.startsWith(PERSONAL_PREFIX))
89195
89626
  continue;
89196
89627
  const skillName = ent.name.slice(PERSONAL_PREFIX.length);
89197
- const skillPath = join84(skillsDir, ent.name);
89628
+ const skillPath = join85(skillsDir, ent.name);
89198
89629
  let fileCount = 0;
89199
89630
  let totalBytes = 0;
89200
89631
  const walk2 = (sub) => {
@@ -89202,10 +89633,10 @@ function listPersonalAction(opts) {
89202
89633
  if (e.isFile()) {
89203
89634
  fileCount += 1;
89204
89635
  try {
89205
- totalBytes += statSync35(join84(sub, e.name)).size;
89636
+ totalBytes += statSync35(join85(sub, e.name)).size;
89206
89637
  } catch {}
89207
89638
  } else if (e.isDirectory()) {
89208
- walk2(join84(sub, e.name));
89639
+ walk2(join85(sub, e.name));
89209
89640
  }
89210
89641
  }
89211
89642
  };
@@ -89244,28 +89675,28 @@ function registerSkillPersonalCommands(program3) {
89244
89675
  // src/cli/skill-search.ts
89245
89676
  init_helpers();
89246
89677
  var import_yaml25 = __toESM(require_dist(), 1);
89247
- import { existsSync as existsSync84, readdirSync as readdirSync33, readFileSync as readFileSync72, statSync as statSync36 } from "node:fs";
89678
+ import { existsSync as existsSync85, readdirSync as readdirSync33, readFileSync as readFileSync73, statSync as statSync36 } from "node:fs";
89248
89679
  import { homedir as homedir50 } from "node:os";
89249
- import { join as join85, resolve as resolve51 } from "node:path";
89680
+ import { join as join86, resolve as resolve52 } from "node:path";
89250
89681
  var PERSONAL_PREFIX2 = "personal-";
89251
89682
  var BUNDLED_SUBDIR = "_bundled";
89252
89683
  var AGENT_NAME_RE3 = /^[a-z][a-z0-9_-]{0,62}$/;
89253
89684
  function defaultAgentsRoot() {
89254
- return resolve51(homedir50(), ".switchroom/agents");
89685
+ return resolve52(homedir50(), ".switchroom/agents");
89255
89686
  }
89256
89687
  function defaultSharedRoot2() {
89257
- return resolve51(homedir50(), ".switchroom/skills");
89688
+ return resolve52(homedir50(), ".switchroom/skills");
89258
89689
  }
89259
89690
  function defaultBundledRoot2() {
89260
- return resolve51(homedir50(), ".switchroom/skills/_bundled");
89691
+ return resolve52(homedir50(), ".switchroom/skills/_bundled");
89261
89692
  }
89262
89693
  function readSkillFrontmatter(skillDir) {
89263
- const mdPath = join85(skillDir, "SKILL.md");
89264
- if (!existsSync84(mdPath))
89694
+ const mdPath = join86(skillDir, "SKILL.md");
89695
+ if (!existsSync85(mdPath))
89265
89696
  return null;
89266
89697
  let content;
89267
89698
  try {
89268
- content = readFileSync72(mdPath, "utf-8");
89699
+ content = readFileSync73(mdPath, "utf-8");
89269
89700
  } catch {
89270
89701
  return null;
89271
89702
  }
@@ -89293,7 +89724,7 @@ function readSkillFrontmatter(skillDir) {
89293
89724
  return { fm: parsed };
89294
89725
  }
89295
89726
  function statSkillMd(skillDir) {
89296
- const mdPath = join85(skillDir, "SKILL.md");
89727
+ const mdPath = join86(skillDir, "SKILL.md");
89297
89728
  try {
89298
89729
  const st = statSync36(mdPath);
89299
89730
  return { size: st.size, mtime: st.mtime.toISOString() };
@@ -89304,8 +89735,8 @@ function statSkillMd(skillDir) {
89304
89735
  function listPersonalSkills(agent, agentsRoot = defaultAgentsRoot()) {
89305
89736
  if (!AGENT_NAME_RE3.test(agent))
89306
89737
  return [];
89307
- const skillsDir = join85(agentsRoot, agent, ".claude/skills");
89308
- if (!existsSync84(skillsDir))
89738
+ const skillsDir = join86(agentsRoot, agent, ".claude/skills");
89739
+ if (!existsSync85(skillsDir))
89309
89740
  return [];
89310
89741
  const out = [];
89311
89742
  let entries;
@@ -89317,7 +89748,7 @@ function listPersonalSkills(agent, agentsRoot = defaultAgentsRoot()) {
89317
89748
  for (const ent of entries) {
89318
89749
  if (!ent.startsWith(PERSONAL_PREFIX2))
89319
89750
  continue;
89320
- const dirPath = join85(skillsDir, ent);
89751
+ const dirPath = join86(skillsDir, ent);
89321
89752
  try {
89322
89753
  if (!statSync36(dirPath).isDirectory())
89323
89754
  continue;
@@ -89343,7 +89774,7 @@ function listPersonalSkills(agent, agentsRoot = defaultAgentsRoot()) {
89343
89774
  return out;
89344
89775
  }
89345
89776
  function listSharedSkills(sharedRoot = defaultSharedRoot2()) {
89346
- if (!existsSync84(sharedRoot))
89777
+ if (!existsSync85(sharedRoot))
89347
89778
  return [];
89348
89779
  const out = [];
89349
89780
  let entries;
@@ -89357,7 +89788,7 @@ function listSharedSkills(sharedRoot = defaultSharedRoot2()) {
89357
89788
  continue;
89358
89789
  if (ent.startsWith("."))
89359
89790
  continue;
89360
- const dirPath = join85(sharedRoot, ent);
89791
+ const dirPath = join86(sharedRoot, ent);
89361
89792
  try {
89362
89793
  if (!statSync36(dirPath).isDirectory())
89363
89794
  continue;
@@ -89381,7 +89812,7 @@ function listSharedSkills(sharedRoot = defaultSharedRoot2()) {
89381
89812
  return out;
89382
89813
  }
89383
89814
  function listBundledSkills(bundledRoot = defaultBundledRoot2()) {
89384
- if (!existsSync84(bundledRoot))
89815
+ if (!existsSync85(bundledRoot))
89385
89816
  return [];
89386
89817
  const out = [];
89387
89818
  let entries;
@@ -89393,7 +89824,7 @@ function listBundledSkills(bundledRoot = defaultBundledRoot2()) {
89393
89824
  for (const ent of entries) {
89394
89825
  if (ent.startsWith("."))
89395
89826
  continue;
89396
- const dirPath = join85(bundledRoot, ent);
89827
+ const dirPath = join86(bundledRoot, ent);
89397
89828
  try {
89398
89829
  if (!statSync36(dirPath).isDirectory())
89399
89830
  continue;
@@ -89537,9 +89968,9 @@ function registerHostdMcpCommand(program3) {
89537
89968
  // src/cli/hostd.ts
89538
89969
  init_source();
89539
89970
  init_helpers();
89540
- import { existsSync as existsSync86, mkdirSync as mkdirSync49, readdirSync as readdirSync34, readFileSync as readFileSync74, writeFileSync as writeFileSync42, statSync as statSync37, copyFileSync as copyFileSync12 } from "node:fs";
89971
+ import { existsSync as existsSync87, mkdirSync as mkdirSync49, readdirSync as readdirSync34, readFileSync as readFileSync75, writeFileSync as writeFileSync42, statSync as statSync37, copyFileSync as copyFileSync12 } from "node:fs";
89541
89972
  import { homedir as homedir51 } from "node:os";
89542
- import { join as join86 } from "node:path";
89973
+ import { join as join87 } from "node:path";
89543
89974
  import { spawnSync as spawnSync19 } from "node:child_process";
89544
89975
 
89545
89976
  // src/cli/deploy-version-guard.ts
@@ -89753,14 +90184,14 @@ function resolveHostdHostHome(env2 = process.env, home2 = homedir51()) {
89753
90184
  return resolved;
89754
90185
  }
89755
90186
  function hostdDir() {
89756
- return join86(homedir51(), ".switchroom", "hostd");
90187
+ return join87(homedir51(), ".switchroom", "hostd");
89757
90188
  }
89758
90189
  function hostdComposePath() {
89759
- return join86(hostdDir(), "docker-compose.yml");
90190
+ return join87(hostdDir(), "docker-compose.yml");
89760
90191
  }
89761
90192
  function backupExistingCompose() {
89762
90193
  const p = hostdComposePath();
89763
- if (!existsSync86(p))
90194
+ if (!existsSync87(p))
89764
90195
  return null;
89765
90196
  const ts = new Date().toISOString().replace(/[:.]/g, "-");
89766
90197
  const bak = `${p}.bak-${ts}`;
@@ -89856,7 +90287,7 @@ function doStatus() {
89856
90287
  const composeYml = hostdComposePath();
89857
90288
  console.log(source_default.bold("switchroom-hostd"));
89858
90289
  console.log("");
89859
- if (!existsSync86(composeYml)) {
90290
+ if (!existsSync87(composeYml)) {
89860
90291
  console.log(source_default.yellow(" compose: not installed"));
89861
90292
  console.log(source_default.dim(" run `switchroom hostd install` to set up."));
89862
90293
  return;
@@ -89877,14 +90308,14 @@ function doStatus() {
89877
90308
  } else {
89878
90309
  console.log(source_default.green(` container: ${ps.stdout.trim()}`));
89879
90310
  }
89880
- if (existsSync86(dir)) {
90311
+ if (existsSync87(dir)) {
89881
90312
  const entries = [];
89882
90313
  try {
89883
90314
  for (const name of readdirSync34(dir)) {
89884
90315
  if (name === "docker-compose.yml" || name.startsWith("docker-compose.yml."))
89885
90316
  continue;
89886
- const sockPath = join86(dir, name, "sock");
89887
- if (existsSync86(sockPath)) {
90317
+ const sockPath = join87(dir, name, "sock");
90318
+ if (existsSync87(sockPath)) {
89888
90319
  const st = statSync37(sockPath);
89889
90320
  if ((st.mode & 61440) === 49152) {
89890
90321
  entries.push(`${name} \u2192 ${sockPath}`);
@@ -89903,7 +90334,7 @@ function doStatus() {
89903
90334
  }
89904
90335
  function doUninstall() {
89905
90336
  const composeYml = hostdComposePath();
89906
- if (!existsSync86(composeYml)) {
90337
+ if (!existsSync87(composeYml)) {
89907
90338
  console.log(source_default.yellow(" No hostd install detected (no compose file at this path)."));
89908
90339
  return;
89909
90340
  }
@@ -89927,12 +90358,12 @@ function registerHostdCommand(program3) {
89927
90358
  hostd.command("uninstall").description("Stop the hostd container. Leaves the compose file in place for re-install.").action(() => doUninstall());
89928
90359
  hostd.command("audit").description("Tail and filter the hostd audit log (privileged-verb call history)").option("--tail <n>", "Number of matching entries to show (default: 50)", "50").option("--agent <name>", "Filter to a specific caller agent").option("--op <verb>", "Filter to a specific hostd verb (e.g. update_apply, agent_restart)").option("--error", "Show only failed (error/denied) entries").option("--verbose", "Show the captured stderr / error tail under each failed row").option("--path <file>", "Override audit log path (for debugging)").action((opts) => {
89929
90360
  const logPath = opts.path ?? defaultAuditLogPath2();
89930
- if (!existsSync86(logPath)) {
90361
+ if (!existsSync87(logPath)) {
89931
90362
  console.error(source_default.yellow(`Audit log not found at ${logPath}.`) + source_default.gray(`
89932
90363
  The log is created when hostd handles its first privileged-verb request.`));
89933
90364
  return;
89934
90365
  }
89935
- const raw = readFileSync74(logPath, "utf-8");
90366
+ const raw = readFileSync75(logPath, "utf-8");
89936
90367
  const limit = Math.max(1, parseInt(opts.tail ?? "50", 10) || 50);
89937
90368
  const filters = {
89938
90369
  agent: opts.agent,
@@ -89974,9 +90405,9 @@ The log is created when hostd handles its first privileged-verb request.`));
89974
90405
  // src/cli/webd.ts
89975
90406
  init_source();
89976
90407
  init_helpers();
89977
- import { existsSync as existsSync87, mkdirSync as mkdirSync50, writeFileSync as writeFileSync43, copyFileSync as copyFileSync13 } from "node:fs";
90408
+ import { existsSync as existsSync88, mkdirSync as mkdirSync50, writeFileSync as writeFileSync43, copyFileSync as copyFileSync13 } from "node:fs";
89978
90409
  import { homedir as homedir52 } from "node:os";
89979
- import { join as join87 } from "node:path";
90410
+ import { join as join88 } from "node:path";
89980
90411
  import { spawnSync as spawnSync20 } from "node:child_process";
89981
90412
  function resolveWebImageTag(explicitTag, release) {
89982
90413
  if (explicitTag)
@@ -90061,14 +90492,14 @@ services:
90061
90492
  `;
90062
90493
  }
90063
90494
  function webdDir() {
90064
- return join87(homedir52(), ".switchroom", "web");
90495
+ return join88(homedir52(), ".switchroom", "web");
90065
90496
  }
90066
90497
  function webdComposePath() {
90067
- return join87(webdDir(), "docker-compose.yml");
90498
+ return join88(webdDir(), "docker-compose.yml");
90068
90499
  }
90069
90500
  function backupExistingCompose2() {
90070
90501
  const p = webdComposePath();
90071
- if (!existsSync87(p))
90502
+ if (!existsSync88(p))
90072
90503
  return null;
90073
90504
  const ts = new Date().toISOString().replace(/[:.]/g, "-");
90074
90505
  const bak = `${p}.bak-${ts}`;
@@ -90152,7 +90583,7 @@ function doStatus2() {
90152
90583
  const composeYml = webdComposePath();
90153
90584
  console.log(source_default.bold("switchroom-web"));
90154
90585
  console.log("");
90155
- if (!existsSync87(composeYml)) {
90586
+ if (!existsSync88(composeYml)) {
90156
90587
  console.log(source_default.yellow(" compose: not installed"));
90157
90588
  console.log(source_default.dim(" run `switchroom webd install` to set up."));
90158
90589
  return;
@@ -90176,7 +90607,7 @@ function doStatus2() {
90176
90607
  }
90177
90608
  function doUninstall2() {
90178
90609
  const composeYml = webdComposePath();
90179
- if (!existsSync87(composeYml)) {
90610
+ if (!existsSync88(composeYml)) {
90180
90611
  console.log(source_default.yellow(" No web-service install detected (no compose file at this path)."));
90181
90612
  return;
90182
90613
  }
@@ -90206,9 +90637,9 @@ function registerWebdCommand(program3) {
90206
90637
  // src/cli/host-repair.ts
90207
90638
  init_source();
90208
90639
  import { homedir as homedir53 } from "node:os";
90209
- import { join as join88 } from "node:path";
90640
+ import { join as join89 } from "node:path";
90210
90641
  var ARTIFACT_ALLOWLIST = {
90211
- dockerComposePluginDir: (home2) => join88(home2, ".docker", "cli-plugins", "docker-compose"),
90642
+ dockerComposePluginDir: (home2) => join89(home2, ".docker", "cli-plugins", "docker-compose"),
90212
90643
  stateSentinel: "/state"
90213
90644
  };
90214
90645
  function isStateBogusAutoDir(probe2) {