switchroom 0.19.8 → 0.19.9

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.
@@ -2120,7 +2120,7 @@ var init_esm = __esm(() => {
2120
2120
  });
2121
2121
 
2122
2122
  // src/build-info.ts
2123
- var VERSION = "0.19.8", COMMIT_SHA = "c356d3ba";
2123
+ var VERSION = "0.19.9", COMMIT_SHA = "9d791e63";
2124
2124
 
2125
2125
  // src/cli/resolve-version.ts
2126
2126
  import { existsSync, readFileSync } from "node:fs";
@@ -23939,7 +23939,7 @@ function bindingsForAgent(agentName, mw, microsoftAccounts) {
23939
23939
  // src/agents/reconcile-default-skills.ts
23940
23940
  import { existsSync as existsSync8, lstatSync as lstatSync2, mkdirSync as mkdirSync3, readdirSync as readdirSync4, readlinkSync as readlinkSync3, rmSync as rmSync2, symlinkSync } from "node:fs";
23941
23941
  import { homedir as homedir3 } from "node:os";
23942
- import { join as join6, resolve as resolve5 } from "node:path";
23942
+ import { dirname as dirname2, isAbsolute, join as join6, relative, resolve as resolve5 } from "node:path";
23943
23943
  function warnMissingPoolDir(poolDir) {
23944
23944
  if (warnedMissingPool.has(poolDir))
23945
23945
  return;
@@ -23947,6 +23947,14 @@ function warnMissingPoolDir(poolDir) {
23947
23947
  process.stderr.write(`switchroom: bundled skills pool dir not found at ${poolDir} \u2014 run \`switchroom update\` to install it.
23948
23948
  `);
23949
23949
  }
23950
+ function warnMissingBuiltinDefault(poolDir, key) {
23951
+ const marker = `${poolDir} ${key}`;
23952
+ if (warnedMissingDefault.has(marker))
23953
+ return;
23954
+ warnedMissingDefault.add(marker);
23955
+ process.stderr.write(`switchroom: ERROR \u2014 builtin default skill "${key}" is missing from the bundled pool ` + `(${poolDir}). It ships in the CLI package but was not synced. ` + `Re-run \`switchroom update\` to repair the pool; if it persists this is a packaging bug.
23956
+ `);
23957
+ }
23950
23958
  function getBundledSkillsPoolDir() {
23951
23959
  return resolve5(homedir3(), ".switchroom/skills/_bundled");
23952
23960
  }
@@ -23961,6 +23969,27 @@ function isOwnedStaleLink(target, poolDir) {
23961
23969
  return true;
23962
23970
  return false;
23963
23971
  }
23972
+ function absoluteLinkTarget(linkPath, storedTarget) {
23973
+ return isAbsolute(storedTarget) ? storedTarget : resolve5(dirname2(linkPath), storedTarget);
23974
+ }
23975
+ function linkTargetFor(dest, src) {
23976
+ return relative(dirname2(dest), src);
23977
+ }
23978
+ function isOwnedBundledLink(dest, poolDir) {
23979
+ let stored = null;
23980
+ try {
23981
+ if (!lstatSync2(dest).isSymbolicLink())
23982
+ return false;
23983
+ stored = readlinkSync3(dest);
23984
+ } catch {
23985
+ return false;
23986
+ }
23987
+ if (!stored)
23988
+ return false;
23989
+ const resolved = isAbsolute(stored) ? stored : resolve5(dirname2(dest), stored);
23990
+ const poolPrefix = poolDir.endsWith("/") ? poolDir : poolDir + "/";
23991
+ return resolved === poolDir || resolved.startsWith(poolPrefix);
23992
+ }
23964
23993
  function reconcileAgentDefaultSkills(agentDir, optOuts = {}, defaults = getBuiltinDefaultSkillEntries(), poolDir = getBundledSkillsPoolDir()) {
23965
23994
  const name = agentDir.split("/").pop() ?? agentDir;
23966
23995
  const result = {
@@ -23969,6 +23998,8 @@ function reconcileAgentDefaultSkills(agentDir, optOuts = {}, defaults = getBuilt
23969
23998
  alreadyPresent: [],
23970
23999
  optedOut: [],
23971
24000
  conflicts: [],
24001
+ missingFromPool: [],
24002
+ pruned: [],
23972
24003
  changed: false
23973
24004
  };
23974
24005
  const claudeDir = join6(agentDir, ".claude");
@@ -23982,15 +24013,32 @@ function reconcileAgentDefaultSkills(agentDir, optOuts = {}, defaults = getBuilt
23982
24013
  return result;
23983
24014
  }
23984
24015
  for (const entry of defaults) {
24016
+ const dest = join6(targetDir, entry.key);
23985
24017
  if (optOuts[entry.optOutKey] === false) {
23986
24018
  result.optedOut.push(entry.key);
24019
+ if (isOwnedBundledLink(dest, poolDir)) {
24020
+ try {
24021
+ rmSync2(dest, { force: true });
24022
+ result.pruned.push(entry.key);
24023
+ result.changed = true;
24024
+ } catch {}
24025
+ }
23987
24026
  continue;
23988
24027
  }
23989
24028
  const src = join6(poolDir, entry.key);
23990
24029
  if (!existsSync8(src)) {
24030
+ result.missingFromPool.push(entry.key);
24031
+ warnMissingBuiltinDefault(poolDir, entry.key);
24032
+ if (isOwnedBundledLink(dest, poolDir)) {
24033
+ try {
24034
+ rmSync2(dest, { force: true });
24035
+ result.pruned.push(entry.key);
24036
+ result.changed = true;
24037
+ } catch {}
24038
+ }
23991
24039
  continue;
23992
24040
  }
23993
- const dest = join6(targetDir, entry.key);
24041
+ const relTarget = linkTargetFor(dest, src);
23994
24042
  let existing;
23995
24043
  try {
23996
24044
  existing = lstatSync2(dest);
@@ -24003,11 +24051,12 @@ function reconcileAgentDefaultSkills(agentDir, optOuts = {}, defaults = getBuilt
24003
24051
  try {
24004
24052
  currentTarget = readlinkSync3(dest);
24005
24053
  } catch {}
24006
- if (currentTarget === src) {
24054
+ if (currentTarget === relTarget) {
24007
24055
  result.alreadyPresent.push(entry.key);
24008
24056
  continue;
24009
24057
  }
24010
- if (currentTarget && isOwnedStaleLink(currentTarget, poolDir)) {
24058
+ const resolvedTarget = currentTarget ? absoluteLinkTarget(dest, currentTarget) : null;
24059
+ if (resolvedTarget && isOwnedStaleLink(resolvedTarget, poolDir)) {
24011
24060
  try {
24012
24061
  rmSync2(dest, { force: true });
24013
24062
  } catch {}
@@ -24021,7 +24070,7 @@ function reconcileAgentDefaultSkills(agentDir, optOuts = {}, defaults = getBuilt
24021
24070
  }
24022
24071
  }
24023
24072
  try {
24024
- symlinkSync(src, dest);
24073
+ symlinkSync(relTarget, dest);
24025
24074
  result.added.push(entry.key);
24026
24075
  result.changed = true;
24027
24076
  } catch (err) {
@@ -24030,10 +24079,11 @@ function reconcileAgentDefaultSkills(agentDir, optOuts = {}, defaults = getBuilt
24030
24079
  }
24031
24080
  return result;
24032
24081
  }
24033
- var warnedMissingPool;
24082
+ var warnedMissingPool, warnedMissingDefault;
24034
24083
  var init_reconcile_default_skills = __esm(() => {
24035
24084
  init_scaffold_integration();
24036
24085
  warnedMissingPool = new Set;
24086
+ warnedMissingDefault = new Set;
24037
24087
  });
24038
24088
 
24039
24089
  // src/agents/sub-agent-telegram-prompt.ts
@@ -24089,7 +24139,7 @@ import {
24089
24139
  copyFileSync as copyFileSync2,
24090
24140
  unlinkSync
24091
24141
  } from "node:fs";
24092
- import { basename as basename2, dirname as dirname2, resolve as resolve6 } from "node:path";
24142
+ import { basename as basename2, dirname as dirname3, resolve as resolve6 } from "node:path";
24093
24143
  function defaultStatePath() {
24094
24144
  return resolveStatePath("topics.json");
24095
24145
  }
@@ -24116,7 +24166,7 @@ function loadTopicState(statePath) {
24116
24166
  }
24117
24167
  function saveTopicState(state, statePath) {
24118
24168
  const path = statePath ?? defaultStatePath();
24119
- const dir = dirname2(path);
24169
+ const dir = dirname3(path);
24120
24170
  if (!existsSync9(dir)) {
24121
24171
  mkdirSync4(dir, { recursive: true });
24122
24172
  }
@@ -24388,7 +24438,7 @@ import {
24388
24438
  lstatSync as lstatSync3,
24389
24439
  realpathSync as realpathSync2
24390
24440
  } from "node:fs";
24391
- import { dirname as dirname3, basename as basename3, resolve as resolve7 } from "node:path";
24441
+ import { dirname as dirname4, basename as basename3, resolve as resolve7 } from "node:path";
24392
24442
  function atomicWriteFileSync2(path, data, mode) {
24393
24443
  let effectivePath = path;
24394
24444
  try {
@@ -24396,7 +24446,7 @@ function atomicWriteFileSync2(path, data, mode) {
24396
24446
  effectivePath = realpathSync2(path);
24397
24447
  }
24398
24448
  } catch {}
24399
- const dir = dirname3(resolve7(effectivePath));
24449
+ const dir = dirname4(resolve7(effectivePath));
24400
24450
  const tmp = resolve7(dir, `.${basename3(effectivePath)}.${process.pid}.${Date.now()}.tmp`);
24401
24451
  try {
24402
24452
  const fd = openSync4(tmp, "wx", mode);
@@ -24533,7 +24583,7 @@ function createVault(passphrase, vaultPath) {
24533
24583
  if (existsSync11(vaultPath)) {
24534
24584
  throw new VaultError(`Vault file already exists: ${vaultPath}`);
24535
24585
  }
24536
- const dir = dirname3(vaultPath);
24586
+ const dir = dirname4(vaultPath);
24537
24587
  if (!existsSync11(dir)) {
24538
24588
  mkdirSync5(dir, { recursive: true, mode: 448 });
24539
24589
  }
@@ -26141,7 +26191,7 @@ import {
26141
26191
  } from "node:fs";
26142
26192
  import { homedir as homedir5 } from "node:os";
26143
26193
  import { execSync, execFileSync as execFileSync6 } from "node:child_process";
26144
- import { join as join11, resolve as resolve11 } from "node:path";
26194
+ import { dirname as dirname5, isAbsolute as isAbsolute2, join as join11, relative as relative2, resolve as resolve11 } from "node:path";
26145
26195
  import { createHash as createHash3 } from "node:crypto";
26146
26196
  function prependReplyDiscipline(rendered, context) {
26147
26197
  const replyDiscipline = renderReplyDisciplineFragment(context);
@@ -26527,7 +26577,8 @@ function migrateLegacySkillsDir(agentDir, skillsPool) {
26527
26577
  } catch {
26528
26578
  continue;
26529
26579
  }
26530
- if (target && target.startsWith(skillsPool)) {
26580
+ const resolved = target ? isAbsolute2(target) ? target : resolve11(dirname5(entryPath), target) : null;
26581
+ if (resolved && resolved.startsWith(skillsPool)) {
26531
26582
  try {
26532
26583
  rmSync4(entryPath, { force: true });
26533
26584
  } catch {}
@@ -26550,6 +26601,7 @@ function syncGlobalSkills(agentDir, declared, skillsDirOverride) {
26550
26601
  console.warn(` WARNING: skill "${name}" not found in pool (${skillsPool}) \u2014 skipping`);
26551
26602
  continue;
26552
26603
  }
26604
+ const relTarget = relative2(dirname5(dest), src);
26553
26605
  let linkStat;
26554
26606
  try {
26555
26607
  linkStat = lstatSync4(dest);
@@ -26562,7 +26614,11 @@ function syncGlobalSkills(agentDir, declared, skillsDirOverride) {
26562
26614
  try {
26563
26615
  target = readlinkSync4(dest);
26564
26616
  } catch {}
26565
- if (target && target.startsWith(skillsPool)) {
26617
+ if (target === relTarget) {
26618
+ continue;
26619
+ }
26620
+ const resolved = target ? isAbsolute2(target) ? target : resolve11(dirname5(dest), target) : null;
26621
+ if (resolved && resolved.startsWith(skillsPool)) {
26566
26622
  try {
26567
26623
  rmSync4(dest, { force: true });
26568
26624
  } catch {}
@@ -26574,7 +26630,7 @@ function syncGlobalSkills(agentDir, declared, skillsDirOverride) {
26574
26630
  }
26575
26631
  }
26576
26632
  try {
26577
- symlinkSync2(src, dest);
26633
+ symlinkSync2(relTarget, dest);
26578
26634
  } catch (err) {
26579
26635
  console.warn(` WARNING: failed to symlink skill "${name}": ${err.message}`);
26580
26636
  }
@@ -26590,10 +26646,11 @@ function syncGlobalSkills(agentDir, declared, skillsDirOverride) {
26590
26646
  } catch {
26591
26647
  continue;
26592
26648
  }
26593
- if (linkTarget && linkTarget.includes("/.switchroom/skills/_bundled/")) {
26649
+ const resolved = linkTarget ? isAbsolute2(linkTarget) ? linkTarget : resolve11(dirname5(entryPath), linkTarget) : null;
26650
+ if (resolved && resolved.includes("/.switchroom/skills/_bundled/")) {
26594
26651
  continue;
26595
26652
  }
26596
- if (linkTarget && linkTarget.startsWith(skillsPool)) {
26653
+ if (resolved && resolved.startsWith(skillsPool)) {
26597
26654
  rmSync4(entryPath, { force: true });
26598
26655
  }
26599
26656
  }
@@ -26646,7 +26703,10 @@ function installSwitchroomSkills(agentDir, opts = {}) {
26646
26703
  try {
26647
26704
  currentTarget = readlinkSync4(dest);
26648
26705
  } catch {}
26649
- if (currentTarget !== join11(builtinSkillsDir, name))
26706
+ if (!currentTarget)
26707
+ continue;
26708
+ const resolvedTarget = isAbsolute2(currentTarget) ? currentTarget : resolve11(dirname5(dest), currentTarget);
26709
+ if (resolvedTarget !== join11(builtinSkillsDir, name))
26650
26710
  continue;
26651
26711
  try {
26652
26712
  rmSync4(dest, { force: true });
@@ -26657,6 +26717,7 @@ function installSwitchroomSkills(agentDir, opts = {}) {
26657
26717
  for (const name of switchroomSkillNames) {
26658
26718
  const src = join11(builtinSkillsDir, name);
26659
26719
  const dest = join11(targetDir, name);
26720
+ const relTarget = relative2(dirname5(dest), src);
26660
26721
  let existing;
26661
26722
  try {
26662
26723
  existing = lstatSync4(dest);
@@ -26669,7 +26730,7 @@ function installSwitchroomSkills(agentDir, opts = {}) {
26669
26730
  try {
26670
26731
  currentTarget = readlinkSync4(dest);
26671
26732
  } catch {}
26672
- if (currentTarget === src)
26733
+ if (currentTarget === relTarget)
26673
26734
  continue;
26674
26735
  try {
26675
26736
  rmSync4(dest, { force: true });
@@ -26679,7 +26740,7 @@ function installSwitchroomSkills(agentDir, opts = {}) {
26679
26740
  }
26680
26741
  }
26681
26742
  try {
26682
- symlinkSync2(src, dest);
26743
+ symlinkSync2(relTarget, dest);
26683
26744
  } catch (err) {
26684
26745
  console.warn(` WARNING: failed to symlink switchroom skill "${name}": ${err.message}`);
26685
26746
  }
@@ -27381,6 +27442,24 @@ function resolveWebkiteMcpEntry(_agentName, agentConfig, _switchroomConfig) {
27381
27442
  }
27382
27443
  };
27383
27444
  }
27445
+ function computeDesiredPermissionAllow(agentConfig, hindsightEnabled) {
27446
+ const tools = agentConfig.tools ?? { allow: [], deny: [] };
27447
+ const rawAllow = tools.allow ?? [];
27448
+ const hasAllWildcard = rawAllow.includes("all");
27449
+ const baseAllow = hasAllWildcard ? [...ALL_BUILTIN_TOOLS, ...rawAllow.filter((t) => t !== "all")] : rawAllow.filter((t) => t !== "all");
27450
+ const dangerousMode = agentConfig.dangerous_mode === true;
27451
+ const hadExplicitAllow = rawAllow.length > 0;
27452
+ const readOnlyDefaults = !dangerousMode && !hadExplicitAllow ? DEFAULT_READ_ONLY_PREAPPROVED_TOOLS : [];
27453
+ return dedupe2([
27454
+ ...baseAllow,
27455
+ ...readOnlyDefaults,
27456
+ ...usesSwitchroomTelegramPlugin(agentConfig) ? SWITCHROOM_TELEGRAM_MCP_TOOLS : [],
27457
+ ...hindsightEnabled ? HINDSIGHT_MCP_TOOLS : [],
27458
+ ...AGENT_CONFIG_MCP_TOOLS,
27459
+ ...HOSTD_MCP_TOOLS,
27460
+ ...agentConfig.mcp_servers?.["webkite"] === false ? [] : WEBKITE_MCP_TOOLS
27461
+ ]);
27462
+ }
27384
27463
  function scaffoldAgent(name, agentConfigRaw, agentsDir, telegramConfig, switchroomConfig, userIdOverride, switchroomConfigPath) {
27385
27464
  const agentConfig = resolveAgentConfig(switchroomConfig?.defaults, switchroomConfig?.profiles, agentConfigRaw);
27386
27465
  const agentDir = resolve11(agentsDir, name);
@@ -27403,20 +27482,8 @@ function scaffoldAgent(name, agentConfigRaw, agentsDir, telegramConfig, switchro
27403
27482
  const tools = agentConfig.tools ?? { allow: [], deny: [] };
27404
27483
  const rawAllow = tools.allow ?? [];
27405
27484
  const hasAllWildcard = rawAllow.includes("all");
27406
- const baseAllow = hasAllWildcard ? [...ALL_BUILTIN_TOOLS, ...rawAllow.filter((t) => t !== "all")] : rawAllow.filter((t) => t !== "all");
27407
- const dangerousMode = agentConfig.dangerous_mode === true;
27408
- const hadExplicitAllow = rawAllow.length > 0;
27409
- const readOnlyDefaults = !dangerousMode && !hadExplicitAllow ? DEFAULT_READ_ONLY_PREAPPROVED_TOOLS : [];
27410
27485
  const hindsightEnabled = isHindsightEnabled(switchroomConfig);
27411
- const permissionAllow = dedupe2([
27412
- ...baseAllow,
27413
- ...readOnlyDefaults,
27414
- ...usesSwitchroomTelegramPlugin(agentConfig) ? SWITCHROOM_TELEGRAM_MCP_TOOLS : [],
27415
- ...hindsightEnabled ? HINDSIGHT_MCP_TOOLS : [],
27416
- ...AGENT_CONFIG_MCP_TOOLS,
27417
- ...HOSTD_MCP_TOOLS,
27418
- ...agentConfig.mcp_servers?.["webkite"] === false ? [] : WEBKITE_MCP_TOOLS
27419
- ]);
27486
+ const permissionAllow = computeDesiredPermissionAllow(agentConfig, hindsightEnabled);
27420
27487
  const hindsightAutoRecallEnabled = hindsightEnabled && agentConfig.memory?.auto_recall !== false;
27421
27488
  const hindsightBankId = agentConfig.memory?.collection ?? name;
27422
27489
  const hindsightApiBaseUrl = switchroomConfig?.memory?.config?.url ? switchroomConfig.memory.config.url.replace(/\/mcp\/?$/, "").replace(/\/$/, "") : HINDSIGHT_DEFAULT_API_BASE_URL;
@@ -28332,23 +28399,11 @@ function reconcileAgentInner(name, agentConfigRaw, agentsDir, telegramConfig, sw
28332
28399
  const tools = agentConfig.tools ?? { allow: [], deny: [] };
28333
28400
  const rawAllow = tools.allow ?? [];
28334
28401
  const hasAllWildcard = rawAllow.includes("all");
28335
- const baseAllow = hasAllWildcard ? [...ALL_BUILTIN_TOOLS, ...rawAllow.filter((t) => t !== "all")] : rawAllow.filter((t) => t !== "all");
28336
- const reconcileDangerousMode = agentConfig.dangerous_mode === true;
28337
- const reconcileHadExplicitAllow = rawAllow.length > 0;
28338
- const reconcileReadOnlyDefaults = !reconcileDangerousMode && !reconcileHadExplicitAllow ? DEFAULT_READ_ONLY_PREAPPROVED_TOOLS : [];
28339
28402
  const hindsightEnabled = isHindsightEnabled(switchroomConfig);
28403
+ const desiredAllow = computeDesiredPermissionAllow(agentConfig, hindsightEnabled);
28340
28404
  if (Array.isArray(tools.allow)) {
28341
28405
  tools.allow = tools.allow.filter((p) => !LEGACY_SWITCHROOM_MCP_TOKENS.includes(p) && !LEGACY_HOSTD_BLANKET_TOKENS.includes(p));
28342
28406
  }
28343
- const desiredAllow = dedupe2([
28344
- ...baseAllow,
28345
- ...reconcileReadOnlyDefaults,
28346
- ...usesSwitchroomTelegramPlugin(agentConfig) ? SWITCHROOM_TELEGRAM_MCP_TOOLS : [],
28347
- ...hindsightEnabled ? HINDSIGHT_MCP_TOOLS : [],
28348
- ...AGENT_CONFIG_MCP_TOOLS,
28349
- ...HOSTD_MCP_TOOLS,
28350
- ...agentConfig.mcp_servers?.["webkite"] === false ? [] : WEBKITE_MCP_TOOLS
28351
- ]);
28352
28407
  const desiredDeny = dedupe2([
28353
28408
  ...tools.deny ?? [],
28354
28409
  ...webkiteDenyForAgent(agentConfig),
@@ -29606,7 +29661,7 @@ var init_scaffold = __esm(() => {
29606
29661
 
29607
29662
  // src/setup/host-capabilities.ts
29608
29663
  import { existsSync as existsSync17, mkdirSync as mkdirSync11, readFileSync as readFileSync14, writeFileSync as writeFileSync5 } from "node:fs";
29609
- import { dirname as dirname4 } from "node:path";
29664
+ import { dirname as dirname6 } from "node:path";
29610
29665
  function hostCapabilitiesPath() {
29611
29666
  return resolveStatePath("host-capabilities.json");
29612
29667
  }
@@ -29621,7 +29676,7 @@ function saveVoiceCapability(caps, now = () => new Date) {
29621
29676
  }
29622
29677
  };
29623
29678
  const path = hostCapabilitiesPath();
29624
- mkdirSync11(dirname4(path), { recursive: true });
29679
+ mkdirSync11(dirname6(path), { recursive: true });
29625
29680
  writeFileSync5(path, JSON.stringify(doc, null, 2) + `
29626
29681
  `, {
29627
29682
  encoding: "utf-8",
@@ -29728,11 +29783,11 @@ var init_grants_db_path = __esm(() => {
29728
29783
 
29729
29784
  // src/agents/compose.ts
29730
29785
  import { existsSync as existsSync19, mkdirSync as mkdirSync13, readFileSync as readFileSync15, lstatSync as lstatSync5, readlinkSync as readlinkSync5, chmodSync as chmodSync4 } from "node:fs";
29731
- import { join as join13, isAbsolute, dirname as dirname6, resolve as resolve13 } from "node:path";
29786
+ import { join as join13, isAbsolute as isAbsolute3, dirname as dirname8, resolve as resolve13 } from "node:path";
29732
29787
  function assertPlausibleHostHome(homePrefix) {
29733
29788
  if (homePrefix === "${HOME}")
29734
29789
  return;
29735
- const bad = !isAbsolute(homePrefix) || CONTAINER_ROOT_PREFIXES.some((p) => homePrefix === p || homePrefix.startsWith(p + "/"));
29790
+ const bad = !isAbsolute3(homePrefix) || CONTAINER_ROOT_PREFIXES.some((p) => homePrefix === p || homePrefix.startsWith(p + "/"));
29736
29791
  if (!bad)
29737
29792
  return;
29738
29793
  throw new Error(`compose: refusing to generate \u2014 the host-home prefix resolved to "${homePrefix}", ` + `which is not a real host path (it looks like an in-container root). Emitting it as a ` + `bind-mount source would make docker auto-create empty dirs on the host and crash the ` + `fleet (start.sh missing \u2192 exec 127; broker EISDIR / SQLite "unable to open").
@@ -29976,8 +30031,8 @@ function conditionalMountPresent(probePath, hostHome, probeHome) {
29976
30031
  if (!lstatSync5(probePath).isSymbolicLink())
29977
30032
  return false;
29978
30033
  let target = readlinkSync5(probePath);
29979
- if (!isAbsolute(target))
29980
- target = resolve13(dirname6(probePath), target);
30034
+ if (!isAbsolute3(target))
30035
+ target = resolve13(dirname8(probePath), target);
29981
30036
  if (hostHome && probeHome && hostHome !== probeHome) {
29982
30037
  if (target.startsWith(hostHome + "/")) {
29983
30038
  return true;
@@ -30026,7 +30081,7 @@ function generateCompose(opts) {
30026
30081
  const lines = [];
30027
30082
  lines.push("# generated by switchroom \u2014 do not edit by hand.");
30028
30083
  lines.push("# Manual edits will be overwritten on the next `switchroom agent add`");
30029
- lines.push("# (or future `switchroom reconcile`). To customise an agent, edit");
30084
+ lines.push("# or `switchroom apply`. To customise an agent, edit");
30030
30085
  lines.push("# switchroom.yaml and re-run the regenerating command.");
30031
30086
  lines.push("");
30032
30087
  lines.push(`# image tag: ${imageTag}`);
@@ -30698,7 +30753,7 @@ var init_operator_uid = () => {};
30698
30753
  import { chownSync as chownSync2 } from "node:fs";
30699
30754
  import { mkdir, readFile, writeFile, rename, copyFile } from "node:fs/promises";
30700
30755
  import { homedir as homedir7 } from "node:os";
30701
- import { basename as basename4, dirname as dirname7, join as join15 } from "node:path";
30756
+ import { basename as basename4, dirname as dirname9, join as join15 } from "node:path";
30702
30757
  function agentHadLiteLLMRouting(composeContent, agentName) {
30703
30758
  const lines = composeContent.split(`
30704
30759
  `);
@@ -30839,7 +30894,7 @@ async function computeComposeContent(opts) {
30839
30894
  async function writeComposeFile(opts) {
30840
30895
  const { content, imageTag, previous, previousImageTag } = await computeComposeContent(opts);
30841
30896
  const operatorUid = resolveOperatorUid();
30842
- await mkdir(dirname7(opts.composePath), { recursive: true });
30897
+ await mkdir(dirname9(opts.composePath), { recursive: true });
30843
30898
  if (previous !== null) {
30844
30899
  try {
30845
30900
  await copyFile(opts.composePath, opts.composePath + ".bak");
@@ -30908,9 +30963,9 @@ var init_tmux = __esm(() => {
30908
30963
 
30909
30964
  // src/agents/compose-env.ts
30910
30965
  import { existsSync as existsSync21 } from "node:fs";
30911
- import { dirname as dirname8 } from "node:path";
30966
+ import { dirname as dirname10 } from "node:path";
30912
30967
  function composeEnvPath(composePath) {
30913
- return dirname8(composePath) + "/.env";
30968
+ return dirname10(composePath) + "/.env";
30914
30969
  }
30915
30970
  function composeEnvFileArgs(composePath) {
30916
30971
  const envPath = composeEnvPath(composePath);
@@ -35578,7 +35633,7 @@ import {
35578
35633
  unlinkSync as unlinkSync7
35579
35634
  } from "node:fs";
35580
35635
  import { createHash as createHash6 } from "node:crypto";
35581
- import { basename as basename5, dirname as dirname9, join as join31 } from "node:path";
35636
+ import { basename as basename5, dirname as dirname11, join as join31 } from "node:path";
35582
35637
  function vaultLayoutPaths(home2) {
35583
35638
  const switchroomRoot = join31(home2, ".switchroom");
35584
35639
  return {
@@ -35731,7 +35786,7 @@ function sha256File(path2) {
35731
35786
  return createHash6("sha256").update(data).digest("hex");
35732
35787
  }
35733
35788
  function atomicReplaceWithSymlink(target, linkTarget) {
35734
- const tmp = join31(dirname9(target), `.${basename5(target)}.symlink-tmp`);
35789
+ const tmp = join31(dirname11(target), `.${basename5(target)}.symlink-tmp`);
35735
35790
  if (existsSync39(tmp)) {
35736
35791
  try {
35737
35792
  unlinkSync7(tmp);
@@ -35785,7 +35840,7 @@ import {
35785
35840
  unlinkSync as unlinkSync8,
35786
35841
  writeSync as writeSync5
35787
35842
  } from "node:fs";
35788
- import { basename as basename6, dirname as dirname10, resolve as resolve27 } from "node:path";
35843
+ import { basename as basename6, dirname as dirname12, resolve as resolve27 } from "node:path";
35789
35844
  function readMachineId() {
35790
35845
  const vitestVal = process.env.VITEST;
35791
35846
  const isTestEnv = vitestVal !== undefined && vitestVal.length > 0;
@@ -35850,7 +35905,7 @@ function decryptAutoUnlock(blob, machineId) {
35850
35905
  }
35851
35906
  function writeAutoUnlockFile(passphrase, filePath) {
35852
35907
  const blob = encryptAutoUnlock(passphrase);
35853
- const dir = dirname10(filePath);
35908
+ const dir = dirname12(filePath);
35854
35909
  mkdirSync23(dir, { recursive: true, mode: 448 });
35855
35910
  const tmp = resolve27(dir, `.${basename6(filePath)}.${process.pid}.${Date.now()}.tmp`);
35856
35911
  try {
@@ -36957,7 +37012,7 @@ function formatForCli(entries, opts = {}) {
36957
37012
  var init_audit_reader = () => {};
36958
37013
 
36959
37014
  // node_modules/.bun/posthog-node@5.29.2/node_modules/posthog-node/dist/extensions/error-tracking/modifiers/module.node.mjs
36960
- import { dirname as dirname14, posix, sep as sep2 } from "path";
37015
+ import { dirname as dirname16, posix, sep as sep2 } from "path";
36961
37016
  function createModulerModifier() {
36962
37017
  const getModuleFromFileName = createGetModuleFromFilename();
36963
37018
  return async (frames) => {
@@ -36966,7 +37021,7 @@ function createModulerModifier() {
36966
37021
  return frames;
36967
37022
  };
36968
37023
  }
36969
- function createGetModuleFromFilename(basePath = process.argv[1] ? dirname14(process.argv[1]) : process.cwd(), isWindows = sep2 === "\\") {
37024
+ function createGetModuleFromFilename(basePath = process.argv[1] ? dirname16(process.argv[1]) : process.cwd(), isWindows = sep2 === "\\") {
36970
37025
  const normalizedBase = isWindows ? normalizeWindowsPath(basePath) : basePath;
36971
37026
  return (filename) => {
36972
37027
  if (!filename)
@@ -41582,7 +41637,7 @@ import {
41582
41637
  readFileSync as readFileSync45,
41583
41638
  writeFileSync as writeFileSync15
41584
41639
  } from "node:fs";
41585
- import { dirname as dirname15 } from "node:path";
41640
+ import { dirname as dirname17 } from "node:path";
41586
41641
  import { randomUUID as randomUUID3 } from "node:crypto";
41587
41642
  function telemetryDisabled() {
41588
41643
  const v = process.env.SWITCHROOM_TELEMETRY_DISABLED;
@@ -41604,7 +41659,7 @@ function getDistinctId() {
41604
41659
  const id = randomUUID3();
41605
41660
  cachedDistinctId = id;
41606
41661
  try {
41607
- mkdirSync27(dirname15(path5), { recursive: true });
41662
+ mkdirSync27(dirname17(path5), { recursive: true });
41608
41663
  writeFileSync15(path5, id, "utf-8");
41609
41664
  } catch {}
41610
41665
  return id;
@@ -41851,7 +41906,7 @@ import {
41851
41906
  readFileSync as readFileSync55,
41852
41907
  readdirSync as readdirSync21
41853
41908
  } from "node:fs";
41854
- import { dirname as dirname19, join as join53 } from "node:path";
41909
+ import { dirname as dirname21, join as join53 } from "node:path";
41855
41910
  import { execSync as execSync2 } from "node:child_process";
41856
41911
  function locateManifestPath() {
41857
41912
  let dir = import.meta.dirname;
@@ -41859,7 +41914,7 @@ function locateManifestPath() {
41859
41914
  const candidate = join53(dir, "dependencies.json");
41860
41915
  if (existsSync60(candidate))
41861
41916
  return candidate;
41862
- dir = dirname19(dir);
41917
+ dir = dirname21(dir);
41863
41918
  }
41864
41919
  return null;
41865
41920
  }
@@ -42713,7 +42768,7 @@ function checkAgentSocketMounts(composeYaml) {
42713
42768
  name: "agent socket-volume isolation",
42714
42769
  status: "fail",
42715
42770
  detail: `Cross-mounted socket volumes: ${violations.join("; ")}`,
42716
- fix: "Re-run `switchroom reconcile` to regenerate the compose from cascade. Hand-edits violating per-agent socket isolation are the load-bearing security invariant."
42771
+ fix: "Re-run `switchroom apply` to regenerate the compose from cascade. Hand-edits violating per-agent socket isolation are the load-bearing security invariant."
42717
42772
  };
42718
42773
  }
42719
42774
  function checkAgentCaps(config) {
@@ -42911,7 +42966,7 @@ function runDockerChecks(args) {
42911
42966
  name: "compose file present",
42912
42967
  status: "warn",
42913
42968
  detail: "Docker mode active but no docker-compose.yml found at ~/.switchroom/compose/docker-compose.yml",
42914
- fix: "Run `switchroom reconcile` to generate it."
42969
+ fix: "Run `switchroom apply` to generate it."
42915
42970
  });
42916
42971
  }
42917
42972
  out.push(...checkContainerRuntimeHealth(args.config, args.dockerPsDeps));
@@ -45933,7 +45988,7 @@ import {
45933
45988
  readdirSync as readdirSync23,
45934
45989
  statSync as statSync38
45935
45990
  } from "node:fs";
45936
- import { dirname as dirname20, join as join68, resolve as resolve39 } from "node:path";
45991
+ import { dirname as dirname22, join as join68, resolve as resolve39 } from "node:path";
45937
45992
  import { createPublicKey, createPrivateKey } from "node:crypto";
45938
45993
  function findInNvm(bin) {
45939
45994
  const nvmRoot = join68(process.env.HOME ?? "", ".nvm", "versions", "node");
@@ -47530,7 +47585,7 @@ async function checkMffAuthFlow(envPath = mffEnvPath(), timeoutMs = 8000) {
47530
47585
  detail: "skipped (MFF_API_URL not set)"
47531
47586
  };
47532
47587
  }
47533
- const credDir = dirname20(envPath);
47588
+ const credDir = dirname22(envPath);
47534
47589
  const authScript = join68(credDir, "claude-auth.py");
47535
47590
  if (!existsSync66(authScript)) {
47536
47591
  return {
@@ -48590,8 +48645,8 @@ var init_fleet_defaults = __esm(() => {
48590
48645
  });
48591
48646
 
48592
48647
  // src/agents/connection-health.ts
48593
- import { mkdirSync as mkdirSync46, writeFileSync as writeFileSync28 } from "node:fs";
48594
- import { join as join84 } from "node:path";
48648
+ import { mkdirSync as mkdirSync47, writeFileSync as writeFileSync29 } from "node:fs";
48649
+ import { join as join85 } from "node:path";
48595
48650
  async function computeAgentConnectionIssues(config, agentName, vaultAclReader) {
48596
48651
  const reqs = computeMcpSecretRequirements(config).filter((r) => r.agent === agentName);
48597
48652
  if (reqs.length === 0)
@@ -48648,10 +48703,10 @@ async function computeAgentConnectionIssues(config, agentName, vaultAclReader) {
48648
48703
  return issues;
48649
48704
  }
48650
48705
  function writeConnectionHealthFile(agentDir, health, deps) {
48651
- const dir = join84(agentDir, ".claude");
48652
- const path8 = join84(dir, CONNECTION_HEALTH_FILENAME);
48653
- (deps?.mkdir ?? ((p, o) => mkdirSync46(p, o)))(dir, { recursive: true });
48654
- (deps?.writeFile ?? ((p, d) => writeFileSync28(p, d)))(path8, JSON.stringify(health, null, 2) + `
48706
+ const dir = join85(agentDir, ".claude");
48707
+ const path8 = join85(dir, CONNECTION_HEALTH_FILENAME);
48708
+ (deps?.mkdir ?? ((p, o) => mkdirSync47(p, o)))(dir, { recursive: true });
48709
+ (deps?.writeFile ?? ((p, d) => writeFileSync29(p, d)))(path8, JSON.stringify(health, null, 2) + `
48655
48710
  `);
48656
48711
  }
48657
48712
  async function refreshAgentConnectionHealth(config, agentName, agentDir, deps) {
@@ -48672,10 +48727,10 @@ var CONNECTION_HEALTH_FILENAME = "connection-health.json";
48672
48727
  var init_connection_health = () => {};
48673
48728
 
48674
48729
  // src/cli/update-prompt-hook.ts
48675
- import { existsSync as existsSync83, readFileSync as readFileSync72, writeFileSync as writeFileSync29, chmodSync as chmodSync12, mkdirSync as mkdirSync47 } from "node:fs";
48676
- import { join as join85 } from "node:path";
48730
+ import { existsSync as existsSync84, readFileSync as readFileSync73, writeFileSync as writeFileSync30, chmodSync as chmodSync12, mkdirSync as mkdirSync48 } from "node:fs";
48731
+ import { join as join86 } from "node:path";
48677
48732
  function containerHookCommand() {
48678
- return join85(CONTAINER_AGENT_DIR, ".claude", "hooks", HOOK_FILENAME);
48733
+ return join86(CONTAINER_AGENT_DIR, ".claude", "hooks", HOOK_FILENAME);
48679
48734
  }
48680
48735
  function updatePromptHookScript() {
48681
48736
  return `#!/bin/bash
@@ -48741,14 +48796,14 @@ exit 0
48741
48796
  `;
48742
48797
  }
48743
48798
  function installUpdatePromptHook(agentDir) {
48744
- const hooksDir = join85(agentDir, ".claude", "hooks");
48745
- mkdirSync47(hooksDir, { recursive: true });
48746
- const scriptPath = join85(hooksDir, HOOK_FILENAME);
48799
+ const hooksDir = join86(agentDir, ".claude", "hooks");
48800
+ mkdirSync48(hooksDir, { recursive: true });
48801
+ const scriptPath = join86(hooksDir, HOOK_FILENAME);
48747
48802
  const desired = updatePromptHookScript();
48748
48803
  let installed = false;
48749
- const existing = existsSync83(scriptPath) ? readFileSync72(scriptPath, "utf-8") : "";
48804
+ const existing = existsSync84(scriptPath) ? readFileSync73(scriptPath, "utf-8") : "";
48750
48805
  if (existing !== desired) {
48751
- writeFileSync29(scriptPath, desired, { mode: 493 });
48806
+ writeFileSync30(scriptPath, desired, { mode: 493 });
48752
48807
  chmodSync12(scriptPath, 493);
48753
48808
  installed = true;
48754
48809
  } else {
@@ -48756,11 +48811,11 @@ function installUpdatePromptHook(agentDir) {
48756
48811
  chmodSync12(scriptPath, 493);
48757
48812
  } catch {}
48758
48813
  }
48759
- const settingsPath = join85(agentDir, ".claude", "settings.json");
48760
- if (!existsSync83(settingsPath)) {
48814
+ const settingsPath = join86(agentDir, ".claude", "settings.json");
48815
+ if (!existsSync84(settingsPath)) {
48761
48816
  return { scriptPath, settingsPath, installed };
48762
48817
  }
48763
- const raw = readFileSync72(settingsPath, "utf-8");
48818
+ const raw = readFileSync73(settingsPath, "utf-8");
48764
48819
  let parsed;
48765
48820
  try {
48766
48821
  parsed = JSON.parse(raw);
@@ -48796,7 +48851,7 @@ function installUpdatePromptHook(agentDir) {
48796
48851
  if (mutated) {
48797
48852
  hooks.UserPromptSubmit = list2;
48798
48853
  parsed.hooks = hooks;
48799
- writeFileSync29(settingsPath, JSON.stringify(parsed, null, 2) + `
48854
+ writeFileSync30(settingsPath, JSON.stringify(parsed, null, 2) + `
48800
48855
  `, { mode: 384 });
48801
48856
  installed = true;
48802
48857
  } else if (!alreadyCorrect) {
@@ -48805,7 +48860,7 @@ function installUpdatePromptHook(agentDir) {
48805
48860
  });
48806
48861
  hooks.UserPromptSubmit = list2;
48807
48862
  parsed.hooks = hooks;
48808
- writeFileSync29(settingsPath, JSON.stringify(parsed, null, 2) + `
48863
+ writeFileSync30(settingsPath, JSON.stringify(parsed, null, 2) + `
48809
48864
  `, { mode: 384 });
48810
48865
  installed = true;
48811
48866
  }
@@ -49189,8 +49244,8 @@ __export(exports_voice_sidecar_token, {
49189
49244
  VOICE_SIDECAR_TOKEN_ENV: () => VOICE_SIDECAR_TOKEN_ENV
49190
49245
  });
49191
49246
  import { randomBytes as randomBytes14 } from "node:crypto";
49192
- import { chmodSync as chmodSync13, chownSync as chownSync7, existsSync as existsSync85, mkdirSync as mkdirSync48, readFileSync as readFileSync73, rmSync as rmSync17, writeFileSync as writeFileSync30 } from "node:fs";
49193
- import { dirname as dirname29 } from "node:path";
49247
+ import { chmodSync as chmodSync13, chownSync as chownSync7, existsSync as existsSync86, mkdirSync as mkdirSync49, readFileSync as readFileSync74, rmSync as rmSync17, writeFileSync as writeFileSync31 } from "node:fs";
49248
+ import { dirname as dirname31 } from "node:path";
49194
49249
  async function defaultResolveOrSeedToken(home2, writeErr) {
49195
49250
  const [{ getViaBrokerStructured: getViaBrokerStructured2, putViaBroker: putViaBroker2 }, { resolveOperatorVaultPassphrase }] = await Promise.all([
49196
49251
  Promise.resolve().then(() => (init_client(), exports_client)),
@@ -49224,8 +49279,8 @@ async function provisionVoiceSidecarToken(composePath, home2, ctx) {
49224
49279
  const envPath = composeEnvPath(composePath);
49225
49280
  if (engine !== "local") {
49226
49281
  try {
49227
- if (existsSync85(envPath)) {
49228
- const body = readFileSync73(envPath, "utf-8");
49282
+ if (existsSync86(envPath)) {
49283
+ const body = readFileSync74(envPath, "utf-8");
49229
49284
  if (body.includes(`${VOICE_SIDECAR_TOKEN_ENV}=`))
49230
49285
  rmSync17(envPath);
49231
49286
  }
@@ -49244,11 +49299,11 @@ async function provisionVoiceSidecarToken(composePath, home2, ctx) {
49244
49299
  if (!token)
49245
49300
  return;
49246
49301
  try {
49247
- mkdirSync48(dirname29(envPath), { recursive: true });
49302
+ mkdirSync49(dirname31(envPath), { recursive: true });
49248
49303
  let body = "";
49249
49304
  try {
49250
- if (existsSync85(envPath))
49251
- body = readFileSync73(envPath, "utf-8");
49305
+ if (existsSync86(envPath))
49306
+ body = readFileSync74(envPath, "utf-8");
49252
49307
  } catch {}
49253
49308
  const line = `${VOICE_SIDECAR_TOKEN_ENV}=${token}`;
49254
49309
  const keyRe = new RegExp(`^${VOICE_SIDECAR_TOKEN_ENV}=.*$`, "m");
@@ -49256,7 +49311,7 @@ async function provisionVoiceSidecarToken(composePath, home2, ctx) {
49256
49311
  `) ? body + `
49257
49312
  ` : body) + line + `
49258
49313
  `;
49259
- writeFileSync30(envPath, next, {
49314
+ writeFileSync31(envPath, next, {
49260
49315
  encoding: "utf-8",
49261
49316
  mode: 384
49262
49317
  });
@@ -49308,11 +49363,11 @@ __export(exports_apply, {
49308
49363
  DEFAULT_COMPOSE_PATH: () => DEFAULT_COMPOSE_PATH2,
49309
49364
  COMPOSE_PROJECT: () => COMPOSE_PROJECT2
49310
49365
  });
49311
- import { accessSync as accessSync3, chmodSync as chmodSync14, chownSync as chownSync8, constants as fsConstants6, copyFileSync as copyFileSync12, existsSync as existsSync86, mkdirSync as mkdirSync49, readFileSync as readFileSync74, readdirSync as readdirSync30, renameSync as renameSync20, statSync as statSync47, writeFileSync as writeFileSync31 } from "node:fs";
49366
+ import { accessSync as accessSync3, chmodSync as chmodSync14, chownSync as chownSync8, constants as fsConstants6, copyFileSync as copyFileSync12, existsSync as existsSync87, mkdirSync as mkdirSync50, readFileSync as readFileSync75, readdirSync as readdirSync31, renameSync as renameSync21, statSync as statSync47, writeFileSync as writeFileSync32 } from "node:fs";
49312
49367
  import { mkdir as mkdir2 } from "node:fs/promises";
49313
49368
  import { spawnSync as childSpawnSync } from "node:child_process";
49314
49369
  import readline from "node:readline";
49315
- import { dirname as dirname30, join as join87, resolve as resolve52 } from "node:path";
49370
+ import { dirname as dirname32, join as join88, resolve as resolve52 } from "node:path";
49316
49371
  import { homedir as homedir49 } from "node:os";
49317
49372
  import { execFileSync as execFileSync27 } from "node:child_process";
49318
49373
  function effectiveLiteLLMEnabled(config, agentResolvedLitellm) {
@@ -49324,7 +49379,7 @@ async function resolveOperatorVaultPassphrase(home2) {
49324
49379
  return envPass;
49325
49380
  try {
49326
49381
  const { readAutoUnlockFile: readAutoUnlockFile2 } = await Promise.resolve().then(() => (init_auto_unlock(), exports_auto_unlock));
49327
- const blobPath = join87(home2, ".switchroom", "vault-auto-unlock");
49382
+ const blobPath = join88(home2, ".switchroom", "vault-auto-unlock");
49328
49383
  const pass = readAutoUnlockFile2(blobPath);
49329
49384
  return pass && pass.length > 0 ? pass : null;
49330
49385
  } catch {
@@ -49333,10 +49388,10 @@ async function resolveOperatorVaultPassphrase(home2) {
49333
49388
  }
49334
49389
  function materializeLitellmMasterKeyForBroker(masterKey, home2 = process.env.HOME ?? "/root") {
49335
49390
  try {
49336
- const stateDir = join87(home2, ".switchroom", "state", "auth-broker");
49337
- mkdirSync49(stateDir, { recursive: true, mode: 448 });
49338
- const path9 = join87(stateDir, LITELLM_MASTER_KEY_STATE_BASENAME);
49339
- writeFileSync31(path9, masterKey.trim() + `
49391
+ const stateDir = join88(home2, ".switchroom", "state", "auth-broker");
49392
+ mkdirSync50(stateDir, { recursive: true, mode: 448 });
49393
+ const path9 = join88(stateDir, LITELLM_MASTER_KEY_STATE_BASENAME);
49394
+ writeFileSync32(path9, masterKey.trim() + `
49340
49395
  `, { mode: 384 });
49341
49396
  try {
49342
49397
  chmodSync14(path9, 384);
@@ -49428,9 +49483,9 @@ async function provisionLiteLLMKeys(config, agentNames, switchroomConfigPath, ct
49428
49483
  const oauthAccount = config.auth?.active;
49429
49484
  let pendingConfigEdits = false;
49430
49485
  let configText = null;
49431
- if (switchroomConfigPath && existsSync86(switchroomConfigPath)) {
49486
+ if (switchroomConfigPath && existsSync87(switchroomConfigPath)) {
49432
49487
  try {
49433
- configText = readFileSync74(switchroomConfigPath, "utf-8");
49488
+ configText = readFileSync75(switchroomConfigPath, "utf-8");
49434
49489
  } catch (err) {
49435
49490
  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.
49436
49491
  `));
@@ -49659,14 +49714,14 @@ async function provisionLiteLLMKeys(config, agentNames, switchroomConfigPath, ct
49659
49714
  function resolveVaultBindMountDir(homeDir, ctx) {
49660
49715
  const isCustomPath = ctx.migrationKind === "custom-path-skipped";
49661
49716
  if (isCustomPath && ctx.customVaultPath) {
49662
- return dirname30(ctx.customVaultPath);
49717
+ return dirname32(ctx.customVaultPath);
49663
49718
  }
49664
- return join87(homeDir, ".switchroom", "vault");
49719
+ return join88(homeDir, ".switchroom", "vault");
49665
49720
  }
49666
49721
  function inspectVaultBindMountDir(vaultDir) {
49667
- if (!existsSync86(vaultDir))
49722
+ if (!existsSync87(vaultDir))
49668
49723
  return { kind: "missing" };
49669
- const entries = readdirSync30(vaultDir);
49724
+ const entries = readdirSync31(vaultDir);
49670
49725
  const unknown = [];
49671
49726
  for (const name of entries) {
49672
49727
  if (KNOWN_VAULT_ARTIFACT_NAMES.has(name))
@@ -49692,60 +49747,60 @@ function hasVaultRefs(value) {
49692
49747
  async function ensureHostMountSources(config) {
49693
49748
  const home2 = resolveHostHomeForCompose();
49694
49749
  const dirs = [
49695
- join87(home2, ".switchroom", "approvals"),
49696
- join87(home2, ".switchroom", "scheduler"),
49697
- join87(home2, ".switchroom", "logs"),
49698
- join87(home2, ".switchroom", "compose"),
49699
- join87(home2, ".switchroom", "broker-operator")
49750
+ join88(home2, ".switchroom", "approvals"),
49751
+ join88(home2, ".switchroom", "scheduler"),
49752
+ join88(home2, ".switchroom", "logs"),
49753
+ join88(home2, ".switchroom", "compose"),
49754
+ join88(home2, ".switchroom", "broker-operator")
49700
49755
  ];
49701
49756
  for (const name of Object.keys(config.agents)) {
49702
- dirs.push(join87(home2, ".switchroom", "agents", name));
49703
- dirs.push(join87(home2, ".switchroom", "logs", name));
49704
- dirs.push(join87(home2, ".claude", "projects", name));
49705
- dirs.push(join87(home2, ".switchroom", "audit", name));
49706
- if (existsSync86(join87(home2, ".switchroom-config"))) {
49707
- dirs.push(join87(home2, ".switchroom-config", "agents", name, "personal-skills"));
49757
+ dirs.push(join88(home2, ".switchroom", "agents", name));
49758
+ dirs.push(join88(home2, ".switchroom", "logs", name));
49759
+ dirs.push(join88(home2, ".claude", "projects", name));
49760
+ dirs.push(join88(home2, ".switchroom", "audit", name));
49761
+ if (existsSync87(join88(home2, ".switchroom-config"))) {
49762
+ dirs.push(join88(home2, ".switchroom-config", "agents", name, "personal-skills"));
49708
49763
  }
49709
49764
  }
49710
49765
  for (const dir of dirs) {
49711
49766
  await mkdir2(dir, { recursive: true });
49712
49767
  }
49713
- const autoUnlockPath = join87(home2, ".switchroom", "vault-auto-unlock");
49714
- if (!existsSync86(autoUnlockPath)) {
49715
- writeFileSync31(autoUnlockPath, "", { mode: 384 });
49768
+ const autoUnlockPath = join88(home2, ".switchroom", "vault-auto-unlock");
49769
+ if (!existsSync87(autoUnlockPath)) {
49770
+ writeFileSync32(autoUnlockPath, "", { mode: 384 });
49716
49771
  }
49717
- const auditLogPath = join87(home2, ".switchroom", "vault-audit.log");
49718
- if (!existsSync86(auditLogPath)) {
49719
- writeFileSync31(auditLogPath, "", { mode: 420 });
49772
+ const auditLogPath = join88(home2, ".switchroom", "vault-audit.log");
49773
+ if (!existsSync87(auditLogPath)) {
49774
+ writeFileSync32(auditLogPath, "", { mode: 420 });
49720
49775
  }
49721
49776
  const grantsDbDir = getGrantsDbDir(home2);
49722
- mkdirSync49(grantsDbDir, { recursive: true, mode: 448 });
49777
+ mkdirSync50(grantsDbDir, { recursive: true, mode: 448 });
49723
49778
  migrateLegacyGrantsDbLocation(getGrantsDbPath(home2));
49724
- const hostdAuditLogPath = join87(home2, ".switchroom", "host-control-audit.log");
49725
- if (!existsSync86(hostdAuditLogPath)) {
49726
- writeFileSync31(hostdAuditLogPath, "", { mode: 420 });
49779
+ const hostdAuditLogPath = join88(home2, ".switchroom", "host-control-audit.log");
49780
+ if (!existsSync87(hostdAuditLogPath)) {
49781
+ writeFileSync32(hostdAuditLogPath, "", { mode: 420 });
49727
49782
  }
49728
49783
  for (const name of Object.keys(config.agents)) {
49729
- const tokenPath = join87(home2, ".switchroom", "agents", name, ".vault-token");
49730
- if (!existsSync86(tokenPath)) {
49731
- writeFileSync31(tokenPath, "", { mode: 384 });
49784
+ const tokenPath = join88(home2, ".switchroom", "agents", name, ".vault-token");
49785
+ if (!existsSync87(tokenPath)) {
49786
+ writeFileSync32(tokenPath, "", { mode: 384 });
49732
49787
  }
49733
49788
  try {
49734
49789
  const uid = allocateAgentUid(name);
49735
49790
  chownSync8(tokenPath, uid, uid);
49736
49791
  } catch {}
49737
49792
  }
49738
- const fleetDir = join87(home2, ".switchroom", "fleet");
49793
+ const fleetDir = join88(home2, ".switchroom", "fleet");
49739
49794
  await mkdir2(fleetDir, { recursive: true });
49740
- const invariantsPath = join87(fleetDir, "switchroom-invariants.md");
49795
+ const invariantsPath = join88(fleetDir, "switchroom-invariants.md");
49741
49796
  const invariantsCanonical = renderFleetInvariants();
49742
- const invariantsCurrent = existsSync86(invariantsPath) ? readFileSync74(invariantsPath, "utf-8") : null;
49797
+ const invariantsCurrent = existsSync87(invariantsPath) ? readFileSync75(invariantsPath, "utf-8") : null;
49743
49798
  if (invariantsCurrent !== invariantsCanonical) {
49744
- writeFileSync31(invariantsPath, invariantsCanonical, { mode: 420 });
49799
+ writeFileSync32(invariantsPath, invariantsCanonical, { mode: 420 });
49745
49800
  }
49746
- const fleetClaudePath = join87(fleetDir, "CLAUDE.md");
49747
- if (!existsSync86(fleetClaudePath)) {
49748
- writeFileSync31(fleetClaudePath, renderFleetDefaultsClaudeMd(), {
49801
+ const fleetClaudePath = join88(fleetDir, "CLAUDE.md");
49802
+ if (!existsSync87(fleetClaudePath)) {
49803
+ writeFileSync32(fleetClaudePath, renderFleetDefaultsClaudeMd(), {
49749
49804
  mode: 420
49750
49805
  });
49751
49806
  }
@@ -49774,7 +49829,7 @@ function isInAgentContainer(vaultPresent, composeV2Present, env2 = process.env)
49774
49829
  function runApplyPreflight(config, opts = {}) {
49775
49830
  const vaultPath = resolvePath(config.vault?.path ?? "~/.switchroom/vault.enc");
49776
49831
  const detect = opts.detectComposeV2 ?? detectComposeV2;
49777
- const vaultMissing = hasVaultRefs(config) && !existsSync86(vaultPath);
49832
+ const vaultMissing = hasVaultRefs(config) && !existsSync87(vaultPath);
49778
49833
  const composeErr = detect();
49779
49834
  if ((vaultMissing || composeErr) && isInAgentContainer(!vaultMissing, composeErr === null)) {
49780
49835
  throw new Error(IN_AGENT_CONTAINER_APPLY_MSG);
@@ -49788,7 +49843,7 @@ function runApplyPreflight(config, opts = {}) {
49788
49843
  detectAndReportLegacyGdriveSlots(vaultPath);
49789
49844
  }
49790
49845
  function detectAndReportLegacyGdriveSlots(vaultPath) {
49791
- if (!existsSync86(vaultPath))
49846
+ if (!existsSync87(vaultPath))
49792
49847
  return;
49793
49848
  const passphrase = process.env.SWITCHROOM_VAULT_PASSPHRASE;
49794
49849
  if (!passphrase)
@@ -49829,17 +49884,17 @@ function detectAndReportLegacyGdriveSlots(vaultPath) {
49829
49884
  }
49830
49885
  function writeInstallTypeCache(homeDir = homedir49()) {
49831
49886
  const ctx = detectInstallType();
49832
- const dir = join87(homeDir, ".switchroom");
49833
- const out = join87(dir, "install-type.json");
49887
+ const dir = join88(homeDir, ".switchroom");
49888
+ const out = join88(dir, "install-type.json");
49834
49889
  const tmp = `${out}.tmp`;
49835
- mkdirSync49(dir, { recursive: true });
49890
+ mkdirSync50(dir, { recursive: true });
49836
49891
  const payload = {
49837
49892
  install_type: ctx.install_type,
49838
49893
  detected_at: new Date().toISOString(),
49839
49894
  source_paths: ctx.source_paths
49840
49895
  };
49841
- writeFileSync31(tmp, JSON.stringify(payload, null, 2), { mode: 420 });
49842
- renameSync20(tmp, out);
49896
+ writeFileSync32(tmp, JSON.stringify(payload, null, 2), { mode: 420 });
49897
+ renameSync21(tmp, out);
49843
49898
  return out;
49844
49899
  }
49845
49900
  async function runApply(config, options, deps = {}, switchroomConfigPath) {
@@ -49897,17 +49952,17 @@ Applying switchroom config...
49897
49952
  writeOut(source_default.green(` + ${name}`) + source_default.gray(` (${agentConfig.extends ?? "default"}) \u2014 ${detail}
49898
49953
  `));
49899
49954
  try {
49900
- installUpdatePromptHook(join87(agentsDir, name));
49955
+ installUpdatePromptHook(join88(agentsDir, name));
49901
49956
  } catch (hookErr) {
49902
49957
  writeOut(source_default.gray(` (update-prompt hook install failed for ${name}: ${hookErr.message})
49903
49958
  `));
49904
49959
  }
49905
- await refreshAgentConnectionHealth(config, name, join87(agentsDir, name), {
49960
+ await refreshAgentConnectionHealth(config, name, join88(agentsDir, name), {
49906
49961
  vaultAclReader: connHealthVaultAclReader
49907
49962
  });
49908
49963
  try {
49909
49964
  const uid = allocateAgentUid(name);
49910
- alignAgentUid(name, join87(agentsDir, name), uid, {
49965
+ alignAgentUid(name, join88(agentsDir, name), uid, {
49911
49966
  confirm: !options.nonInteractive,
49912
49967
  writeOut
49913
49968
  });
@@ -49952,7 +50007,7 @@ Applying switchroom config...
49952
50007
  for (const name of agentNames) {
49953
50008
  try {
49954
50009
  const uid = allocateAgentUid(name);
49955
- alignAgentUid(name, join87(agentsDir, name), uid, {
50010
+ alignAgentUid(name, join88(agentsDir, name), uid, {
49956
50011
  confirm: !options.nonInteractive,
49957
50012
  writeOut
49958
50013
  });
@@ -50290,18 +50345,18 @@ function copyExampleConfig2(name) {
50290
50345
  throw new Error(`Invalid example name: ${name} (must match /^[a-z0-9_-]+$/)`);
50291
50346
  }
50292
50347
  const dest = resolve52(process.cwd(), "switchroom.yaml");
50293
- if (existsSync86(dest)) {
50348
+ if (existsSync87(dest)) {
50294
50349
  console.error(source_default.yellow("switchroom.yaml already exists \u2014 skipping example copy"));
50295
50350
  return;
50296
50351
  }
50297
50352
  const embedded = EMBEDDED_EXAMPLES[name];
50298
50353
  if (embedded !== undefined) {
50299
- writeFileSync31(dest, embedded, { encoding: "utf8" });
50354
+ writeFileSync32(dest, embedded, { encoding: "utf8" });
50300
50355
  console.log(source_default.green(`Copied ${name}.yaml -> switchroom.yaml`));
50301
50356
  return;
50302
50357
  }
50303
50358
  const exampleFile = resolve52(import.meta.dirname, `../../examples/${name}.yaml`);
50304
- if (!existsSync86(exampleFile)) {
50359
+ if (!existsSync87(exampleFile)) {
50305
50360
  throw new Error(`Example config not found: ${name}.yaml (available: ${Object.keys(EMBEDDED_EXAMPLES).join(", ")})`);
50306
50361
  }
50307
50362
  copyFileSync12(exampleFile, dest);
@@ -50312,8 +50367,8 @@ function findUnwritableAgentDirs(config, opts) {
50312
50367
  const targets = opts.only ? [opts.only] : Object.keys(config.agents ?? {});
50313
50368
  const unwritable = [];
50314
50369
  for (const name of targets) {
50315
- const startSh = join87(agentsDir, name, "start.sh");
50316
- if (!existsSync86(startSh))
50370
+ const startSh = join88(agentsDir, name, "start.sh");
50371
+ if (!existsSync87(startSh))
50317
50372
  continue;
50318
50373
  try {
50319
50374
  accessSync3(startSh, fsConstants6.W_OK);
@@ -50518,7 +50573,7 @@ var init_apply = __esm(() => {
50518
50573
  switchroom: switchroom_default,
50519
50574
  minimal: minimal_default
50520
50575
  };
50521
- DEFAULT_COMPOSE_PATH2 = join87(homedir49(), ".switchroom", "compose", "docker-compose.yml");
50576
+ DEFAULT_COMPOSE_PATH2 = join88(homedir49(), ".switchroom", "compose", "docker-compose.yml");
50522
50577
  IN_AGENT_CONTAINER_APPLY_MSG = "`switchroom apply`'s full per-agent scaffold cannot run from inside an " + "agent container \u2014 this is a host/hostd operation by construction " + "(no vault at the container HOME, and no `docker compose` v2 plugin here).\nTo roll the fleet to a new version, drive the hostd rollout (`mcp__hostd__rollout`): it runs a `--compose-only` apply plus a per-agent restart-reconcile, and each agent refreshes its own templates " + `on restart \u2014 the roll completes without any agent running a full apply.
50523
50578
  ` + "A full host-side `sudo switchroom apply` is only needed for structural changes (compose regeneration / new-agent scaffolding), and is run by the operator on the host, never from inside an agent.";
50524
50579
  SELF_ELEVATE_PRESERVED_ENV = [
@@ -59829,49 +59884,49 @@ var require_fast_uri = __commonJS((exports2, module) => {
59829
59884
  schemelessOptions.skipEscape = true;
59830
59885
  return serialize(resolved, schemelessOptions);
59831
59886
  }
59832
- function resolveComponent(base, relative4, options, skipNormalization) {
59887
+ function resolveComponent(base, relative6, options, skipNormalization) {
59833
59888
  const target = {};
59834
59889
  if (!skipNormalization) {
59835
59890
  base = parse6(serialize(base, options), options);
59836
- relative4 = parse6(serialize(relative4, options), options);
59891
+ relative6 = parse6(serialize(relative6, options), options);
59837
59892
  }
59838
59893
  options = options || {};
59839
- if (!options.tolerant && relative4.scheme) {
59840
- target.scheme = relative4.scheme;
59841
- target.userinfo = relative4.userinfo;
59842
- target.host = relative4.host;
59843
- target.port = relative4.port;
59844
- target.path = removeDotSegments(relative4.path || "");
59845
- target.query = relative4.query;
59894
+ if (!options.tolerant && relative6.scheme) {
59895
+ target.scheme = relative6.scheme;
59896
+ target.userinfo = relative6.userinfo;
59897
+ target.host = relative6.host;
59898
+ target.port = relative6.port;
59899
+ target.path = removeDotSegments(relative6.path || "");
59900
+ target.query = relative6.query;
59846
59901
  } else {
59847
- if (relative4.userinfo !== undefined || relative4.host !== undefined || relative4.port !== undefined) {
59848
- target.userinfo = relative4.userinfo;
59849
- target.host = relative4.host;
59850
- target.port = relative4.port;
59851
- target.path = removeDotSegments(relative4.path || "");
59852
- target.query = relative4.query;
59902
+ if (relative6.userinfo !== undefined || relative6.host !== undefined || relative6.port !== undefined) {
59903
+ target.userinfo = relative6.userinfo;
59904
+ target.host = relative6.host;
59905
+ target.port = relative6.port;
59906
+ target.path = removeDotSegments(relative6.path || "");
59907
+ target.query = relative6.query;
59853
59908
  } else {
59854
- if (!relative4.path) {
59909
+ if (!relative6.path) {
59855
59910
  target.path = base.path;
59856
- if (relative4.query !== undefined) {
59857
- target.query = relative4.query;
59911
+ if (relative6.query !== undefined) {
59912
+ target.query = relative6.query;
59858
59913
  } else {
59859
59914
  target.query = base.query;
59860
59915
  }
59861
59916
  } else {
59862
- if (relative4.path[0] === "/") {
59863
- target.path = removeDotSegments(relative4.path);
59917
+ if (relative6.path[0] === "/") {
59918
+ target.path = removeDotSegments(relative6.path);
59864
59919
  } else {
59865
59920
  if ((base.userinfo !== undefined || base.host !== undefined || base.port !== undefined) && !base.path) {
59866
- target.path = "/" + relative4.path;
59921
+ target.path = "/" + relative6.path;
59867
59922
  } else if (!base.path) {
59868
- target.path = relative4.path;
59923
+ target.path = relative6.path;
59869
59924
  } else {
59870
- target.path = base.path.slice(0, base.path.lastIndexOf("/") + 1) + relative4.path;
59925
+ target.path = base.path.slice(0, base.path.lastIndexOf("/") + 1) + relative6.path;
59871
59926
  }
59872
59927
  target.path = removeDotSegments(target.path);
59873
59928
  }
59874
- target.query = relative4.query;
59929
+ target.query = relative6.query;
59875
59930
  }
59876
59931
  target.userinfo = base.userinfo;
59877
59932
  target.host = base.host;
@@ -59879,7 +59934,7 @@ var require_fast_uri = __commonJS((exports2, module) => {
59879
59934
  }
59880
59935
  target.scheme = base.scheme;
59881
59936
  }
59882
- target.fragment = relative4.fragment;
59937
+ target.fragment = relative6.fragment;
59883
59938
  return target;
59884
59939
  }
59885
59940
  function equal(uriA, uriB, options) {
@@ -63967,7 +64022,7 @@ __export(exports_server2, {
63967
64022
  TOOLS: () => TOOLS2
63968
64023
  });
63969
64024
  import { randomBytes as randomBytes16 } from "node:crypto";
63970
- import { existsSync as existsSync95, readFileSync as readFileSync83 } from "node:fs";
64025
+ import { existsSync as existsSync96, readFileSync as readFileSync84 } from "node:fs";
63971
64026
  function selfSocketPath() {
63972
64027
  return `/run/switchroom/hostd/${SELF_AGENT}/sock`;
63973
64028
  }
@@ -63994,7 +64049,7 @@ async function dispatchTool2(name, args) {
63994
64049
  return errorText2("hostd MCP: SWITCHROOM_AGENT_NAME env var is not set \u2014 cannot " + "determine which per-agent socket to talk to.");
63995
64050
  }
63996
64051
  const sockPath = selfSocketPath();
63997
- if (!existsSync95(sockPath)) {
64052
+ if (!existsSync96(sockPath)) {
63998
64053
  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.`);
63999
64054
  }
64000
64055
  let req;
@@ -64245,18 +64300,18 @@ function resolveAuditLogPath() {
64245
64300
  if (process.env.HOSTD_AUDIT_LOG_PATH)
64246
64301
  return process.env.HOSTD_AUDIT_LOG_PATH;
64247
64302
  const bindMounted = "/host-home/.switchroom/host-control-audit.log";
64248
- if (existsSync95(bindMounted))
64303
+ if (existsSync96(bindMounted))
64249
64304
  return bindMounted;
64250
64305
  return defaultAuditLogPath2();
64251
64306
  }
64252
64307
  function getLastUpdateApplyStatus() {
64253
64308
  const path9 = resolveAuditLogPath();
64254
- if (!existsSync95(path9)) {
64309
+ if (!existsSync96(path9)) {
64255
64310
  return errorText2(`get_status: audit log not found at ${path9}. No update_apply has run yet?`);
64256
64311
  }
64257
64312
  let raw;
64258
64313
  try {
64259
- raw = readFileSync83(path9, "utf-8");
64314
+ raw = readFileSync84(path9, "utf-8");
64260
64315
  } catch (err2) {
64261
64316
  return errorText2(`get_status: failed to read audit log at ${path9}: ${err2.message}`);
64262
64317
  }
@@ -65006,14 +65061,14 @@ var init_header_passthrough_guard = __esm(() => {
65006
65061
  });
65007
65062
 
65008
65063
  // src/fleet-health/litellm-config-sensor.ts
65009
- import { readFileSync as readFileSync85, existsSync as existsSync98 } from "node:fs";
65064
+ import { readFileSync as readFileSync86, existsSync as existsSync99 } from "node:fs";
65010
65065
  function resolveLitellmConfigPath(explicit) {
65011
65066
  return explicit ?? process.env.LITELLM_CONFIG_PATH ?? DEFAULT_LITELLM_CONFIG_PATH;
65012
65067
  }
65013
65068
  function scanLitellmConfig(opts = {}) {
65014
65069
  const path9 = resolveLitellmConfigPath(opts.path);
65015
- const exists = opts.existsFn ?? existsSync98;
65016
- const read = opts.readFn ?? ((p) => readFileSync85(p, "utf-8"));
65070
+ const exists = opts.existsFn ?? existsSync99;
65071
+ const read = opts.readFn ?? ((p) => readFileSync86(p, "utf-8"));
65017
65072
  const log = opts.log ?? (() => {});
65018
65073
  const nowIso = opts.nowIso ?? new Date().toISOString();
65019
65074
  if (!exists(path9)) {
@@ -65068,23 +65123,23 @@ __export(exports_scan, {
65068
65123
  ledgerPathForBase: () => ledgerPathForBase
65069
65124
  });
65070
65125
  import {
65071
- readFileSync as readFileSync86,
65072
- readdirSync as readdirSync38,
65073
- existsSync as existsSync99,
65074
- mkdirSync as mkdirSync56,
65075
- writeFileSync as writeFileSync37
65126
+ readFileSync as readFileSync87,
65127
+ readdirSync as readdirSync39,
65128
+ existsSync as existsSync100,
65129
+ mkdirSync as mkdirSync57,
65130
+ writeFileSync as writeFileSync38
65076
65131
  } from "node:fs";
65077
- import { resolve as resolve57, dirname as dirname33 } from "node:path";
65132
+ import { resolve as resolve57, dirname as dirname35 } from "node:path";
65078
65133
  import { homedir as homedir58 } from "node:os";
65079
65134
  function resolveSwitchroomBase(home2 = process.env.SWITCHROOM_HOME ?? process.env.HOME ?? homedir58()) {
65080
65135
  return resolve57(home2, ".switchroom");
65081
65136
  }
65082
65137
  function listAgents(base) {
65083
65138
  const dir = resolve57(base, "agents");
65084
- if (!existsSync99(dir))
65139
+ if (!existsSync100(dir))
65085
65140
  return [];
65086
65141
  try {
65087
- return readdirSync38(dir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name).sort();
65142
+ return readdirSync39(dir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name).sort();
65088
65143
  } catch {
65089
65144
  return [];
65090
65145
  }
@@ -65110,16 +65165,16 @@ function runScan(opts = {}) {
65110
65165
  let gwText = "";
65111
65166
  let sawArtifact = false;
65112
65167
  try {
65113
- if (existsSync99(turnsPath)) {
65114
- turnsText = readFileSync86(turnsPath, "utf-8");
65168
+ if (existsSync100(turnsPath)) {
65169
+ turnsText = readFileSync87(turnsPath, "utf-8");
65115
65170
  sawArtifact = true;
65116
65171
  }
65117
65172
  } catch (e) {
65118
65173
  log(`fleet-health: WARN skipping ${agent} turns.jsonl unreadable: ${String(e)}`);
65119
65174
  }
65120
65175
  try {
65121
- if (existsSync99(gwPath)) {
65122
- gwText = readFileSync86(gwPath, "utf-8");
65176
+ if (existsSync100(gwPath)) {
65177
+ gwText = readFileSync87(gwPath, "utf-8");
65123
65178
  sawArtifact = true;
65124
65179
  }
65125
65180
  } catch (e) {
@@ -65161,20 +65216,20 @@ function runScan(opts = {}) {
65161
65216
  function readLedgerIfPresent(base) {
65162
65217
  const path9 = ledgerPathForBase(base);
65163
65218
  try {
65164
- if (!existsSync99(path9))
65219
+ if (!existsSync100(path9))
65165
65220
  return null;
65166
- return JSON.parse(readFileSync86(path9, "utf-8"));
65221
+ return JSON.parse(readFileSync87(path9, "utf-8"));
65167
65222
  } catch {
65168
65223
  return null;
65169
65224
  }
65170
65225
  }
65171
65226
  function ledgerPathForBase(base) {
65172
- return fleetHealthLedgerPath(dirname33(base));
65227
+ return fleetHealthLedgerPath(dirname35(base));
65173
65228
  }
65174
65229
  function writeLedger(base, ledger) {
65175
65230
  const path9 = ledgerPathForBase(base);
65176
- mkdirSync56(dirname33(path9), { recursive: true });
65177
- writeFileSync37(path9, JSON.stringify(ledger, null, 2) + `
65231
+ mkdirSync57(dirname35(path9), { recursive: true });
65232
+ writeFileSync38(path9, JSON.stringify(ledger, null, 2) + `
65178
65233
  `, "utf-8");
65179
65234
  return path9;
65180
65235
  }
@@ -72180,7 +72235,7 @@ init_audit_log();
72180
72235
  init_test_isolation_guard();
72181
72236
  import * as net3 from "node:net";
72182
72237
  import { mkdirSync as mkdirSync25, chmodSync as chmodSync9, chownSync as chownSync4, existsSync as existsSync43, readFileSync as readFileSync35, readdirSync as readdirSync18, statSync as statSync26, unlinkSync as unlinkSync10, writeFileSync as writeFileSync14, renameSync as renameSync14 } from "node:fs";
72183
- import { dirname as dirname13, resolve as resolve29, basename as basename7 } from "node:path";
72238
+ import { dirname as dirname15, resolve as resolve29, basename as basename7 } from "node:path";
72184
72239
  import * as os4 from "node:os";
72185
72240
  import * as path4 from "node:path";
72186
72241
 
@@ -74556,7 +74611,7 @@ class VaultBroker {
74556
74611
  this.passphrase = this.testOpts._testPassphrase;
74557
74612
  }
74558
74613
  process.umask(63);
74559
- const parentDir = dirname13(this.socketPath);
74614
+ const parentDir = dirname15(this.socketPath);
74560
74615
  mkdirSync25(parentDir, { recursive: true, mode: 448 });
74561
74616
  try {
74562
74617
  chmodSync9(parentDir, 448);
@@ -76101,15 +76156,15 @@ class VaultBroker {
76101
76156
  }
76102
76157
  }
76103
76158
  function detectVaultLayoutDrift(vaultPath) {
76104
- const dir = dirname13(vaultPath);
76159
+ const dir = dirname15(vaultPath);
76105
76160
  if (basename7(dir) !== "vault")
76106
76161
  return;
76107
76162
  if (basename7(vaultPath) !== "vault.enc")
76108
76163
  return;
76109
- const switchroomDir = dirname13(dir);
76164
+ const switchroomDir = dirname15(dir);
76110
76165
  if (basename7(switchroomDir) !== ".switchroom")
76111
76166
  return;
76112
- const home2 = dirname13(switchroomDir);
76167
+ const home2 = dirname15(switchroomDir);
76113
76168
  const result = inspectVaultLayout(home2);
76114
76169
  if (result.kind === "divergent") {
76115
76170
  throw new VaultError(`Vault layout divergence detected at boot: ${result.details.oldPath} and ${result.details.newPath} are both regular files with different content. An older switchroom CLI may have written to the legacy path after migration ran. Run \`switchroom apply\` from the host to surface the recovery recipe (state E refusal with literal \`mv\` commands). See docs/operators/state-e-recovery.md.`);
@@ -79590,7 +79645,7 @@ import {
79590
79645
  writeSync as writeSync8,
79591
79646
  constants as fsConstants3
79592
79647
  } from "node:fs";
79593
- import { resolve as resolve34, extname, join as join51, relative, dirname as dirname16 } from "node:path";
79648
+ import { resolve as resolve34, extname, join as join51, relative as relative3, dirname as dirname18 } from "node:path";
79594
79649
  import { homedir as homedir28 } from "node:os";
79595
79650
  import { timingSafeEqual as timingSafeEqual3, randomBytes as randomBytes11 } from "node:crypto";
79596
79651
 
@@ -83051,7 +83106,7 @@ function resolveWebToken() {
83051
83106
  return existing;
83052
83107
  }
83053
83108
  const token = randomBytes11(32).toString("hex");
83054
- mkdirSync31(dirname16(tokenPath), { recursive: true, mode: 448 });
83109
+ mkdirSync31(dirname18(tokenPath), { recursive: true, mode: 448 });
83055
83110
  try {
83056
83111
  const fd = openSync11(tokenPath, fsConstants3.O_WRONLY | fsConstants3.O_CREAT | fsConstants3.O_EXCL, 384);
83057
83112
  try {
@@ -83638,7 +83693,7 @@ function startWebServer(config, port, hostname = "127.0.0.1", configPath) {
83638
83693
  } catch {
83639
83694
  return new Response("Not Found", { status: 404 });
83640
83695
  }
83641
- const rel = relative(uiDir, realFullPath);
83696
+ const rel = relative3(uiDir, realFullPath);
83642
83697
  if (rel.startsWith("..") || resolve34(uiDir, rel) !== realFullPath) {
83643
83698
  return new Response("Forbidden", { status: 403 });
83644
83699
  }
@@ -83768,7 +83823,7 @@ init_loader();
83768
83823
 
83769
83824
  // src/web/startup-guard.ts
83770
83825
  import { existsSync as existsSync58, readFileSync as readFileSync53, writeFileSync as writeFileSync18, mkdirSync as mkdirSync32, statSync as statSync33, unlinkSync as unlinkSync13 } from "node:fs";
83771
- import { dirname as dirname17 } from "node:path";
83826
+ import { dirname as dirname19 } from "node:path";
83772
83827
  function detectConfigMountFault(configPath, deps = {}) {
83773
83828
  const stat = deps.stat ?? ((p) => statSync33(p));
83774
83829
  let st;
@@ -83815,7 +83870,7 @@ function readCrashState(statePath) {
83815
83870
  }
83816
83871
  function writeCrashState(statePath, state) {
83817
83872
  try {
83818
- mkdirSync32(dirname17(statePath), { recursive: true });
83873
+ mkdirSync32(dirname19(statePath), { recursive: true });
83819
83874
  writeFileSync18(statePath, JSON.stringify(state), { mode: 384 });
83820
83875
  } catch {}
83821
83876
  }
@@ -83911,7 +83966,7 @@ init_atomic();
83911
83966
  init_loader();
83912
83967
  init_scaffold();
83913
83968
  import { existsSync as existsSync59, copyFileSync as copyFileSync9, readFileSync as readFileSync54, mkdirSync as mkdirSync33, statSync as statSync34 } from "node:fs";
83914
- import { resolve as resolve35, dirname as dirname18 } from "node:path";
83969
+ import { resolve as resolve35, dirname as dirname20 } from "node:path";
83915
83970
  init_state();
83916
83971
  init_vault();
83917
83972
  init_manager();
@@ -84223,7 +84278,7 @@ async function copyExampleConfig(nonInteractive) {
84223
84278
  if (!existsSync59(srcFile)) {
84224
84279
  throw new ConfigError(`Example config not found: ${choice}.yaml`);
84225
84280
  }
84226
- mkdirSync33(dirname18(destFile), { recursive: true });
84281
+ mkdirSync33(dirname20(destFile), { recursive: true });
84227
84282
  copyFileSync9(srcFile, destFile);
84228
84283
  console.log(source_default.green(` Copied ${choice}.yaml -> ${destFile}`));
84229
84284
  console.log(source_default.yellow(` Edit ${destFile} to customize, then re-run switchroom setup.`));
@@ -85003,9 +85058,9 @@ init_source();
85003
85058
  init_loader();
85004
85059
  init_lifecycle();
85005
85060
  init_compose_env();
85006
- import { cpSync as cpSync2, existsSync as existsSync67, mkdirSync as mkdirSync35, readFileSync as readFileSync60, realpathSync as realpathSync6, rmSync as rmSync12, statSync as statSync40, chownSync as chownSync5 } from "node:fs";
85061
+ import { existsSync as existsSync68, mkdirSync as mkdirSync36, readFileSync as readFileSync61, realpathSync as realpathSync6, statSync as statSync40, chownSync as chownSync5 } from "node:fs";
85007
85062
  import { spawnSync as spawnSync12 } from "node:child_process";
85008
- import { join as join69, dirname as dirname21, resolve as resolve40 } from "node:path";
85063
+ import { join as join70, dirname as dirname23, resolve as resolve40 } from "node:path";
85009
85064
  import { homedir as homedir40 } from "node:os";
85010
85065
 
85011
85066
  // src/cli/release-yaml.ts
@@ -85096,10 +85151,132 @@ ${lines.join(`
85096
85151
 
85097
85152
  // src/cli/update.ts
85098
85153
  init_hindsight();
85154
+ init_scaffold_integration();
85155
+
85156
+ // src/cli/sync-bundled-skills.ts
85157
+ import {
85158
+ cpSync as cpSync2,
85159
+ existsSync as existsSync67,
85160
+ mkdirSync as mkdirSync35,
85161
+ readFileSync as readFileSync60,
85162
+ readdirSync as readdirSync24,
85163
+ renameSync as renameSync16,
85164
+ rmSync as rmSync12,
85165
+ writeFileSync as writeFileSync19
85166
+ } from "node:fs";
85167
+ import { join as join69 } from "node:path";
85168
+ var BUNDLED_SKILL_MANIFEST_NAME = ".switchroom-manifest.json";
85169
+ function listSkillDirs(dir) {
85170
+ if (!existsSync67(dir))
85171
+ return [];
85172
+ return readdirSync24(dir, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name);
85173
+ }
85174
+ function readBundledSkillManifest(poolDir) {
85175
+ const path5 = join69(poolDir, BUNDLED_SKILL_MANIFEST_NAME);
85176
+ if (!existsSync67(path5))
85177
+ return { firstRun: true };
85178
+ try {
85179
+ const parsed = JSON.parse(readFileSync60(path5, "utf8"));
85180
+ if (!parsed || typeof parsed !== "object" || !Array.isArray(parsed.skills) || !parsed.skills.every((s) => typeof s === "string")) {
85181
+ return { corrupt: true };
85182
+ }
85183
+ const m = parsed;
85184
+ return { manifest: { version: String(m.version ?? ""), skills: m.skills, updatedAt: String(m.updatedAt ?? "") } };
85185
+ } catch {
85186
+ return { corrupt: true };
85187
+ }
85188
+ }
85189
+ function stageAndSwap(srcSkill, destSkill, poolDir, name) {
85190
+ const staging = join69(poolDir, `.tmp-${name}-${process.pid}-${Date.now()}`);
85191
+ try {
85192
+ rmSync12(staging, { recursive: true, force: true });
85193
+ cpSync2(srcSkill, staging, { recursive: true, dereference: false });
85194
+ rmSync12(destSkill, { recursive: true, force: true });
85195
+ renameSync16(staging, destSkill);
85196
+ } finally {
85197
+ rmSync12(staging, { recursive: true, force: true });
85198
+ }
85199
+ }
85200
+ function syncBundledSkills(opts) {
85201
+ const { source, dest, version: version2 } = opts;
85202
+ const result = {
85203
+ added: [],
85204
+ updated: [],
85205
+ removed: [],
85206
+ preserved: [],
85207
+ ownershipTransferred: [],
85208
+ firstRun: false,
85209
+ manifestCorrupt: false
85210
+ };
85211
+ mkdirSync35(dest, { recursive: true });
85212
+ const prior = readBundledSkillManifest(dest);
85213
+ const priorSkills = new Set("manifest" in prior ? prior.manifest.skills : []);
85214
+ result.firstRun = "firstRun" in prior;
85215
+ result.manifestCorrupt = "corrupt" in prior;
85216
+ const shipped = listSkillDirs(source).sort();
85217
+ const shippedSet = new Set(shipped);
85218
+ for (const name of shipped) {
85219
+ const destSkill = join69(dest, name);
85220
+ const existed = existsSync67(destSkill);
85221
+ let transferred = false;
85222
+ if (existed && !priorSkills.has(name) && !result.firstRun) {
85223
+ const backup = join69(dest, `${name}.operator-backup-${process.pid}-${Date.now()}`);
85224
+ try {
85225
+ renameSync16(destSkill, backup);
85226
+ transferred = true;
85227
+ result.ownershipTransferred.push(name);
85228
+ process.stderr.write(`switchroom: WARNING \u2014 a shipped skill "${name}" collides with an ` + `operator-added pool dir of the same name. Preserved the existing ` + `content as "${backup}" and installed the shipped skill under "${name}". ` + `If you meant to keep your version, rename it to a distinct skill name.
85229
+ `);
85230
+ } catch {
85231
+ result.ownershipTransferred.push(name);
85232
+ process.stderr.write(`switchroom: WARNING \u2014 shipped skill "${name}" collides with an ` + `operator-added pool dir and the preservation backup failed; left the ` + `existing dir in place and did NOT install the shipped skill. Resolve ` + `the name collision manually.
85233
+ `);
85234
+ continue;
85235
+ }
85236
+ }
85237
+ stageAndSwap(join69(source, name), destSkill, dest, name);
85238
+ if (!transferred && (priorSkills.has(name) || existed))
85239
+ result.updated.push(name);
85240
+ else
85241
+ result.added.push(name);
85242
+ }
85243
+ if (!result.firstRun && !result.manifestCorrupt) {
85244
+ for (const name of priorSkills) {
85245
+ if (shippedSet.has(name))
85246
+ continue;
85247
+ const target = join69(dest, name);
85248
+ if (existsSync67(target)) {
85249
+ rmSync12(target, { recursive: true, force: true });
85250
+ result.removed.push(name);
85251
+ }
85252
+ }
85253
+ }
85254
+ for (const name of listSkillDirs(dest)) {
85255
+ if (!shippedSet.has(name) && !priorSkills.has(name)) {
85256
+ result.preserved.push(name);
85257
+ }
85258
+ }
85259
+ result.removed.sort();
85260
+ result.preserved.sort();
85261
+ const manifest = {
85262
+ version: version2,
85263
+ skills: shipped,
85264
+ updatedAt: new Date().toISOString()
85265
+ };
85266
+ const manifestPath = join69(dest, BUNDLED_SKILL_MANIFEST_NAME);
85267
+ const manifestTmp = join69(dest, `${BUNDLED_SKILL_MANIFEST_NAME}.tmp-${process.pid}-${Date.now()}`);
85268
+ writeFileSync19(manifestTmp, JSON.stringify(manifest, null, 2) + `
85269
+ `, "utf8");
85270
+ renameSync16(manifestTmp, manifestPath);
85271
+ return result;
85272
+ }
85273
+
85274
+ // src/cli/update.ts
85275
+ init_resolve_version();
85099
85276
  function defaultPersistPin(configPath) {
85100
85277
  return (pin) => {
85101
85278
  const path5 = configPath ?? findConfigFile();
85102
- const before = readFileSync60(path5, "utf8");
85279
+ const before = readFileSync61(path5, "utf8");
85103
85280
  const after = setReleasePinInConfig(before, pin);
85104
85281
  if (after === before)
85105
85282
  return;
@@ -85113,18 +85290,18 @@ function defaultPersistPin(configPath) {
85113
85290
  } catch {}
85114
85291
  };
85115
85292
  }
85116
- var DEFAULT_COMPOSE_PATH = join69(homedir40(), ".switchroom", "compose", "docker-compose.yml");
85293
+ var DEFAULT_COMPOSE_PATH = join70(homedir40(), ".switchroom", "compose", "docker-compose.yml");
85117
85294
  function runningFromSwitchroomCheckout(scriptPath) {
85118
- let dir = dirname21(scriptPath);
85295
+ let dir = dirname23(scriptPath);
85119
85296
  for (let i = 0;i < 12; i++) {
85120
- if (existsSync67(join69(dir, ".git"))) {
85297
+ if (existsSync68(join70(dir, ".git"))) {
85121
85298
  try {
85122
- const pkg = JSON.parse(readFileSync60(join69(dir, "package.json"), "utf-8"));
85299
+ const pkg = JSON.parse(readFileSync61(join70(dir, "package.json"), "utf-8"));
85123
85300
  if (pkg.name === "switchroom")
85124
85301
  return true;
85125
85302
  } catch {}
85126
85303
  }
85127
- const parent = dirname21(dir);
85304
+ const parent = dirname23(dir);
85128
85305
  if (parent === dir)
85129
85306
  break;
85130
85307
  dir = parent;
@@ -85204,7 +85381,7 @@ function planUpdate(opts) {
85204
85381
  steps.push({
85205
85382
  name: "pull-images",
85206
85383
  description: "Pull broker / kernel / agent images from GHCR",
85207
- skipReason: opts.skipImages ? "--skip-images flag set" : !existsSync67(composePath) ? `compose file not found at ${composePath} (run \`switchroom apply --compose-only\` first)` : undefined,
85384
+ skipReason: opts.skipImages ? "--skip-images flag set" : !existsSync68(composePath) ? `compose file not found at ${composePath} (run \`switchroom apply --compose-only\` first)` : undefined,
85208
85385
  run: () => {
85209
85386
  const r = runner("docker", [
85210
85387
  "compose",
@@ -85330,23 +85507,48 @@ function planUpdate(opts) {
85330
85507
  return;
85331
85508
  }
85332
85509
  const source = resolve40(import.meta.dirname, "../../skills");
85333
- const dest = join69(homedir40(), ".switchroom", "skills", "_bundled");
85334
- if (!existsSync67(source)) {
85510
+ const dest = join70(homedir40(), ".switchroom", "skills", "_bundled");
85511
+ if (!existsSync68(source)) {
85335
85512
  process.stderr.write(`switchroom update: sync-bundled-skills \u2014 CLI bundle has no adjacent skills/ at ${source}; skipping.
85336
85513
  `);
85337
85514
  return;
85338
85515
  }
85339
85516
  try {
85340
- if (existsSync67(dest)) {
85341
- rmSync12(dest, { recursive: true, force: true });
85517
+ mkdirSync36(dirname23(dest), { recursive: true });
85518
+ const r = syncBundledSkills({
85519
+ source,
85520
+ dest,
85521
+ version: SWITCHROOM_VERSION
85522
+ });
85523
+ if (r.manifestCorrupt) {
85524
+ process.stderr.write(`switchroom update: sync-bundled-skills \u2014 pool manifest was unreadable; ` + `deleted nothing (fail-closed) and rewrote a clean manifest.
85525
+ `);
85526
+ }
85527
+ if (r.removed.length > 0) {
85528
+ process.stderr.write(`switchroom update: sync-bundled-skills \u2014 removed ${r.removed.length} retired ` + `bundled skill(s): ${r.removed.join(", ")}.
85529
+ `);
85342
85530
  }
85343
- mkdirSync35(dirname21(dest), { recursive: true });
85344
- cpSync2(source, dest, { recursive: true, dereference: false });
85345
85531
  } catch (err) {
85346
85532
  throw new Error(`sync-bundled-skills failed: ${err.message}`);
85347
85533
  }
85348
85534
  }
85349
85535
  });
85536
+ steps.push({
85537
+ name: "verify-bundled-skills",
85538
+ description: "Assert every builtin default skill is present in ~/.switchroom/skills/_bundled/ after sync.",
85539
+ run: () => {
85540
+ if (opts.syncBundledSkillsFn)
85541
+ return;
85542
+ const dest = join70(homedir40(), ".switchroom", "skills", "_bundled");
85543
+ if (!existsSync68(dest)) {
85544
+ return;
85545
+ }
85546
+ const missing = getBuiltinDefaultSkillEntries().map((e) => e.key).filter((key) => !existsSync68(join70(dest, key)));
85547
+ if (missing.length > 0) {
85548
+ throw new Error(`verify-bundled-skills: builtin default skill(s) missing from the pool after sync: ` + `${missing.join(", ")}. These ship in the CLI package and must exist in ${dest}. ` + `This is a broken sync or a packaging regression \u2014 the pool is not converged.`);
85549
+ }
85550
+ }
85551
+ });
85350
85552
  steps.push({
85351
85553
  name: "stamp-restart-marker",
85352
85554
  description: 'Write a clean-shutdown marker for every agent (reason="operator: switchroom update") so the post-recreate boot card renders as graceful rather than crash',
@@ -85376,7 +85578,7 @@ function planUpdate(opts) {
85376
85578
  description: "docker compose up -d --remove-orphans (recreates services with new images / compose)",
85377
85579
  run: () => {
85378
85580
  try {
85379
- const composeText = readFileSync60(composePath, "utf8");
85581
+ const composeText = readFileSync61(composePath, "utf8");
85380
85582
  const pf = validateBindSources(composeText);
85381
85583
  if (!pf.ok)
85382
85584
  throw new Error(formatPreflightError(pf));
@@ -85453,12 +85655,12 @@ function defaultStatusProbe(composePath) {
85453
85655
  try {
85454
85656
  cliBuiltAt = new Date(statSync40(scriptPath).mtimeMs).toISOString();
85455
85657
  } catch {}
85456
- let dir = dirname21(scriptPath);
85658
+ let dir = dirname23(scriptPath);
85457
85659
  for (let i = 0;i < 8; i++) {
85458
- const pkgPath = join69(dir, "package.json");
85459
- if (existsSync67(pkgPath)) {
85660
+ const pkgPath = join70(dir, "package.json");
85661
+ if (existsSync68(pkgPath)) {
85460
85662
  try {
85461
- const pkg = JSON.parse(readFileSync60(pkgPath, "utf-8"));
85663
+ const pkg = JSON.parse(readFileSync61(pkgPath, "utf-8"));
85462
85664
  if (typeof pkg.version === "string")
85463
85665
  cliVersion = pkg.version;
85464
85666
  } catch (err) {
@@ -85466,7 +85668,7 @@ function defaultStatusProbe(composePath) {
85466
85668
  }
85467
85669
  break;
85468
85670
  }
85469
- const parent = dirname21(dir);
85671
+ const parent = dirname23(dir);
85470
85672
  if (parent === dir)
85471
85673
  break;
85472
85674
  dir = parent;
@@ -85479,7 +85681,7 @@ function defaultStatusProbe(composePath) {
85479
85681
  warnings.push("could not resolve CLI version (no package.json found above the resolved script path)");
85480
85682
  }
85481
85683
  const services = [];
85482
- if (!existsSync67(composePath)) {
85684
+ if (!existsSync68(composePath)) {
85483
85685
  warnings.push(`compose file not found at ${composePath}; service status unknown`);
85484
85686
  return { cliVersion, cliBuiltAt, services, warnings };
85485
85687
  }
@@ -85675,7 +85877,7 @@ function registerUpdateCommand(program3) {
85675
85877
  // src/cli/rollout.ts
85676
85878
  init_helpers();
85677
85879
  import { spawnSync as spawnSync14 } from "node:child_process";
85678
- import { readFileSync as readFileSync61, chownSync as chownSync6, statSync as statSync41 } from "node:fs";
85880
+ import { readFileSync as readFileSync62, chownSync as chownSync6, statSync as statSync41 } from "node:fs";
85679
85881
  import { homedir as homedir41 } from "node:os";
85680
85882
  init_operator_uid();
85681
85883
  init_atomic();
@@ -85961,7 +86163,7 @@ function resolveRollbackTarget(auditLogPath) {
85961
86163
  const logPath = auditLogPath ?? defaultAuditLogPath2(homedir41());
85962
86164
  let raw;
85963
86165
  try {
85964
- raw = readFileSync61(logPath, "utf8");
86166
+ raw = readFileSync62(logPath, "utf8");
85965
86167
  } catch {
85966
86168
  return null;
85967
86169
  }
@@ -86079,7 +86281,7 @@ function registerRolloutCommand(program3) {
86079
86281
  `),
86080
86282
  webImageTag: () => deployedImageTag("switchroom-web"),
86081
86283
  persistPin: (pin) => {
86082
- const before = readFileSync61(configPath, "utf8");
86284
+ const before = readFileSync62(configPath, "utf8");
86083
86285
  const after = setReleasePinInConfig(before, pin);
86084
86286
  if (after === before)
86085
86287
  return;
@@ -86157,8 +86359,8 @@ init_helpers();
86157
86359
  init_lifecycle();
86158
86360
  init_resolve_version();
86159
86361
  import { execSync as execSync3 } from "node:child_process";
86160
- import { existsSync as existsSync68, readFileSync as readFileSync62 } from "node:fs";
86161
- import { dirname as dirname22, join as join70 } from "node:path";
86362
+ import { existsSync as existsSync69, readFileSync as readFileSync63 } from "node:fs";
86363
+ import { dirname as dirname24, join as join71 } from "node:path";
86162
86364
  function getClaudeCodeVersion() {
86163
86365
  try {
86164
86366
  const out = execSync3("claude --version 2>/dev/null", {
@@ -86208,16 +86410,16 @@ function formatUptime3(timestamp) {
86208
86410
  function locateSwitchroomInstallDir() {
86209
86411
  let dir = import.meta.dirname;
86210
86412
  for (let i = 0;i < 10 && dir && dir !== "/"; i++) {
86211
- const pkgPath = join70(dir, "package.json");
86212
- if (existsSync68(pkgPath)) {
86413
+ const pkgPath = join71(dir, "package.json");
86414
+ if (existsSync69(pkgPath)) {
86213
86415
  try {
86214
- const pkg = JSON.parse(readFileSync62(pkgPath, "utf-8"));
86215
- if (pkg.name === "switchroom" && existsSync68(join70(dir, ".git"))) {
86416
+ const pkg = JSON.parse(readFileSync63(pkgPath, "utf-8"));
86417
+ if (pkg.name === "switchroom" && existsSync69(join71(dir, ".git"))) {
86216
86418
  return dir;
86217
86419
  }
86218
86420
  } catch {}
86219
86421
  }
86220
- dir = dirname22(dir);
86422
+ dir = dirname24(dir);
86221
86423
  }
86222
86424
  return null;
86223
86425
  }
@@ -86390,29 +86592,29 @@ import { resolve as resolve42 } from "node:path";
86390
86592
 
86391
86593
  // src/agents/session-retention.ts
86392
86594
  import {
86393
- existsSync as existsSync69,
86394
- readdirSync as readdirSync24,
86595
+ existsSync as existsSync70,
86596
+ readdirSync as readdirSync25,
86395
86597
  statSync as statSync42,
86396
86598
  unlinkSync as unlinkSync14
86397
86599
  } from "node:fs";
86398
- import { join as join71 } from "node:path";
86600
+ import { join as join72 } from "node:path";
86399
86601
  var DEFAULT_SESSION_RETENTION_MAX_COUNT = 20;
86400
86602
  var DEFAULT_SESSION_RETENTION_MAX_AGE_DAYS = 30;
86401
86603
  var MIN_KEEP = 2;
86402
86604
  function collectSessionJsonl(claudeConfigDir) {
86403
- const projects = join71(claudeConfigDir, "projects");
86404
- if (!existsSync69(projects))
86605
+ const projects = join72(claudeConfigDir, "projects");
86606
+ if (!existsSync70(projects))
86405
86607
  return [];
86406
86608
  const found = [];
86407
86609
  const walk2 = (dir) => {
86408
86610
  let entries;
86409
86611
  try {
86410
- entries = readdirSync24(dir);
86612
+ entries = readdirSync25(dir);
86411
86613
  } catch {
86412
86614
  return;
86413
86615
  }
86414
86616
  for (const name of entries) {
86415
- const full = join71(dir, name);
86617
+ const full = join72(dir, name);
86416
86618
  let st;
86417
86619
  try {
86418
86620
  st = statSync42(full);
@@ -86532,18 +86734,18 @@ function registerHandoffCommand(program3) {
86532
86734
  // src/issues/store.ts
86533
86735
  import {
86534
86736
  closeSync as closeSync12,
86535
- existsSync as existsSync70,
86536
- mkdirSync as mkdirSync36,
86737
+ existsSync as existsSync71,
86738
+ mkdirSync as mkdirSync37,
86537
86739
  openSync as openSync12,
86538
- readdirSync as readdirSync25,
86539
- readFileSync as readFileSync63,
86540
- renameSync as renameSync16,
86740
+ readdirSync as readdirSync26,
86741
+ readFileSync as readFileSync64,
86742
+ renameSync as renameSync17,
86541
86743
  statSync as statSync43,
86542
86744
  unlinkSync as unlinkSync15,
86543
- writeFileSync as writeFileSync19,
86745
+ writeFileSync as writeFileSync20,
86544
86746
  writeSync as writeSync9
86545
86747
  } from "node:fs";
86546
- import { join as join72 } from "node:path";
86748
+ import { join as join73 } from "node:path";
86547
86749
  import { randomBytes as randomBytes12 } from "node:crypto";
86548
86750
  import { execSync as execSync4 } from "node:child_process";
86549
86751
 
@@ -86974,12 +87176,12 @@ function redactedMarker(ruleId) {
86974
87176
  var ISSUES_FILE = "issues.jsonl";
86975
87177
  var ISSUES_LOCK = "issues.lock";
86976
87178
  function readAll(stateDir) {
86977
- const path5 = join72(stateDir, ISSUES_FILE);
86978
- if (!existsSync70(path5))
87179
+ const path5 = join73(stateDir, ISSUES_FILE);
87180
+ if (!existsSync71(path5))
86979
87181
  return [];
86980
87182
  let raw;
86981
87183
  try {
86982
- raw = readFileSync63(path5, "utf-8");
87184
+ raw = readFileSync64(path5, "utf-8");
86983
87185
  } catch {
86984
87186
  return [];
86985
87187
  }
@@ -87052,7 +87254,7 @@ function record(stateDir, input, nowFn = Date.now) {
87052
87254
  });
87053
87255
  }
87054
87256
  function resolve43(stateDir, fingerprint, nowFn = Date.now) {
87055
- if (!existsSync70(join72(stateDir, ISSUES_FILE)))
87257
+ if (!existsSync71(join73(stateDir, ISSUES_FILE)))
87056
87258
  return 0;
87057
87259
  return withLock(stateDir, () => {
87058
87260
  const all = readAll(stateDir);
@@ -87070,7 +87272,7 @@ function resolve43(stateDir, fingerprint, nowFn = Date.now) {
87070
87272
  });
87071
87273
  }
87072
87274
  function resolveAllBySource(stateDir, source, nowFn = Date.now) {
87073
- if (!existsSync70(join72(stateDir, ISSUES_FILE)))
87275
+ if (!existsSync71(join73(stateDir, ISSUES_FILE)))
87074
87276
  return 0;
87075
87277
  return withLock(stateDir, () => {
87076
87278
  const all = readAll(stateDir);
@@ -87088,7 +87290,7 @@ function resolveAllBySource(stateDir, source, nowFn = Date.now) {
87088
87290
  });
87089
87291
  }
87090
87292
  function prune(stateDir, opts = {}) {
87091
- if (!existsSync70(join72(stateDir, ISSUES_FILE)))
87293
+ if (!existsSync71(join73(stateDir, ISSUES_FILE)))
87092
87294
  return 0;
87093
87295
  return withLock(stateDir, () => {
87094
87296
  const all = readAll(stateDir);
@@ -87118,24 +87320,24 @@ function prune(stateDir, opts = {}) {
87118
87320
  });
87119
87321
  }
87120
87322
  function ensureDir(stateDir) {
87121
- mkdirSync36(stateDir, { recursive: true });
87323
+ mkdirSync37(stateDir, { recursive: true });
87122
87324
  }
87123
87325
  function writeAll(stateDir, events) {
87124
- const path5 = join72(stateDir, ISSUES_FILE);
87326
+ const path5 = join73(stateDir, ISSUES_FILE);
87125
87327
  sweepOrphanTmpFiles(stateDir);
87126
87328
  const tmp = `${path5}.tmp-${process.pid}-${randomBytes12(4).toString("hex")}`;
87127
87329
  const body = events.length === 0 ? "" : events.map((e) => JSON.stringify(e)).join(`
87128
87330
  `) + `
87129
87331
  `;
87130
- writeFileSync19(tmp, body, "utf-8");
87131
- renameSync16(tmp, path5);
87332
+ writeFileSync20(tmp, body, "utf-8");
87333
+ renameSync17(tmp, path5);
87132
87334
  }
87133
87335
  var ORPHAN_TMP_TTL_MS = 60000;
87134
87336
  var TMP_PREFIX = `${ISSUES_FILE}.tmp-`;
87135
87337
  function sweepOrphanTmpFiles(stateDir) {
87136
87338
  let entries;
87137
87339
  try {
87138
- entries = readdirSync25(stateDir);
87340
+ entries = readdirSync26(stateDir);
87139
87341
  } catch {
87140
87342
  return;
87141
87343
  }
@@ -87143,7 +87345,7 @@ function sweepOrphanTmpFiles(stateDir) {
87143
87345
  for (const entry of entries) {
87144
87346
  if (!entry.startsWith(TMP_PREFIX))
87145
87347
  continue;
87146
- const tmpPath = join72(stateDir, entry);
87348
+ const tmpPath = join73(stateDir, entry);
87147
87349
  try {
87148
87350
  const stat = statSync43(tmpPath);
87149
87351
  if (stat.mtimeMs < cutoff) {
@@ -87155,7 +87357,7 @@ function sweepOrphanTmpFiles(stateDir) {
87155
87357
  var LOCK_RETRY_MS = 25;
87156
87358
  var LOCK_TIMEOUT_MS = 1e4;
87157
87359
  function withLock(stateDir, fn) {
87158
- const lockPath = join72(stateDir, ISSUES_LOCK);
87360
+ const lockPath = join73(stateDir, ISSUES_LOCK);
87159
87361
  const startedAt = Date.now();
87160
87362
  let fd = null;
87161
87363
  while (fd === null) {
@@ -87190,7 +87392,7 @@ function withLock(stateDir, fn) {
87190
87392
  function tryStealStaleLock(lockPath) {
87191
87393
  let pidStr;
87192
87394
  try {
87193
- pidStr = readFileSync63(lockPath, "utf-8").trim();
87395
+ pidStr = readFileSync64(lockPath, "utf-8").trim();
87194
87396
  } catch {
87195
87397
  return true;
87196
87398
  }
@@ -87438,20 +87640,20 @@ function relTime(deltaMs) {
87438
87640
 
87439
87641
  // src/cli/deps.ts
87440
87642
  init_source();
87441
- import { existsSync as existsSync73 } from "node:fs";
87643
+ import { existsSync as existsSync74 } from "node:fs";
87442
87644
  import { homedir as homedir44 } from "node:os";
87443
- import { join as join75, resolve as resolve44 } from "node:path";
87645
+ import { join as join76, resolve as resolve44 } from "node:path";
87444
87646
 
87445
87647
  // src/deps/python.ts
87446
87648
  import { createHash as createHash13 } from "node:crypto";
87447
87649
  import {
87448
- existsSync as existsSync71,
87449
- mkdirSync as mkdirSync37,
87450
- readFileSync as readFileSync64,
87650
+ existsSync as existsSync72,
87651
+ mkdirSync as mkdirSync38,
87652
+ readFileSync as readFileSync65,
87451
87653
  rmSync as rmSync13,
87452
- writeFileSync as writeFileSync20
87654
+ writeFileSync as writeFileSync21
87453
87655
  } from "node:fs";
87454
- import { dirname as dirname23, join as join73 } from "node:path";
87656
+ import { dirname as dirname25, join as join74 } from "node:path";
87455
87657
  import { homedir as homedir42 } from "node:os";
87456
87658
  import { execFileSync as execFileSync21 } from "node:child_process";
87457
87659
 
@@ -87464,26 +87666,26 @@ class PythonEnvError extends Error {
87464
87666
  }
87465
87667
  }
87466
87668
  function defaultPythonCacheRoot() {
87467
- return join73(homedir42(), ".switchroom", "deps", "python");
87669
+ return join74(homedir42(), ".switchroom", "deps", "python");
87468
87670
  }
87469
87671
  function hashFile(path5) {
87470
- return createHash13("sha256").update(readFileSync64(path5)).digest("hex");
87672
+ return createHash13("sha256").update(readFileSync65(path5)).digest("hex");
87471
87673
  }
87472
87674
  function ensurePythonEnv(opts) {
87473
87675
  const { skillName, requirementsPath, force = false } = opts;
87474
87676
  const cacheRoot = opts.cacheRoot ?? defaultPythonCacheRoot();
87475
87677
  const hostPython = opts.pythonBin ?? "python3";
87476
- if (!existsSync71(requirementsPath)) {
87678
+ if (!existsSync72(requirementsPath)) {
87477
87679
  throw new PythonEnvError(`requirements file not found: ${requirementsPath}`);
87478
87680
  }
87479
- const venvDir = join73(cacheRoot, skillName);
87480
- const stampPath = join73(venvDir, ".requirements.sha256");
87481
- const binDir = join73(venvDir, "bin");
87482
- const pythonBin = join73(binDir, "python");
87483
- const pipBin = join73(binDir, "pip");
87681
+ const venvDir = join74(cacheRoot, skillName);
87682
+ const stampPath = join74(venvDir, ".requirements.sha256");
87683
+ const binDir = join74(venvDir, "bin");
87684
+ const pythonBin = join74(binDir, "python");
87685
+ const pipBin = join74(binDir, "pip");
87484
87686
  const targetHash = hashFile(requirementsPath);
87485
- if (!force && existsSync71(stampPath) && existsSync71(pythonBin)) {
87486
- const existingHash = readFileSync64(stampPath, "utf8").trim();
87687
+ if (!force && existsSync72(stampPath) && existsSync72(pythonBin)) {
87688
+ const existingHash = readFileSync65(stampPath, "utf8").trim();
87487
87689
  if (existingHash === targetHash) {
87488
87690
  return {
87489
87691
  skillName,
@@ -87495,10 +87697,10 @@ function ensurePythonEnv(opts) {
87495
87697
  };
87496
87698
  }
87497
87699
  }
87498
- if (existsSync71(venvDir)) {
87700
+ if (existsSync72(venvDir)) {
87499
87701
  rmSync13(venvDir, { recursive: true, force: true });
87500
87702
  }
87501
- mkdirSync37(dirname23(venvDir), { recursive: true });
87703
+ mkdirSync38(dirname25(venvDir), { recursive: true });
87502
87704
  try {
87503
87705
  execFileSync21(hostPython, ["-m", "venv", venvDir], { stdio: "pipe" });
87504
87706
  } catch (err) {
@@ -87517,7 +87719,7 @@ function ensurePythonEnv(opts) {
87517
87719
  const e = err;
87518
87720
  throw new PythonEnvError(`Failed to install requirements for skill "${skillName}": ${e.message}`, e.stderr?.toString());
87519
87721
  }
87520
- writeFileSync20(stampPath, targetHash + `
87722
+ writeFileSync21(stampPath, targetHash + `
87521
87723
  `);
87522
87724
  return {
87523
87725
  skillName,
@@ -87533,13 +87735,13 @@ function ensurePythonEnv(opts) {
87533
87735
  import { createHash as createHash14 } from "node:crypto";
87534
87736
  import {
87535
87737
  copyFileSync as copyFileSync10,
87536
- existsSync as existsSync72,
87537
- mkdirSync as mkdirSync38,
87538
- readFileSync as readFileSync65,
87738
+ existsSync as existsSync73,
87739
+ mkdirSync as mkdirSync39,
87740
+ readFileSync as readFileSync66,
87539
87741
  rmSync as rmSync14,
87540
- writeFileSync as writeFileSync21
87742
+ writeFileSync as writeFileSync22
87541
87743
  } from "node:fs";
87542
- import { dirname as dirname24, join as join74 } from "node:path";
87744
+ import { dirname as dirname26, join as join75 } from "node:path";
87543
87745
  import { homedir as homedir43 } from "node:os";
87544
87746
  import { execFileSync as execFileSync22 } from "node:child_process";
87545
87747
 
@@ -87563,23 +87765,23 @@ var LOCKFILES_FOR = {
87563
87765
  npm: ["package-lock.json"]
87564
87766
  };
87565
87767
  function defaultNodeCacheRoot() {
87566
- return join74(homedir43(), ".switchroom", "deps", "node");
87768
+ return join75(homedir43(), ".switchroom", "deps", "node");
87567
87769
  }
87568
87770
  function hashDepInputs(packageJsonPath) {
87569
- const sourceDir = dirname24(packageJsonPath);
87771
+ const sourceDir = dirname26(packageJsonPath);
87570
87772
  const hasher = createHash14("sha256");
87571
87773
  hasher.update(`package.json
87572
87774
  `);
87573
- hasher.update(readFileSync65(packageJsonPath));
87775
+ hasher.update(readFileSync66(packageJsonPath));
87574
87776
  for (const lockName of ALL_LOCKFILES) {
87575
- const lockPath = join74(sourceDir, lockName);
87576
- if (existsSync72(lockPath)) {
87777
+ const lockPath = join75(sourceDir, lockName);
87778
+ if (existsSync73(lockPath)) {
87577
87779
  hasher.update(`
87578
87780
  `);
87579
87781
  hasher.update(lockName);
87580
87782
  hasher.update(`
87581
87783
  `);
87582
- hasher.update(readFileSync65(lockPath));
87784
+ hasher.update(readFileSync66(lockPath));
87583
87785
  }
87584
87786
  }
87585
87787
  return hasher.digest("hex");
@@ -87588,17 +87790,17 @@ function ensureNodeEnv(opts) {
87588
87790
  const { skillName, packageJsonPath, force = false } = opts;
87589
87791
  const cacheRoot = opts.cacheRoot ?? defaultNodeCacheRoot();
87590
87792
  const installer = opts.installer ?? "bun";
87591
- if (!existsSync72(packageJsonPath)) {
87793
+ if (!existsSync73(packageJsonPath)) {
87592
87794
  throw new NodeEnvError(`package.json not found: ${packageJsonPath}`);
87593
87795
  }
87594
- const sourceDir = dirname24(packageJsonPath);
87595
- const envDir = join74(cacheRoot, skillName);
87596
- const stampPath = join74(envDir, ".package.sha256");
87597
- const nodeModulesDir = join74(envDir, "node_modules");
87598
- const binDir = join74(nodeModulesDir, ".bin");
87796
+ const sourceDir = dirname26(packageJsonPath);
87797
+ const envDir = join75(cacheRoot, skillName);
87798
+ const stampPath = join75(envDir, ".package.sha256");
87799
+ const nodeModulesDir = join75(envDir, "node_modules");
87800
+ const binDir = join75(nodeModulesDir, ".bin");
87599
87801
  const targetHash = hashDepInputs(packageJsonPath);
87600
- if (!force && existsSync72(stampPath) && existsSync72(nodeModulesDir)) {
87601
- const existingHash = readFileSync65(stampPath, "utf8").trim();
87802
+ if (!force && existsSync73(stampPath) && existsSync73(nodeModulesDir)) {
87803
+ const existingHash = readFileSync66(stampPath, "utf8").trim();
87602
87804
  if (existingHash === targetHash) {
87603
87805
  return {
87604
87806
  skillName,
@@ -87609,16 +87811,16 @@ function ensureNodeEnv(opts) {
87609
87811
  };
87610
87812
  }
87611
87813
  }
87612
- if (existsSync72(envDir)) {
87814
+ if (existsSync73(envDir)) {
87613
87815
  rmSync14(envDir, { recursive: true, force: true });
87614
87816
  }
87615
- mkdirSync38(envDir, { recursive: true });
87616
- copyFileSync10(packageJsonPath, join74(envDir, "package.json"));
87817
+ mkdirSync39(envDir, { recursive: true });
87818
+ copyFileSync10(packageJsonPath, join75(envDir, "package.json"));
87617
87819
  let copiedLockfile = false;
87618
87820
  for (const lockName of LOCKFILES_FOR[installer]) {
87619
- const lockPath = join74(sourceDir, lockName);
87620
- if (existsSync72(lockPath)) {
87621
- copyFileSync10(lockPath, join74(envDir, lockName));
87821
+ const lockPath = join75(sourceDir, lockName);
87822
+ if (existsSync73(lockPath)) {
87823
+ copyFileSync10(lockPath, join75(envDir, lockName));
87622
87824
  copiedLockfile = true;
87623
87825
  }
87624
87826
  }
@@ -87634,7 +87836,7 @@ function ensureNodeEnv(opts) {
87634
87836
  const e = err;
87635
87837
  throw new NodeEnvError(`Failed to install node deps for skill "${skillName}" with ${installer}: ${e.message}`, e.stderr?.toString());
87636
87838
  }
87637
- writeFileSync21(stampPath, targetHash + `
87839
+ writeFileSync22(stampPath, targetHash + `
87638
87840
  `);
87639
87841
  return {
87640
87842
  skillName,
@@ -87653,22 +87855,22 @@ function registerDepsCommand(program3) {
87653
87855
  const deps = program3.command("deps").description("Manage cached per-skill dependency environments");
87654
87856
  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) => {
87655
87857
  const skillsRoot = builtinSkillsRoot();
87656
- if (!existsSync73(skillsRoot)) {
87858
+ if (!existsSync74(skillsRoot)) {
87657
87859
  console.error(source_default.red(`Bundled skills pool dir not found at ${skillsRoot} \u2014 run \`switchroom update\` to install it.`));
87658
87860
  process.exit(1);
87659
87861
  }
87660
- const skillDir = join75(skillsRoot, skill);
87661
- if (!existsSync73(skillDir)) {
87862
+ const skillDir = join76(skillsRoot, skill);
87863
+ if (!existsSync74(skillDir)) {
87662
87864
  console.error(source_default.red(`Unknown skill: ${skill} (no dir at ${skillDir})`));
87663
87865
  process.exit(1);
87664
87866
  }
87665
- const requirementsPath = join75(skillDir, "requirements.txt");
87666
- const packageJsonPath = join75(skillDir, "package.json");
87667
- const wantPython = opts.python ?? (!opts.python && !opts.node && existsSync73(requirementsPath));
87668
- const wantNode = opts.node ?? (!opts.python && !opts.node && existsSync73(packageJsonPath));
87867
+ const requirementsPath = join76(skillDir, "requirements.txt");
87868
+ const packageJsonPath = join76(skillDir, "package.json");
87869
+ const wantPython = opts.python ?? (!opts.python && !opts.node && existsSync74(requirementsPath));
87870
+ const wantNode = opts.node ?? (!opts.python && !opts.node && existsSync74(packageJsonPath));
87669
87871
  let did = 0;
87670
87872
  if (wantPython) {
87671
- if (!existsSync73(requirementsPath)) {
87873
+ if (!existsSync74(requirementsPath)) {
87672
87874
  console.error(source_default.red(`Skill "${skill}" has no requirements.txt at ${requirementsPath}`));
87673
87875
  process.exit(1);
87674
87876
  }
@@ -87692,7 +87894,7 @@ function registerDepsCommand(program3) {
87692
87894
  }
87693
87895
  }
87694
87896
  if (wantNode) {
87695
- if (!existsSync73(packageJsonPath)) {
87897
+ if (!existsSync74(packageJsonPath)) {
87696
87898
  console.error(source_default.red(`Skill "${skill}" has no package.json at ${packageJsonPath}`));
87697
87899
  process.exit(1);
87698
87900
  }
@@ -87725,7 +87927,7 @@ function registerDepsCommand(program3) {
87725
87927
  // src/cli/workspace.ts
87726
87928
  init_helpers();
87727
87929
  init_loader();
87728
- import { existsSync as existsSync74 } from "node:fs";
87930
+ import { existsSync as existsSync75 } from "node:fs";
87729
87931
  import { resolve as resolve45, sep as sep3 } from "node:path";
87730
87932
  import { spawnSync as spawnSync15 } from "node:child_process";
87731
87933
 
@@ -88502,7 +88704,7 @@ function registerWorkspaceCommand(program3) {
88502
88704
  if (!dir)
88503
88705
  return;
88504
88706
  const gitDir = resolve45(dir, ".git");
88505
- if (!existsSync74(gitDir)) {
88707
+ if (!existsSync75(gitDir)) {
88506
88708
  process.stdout.write(`Workspace is not a git repository. Re-run \`switchroom agent create ${agentName}\` ` + `or manually \`git init\` in ${dir} to enable versioning.
88507
88709
  `);
88508
88710
  return;
@@ -88556,7 +88758,7 @@ function registerWorkspaceCommand(program3) {
88556
88758
  if (!dir)
88557
88759
  return;
88558
88760
  const gitDir = resolve45(dir, ".git");
88559
- if (!existsSync74(gitDir)) {
88761
+ if (!existsSync75(gitDir)) {
88560
88762
  process.stdout.write(`Workspace is not a git repository.
88561
88763
  `);
88562
88764
  return;
@@ -88581,7 +88783,7 @@ function resolveAgentWorkspaceDirOrExit(program3, agentName) {
88581
88783
  const agentsDir = resolveAgentsDir(config);
88582
88784
  const agentDir = resolve45(agentsDir, agentName);
88583
88785
  const dir = resolveAgentWorkspaceDir(agentDir);
88584
- if (!existsSync74(dir)) {
88786
+ if (!existsSync75(dir)) {
88585
88787
  process.stderr.write(`workspace: ${dir} does not exist yet. Run \`switchroom setup\` or \`switchroom agent scaffold ${agentName}\` to seed it.
88586
88788
  `);
88587
88789
  return;
@@ -88617,8 +88819,8 @@ function safeParseInt(value, fallback) {
88617
88819
  init_helpers();
88618
88820
  init_loader();
88619
88821
  init_merge();
88620
- import { copyFileSync as copyFileSync11, existsSync as existsSync75, readFileSync as readFileSync66, writeFileSync as writeFileSync22 } from "node:fs";
88621
- import { join as join76, resolve as resolve46 } from "node:path";
88822
+ import { copyFileSync as copyFileSync11, existsSync as existsSync76, readFileSync as readFileSync67, writeFileSync as writeFileSync23 } from "node:fs";
88823
+ import { join as join77, resolve as resolve46 } from "node:path";
88622
88824
  init_scaffold();
88623
88825
  init_profiles();
88624
88826
  init_schema();
@@ -88635,7 +88837,7 @@ function resolveSoulTargetOrExit(program3, agentName) {
88635
88837
  const agentsDir = resolveAgentsDir(config);
88636
88838
  const agentDir = resolve46(agentsDir, agentName);
88637
88839
  const workspaceDir = resolveAgentWorkspaceDir(agentDir);
88638
- if (!existsSync75(workspaceDir)) {
88840
+ if (!existsSync76(workspaceDir)) {
88639
88841
  console.error(`soul: ${workspaceDir} does not exist yet. Run \`switchroom setup\` ` + `or \`switchroom agent scaffold ${agentName}\` to seed it.`);
88640
88842
  process.exit(1);
88641
88843
  }
@@ -88644,7 +88846,7 @@ function resolveSoulTargetOrExit(program3, agentName) {
88644
88846
  profileName,
88645
88847
  profilePath,
88646
88848
  workspaceDir,
88647
- soulPath: join76(workspaceDir, "SOUL.md"),
88849
+ soulPath: join77(workspaceDir, "SOUL.md"),
88648
88850
  soul: merged.soul
88649
88851
  };
88650
88852
  }
@@ -88661,11 +88863,11 @@ function registerSoulCommand(program3) {
88661
88863
  const t = resolveSoulTargetOrExit(program3, agentName);
88662
88864
  if (!t)
88663
88865
  return;
88664
- if (!existsSync75(t.soulPath)) {
88866
+ if (!existsSync76(t.soulPath)) {
88665
88867
  console.error(`soul: ${t.soulPath} does not exist yet \u2014 run ` + `\`switchroom soul reset ${agentName}\` to seed it.`);
88666
88868
  process.exit(1);
88667
88869
  }
88668
- process.stdout.write(readFileSync66(t.soulPath, "utf-8"));
88870
+ process.stdout.write(readFileSync67(t.soulPath, "utf-8"));
88669
88871
  }));
88670
88872
  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) => {
88671
88873
  const t = resolveSoulTargetOrExit(program3, agentName);
@@ -88676,7 +88878,7 @@ function registerSoulCommand(program3) {
88676
88878
  console.error(`soul: profile "${t.profileName}" ships no SOUL.md.hbs \u2014 ` + `nothing to re-seed from.`);
88677
88879
  process.exit(1);
88678
88880
  }
88679
- const exists = existsSync75(t.soulPath);
88881
+ const exists = existsSync76(t.soulPath);
88680
88882
  if (exists && !opts.yes) {
88681
88883
  if (!isInteractive()) {
88682
88884
  console.error(`soul: ${t.soulPath} already exists. Re-run with --yes to ` + `replace it (the current file is backed up to SOUL.md.bak).`);
@@ -88691,12 +88893,12 @@ function registerSoulCommand(program3) {
88691
88893
  let backupPath;
88692
88894
  if (exists) {
88693
88895
  backupPath = `${t.soulPath}.bak`;
88694
- if (existsSync75(backupPath)) {
88896
+ if (existsSync76(backupPath)) {
88695
88897
  backupPath = `${t.soulPath}.bak.${Date.now()}`;
88696
88898
  }
88697
88899
  copyFileSync11(t.soulPath, backupPath);
88698
88900
  }
88699
- writeFileSync22(t.soulPath, content, "utf-8");
88901
+ writeFileSync23(t.soulPath, content, "utf-8");
88700
88902
  if (backupPath) {
88701
88903
  console.log(`soul: re-seeded ${agentName}'s SOUL.md from profile ` + `"${t.profileName}".
88702
88904
  ` + ` Previous version saved to ${backupPath}`);
@@ -88710,8 +88912,8 @@ function registerSoulCommand(program3) {
88710
88912
  // src/cli/debug.ts
88711
88913
  init_helpers();
88712
88914
  init_loader();
88713
- import { existsSync as existsSync76, readFileSync as readFileSync67, readdirSync as readdirSync26, statSync as statSync44 } from "node:fs";
88714
- import { resolve as resolve47, join as join77 } from "node:path";
88915
+ import { existsSync as existsSync77, readFileSync as readFileSync68, readdirSync as readdirSync27, statSync as statSync44 } from "node:fs";
88916
+ import { resolve as resolve47, join as join78 } from "node:path";
88715
88917
  import { createHash as createHash15 } from "node:crypto";
88716
88918
  init_merge();
88717
88919
  init_hindsight2();
@@ -88722,11 +88924,11 @@ function estimateTokens(bytes) {
88722
88924
  return Math.round(bytes / 3.7);
88723
88925
  }
88724
88926
  function readMcpServerNames(agentDir) {
88725
- const mcpPath = join77(agentDir, ".mcp.json");
88726
- if (!existsSync76(mcpPath))
88927
+ const mcpPath = join78(agentDir, ".mcp.json");
88928
+ if (!existsSync77(mcpPath))
88727
88929
  return [];
88728
88930
  try {
88729
- const parsed = JSON.parse(readFileSync67(mcpPath, "utf-8"));
88931
+ const parsed = JSON.parse(readFileSync68(mcpPath, "utf-8"));
88730
88932
  return Object.keys(parsed.mcpServers ?? {});
88731
88933
  } catch {
88732
88934
  return null;
@@ -88736,18 +88938,18 @@ function sha256(content) {
88736
88938
  return createHash15("sha256").update(content).digest("hex").slice(0, 16);
88737
88939
  }
88738
88940
  function findLatestTranscriptJsonl(claudeConfigDir) {
88739
- const projectsDir = join77(claudeConfigDir, "projects");
88740
- if (!existsSync76(projectsDir))
88941
+ const projectsDir = join78(claudeConfigDir, "projects");
88942
+ if (!existsSync77(projectsDir))
88741
88943
  return;
88742
88944
  try {
88743
- const entries = readdirSync26(projectsDir, { withFileTypes: true });
88945
+ const entries = readdirSync27(projectsDir, { withFileTypes: true });
88744
88946
  let latest;
88745
88947
  for (const entry of entries) {
88746
88948
  if (!entry.isDirectory())
88747
88949
  continue;
88748
- const projectPath = join77(projectsDir, entry.name);
88749
- const transcriptPath = join77(projectPath, "transcript.jsonl");
88750
- if (!existsSync76(transcriptPath))
88950
+ const projectPath = join78(projectsDir, entry.name);
88951
+ const transcriptPath = join78(projectPath, "transcript.jsonl");
88952
+ if (!existsSync77(transcriptPath))
88751
88953
  continue;
88752
88954
  const stat3 = statSync44(transcriptPath);
88753
88955
  if (!latest || stat3.mtimeMs > latest.mtime) {
@@ -88761,7 +88963,7 @@ function findLatestTranscriptJsonl(claudeConfigDir) {
88761
88963
  }
88762
88964
  function extractLatestUserMessage(transcriptPath) {
88763
88965
  try {
88764
- const content = readFileSync67(transcriptPath, "utf-8");
88966
+ const content = readFileSync68(transcriptPath, "utf-8");
88765
88967
  const lines = content.trim().split(`
88766
88968
  `).filter(Boolean);
88767
88969
  for (let i = lines.length - 1;i >= 0; i--) {
@@ -88810,16 +89012,16 @@ function registerDebugCommand(program3) {
88810
89012
  }
88811
89013
  const agentsDir = resolveAgentsDir(config);
88812
89014
  const agentDir = resolve47(agentsDir, agentName);
88813
- if (!existsSync76(agentDir)) {
89015
+ if (!existsSync77(agentDir)) {
88814
89016
  console.error(`Agent directory not found: ${agentDir}`);
88815
89017
  process.exit(1);
88816
89018
  }
88817
89019
  const workspaceDir = resolveAgentWorkspaceDir(agentDir);
88818
- const claudeConfigDir = join77(agentDir, ".claude");
88819
- const claudeMdPath = join77(agentDir, "CLAUDE.md");
88820
- const soulMdPath = join77(agentDir, "SOUL.md");
88821
- const workspaceSoulMdPath = join77(workspaceDir, "SOUL.md");
88822
- const handoffPath = join77(agentDir, ".handoff.md");
89020
+ const claudeConfigDir = join78(agentDir, ".claude");
89021
+ const claudeMdPath = join78(agentDir, "CLAUDE.md");
89022
+ const soulMdPath = join78(agentDir, "SOUL.md");
89023
+ const workspaceSoulMdPath = join78(workspaceDir, "SOUL.md");
89024
+ const handoffPath = join78(agentDir, ".handoff.md");
88823
89025
  const lastN = parseInt(opts.last, 10);
88824
89026
  if (isNaN(lastN) || lastN < 1) {
88825
89027
  console.error("--last must be a positive integer");
@@ -88865,7 +89067,7 @@ function registerDebugCommand(program3) {
88865
89067
  }
88866
89068
  console.log(`=== Append System Prompt (per-session) ===
88867
89069
  `);
88868
- const handoffContent = existsSync76(handoffPath) ? readFileSync67(handoffPath, "utf-8") : "";
89070
+ const handoffContent = existsSync77(handoffPath) ? readFileSync68(handoffPath, "utf-8") : "";
88869
89071
  if (handoffContent.trim().length > 0) {
88870
89072
  console.log(`-- Handoff Briefing (${formatBytes(handoffContent.length)}) --`);
88871
89073
  console.log(handoffContent);
@@ -88876,7 +89078,7 @@ function registerDebugCommand(program3) {
88876
89078
  }
88877
89079
  console.log(`=== CLAUDE.md (auto-loaded by Claude Code) ===
88878
89080
  `);
88879
- const claudeMdContent = existsSync76(claudeMdPath) ? readFileSync67(claudeMdPath, "utf-8") : "";
89081
+ const claudeMdContent = existsSync77(claudeMdPath) ? readFileSync68(claudeMdPath, "utf-8") : "";
88880
89082
  if (claudeMdContent.trim().length > 0) {
88881
89083
  console.log(`(${formatBytes(claudeMdContent.length)})`);
88882
89084
  console.log(claudeMdContent);
@@ -88887,7 +89089,7 @@ function registerDebugCommand(program3) {
88887
89089
  }
88888
89090
  console.log(`=== Persona (SOUL.md) ===
88889
89091
  `);
88890
- const soulMdContent = existsSync76(soulMdPath) ? readFileSync67(soulMdPath, "utf-8") : existsSync76(workspaceSoulMdPath) ? readFileSync67(workspaceSoulMdPath, "utf-8") : "";
89092
+ const soulMdContent = existsSync77(soulMdPath) ? readFileSync68(soulMdPath, "utf-8") : existsSync77(workspaceSoulMdPath) ? readFileSync68(workspaceSoulMdPath, "utf-8") : "";
88891
89093
  if (soulMdContent.trim().length > 0) {
88892
89094
  console.log(`(${formatBytes(soulMdContent.length)})`);
88893
89095
  console.log(soulMdContent);
@@ -88948,11 +89150,11 @@ function registerDebugCommand(program3) {
88948
89150
  const soulMdBytes = soulMdContent.length;
88949
89151
  const perTurnBytes = dynamicResult.concatenated.length;
88950
89152
  const userBytes = userMessage?.text.length ?? 0;
88951
- const fleetDir = join77(agentsDir, "..", "fleet");
88952
- const fleetInvPath = join77(fleetDir, "switchroom-invariants.md");
88953
- const fleetClaudePath = join77(fleetDir, "CLAUDE.md");
88954
- const fleetInvBytes = existsSync76(fleetInvPath) ? readFileSync67(fleetInvPath, "utf-8").length : 0;
88955
- const fleetClaudeBytes = existsSync76(fleetClaudePath) ? readFileSync67(fleetClaudePath, "utf-8").length : 0;
89153
+ const fleetDir = join78(agentsDir, "..", "fleet");
89154
+ const fleetInvPath = join78(fleetDir, "switchroom-invariants.md");
89155
+ const fleetClaudePath = join78(fleetDir, "CLAUDE.md");
89156
+ const fleetInvBytes = existsSync77(fleetInvPath) ? readFileSync68(fleetInvPath, "utf-8").length : 0;
89157
+ const fleetClaudeBytes = existsSync77(fleetClaudePath) ? readFileSync68(fleetClaudePath, "utf-8").length : 0;
88956
89158
  const fleetBytes = fleetInvBytes + fleetClaudeBytes;
88957
89159
  const totalBytes = stableBytes + perSessionBytes + claudeMdBytes + fleetBytes + perTurnBytes + userBytes;
88958
89160
  console.log(`Stable prefix: ${formatBytes(stableBytes).padEnd(20)} (cache-hot; includes SOUL.md ${soulMdBytes.toLocaleString()}B)`);
@@ -88985,44 +89187,44 @@ init_source();
88985
89187
 
88986
89188
  // src/worktree/claim.ts
88987
89189
  import { execFileSync as execFileSync23 } from "node:child_process";
88988
- import { closeSync as closeSync13, mkdirSync as mkdirSync40, openSync as openSync13, existsSync as existsSync78, unlinkSync as unlinkSync17 } from "node:fs";
88989
- import { join as join79, resolve as resolve49 } from "node:path";
89190
+ import { closeSync as closeSync13, mkdirSync as mkdirSync41, openSync as openSync13, existsSync as existsSync79, unlinkSync as unlinkSync17 } from "node:fs";
89191
+ import { join as join80, resolve as resolve49 } from "node:path";
88990
89192
  import { homedir as homedir46 } from "node:os";
88991
89193
  import { randomBytes as randomBytes13 } from "node:crypto";
88992
89194
 
88993
89195
  // src/worktree/registry.ts
88994
89196
  import {
88995
- mkdirSync as mkdirSync39,
88996
- writeFileSync as writeFileSync23,
88997
- readFileSync as readFileSync68,
88998
- readdirSync as readdirSync27,
89197
+ mkdirSync as mkdirSync40,
89198
+ writeFileSync as writeFileSync24,
89199
+ readFileSync as readFileSync69,
89200
+ readdirSync as readdirSync28,
88999
89201
  unlinkSync as unlinkSync16,
89000
- existsSync as existsSync77,
89001
- renameSync as renameSync17
89202
+ existsSync as existsSync78,
89203
+ renameSync as renameSync18
89002
89204
  } from "node:fs";
89003
- import { join as join78, resolve as resolve48 } from "node:path";
89205
+ import { join as join79, resolve as resolve48 } from "node:path";
89004
89206
  import { homedir as homedir45 } from "node:os";
89005
89207
  function registryDir() {
89006
- return resolve48(process.env.SWITCHROOM_WORKTREE_DIR ?? join78(homedir45(), ".switchroom", "worktrees"));
89208
+ return resolve48(process.env.SWITCHROOM_WORKTREE_DIR ?? join79(homedir45(), ".switchroom", "worktrees"));
89007
89209
  }
89008
89210
  function recordPath(id) {
89009
- return join78(registryDir(), `${id}.json`);
89211
+ return join79(registryDir(), `${id}.json`);
89010
89212
  }
89011
89213
  function ensureDir2() {
89012
- mkdirSync39(registryDir(), { recursive: true });
89214
+ mkdirSync40(registryDir(), { recursive: true });
89013
89215
  }
89014
89216
  function writeRecord(record2) {
89015
89217
  ensureDir2();
89016
89218
  const target = recordPath(record2.id);
89017
89219
  const tmp = `${target}.tmp${process.pid}`;
89018
- writeFileSync23(tmp, JSON.stringify(record2, null, 2) + `
89220
+ writeFileSync24(tmp, JSON.stringify(record2, null, 2) + `
89019
89221
  `, { mode: 384 });
89020
- renameSync17(tmp, target);
89222
+ renameSync18(tmp, target);
89021
89223
  }
89022
89224
  function readRecord(id) {
89023
89225
  const path8 = recordPath(id);
89024
89226
  try {
89025
- const raw = readFileSync68(path8, "utf8");
89227
+ const raw = readFileSync69(path8, "utf8");
89026
89228
  return JSON.parse(raw);
89027
89229
  } catch {
89028
89230
  return null;
@@ -89038,7 +89240,7 @@ function listRecords() {
89038
89240
  ensureDir2();
89039
89241
  const dir = registryDir();
89040
89242
  const records = [];
89041
- for (const entry of readdirSync27(dir)) {
89243
+ for (const entry of readdirSync28(dir)) {
89042
89244
  if (!entry.endsWith(".json"))
89043
89245
  continue;
89044
89246
  const id = entry.slice(0, -5);
@@ -89055,9 +89257,9 @@ function countByRepo(repoPath) {
89055
89257
  // src/worktree/claim.ts
89056
89258
  function acquireRepoLock(repoPath) {
89057
89259
  const lockDir = registryDir();
89058
- mkdirSync40(lockDir, { recursive: true });
89260
+ mkdirSync41(lockDir, { recursive: true });
89059
89261
  const lockName = repoPath.replace(/[^A-Za-z0-9]/g, "_");
89060
- const lockPath = join79(lockDir, `.lock-${lockName}`);
89262
+ const lockPath = join80(lockDir, `.lock-${lockName}`);
89061
89263
  const deadline = Date.now() + 5000;
89062
89264
  let fd = null;
89063
89265
  while (fd === null) {
@@ -89084,7 +89286,7 @@ function acquireRepoLock(repoPath) {
89084
89286
  }
89085
89287
  var DEFAULT_CONCURRENCY = 5;
89086
89288
  function worktreesBaseDir() {
89087
- return resolve49(process.env.SWITCHROOM_WORKTREE_BASE ?? join79(homedir46(), ".switchroom", "worktree-checkouts"));
89289
+ return resolve49(process.env.SWITCHROOM_WORKTREE_BASE ?? join80(homedir46(), ".switchroom", "worktree-checkouts"));
89088
89290
  }
89089
89291
  function shortId() {
89090
89292
  return randomBytes13(4).toString("hex");
@@ -89106,12 +89308,12 @@ function resolveRepoPath(repo, codeRepos) {
89106
89308
  }
89107
89309
  function expandHome(p) {
89108
89310
  if (p.startsWith("~/"))
89109
- return join79(homedir46(), p.slice(2));
89311
+ return join80(homedir46(), p.slice(2));
89110
89312
  return p;
89111
89313
  }
89112
89314
  async function claimWorktree(input, codeRepos) {
89113
89315
  const repoPath = resolveRepoPath(input.repo, codeRepos);
89114
- if (!existsSync78(repoPath)) {
89316
+ if (!existsSync79(repoPath)) {
89115
89317
  throw new Error(`Repository path does not exist: ${repoPath}`);
89116
89318
  }
89117
89319
  let concurrencyCap = DEFAULT_CONCURRENCY;
@@ -89133,8 +89335,8 @@ async function claimWorktree(input, codeRepos) {
89133
89335
  const taskSuffix = input.taskName ? sanitizeTaskName(input.taskName) : "task";
89134
89336
  branch = `task/${taskSuffix}-${id}`;
89135
89337
  const baseDir = worktreesBaseDir();
89136
- mkdirSync40(baseDir, { recursive: true });
89137
- worktreePath = join79(baseDir, `${id}-${taskSuffix}`);
89338
+ mkdirSync41(baseDir, { recursive: true });
89339
+ worktreePath = join80(baseDir, `${id}-${taskSuffix}`);
89138
89340
  const ambientOwner = process.env.SWITCHROOM_AGENT_NAME;
89139
89341
  const ownerAgent = input.ownerAgent ?? (ambientOwner != null && ambientOwner !== "" ? ambientOwner : undefined);
89140
89342
  const now = new Date().toISOString();
@@ -89167,7 +89369,7 @@ async function claimWorktree(input, codeRepos) {
89167
89369
 
89168
89370
  // src/worktree/release.ts
89169
89371
  import { execFileSync as execFileSync24 } from "node:child_process";
89170
- import { existsSync as existsSync79 } from "node:fs";
89372
+ import { existsSync as existsSync80 } from "node:fs";
89171
89373
  function releaseWorktree(input) {
89172
89374
  const { id } = input;
89173
89375
  const record2 = readRecord(id);
@@ -89175,7 +89377,7 @@ function releaseWorktree(input) {
89175
89377
  return { released: true };
89176
89378
  }
89177
89379
  let gitSuccess = true;
89178
- if (existsSync79(record2.path)) {
89380
+ if (existsSync80(record2.path)) {
89179
89381
  try {
89180
89382
  execFileSync24("git", ["worktree", "remove", "--force", record2.path], {
89181
89383
  cwd: record2.repo,
@@ -89214,7 +89416,7 @@ function listWorktrees() {
89214
89416
 
89215
89417
  // src/worktree/reaper.ts
89216
89418
  import { execFileSync as execFileSync25 } from "node:child_process";
89217
- import { existsSync as existsSync80 } from "node:fs";
89419
+ import { existsSync as existsSync81 } from "node:fs";
89218
89420
  var STALE_THRESHOLD_MS = 10 * 60 * 1000;
89219
89421
  function reapSkipReasonText(action) {
89220
89422
  switch (action) {
@@ -89275,7 +89477,7 @@ function planReaper(nowMs, deps = {}) {
89275
89477
  const plan = [];
89276
89478
  for (const record2 of listRecords()) {
89277
89479
  const heartbeatAge = now - new Date(record2.heartbeatAt).getTime();
89278
- const worktreeExists = existsSync80(record2.path);
89480
+ const worktreeExists = existsSync81(record2.path);
89279
89481
  if (!worktreeExists) {
89280
89482
  plan.push({
89281
89483
  record: record2,
@@ -89356,16 +89558,16 @@ function runReaper(nowMs, deps = {}) {
89356
89558
  // src/worktree/gc.ts
89357
89559
  import { execFileSync as execFileSync26 } from "node:child_process";
89358
89560
  import {
89359
- existsSync as existsSync81,
89360
- readFileSync as readFileSync69,
89361
- readdirSync as readdirSync28,
89561
+ existsSync as existsSync82,
89562
+ readFileSync as readFileSync70,
89563
+ readdirSync as readdirSync29,
89362
89564
  statSync as statSync45,
89363
- renameSync as renameSync18,
89364
- mkdirSync as mkdirSync41,
89565
+ renameSync as renameSync19,
89566
+ mkdirSync as mkdirSync42,
89365
89567
  rmSync as rmSync15
89366
89568
  } from "node:fs";
89367
89569
  import { homedir as homedir47 } from "node:os";
89368
- import { join as join80, resolve as resolve50 } from "node:path";
89570
+ import { join as join81, resolve as resolve50 } from "node:path";
89369
89571
  function parseGitdirPointer(dotGitFileContents) {
89370
89572
  const m = /^gitdir:\s*(.+?)\s*$/m.exec(dotGitFileContents);
89371
89573
  return m ? m[1] : null;
@@ -89480,17 +89682,17 @@ function defaultPrSignal(repo, branch, exec) {
89480
89682
  }
89481
89683
  }
89482
89684
  function trashRoot() {
89483
- return resolve50(process.env.SWITCHROOM_WORKTREE_TRASH ?? join80(homedir47(), ".switchroom", "worktree-gc-trash"));
89685
+ return resolve50(process.env.SWITCHROOM_WORKTREE_TRASH ?? join81(homedir47(), ".switchroom", "worktree-gc-trash"));
89484
89686
  }
89485
89687
  function planGc(roots, deps = {}) {
89486
- const exists = deps.existsSync ?? existsSync81;
89487
- const readDir = deps.readDir ?? ((p) => readdirSync28(p));
89488
- const readFile4 = deps.readFile ?? ((p) => readFileSync69(p, "utf8"));
89688
+ const exists = deps.existsSync ?? existsSync82;
89689
+ const readDir = deps.readDir ?? ((p) => readdirSync29(p));
89690
+ const readFile4 = deps.readFile ?? ((p) => readFileSync70(p, "utf8"));
89489
89691
  const stat3 = deps.stat ?? ((p) => statSync45(p));
89490
89692
  const exec = deps.exec ?? defaultExec;
89491
89693
  const prSignal = deps.prSignal ?? ((repo, branch) => defaultPrSignal(repo, branch, exec));
89492
89694
  const stamp = deps.dateStamp ?? "undated";
89493
- const trash = join80(trashRoot(), stamp);
89695
+ const trash = join81(trashRoot(), stamp);
89494
89696
  let claimed;
89495
89697
  try {
89496
89698
  claimed = new Set(listRecords().map((r) => resolve50(r.path)));
@@ -89526,10 +89728,10 @@ function planGc(roots, deps = {}) {
89526
89728
  continue;
89527
89729
  }
89528
89730
  for (const name of entries) {
89529
- const dir = join80(root, name);
89731
+ const dir = join81(root, name);
89530
89732
  if (isEphemeralPath(dir))
89531
89733
  continue;
89532
- const dotGit = join80(dir, ".git");
89734
+ const dotGit = join81(dir, ".git");
89533
89735
  if (!exists(dotGit))
89534
89736
  continue;
89535
89737
  let st;
@@ -89558,7 +89760,7 @@ function planGc(roots, deps = {}) {
89558
89760
  ownerRepos.add(repoRoot);
89559
89761
  if (exists(ptr))
89560
89762
  continue;
89561
- orphans.push({ dir, owner: repoRoot, dest: join80(trash, name) });
89763
+ orphans.push({ dir, owner: repoRoot, dest: join81(trash, name) });
89562
89764
  }
89563
89765
  }
89564
89766
  const registered = [];
@@ -89613,10 +89815,10 @@ function planGc(roots, deps = {}) {
89613
89815
  }
89614
89816
  function applyGc(plan, deps = {}) {
89615
89817
  const exec = deps.exec ?? defaultExec;
89616
- const mkdirp = deps.mkdirp ?? ((p) => void mkdirSync41(p, { recursive: true }));
89818
+ const mkdirp = deps.mkdirp ?? ((p) => void mkdirSync42(p, { recursive: true }));
89617
89819
  const move = deps.move ?? ((src, dest) => {
89618
89820
  try {
89619
- renameSync18(src, dest);
89821
+ renameSync19(src, dest);
89620
89822
  } catch {
89621
89823
  exec("mv", [src, dest]);
89622
89824
  }
@@ -89662,14 +89864,14 @@ function selectPurgeTargets(entries, olderThanDays) {
89662
89864
  return entries.filter((e) => e.ageDays >= olderThanDays).map((e) => e.path);
89663
89865
  }
89664
89866
  function listTrashEntries(nowMs, deps = {}) {
89665
- const exists = deps.existsSync ?? existsSync81;
89666
- const readDir = deps.readDir ?? ((p) => readdirSync28(p));
89867
+ const exists = deps.existsSync ?? existsSync82;
89868
+ const readDir = deps.readDir ?? ((p) => readdirSync29(p));
89667
89869
  const root = trashRoot();
89668
89870
  if (!exists(root))
89669
89871
  return [];
89670
89872
  const out = [];
89671
89873
  for (const stamp of readDir(root)) {
89672
- const stampDir = join80(root, stamp);
89874
+ const stampDir = join81(root, stamp);
89673
89875
  let names;
89674
89876
  try {
89675
89877
  names = readDir(stampDir);
@@ -89677,7 +89879,7 @@ function listTrashEntries(nowMs, deps = {}) {
89677
89879
  continue;
89678
89880
  }
89679
89881
  for (const name of names) {
89680
- const p = join80(stampDir, name);
89882
+ const p = join81(stampDir, name);
89681
89883
  let mtimeMs = nowMs;
89682
89884
  try {
89683
89885
  mtimeMs = statSync45(p).mtimeMs;
@@ -89701,7 +89903,7 @@ function purgeTrash(paths) {
89701
89903
  return { deleted, errors: errors2 };
89702
89904
  }
89703
89905
  function defaultRoots() {
89704
- return [join80(homedir47(), "code")];
89906
+ return [join81(homedir47(), "code")];
89705
89907
  }
89706
89908
 
89707
89909
  // src/cli/worktree.ts
@@ -89924,12 +90126,12 @@ init_drive();
89924
90126
  init_scaffold_integration();
89925
90127
  import {
89926
90128
  chmodSync as chmodSync11,
89927
- mkdirSync as mkdirSync42,
89928
- readdirSync as readdirSync29,
90129
+ mkdirSync as mkdirSync43,
90130
+ readdirSync as readdirSync30,
89929
90131
  rmSync as rmSync16,
89930
- writeFileSync as writeFileSync24
90132
+ writeFileSync as writeFileSync25
89931
90133
  } from "node:fs";
89932
- import { join as join81 } from "node:path";
90134
+ import { join as join82 } from "node:path";
89933
90135
  function encodeCredentialsFilename(email) {
89934
90136
  const SAFE = new Set([
89935
90137
  ..."ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
@@ -90119,17 +90321,17 @@ function resolveCredentialsDir(env2) {
90119
90321
  if (explicit && explicit.length > 0)
90120
90322
  return explicit;
90121
90323
  const stateBase = env2.SWITCHROOM_CONTAINER === "1" ? "/state/agent" : env2.HOME ?? ".";
90122
- return join81(stateBase, "google-workspace-mcp", "credentials");
90324
+ return join82(stateBase, "google-workspace-mcp", "credentials");
90123
90325
  }
90124
90326
  function writeSeedFile(dir, email, seed) {
90125
- mkdirSync42(dir, { recursive: true, mode: 448 });
90327
+ mkdirSync43(dir, { recursive: true, mode: 448 });
90126
90328
  chmodSync11(dir, 448);
90127
- for (const name of readdirSync29(dir)) {
90128
- rmSync16(join81(dir, name), { force: true, recursive: true });
90329
+ for (const name of readdirSync30(dir)) {
90330
+ rmSync16(join82(dir, name), { force: true, recursive: true });
90129
90331
  }
90130
90332
  const filename = encodeCredentialsFilename(email);
90131
- const filePath = join81(dir, filename);
90132
- writeFileSync24(filePath, JSON.stringify(seed), { mode: 384 });
90333
+ const filePath = join82(dir, filename);
90334
+ writeFileSync25(filePath, JSON.stringify(seed), { mode: 384 });
90133
90335
  chmodSync11(filePath, 384);
90134
90336
  return filePath;
90135
90337
  }
@@ -90287,8 +90489,8 @@ function registerDriveMcpLauncherCommand(program3) {
90287
90489
  // src/cli/m365-mcp-launcher.ts
90288
90490
  init_scaffold_integration();
90289
90491
  import { spawn as spawn5 } from "node:child_process";
90290
- import { writeFileSync as writeFileSync25, mkdirSync as mkdirSync43 } from "node:fs";
90291
- import { dirname as dirname25, join as join82 } from "node:path";
90492
+ import { writeFileSync as writeFileSync26, mkdirSync as mkdirSync44 } from "node:fs";
90493
+ import { dirname as dirname27, join as join83 } from "node:path";
90292
90494
  var SOFTERIA_TOKEN_ENV = "MS365_MCP_OAUTH_TOKEN";
90293
90495
  var DEFAULT_REFRESH_LEAD_MS = 5 * 60 * 1000;
90294
90496
  var MAX_REFRESH_INTERVAL_MS = 60 * 60 * 1000;
@@ -90324,8 +90526,8 @@ function computeRefreshDelayMs(expiresAt, now, leadMs = DEFAULT_REFRESH_LEAD_MS)
90324
90526
  function writeRefreshHeartbeat(agentName, data, account) {
90325
90527
  const path8 = heartbeatPath(agentName, account);
90326
90528
  try {
90327
- mkdirSync43(dirname25(path8), { recursive: true });
90328
- writeFileSync25(path8, JSON.stringify(data, null, 2), { mode: 420 });
90529
+ mkdirSync44(dirname27(path8), { recursive: true });
90530
+ writeFileSync26(path8, JSON.stringify(data, null, 2), { mode: 420 });
90329
90531
  } catch {}
90330
90532
  }
90331
90533
  function heartbeatPath(agentName, account) {
@@ -90333,7 +90535,7 @@ function heartbeatPath(agentName, account) {
90333
90535
  const override = process.env.SWITCHROOM_M365_HEARTBEAT_DIR;
90334
90536
  if (override) {
90335
90537
  const base = slug ? `m365-launcher-${agentName}-${slug}` : `m365-launcher-${agentName}`;
90336
- return join82(override, `${base}.heartbeat.json`);
90538
+ return join83(override, `${base}.heartbeat.json`);
90337
90539
  }
90338
90540
  return slug ? `/state/agent/m365-launcher-${slug}.heartbeat.json` : "/state/agent/m365-launcher.heartbeat.json";
90339
90541
  }
@@ -90565,8 +90767,8 @@ function registerM365McpLauncherCommand(program3) {
90565
90767
  // src/cli/notion-mcp-launcher.ts
90566
90768
  init_scaffold_integration();
90567
90769
  import { spawn as spawn6 } from "node:child_process";
90568
- import { existsSync as existsSync82, mkdirSync as mkdirSync44, writeFileSync as writeFileSync26 } from "node:fs";
90569
- import { dirname as dirname26 } from "node:path";
90770
+ import { existsSync as existsSync83, mkdirSync as mkdirSync45, writeFileSync as writeFileSync27 } from "node:fs";
90771
+ import { dirname as dirname28 } from "node:path";
90570
90772
  var HEARTBEAT_WRITE_INTERVAL_MS = 30 * 1000;
90571
90773
  var DEFAULT_HEARTBEAT_PATH = "/state/agent/notion-launcher.heartbeat.json";
90572
90774
  var DEFAULT_VAULT_KEY = "notion/integration-token";
@@ -90576,10 +90778,10 @@ function buildNotionMcpArgs(opts) {
90576
90778
  }
90577
90779
  function defaultWriteHeartbeat(path8, contents) {
90578
90780
  try {
90579
- const dir = dirname26(path8);
90580
- if (!existsSync82(dir))
90581
- mkdirSync44(dir, { recursive: true });
90582
- writeFileSync26(path8, contents);
90781
+ const dir = dirname28(path8);
90782
+ if (!existsSync83(dir))
90783
+ mkdirSync45(dir, { recursive: true });
90784
+ writeFileSync27(path8, contents);
90583
90785
  } catch {}
90584
90786
  }
90585
90787
  async function runNotionMcpLauncher(opts, runtime) {
@@ -90689,9 +90891,9 @@ function registerNotionMcpLauncherCommand(program3) {
90689
90891
 
90690
90892
  // src/cli/hindsight-mcp-shim.ts
90691
90893
  init_hindsight();
90692
- import { mkdirSync as mkdirSync45, readFileSync as readFileSync70, renameSync as renameSync19, writeFileSync as writeFileSync27 } from "node:fs";
90894
+ import { mkdirSync as mkdirSync46, readFileSync as readFileSync71, renameSync as renameSync20, writeFileSync as writeFileSync28 } from "node:fs";
90693
90895
  import { tmpdir as tmpdir5 } from "node:os";
90694
- import { join as join83 } from "node:path";
90896
+ import { join as join84 } from "node:path";
90695
90897
  import { createInterface as createInterface6 } from "node:readline";
90696
90898
  var SHIM_SUPPORTED_PROTOCOL_VERSIONS = [
90697
90899
  "2025-06-18",
@@ -90914,22 +91116,22 @@ class HindsightShim {
90914
91116
  `));
90915
91117
  }
90916
91118
  get cachePath() {
90917
- return join83(this.opts.cacheDir, TOOLS_CACHE_FILENAME);
91119
+ return join84(this.opts.cacheDir, TOOLS_CACHE_FILENAME);
90918
91120
  }
90919
91121
  writeCache(result) {
90920
91122
  try {
90921
- mkdirSync45(this.opts.cacheDir, { recursive: true });
90922
- const tmp = join83(this.opts.cacheDir, `.${TOOLS_CACHE_FILENAME}.${process.pid}.tmp`);
90923
- writeFileSync27(tmp, JSON.stringify(result, null, 2) + `
91123
+ mkdirSync46(this.opts.cacheDir, { recursive: true });
91124
+ const tmp = join84(this.opts.cacheDir, `.${TOOLS_CACHE_FILENAME}.${process.pid}.tmp`);
91125
+ writeFileSync28(tmp, JSON.stringify(result, null, 2) + `
90924
91126
  `);
90925
- renameSync19(tmp, this.cachePath);
91127
+ renameSync20(tmp, this.cachePath);
90926
91128
  } catch (err) {
90927
91129
  this.log(`[hindsight-shim] cache write failed: ${String(err)}`);
90928
91130
  }
90929
91131
  }
90930
91132
  readCache() {
90931
91133
  try {
90932
- const parsed = JSON.parse(readFileSync70(this.cachePath, "utf-8"));
91134
+ const parsed = JSON.parse(readFileSync71(this.cachePath, "utf-8"));
90933
91135
  if (Array.isArray(parsed.tools))
90934
91136
  return parsed;
90935
91137
  return null;
@@ -91092,7 +91294,7 @@ function resolveShimOptionsFromEnv(env2) {
91092
91294
  return {
91093
91295
  url: env2.HINDSIGHT_MCP_URL || HINDSIGHT_DEFAULT_MCP_URL,
91094
91296
  bankId: env2.HINDSIGHT_BANK_ID || "",
91095
- cacheDir: env2.HINDSIGHT_SHIM_CACHE_DIR || join83(home2, ".hindsight-shim")
91297
+ cacheDir: env2.HINDSIGHT_SHIM_CACHE_DIR || join84(home2, ".hindsight-shim")
91096
91298
  };
91097
91299
  }
91098
91300
  function registerHindsightMcpShimCommand(program3) {
@@ -91105,7 +91307,7 @@ function registerHindsightMcpShimCommand(program3) {
91105
91307
 
91106
91308
  // src/cli/deliver-file.ts
91107
91309
  init_client2();
91108
- import { readFileSync as readFileSync71, statSync as statSync46 } from "node:fs";
91310
+ import { readFileSync as readFileSync72, statSync as statSync46 } from "node:fs";
91109
91311
  import { basename as basename11 } from "node:path";
91110
91312
 
91111
91313
  // src/delivery/onedrive.ts
@@ -91445,7 +91647,7 @@ async function defaultResolveProvider() {
91445
91647
  async function runDeliverFile(localPath, deps = {}) {
91446
91648
  const agentName = safeAgentName(deps.agentName ?? process.env.SWITCHROOM_AGENT_NAME);
91447
91649
  const sizeOf = deps.fileSize ?? ((p) => statSync46(p).size);
91448
- const read = deps.readFile ?? ((p) => new Uint8Array(readFileSync71(p)));
91650
+ const read = deps.readFile ?? ((p) => new Uint8Array(readFileSync72(p)));
91449
91651
  const resolveProvider = deps.resolveProvider ?? defaultResolveProvider;
91450
91652
  let size;
91451
91653
  try {
@@ -91766,8 +91968,8 @@ function runRedactStdin() {
91766
91968
  }
91767
91969
 
91768
91970
  // src/cli/status-ask.ts
91769
- import { readFileSync as readFileSync75, existsSync as existsSync87, readdirSync as readdirSync31 } from "node:fs";
91770
- import { join as join88 } from "node:path";
91971
+ import { readFileSync as readFileSync76, existsSync as existsSync88, readdirSync as readdirSync32 } from "node:fs";
91972
+ import { join as join89 } from "node:path";
91771
91973
  import { homedir as homedir50 } from "node:os";
91772
91974
 
91773
91975
  // src/status-ask/report.ts
@@ -92042,7 +92244,7 @@ function runReport(opts) {
92042
92244
  for (const src of sources) {
92043
92245
  let content;
92044
92246
  try {
92045
- content = readFileSync75(src.path, "utf-8");
92247
+ content = readFileSync76(src.path, "utf-8");
92046
92248
  } catch (err) {
92047
92249
  process.stderr.write(`status-ask report: cannot read ${src.path}: ${err instanceof Error ? err.message : String(err)}
92048
92250
  `);
@@ -92089,7 +92291,7 @@ function runReport(opts) {
92089
92291
  function resolveSources(explicitPath) {
92090
92292
  if (explicitPath != null && explicitPath.trim() !== "") {
92091
92293
  const trimmed = explicitPath.trim();
92092
- if (!existsSync87(trimmed)) {
92294
+ if (!existsSync88(trimmed)) {
92093
92295
  process.stderr.write(`status-ask report: ${trimmed}: file not found
92094
92296
  `);
92095
92297
  process.exit(1);
@@ -92103,20 +92305,20 @@ function resolveSources(explicitPath) {
92103
92305
  const config = loadConfig();
92104
92306
  agentsDir = resolveAgentsDir(config);
92105
92307
  } catch {
92106
- agentsDir = join88(homedir50(), ".switchroom", "agents");
92308
+ agentsDir = join89(homedir50(), ".switchroom", "agents");
92107
92309
  }
92108
- if (!existsSync87(agentsDir))
92310
+ if (!existsSync88(agentsDir))
92109
92311
  return [];
92110
92312
  const sources = [];
92111
92313
  let entries;
92112
92314
  try {
92113
- entries = readdirSync31(agentsDir);
92315
+ entries = readdirSync32(agentsDir);
92114
92316
  } catch {
92115
92317
  return [];
92116
92318
  }
92117
92319
  for (const name of entries) {
92118
- const path9 = join88(agentsDir, name, "runtime-metrics.jsonl");
92119
- if (existsSync87(path9)) {
92320
+ const path9 = join89(agentsDir, name, "runtime-metrics.jsonl");
92321
+ if (existsSync88(path9)) {
92120
92322
  sources.push({ path: path9, agent: name });
92121
92323
  }
92122
92324
  }
@@ -92146,45 +92348,45 @@ var import_yaml21 = __toESM(require_dist(), 1);
92146
92348
  init_paths();
92147
92349
  import {
92148
92350
  closeSync as closeSync14,
92149
- existsSync as existsSync88,
92351
+ existsSync as existsSync89,
92150
92352
  fsyncSync as fsyncSync8,
92151
- mkdirSync as mkdirSync50,
92353
+ mkdirSync as mkdirSync51,
92152
92354
  openSync as openSync14,
92153
- readdirSync as readdirSync32,
92154
- readFileSync as readFileSync76,
92155
- renameSync as renameSync21,
92355
+ readdirSync as readdirSync33,
92356
+ readFileSync as readFileSync77,
92357
+ renameSync as renameSync22,
92156
92358
  statSync as statSync48,
92157
92359
  unlinkSync as unlinkSync18,
92158
92360
  writeSync as writeSync10
92159
92361
  } from "node:fs";
92160
- import { join as join89, resolve as resolve53 } from "node:path";
92362
+ import { join as join90, resolve as resolve53 } from "node:path";
92161
92363
  var STAGING_SUBDIR = ".staging";
92162
92364
  function overlayPathsFor(agent, opts = {}) {
92163
92365
  const base = opts.root ? resolve53(opts.root, agent) : resolve53(resolveDualPath(`~/.switchroom/agents/${agent}`));
92164
- const scheduleDir = join89(base, "schedule.d");
92165
- const scheduleStagingDir = join89(scheduleDir, STAGING_SUBDIR);
92166
- const skillsDir = join89(base, "skills.d");
92167
- const skillsStagingDir = join89(skillsDir, STAGING_SUBDIR);
92366
+ const scheduleDir = join90(base, "schedule.d");
92367
+ const scheduleStagingDir = join90(scheduleDir, STAGING_SUBDIR);
92368
+ const skillsDir = join90(base, "skills.d");
92369
+ const skillsStagingDir = join90(skillsDir, STAGING_SUBDIR);
92168
92370
  return {
92169
92371
  agentRoot: base,
92170
92372
  scheduleDir,
92171
92373
  scheduleStagingDir,
92172
92374
  skillsDir,
92173
92375
  skillsStagingDir,
92174
- lockPath: join89(base, ".lock"),
92376
+ lockPath: join90(base, ".lock"),
92175
92377
  stagingDir: scheduleStagingDir
92176
92378
  };
92177
92379
  }
92178
92380
  function ensureDirs(paths) {
92179
- mkdirSync50(paths.scheduleDir, { recursive: true });
92180
- mkdirSync50(paths.scheduleStagingDir, { recursive: true });
92381
+ mkdirSync51(paths.scheduleDir, { recursive: true });
92382
+ mkdirSync51(paths.scheduleStagingDir, { recursive: true });
92181
92383
  }
92182
92384
  function ensureSkillsDirs(paths) {
92183
- mkdirSync50(paths.skillsDir, { recursive: true });
92184
- mkdirSync50(paths.skillsStagingDir, { recursive: true });
92385
+ mkdirSync51(paths.skillsDir, { recursive: true });
92386
+ mkdirSync51(paths.skillsStagingDir, { recursive: true });
92185
92387
  }
92186
92388
  function withAgentLock(paths, fn) {
92187
- mkdirSync50(paths.agentRoot, { recursive: true });
92389
+ mkdirSync51(paths.agentRoot, { recursive: true });
92188
92390
  const start = Date.now();
92189
92391
  const TIMEOUT_MS = 5000;
92190
92392
  let fd = null;
@@ -92225,8 +92427,8 @@ function writeOverlayEntry(agent, slug, yamlText, opts = {}) {
92225
92427
  const paths = overlayPathsFor(agent, opts);
92226
92428
  return withAgentLock(paths, () => {
92227
92429
  ensureDirs(paths);
92228
- const stagingPath = join89(paths.scheduleStagingDir, `${slug}.yaml`);
92229
- const finalPath = join89(paths.scheduleDir, `${slug}.yaml`);
92430
+ const stagingPath = join90(paths.scheduleStagingDir, `${slug}.yaml`);
92431
+ const finalPath = join90(paths.scheduleDir, `${slug}.yaml`);
92230
92432
  const fd = openSync14(stagingPath, "w", 384);
92231
92433
  try {
92232
92434
  writeSync10(fd, yamlText);
@@ -92234,7 +92436,7 @@ function writeOverlayEntry(agent, slug, yamlText, opts = {}) {
92234
92436
  } finally {
92235
92437
  closeSync14(fd);
92236
92438
  }
92237
- renameSync21(stagingPath, finalPath);
92439
+ renameSync22(stagingPath, finalPath);
92238
92440
  return finalPath;
92239
92441
  });
92240
92442
  }
@@ -92242,8 +92444,8 @@ function writeSkillsOverlayEntry(agent, slug, yamlText, opts = {}) {
92242
92444
  const paths = overlayPathsFor(agent, opts);
92243
92445
  return withAgentLock(paths, () => {
92244
92446
  ensureSkillsDirs(paths);
92245
- const stagingPath = join89(paths.skillsStagingDir, `${slug}.yaml`);
92246
- const finalPath = join89(paths.skillsDir, `${slug}.yaml`);
92447
+ const stagingPath = join90(paths.skillsStagingDir, `${slug}.yaml`);
92448
+ const finalPath = join90(paths.skillsDir, `${slug}.yaml`);
92247
92449
  const fd = openSync14(stagingPath, "w", 384);
92248
92450
  try {
92249
92451
  writeSync10(fd, yamlText);
@@ -92251,15 +92453,15 @@ function writeSkillsOverlayEntry(agent, slug, yamlText, opts = {}) {
92251
92453
  } finally {
92252
92454
  closeSync14(fd);
92253
92455
  }
92254
- renameSync21(stagingPath, finalPath);
92456
+ renameSync22(stagingPath, finalPath);
92255
92457
  return finalPath;
92256
92458
  });
92257
92459
  }
92258
92460
  function deleteSkillsOverlayEntry(agent, slug, opts = {}) {
92259
92461
  const paths = overlayPathsFor(agent, opts);
92260
92462
  return withAgentLock(paths, () => {
92261
- const finalPath = join89(paths.skillsDir, `${slug}.yaml`);
92262
- if (!existsSync88(finalPath))
92463
+ const finalPath = join90(paths.skillsDir, `${slug}.yaml`);
92464
+ if (!existsSync89(finalPath))
92263
92465
  return false;
92264
92466
  unlinkSync18(finalPath);
92265
92467
  return true;
@@ -92267,15 +92469,15 @@ function deleteSkillsOverlayEntry(agent, slug, opts = {}) {
92267
92469
  }
92268
92470
  function listSkillsOverlayEntries(agent, opts = {}) {
92269
92471
  const paths = overlayPathsFor(agent, opts);
92270
- if (!existsSync88(paths.skillsDir))
92472
+ if (!existsSync89(paths.skillsDir))
92271
92473
  return [];
92272
92474
  const out = [];
92273
- for (const name of readdirSync32(paths.skillsDir)) {
92475
+ for (const name of readdirSync33(paths.skillsDir)) {
92274
92476
  if (!/\.ya?ml$/i.test(name))
92275
92477
  continue;
92276
- const full = join89(paths.skillsDir, name);
92478
+ const full = join90(paths.skillsDir, name);
92277
92479
  try {
92278
- const raw = readFileSync76(full, "utf-8");
92480
+ const raw = readFileSync77(full, "utf-8");
92279
92481
  const slug = name.replace(/\.ya?ml$/i, "");
92280
92482
  out.push({ slug, path: full, raw });
92281
92483
  } catch {}
@@ -92285,8 +92487,8 @@ function listSkillsOverlayEntries(agent, opts = {}) {
92285
92487
  function deleteOverlayEntry(agent, slug, opts = {}) {
92286
92488
  const paths = overlayPathsFor(agent, opts);
92287
92489
  return withAgentLock(paths, () => {
92288
- const finalPath = join89(paths.scheduleDir, `${slug}.yaml`);
92289
- if (!existsSync88(finalPath))
92490
+ const finalPath = join90(paths.scheduleDir, `${slug}.yaml`);
92491
+ if (!existsSync89(finalPath))
92290
92492
  return false;
92291
92493
  unlinkSync18(finalPath);
92292
92494
  return true;
@@ -92294,15 +92496,15 @@ function deleteOverlayEntry(agent, slug, opts = {}) {
92294
92496
  }
92295
92497
  function listOverlayEntries(agent, opts = {}) {
92296
92498
  const paths = overlayPathsFor(agent, opts);
92297
- if (!existsSync88(paths.scheduleDir))
92499
+ if (!existsSync89(paths.scheduleDir))
92298
92500
  return [];
92299
92501
  const out = [];
92300
- for (const name of readdirSync32(paths.scheduleDir)) {
92502
+ for (const name of readdirSync33(paths.scheduleDir)) {
92301
92503
  if (!/\.ya?ml$/i.test(name))
92302
92504
  continue;
92303
- const full = join89(paths.scheduleDir, name);
92505
+ const full = join90(paths.scheduleDir, name);
92304
92506
  try {
92305
- const raw = readFileSync76(full, "utf-8");
92507
+ const raw = readFileSync77(full, "utf-8");
92306
92508
  const slug = name.replace(/\.ya?ml$/i, "");
92307
92509
  out.push({ slug, path: full, raw });
92308
92510
  } catch {}
@@ -92522,27 +92724,27 @@ function reconcileAgentCronOnly(agent) {
92522
92724
  // src/cli/agent-config-pending.ts
92523
92725
  import {
92524
92726
  closeSync as closeSync15,
92525
- existsSync as existsSync89,
92727
+ existsSync as existsSync90,
92526
92728
  fsyncSync as fsyncSync9,
92527
- mkdirSync as mkdirSync51,
92729
+ mkdirSync as mkdirSync52,
92528
92730
  openSync as openSync15,
92529
- readdirSync as readdirSync33,
92530
- readFileSync as readFileSync77,
92531
- renameSync as renameSync22,
92731
+ readdirSync as readdirSync34,
92732
+ readFileSync as readFileSync78,
92733
+ renameSync as renameSync23,
92532
92734
  unlinkSync as unlinkSync19,
92533
- writeFileSync as writeFileSync32,
92735
+ writeFileSync as writeFileSync33,
92534
92736
  writeSync as writeSync11
92535
92737
  } from "node:fs";
92536
- import { join as join90 } from "node:path";
92738
+ import { join as join91 } from "node:path";
92537
92739
  import { randomBytes as randomBytes15 } from "node:crypto";
92538
92740
  var STAGE_ID_PREFIX = "cap_";
92539
92741
  function pendingDir(agent, opts = {}) {
92540
92742
  const paths = overlayPathsFor(agent, opts);
92541
- return join90(paths.scheduleDir, ".pending");
92743
+ return join91(paths.scheduleDir, ".pending");
92542
92744
  }
92543
92745
  function ensurePendingDir(agent, opts = {}) {
92544
92746
  const dir = pendingDir(agent, opts);
92545
- mkdirSync51(dir, { recursive: true });
92747
+ mkdirSync52(dir, { recursive: true });
92546
92748
  return dir;
92547
92749
  }
92548
92750
  function newStageId() {
@@ -92551,8 +92753,8 @@ function newStageId() {
92551
92753
  function stagePendingScheduleEntry(opts) {
92552
92754
  const dir = ensurePendingDir(opts.agent, { root: opts.root });
92553
92755
  const stageId = opts.stageId ?? newStageId();
92554
- const yamlPath = join90(dir, `${stageId}.yaml`);
92555
- const metaPath = join90(dir, `${stageId}.meta.json`);
92756
+ const yamlPath = join91(dir, `${stageId}.yaml`);
92757
+ const metaPath = join91(dir, `${stageId}.meta.json`);
92556
92758
  const meta = {
92557
92759
  v: 1,
92558
92760
  stage_id: stageId,
@@ -92571,27 +92773,27 @@ function stagePendingScheduleEntry(opts) {
92571
92773
  } finally {
92572
92774
  closeSync15(fd);
92573
92775
  }
92574
- renameSync22(yamlTmp, yamlPath);
92776
+ renameSync23(yamlTmp, yamlPath);
92575
92777
  }
92576
- writeFileSync32(metaPath, JSON.stringify(meta, null, 2) + `
92778
+ writeFileSync33(metaPath, JSON.stringify(meta, null, 2) + `
92577
92779
  `, { mode: 384 });
92578
92780
  return { stageId, yamlPath, metaPath };
92579
92781
  }
92580
92782
  function listPendingScheduleEntries(agent, opts = {}) {
92581
92783
  const dir = pendingDir(agent, opts);
92582
- if (!existsSync89(dir))
92784
+ if (!existsSync90(dir))
92583
92785
  return [];
92584
92786
  const out = [];
92585
- for (const name of readdirSync33(dir).sort()) {
92787
+ for (const name of readdirSync34(dir).sort()) {
92586
92788
  if (!name.endsWith(".meta.json"))
92587
92789
  continue;
92588
92790
  const stageId = name.slice(0, -".meta.json".length);
92589
- const metaPath = join90(dir, name);
92590
- const yamlPath = join90(dir, `${stageId}.yaml`);
92591
- if (!existsSync89(yamlPath))
92791
+ const metaPath = join91(dir, name);
92792
+ const yamlPath = join91(dir, `${stageId}.yaml`);
92793
+ if (!existsSync90(yamlPath))
92592
92794
  continue;
92593
92795
  try {
92594
- const meta = JSON.parse(readFileSync77(metaPath, "utf-8"));
92796
+ const meta = JSON.parse(readFileSync78(metaPath, "utf-8"));
92595
92797
  if (meta?.v !== 1 || typeof meta.stage_id !== "string")
92596
92798
  continue;
92597
92799
  out.push({ stageId: meta.stage_id, agent: meta.agent, yamlPath, metaPath, meta });
@@ -92606,11 +92808,11 @@ function commitPendingScheduleEntry(opts) {
92606
92808
  return { committed: false, reason: "not_found" };
92607
92809
  const slug = match.meta.entry.name ?? match.stageId;
92608
92810
  const paths = overlayPathsFor(opts.agent, { root: opts.root });
92609
- const finalPath = join90(paths.scheduleDir, `${slug}.yaml`);
92610
- if (existsSync89(finalPath)) {
92811
+ const finalPath = join91(paths.scheduleDir, `${slug}.yaml`);
92812
+ if (existsSync90(finalPath)) {
92611
92813
  return { committed: false, reason: "slug_collision" };
92612
92814
  }
92613
- renameSync22(match.yamlPath, finalPath);
92815
+ renameSync23(match.yamlPath, finalPath);
92614
92816
  unlinkSync19(match.metaPath);
92615
92817
  return { committed: true, path: finalPath, slug };
92616
92818
  }
@@ -92629,7 +92831,7 @@ function denyPendingScheduleEntry(opts) {
92629
92831
  }
92630
92832
 
92631
92833
  // src/cli/agent-config-write.ts
92632
- import { existsSync as existsSync90, readFileSync as readFileSync78 } from "node:fs";
92834
+ import { existsSync as existsSync91, readFileSync as readFileSync79 } from "node:fs";
92633
92835
  import { execFileSync as execFileSync28 } from "node:child_process";
92634
92836
 
92635
92837
  // src/scheduler/schedule-report.ts
@@ -93019,8 +93221,8 @@ function scheduleRemove(opts) {
93019
93221
  }
93020
93222
  let priorContent = null;
93021
93223
  try {
93022
- if (existsSync90(match.path))
93023
- priorContent = readFileSync78(match.path, "utf-8");
93224
+ if (existsSync91(match.path))
93225
+ priorContent = readFileSync79(match.path, "utf-8");
93024
93226
  } catch {}
93025
93227
  deleteOverlayEntry(agent, match.slug, { root: opts.root });
93026
93228
  const reconcileFn = opts.reconcile === undefined ? opts.root ? null : reconcileAgentCronOnly : opts.reconcile;
@@ -93223,7 +93425,7 @@ function registerAgentConfigWriteCommands(program3) {
93223
93425
  }
93224
93426
  let blob;
93225
93427
  if (opts.jsonl) {
93226
- blob = existsSync90(opts.jsonl) ? readFileSync78(opts.jsonl, "utf-8") : "";
93428
+ blob = existsSync91(opts.jsonl) ? readFileSync79(opts.jsonl, "utf-8") : "";
93227
93429
  } else {
93228
93430
  try {
93229
93431
  blob = execFileSync28("docker", ["exec", `switchroom-${agent}`, "cat", "/state/agent/scheduler.jsonl"], {
@@ -93255,11 +93457,11 @@ function registerAgentConfigWriteCommands(program3) {
93255
93457
 
93256
93458
  // src/cli/agent-config-skill-write.ts
93257
93459
  var import_yaml22 = __toESM(require_dist(), 1);
93258
- import { existsSync as existsSync91 } from "node:fs";
93460
+ import { existsSync as existsSync92 } from "node:fs";
93259
93461
  init_reconcile_default_skills();
93260
93462
  init_agent_config();
93261
93463
  var import_yaml23 = __toESM(require_dist(), 1);
93262
- import { join as join91 } from "node:path";
93464
+ import { join as join92 } from "node:path";
93263
93465
  var MAX_SKILLS_PER_AGENT = 20;
93264
93466
  var V1_ALLOWED_SOURCE_PREFIX = "bundled:";
93265
93467
  function exitCodeFor2(code) {
@@ -93334,8 +93536,8 @@ function skillInstall(opts) {
93334
93536
  return err("E_SKILL_QUOTA_EXCEEDED", `agent ${agent} already has ${used} overlay-installed skills (cap ${MAX_SKILLS_PER_AGENT})`);
93335
93537
  }
93336
93538
  const poolDir = opts.bundledSkillsPoolDir ?? getBundledSkillsPoolDir();
93337
- const skillPath = join91(poolDir, skillName);
93338
- if (!existsSync91(skillPath)) {
93539
+ const skillPath = join92(poolDir, skillName);
93540
+ if (!existsSync92(skillPath)) {
93339
93541
  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.`);
93340
93542
  }
93341
93543
  const yamlText = import_yaml22.stringify({ skills: [skillName] });
@@ -93499,21 +93701,21 @@ function registerAgentConfigSkillWriteCommands(program3) {
93499
93701
  // src/cli/skill.ts
93500
93702
  import {
93501
93703
  closeSync as closeSync16,
93502
- existsSync as existsSync92,
93704
+ existsSync as existsSync93,
93503
93705
  lstatSync as lstatSync11,
93504
- mkdirSync as mkdirSync52,
93706
+ mkdirSync as mkdirSync53,
93505
93707
  mkdtempSync as mkdtempSync5,
93506
93708
  openSync as openSync16,
93507
- readFileSync as readFileSync79,
93508
- readdirSync as readdirSync34,
93709
+ readFileSync as readFileSync80,
93710
+ readdirSync as readdirSync35,
93509
93711
  realpathSync as realpathSync7,
93510
- renameSync as renameSync23,
93712
+ renameSync as renameSync24,
93511
93713
  rmSync as rmSync18,
93512
93714
  statSync as statSync49,
93513
- writeFileSync as writeFileSync33
93715
+ writeFileSync as writeFileSync34
93514
93716
  } from "node:fs";
93515
93717
  import { tmpdir as tmpdir6, homedir as homedir51 } from "node:os";
93516
- import { dirname as dirname31, join as join92, relative as relative2, resolve as resolve54 } from "node:path";
93718
+ import { dirname as dirname33, join as join93, relative as relative4, resolve as resolve54 } from "node:path";
93517
93719
  import { spawnSync as spawnSync16 } from "node:child_process";
93518
93720
 
93519
93721
  // src/cli/skill-common.ts
@@ -93747,7 +93949,7 @@ function scanForClaudeP2(content) {
93747
93949
  function resolveSkillsPoolDir2(override) {
93748
93950
  const raw = override ?? "~/.switchroom/skills";
93749
93951
  if (raw.startsWith("~/")) {
93750
- return join92(homedir51(), raw.slice(2));
93952
+ return join93(homedir51(), raw.slice(2));
93751
93953
  }
93752
93954
  if (raw === "~")
93753
93955
  return homedir51();
@@ -93784,10 +93986,10 @@ function loadFromDir(dir) {
93784
93986
  }
93785
93987
  const files = {};
93786
93988
  const walk2 = (sub) => {
93787
- const entries = readdirSync34(sub, { withFileTypes: true });
93989
+ const entries = readdirSync35(sub, { withFileTypes: true });
93788
93990
  for (const ent of entries) {
93789
- const full = join92(sub, ent.name);
93790
- const rel = relative2(abs, full);
93991
+ const full = join93(sub, ent.name);
93992
+ const rel = relative4(abs, full);
93791
93993
  if (ent.isSymbolicLink()) {
93792
93994
  fail3(`refusing to read symlink inside --from dir: ${rel}`);
93793
93995
  }
@@ -93796,7 +93998,7 @@ function loadFromDir(dir) {
93796
93998
  continue;
93797
93999
  }
93798
94000
  if (ent.isFile()) {
93799
- const buf = readFileSync79(full);
94001
+ const buf = readFileSync80(full);
93800
94002
  files[rel.replace(/\\/g, "/")] = buf.toString("utf-8");
93801
94003
  }
93802
94004
  }
@@ -93821,7 +94023,7 @@ function loadFromTarball(tarPath) {
93821
94023
  fail3(`tarball contains disallowed path: ${JSON.stringify(entry)} \u2014 ` + `refusing to extract before any file is written`);
93822
94024
  }
93823
94025
  }
93824
- const staging = mkdtempSync5(join92(tmpdir6(), "skill-apply-extract-"));
94026
+ const staging = mkdtempSync5(join93(tmpdir6(), "skill-apply-extract-"));
93825
94027
  try {
93826
94028
  const flags = isGz ? ["-xzf"] : ["-xf"];
93827
94029
  const r = spawnSync16("tar", [
@@ -93845,7 +94047,7 @@ function loadFromTarball(tarPath) {
93845
94047
  }
93846
94048
  }
93847
94049
  function loadSingleFile(filePath) {
93848
- const content = readFileSync79(filePath, "utf-8");
94050
+ const content = readFileSync80(filePath, "utf-8");
93849
94051
  return { "SKILL.md": content };
93850
94052
  }
93851
94053
  function loadFromStdin() {
@@ -93907,10 +94109,10 @@ function validatePayload(name, files) {
93907
94109
  errors2.push(`${path9} fails \`bash -n\` syntax check: ${(r.stderr ?? "").trim()}`);
93908
94110
  }
93909
94111
  } else if (PY_SCRIPT_RE2.test(path9)) {
93910
- const tmp = mkdtempSync5(join92(tmpdir6(), "skill-apply-py-"));
93911
- const tmpPy = join92(tmp, "check.py");
94112
+ const tmp = mkdtempSync5(join93(tmpdir6(), "skill-apply-py-"));
94113
+ const tmpPy = join93(tmp, "check.py");
93912
94114
  try {
93913
- writeFileSync33(tmpPy, content);
94115
+ writeFileSync34(tmpPy, content);
93914
94116
  const r = spawnSync16("python3", ["-m", "py_compile", tmpPy], {
93915
94117
  encoding: "utf-8"
93916
94118
  });
@@ -93928,15 +94130,15 @@ function validatePayload(name, files) {
93928
94130
  function diffSummary(currentDir, files) {
93929
94131
  const lines = [];
93930
94132
  const currentFiles = {};
93931
- if (existsSync92(currentDir)) {
94133
+ if (existsSync93(currentDir)) {
93932
94134
  const walk2 = (sub) => {
93933
- for (const ent of readdirSync34(sub, { withFileTypes: true })) {
93934
- const full = join92(sub, ent.name);
93935
- const rel = relative2(currentDir, full);
94135
+ for (const ent of readdirSync35(sub, { withFileTypes: true })) {
94136
+ const full = join93(sub, ent.name);
94137
+ const rel = relative4(currentDir, full);
93936
94138
  if (ent.isDirectory()) {
93937
94139
  walk2(full);
93938
94140
  } else if (ent.isFile()) {
93939
- currentFiles[rel.replace(/\\/g, "/")] = readFileSync79(full, "utf-8");
94141
+ currentFiles[rel.replace(/\\/g, "/")] = readFileSync80(full, "utf-8");
93940
94142
  }
93941
94143
  }
93942
94144
  };
@@ -93964,10 +94166,10 @@ function diffSummary(currentDir, files) {
93964
94166
  `);
93965
94167
  }
93966
94168
  function writePayload(poolDir, name, files) {
93967
- if (!existsSync92(poolDir)) {
93968
- mkdirSync52(poolDir, { recursive: true, mode: 493 });
94169
+ if (!existsSync93(poolDir)) {
94170
+ mkdirSync53(poolDir, { recursive: true, mode: 493 });
93969
94171
  }
93970
- const target = join92(poolDir, name);
94172
+ const target = join93(poolDir, name);
93971
94173
  let targetIsSymlink = false;
93972
94174
  try {
93973
94175
  const st = lstatSync11(target);
@@ -93978,15 +94180,15 @@ function writePayload(poolDir, name, files) {
93978
94180
  if (targetIsSymlink) {
93979
94181
  fail3(`refusing to overwrite symlink at ${target}; investigate manually`);
93980
94182
  }
93981
- const staging = mkdtempSync5(join92(poolDir, `.skill-apply-stage-${name}-`));
94183
+ const staging = mkdtempSync5(join93(poolDir, `.skill-apply-stage-${name}-`));
93982
94184
  let oldRename = null;
93983
94185
  try {
93984
94186
  for (const [path9, content] of Object.entries(files)) {
93985
- const full = join92(staging, path9);
93986
- mkdirSync52(dirname31(full), { recursive: true, mode: 493 });
94187
+ const full = join93(staging, path9);
94188
+ mkdirSync53(dirname33(full), { recursive: true, mode: 493 });
93987
94189
  const fd = openSync16(full, "wx");
93988
94190
  try {
93989
- writeFileSync33(fd, content);
94191
+ writeFileSync34(fd, content);
93990
94192
  } finally {
93991
94193
  closeSync16(fd);
93992
94194
  }
@@ -94002,9 +94204,9 @@ function writePayload(poolDir, name, files) {
94002
94204
  } catch {}
94003
94205
  if (targetExists) {
94004
94206
  oldRename = `${target}.skill-apply-old-${Date.now()}`;
94005
- renameSync23(target, oldRename);
94207
+ renameSync24(target, oldRename);
94006
94208
  }
94007
- renameSync23(staging, target);
94209
+ renameSync24(staging, target);
94008
94210
  if (oldRename) {
94009
94211
  rmSync18(oldRename, { recursive: true, force: true });
94010
94212
  oldRename = null;
@@ -94013,12 +94215,12 @@ function writePayload(poolDir, name, files) {
94013
94215
  try {
94014
94216
  rmSync18(staging, { recursive: true, force: true });
94015
94217
  } catch {}
94016
- if (oldRename && existsSync92(oldRename)) {
94218
+ if (oldRename && existsSync93(oldRename)) {
94017
94219
  try {
94018
- if (existsSync92(target)) {
94220
+ if (existsSync93(target)) {
94019
94221
  rmSync18(target, { recursive: true, force: true });
94020
94222
  }
94021
- renameSync23(oldRename, target);
94223
+ renameSync24(oldRename, target);
94022
94224
  } catch {}
94023
94225
  }
94024
94226
  throw err2;
@@ -94036,7 +94238,7 @@ function registerSkillCommand(program3) {
94036
94238
  files = loadFromStdin();
94037
94239
  } else {
94038
94240
  const fromPath = resolve54(opts.from);
94039
- if (!existsSync92(fromPath)) {
94241
+ if (!existsSync93(fromPath)) {
94040
94242
  fail3(`--from path does not exist: ${opts.from}`);
94041
94243
  }
94042
94244
  const st = statSync49(fromPath);
@@ -94060,7 +94262,7 @@ function registerSkillCommand(program3) {
94060
94262
  }
94061
94263
  const config = loadConfig();
94062
94264
  const poolDir = resolveSkillsPoolDir2(config.switchroom?.skills_dir);
94063
- const currentDir = join92(poolDir, name);
94265
+ const currentDir = join93(poolDir, name);
94064
94266
  console.log(source_default.bold(`Skill: ${name}`) + source_default.gray(` (${Object.keys(files).length} files, ${sumBytes(files)} bytes)`));
94065
94267
  console.log(source_default.bold("Diff vs current pool content:"));
94066
94268
  console.log(diffSummary(currentDir, files));
@@ -94092,20 +94294,20 @@ function sumBytes(files) {
94092
94294
  init_esm();
94093
94295
  import {
94094
94296
  closeSync as closeSync17,
94095
- existsSync as existsSync93,
94297
+ existsSync as existsSync94,
94096
94298
  lstatSync as lstatSync12,
94097
- mkdirSync as mkdirSync53,
94299
+ mkdirSync as mkdirSync54,
94098
94300
  mkdtempSync as mkdtempSync6,
94099
94301
  openSync as openSync17,
94100
- readFileSync as readFileSync80,
94101
- readdirSync as readdirSync35,
94102
- renameSync as renameSync24,
94302
+ readFileSync as readFileSync81,
94303
+ readdirSync as readdirSync36,
94304
+ renameSync as renameSync25,
94103
94305
  rmSync as rmSync19,
94104
94306
  statSync as statSync50,
94105
94307
  utimesSync,
94106
- writeFileSync as writeFileSync34
94308
+ writeFileSync as writeFileSync35
94107
94309
  } from "node:fs";
94108
- import { dirname as dirname32, join as join93, relative as relative3, resolve as resolve55 } from "node:path";
94310
+ import { dirname as dirname34, join as join94, relative as relative5, resolve as resolve55 } from "node:path";
94109
94311
  import { homedir as homedir52, tmpdir as tmpdir7 } from "node:os";
94110
94312
  import { spawnSync as spawnSync17 } from "node:child_process";
94111
94313
  init_helpers();
@@ -94117,18 +94319,18 @@ var TRASH_TTL_MS = 24 * 60 * 60 * 1000;
94117
94319
  var PERSONAL_SKILLS_SUBPATH = "personal-skills";
94118
94320
  function resolveConfigSkillsDir(agent) {
94119
94321
  const override = process.env.SWITCHROOM_CONFIG_DIR;
94120
- const candidate = override ? resolve55(override) : join93(homedir52(), ".switchroom-config");
94121
- if (!existsSync93(candidate))
94322
+ const candidate = override ? resolve55(override) : join94(homedir52(), ".switchroom-config");
94323
+ if (!existsSync94(candidate))
94122
94324
  return null;
94123
- return join93(candidate, "agents", agent, PERSONAL_SKILLS_SUBPATH);
94325
+ return join94(candidate, "agents", agent, PERSONAL_SKILLS_SUBPATH);
94124
94326
  }
94125
94327
  var MIRROR_PRIOR_TTL_MS = 24 * 60 * 60 * 1000;
94126
94328
  function sweepMirrorPriors(configSkillsRoot) {
94127
94329
  try {
94128
- if (!existsSync93(configSkillsRoot))
94330
+ if (!existsSync94(configSkillsRoot))
94129
94331
  return;
94130
94332
  const now = Date.now();
94131
- for (const ent of readdirSync35(configSkillsRoot)) {
94333
+ for (const ent of readdirSync36(configSkillsRoot)) {
94132
94334
  const m = /^\.(?:.+)-(?:prior|trash)-(\d+)$/.exec(ent);
94133
94335
  if (!m)
94134
94336
  continue;
@@ -94138,7 +94340,7 @@ function sweepMirrorPriors(configSkillsRoot) {
94138
94340
  if (now - ts < MIRROR_PRIOR_TTL_MS)
94139
94341
  continue;
94140
94342
  try {
94141
- rmSync19(join93(configSkillsRoot, ent), { recursive: true, force: true });
94343
+ rmSync19(join94(configSkillsRoot, ent), { recursive: true, force: true });
94142
94344
  } catch {}
94143
94345
  }
94144
94346
  } catch {}
@@ -94147,7 +94349,7 @@ function mirrorToConfigRepo(agent, name, liveSkillDir) {
94147
94349
  const configSkillsRoot = resolveConfigSkillsDir(agent);
94148
94350
  if (!configSkillsRoot)
94149
94351
  return;
94150
- const dest = join93(configSkillsRoot, name);
94352
+ const dest = join94(configSkillsRoot, name);
94151
94353
  try {
94152
94354
  if (liveSkillDir !== null) {
94153
94355
  try {
@@ -94161,35 +94363,35 @@ function mirrorToConfigRepo(agent, name, liveSkillDir) {
94161
94363
  }
94162
94364
  if (liveSkillDir === null) {
94163
94365
  sweepMirrorPriors(configSkillsRoot);
94164
- if (existsSync93(dest)) {
94165
- const trash = join93(configSkillsRoot, `.${name}-trash-${Date.now()}`);
94166
- renameSync24(dest, trash);
94366
+ if (existsSync94(dest)) {
94367
+ const trash = join94(configSkillsRoot, `.${name}-trash-${Date.now()}`);
94368
+ renameSync25(dest, trash);
94167
94369
  }
94168
94370
  return;
94169
94371
  }
94170
- mkdirSync53(configSkillsRoot, { recursive: true, mode: 493 });
94372
+ mkdirSync54(configSkillsRoot, { recursive: true, mode: 493 });
94171
94373
  sweepMirrorPriors(configSkillsRoot);
94172
- const staging = mkdtempSync6(join93(configSkillsRoot, `.${name}-staging-`));
94374
+ const staging = mkdtempSync6(join94(configSkillsRoot, `.${name}-staging-`));
94173
94375
  const walk2 = (src, dst) => {
94174
- mkdirSync53(dst, { recursive: true, mode: 493 });
94175
- for (const ent of readdirSync35(src, { withFileTypes: true })) {
94176
- const s = join93(src, ent.name);
94177
- const d = join93(dst, ent.name);
94376
+ mkdirSync54(dst, { recursive: true, mode: 493 });
94377
+ for (const ent of readdirSync36(src, { withFileTypes: true })) {
94378
+ const s = join94(src, ent.name);
94379
+ const d = join94(dst, ent.name);
94178
94380
  if (ent.isSymbolicLink())
94179
94381
  continue;
94180
94382
  if (ent.isDirectory())
94181
94383
  walk2(s, d);
94182
94384
  else if (ent.isFile()) {
94183
- writeFileSync34(d, readFileSync80(s));
94385
+ writeFileSync35(d, readFileSync81(s));
94184
94386
  }
94185
94387
  }
94186
94388
  };
94187
94389
  walk2(liveSkillDir, staging);
94188
- if (existsSync93(dest)) {
94189
- const prior = join93(configSkillsRoot, `.${name}-prior-${Date.now()}`);
94190
- renameSync24(dest, prior);
94390
+ if (existsSync94(dest)) {
94391
+ const prior = join94(configSkillsRoot, `.${name}-prior-${Date.now()}`);
94392
+ renameSync25(dest, prior);
94191
94393
  }
94192
- renameSync24(staging, dest);
94394
+ renameSync25(staging, dest);
94193
94395
  } catch (err2) {
94194
94396
  process.stderr.write(source_default.yellow(`warning: mirror to ${dest} failed (${err2.message ?? err2}); ` + `live copy still works, but this skill is not version-controlled until next successful sync.
94195
94397
  `));
@@ -94216,20 +94418,20 @@ function resolveAgent(opts) {
94216
94418
  function resolveAgentsRoot(opts) {
94217
94419
  if (opts.root)
94218
94420
  return resolve55(opts.root);
94219
- return join93(homedir52(), ".switchroom", "agents");
94421
+ return join94(homedir52(), ".switchroom", "agents");
94220
94422
  }
94221
94423
  function personalSkillDir(agentsRoot, agent, name) {
94222
- return join93(agentsRoot, agent, ".claude", "skills", PERSONAL_PREFIX + name);
94424
+ return join94(agentsRoot, agent, ".claude", "skills", PERSONAL_PREFIX + name);
94223
94425
  }
94224
94426
  function trashDir(agentsRoot, agent) {
94225
- return join93(agentsRoot, agent, ".claude", TRASH_DIRNAME);
94427
+ return join94(agentsRoot, agent, ".claude", TRASH_DIRNAME);
94226
94428
  }
94227
94429
  function countPersonalSkills(agentsRoot, agent) {
94228
- const skillsDir = join93(agentsRoot, agent, ".claude", "skills");
94229
- if (!existsSync93(skillsDir))
94430
+ const skillsDir = join94(agentsRoot, agent, ".claude", "skills");
94431
+ if (!existsSync94(skillsDir))
94230
94432
  return 0;
94231
94433
  let n = 0;
94232
- for (const ent of readdirSync35(skillsDir, { withFileTypes: true })) {
94434
+ for (const ent of readdirSync36(skillsDir, { withFileTypes: true })) {
94233
94435
  if (ent.isDirectory() && ent.name.startsWith(PERSONAL_PREFIX))
94234
94436
  n += 1;
94235
94437
  }
@@ -94262,18 +94464,18 @@ function loadFromDir2(dir) {
94262
94464
  }
94263
94465
  const files = {};
94264
94466
  const walk2 = (sub) => {
94265
- for (const ent of readdirSync35(sub, { withFileTypes: true })) {
94266
- const full = join93(sub, ent.name);
94467
+ for (const ent of readdirSync36(sub, { withFileTypes: true })) {
94468
+ const full = join94(sub, ent.name);
94267
94469
  if (ent.isSymbolicLink()) {
94268
- fail4(`refusing to read symlink in --from dir: ${relative3(abs, full)}`);
94470
+ fail4(`refusing to read symlink in --from dir: ${relative5(abs, full)}`);
94269
94471
  }
94270
94472
  if (ent.isDirectory()) {
94271
94473
  walk2(full);
94272
94474
  continue;
94273
94475
  }
94274
94476
  if (ent.isFile()) {
94275
- const rel = relative3(abs, full).replace(/\\/g, "/");
94276
- files[rel] = readFileSync80(full, "utf-8");
94477
+ const rel = relative5(abs, full).replace(/\\/g, "/");
94478
+ files[rel] = readFileSync81(full, "utf-8");
94277
94479
  }
94278
94480
  }
94279
94481
  };
@@ -94316,10 +94518,10 @@ function behavioralValidate(files) {
94316
94518
  errors2.push(`${path9} fails \`bash -n\`: ${(r.stderr ?? "").trim()}`);
94317
94519
  }
94318
94520
  } else if (PY_SCRIPT_RE.test(path9)) {
94319
- const tmp = mkdtempSync6(join93(tmpdir7(), "skill-personal-py-"));
94320
- const tmpPy = join93(tmp, "check.py");
94521
+ const tmp = mkdtempSync6(join94(tmpdir7(), "skill-personal-py-"));
94522
+ const tmpPy = join94(tmp, "check.py");
94321
94523
  try {
94322
- writeFileSync34(tmpPy, content);
94524
+ writeFileSync35(tmpPy, content);
94323
94525
  const r = spawnSync17("python3", ["-m", "py_compile", tmpPy], {
94324
94526
  encoding: "utf-8"
94325
94527
  });
@@ -94335,13 +94537,13 @@ function behavioralValidate(files) {
94335
94537
  }
94336
94538
  function sweepTrash(agentsRoot, agent) {
94337
94539
  const trash = trashDir(agentsRoot, agent);
94338
- if (!existsSync93(trash))
94540
+ if (!existsSync94(trash))
94339
94541
  return;
94340
94542
  const now = Date.now();
94341
- for (const ent of readdirSync35(trash, { withFileTypes: true })) {
94543
+ for (const ent of readdirSync36(trash, { withFileTypes: true })) {
94342
94544
  if (!ent.isDirectory())
94343
94545
  continue;
94344
- const entPath = join93(trash, ent.name);
94546
+ const entPath = join94(trash, ent.name);
94345
94547
  try {
94346
94548
  const st = statSync50(entPath);
94347
94549
  if (now - st.mtimeMs > TRASH_TTL_MS) {
@@ -94361,16 +94563,16 @@ function writePersonalSkill(targetDir, files) {
94361
94563
  if (targetIsSymlink) {
94362
94564
  fail4(`refusing to overwrite symlink at ${targetDir}; investigate manually`);
94363
94565
  }
94364
- mkdirSync53(dirname32(targetDir), { recursive: true, mode: 493 });
94365
- const staging = mkdtempSync6(join93(dirname32(targetDir), `.skill-personal-stage-`));
94566
+ mkdirSync54(dirname34(targetDir), { recursive: true, mode: 493 });
94567
+ const staging = mkdtempSync6(join94(dirname34(targetDir), `.skill-personal-stage-`));
94366
94568
  let oldRename = null;
94367
94569
  try {
94368
94570
  for (const [path9, content] of Object.entries(files)) {
94369
- const full = join93(staging, path9);
94370
- mkdirSync53(dirname32(full), { recursive: true, mode: 493 });
94571
+ const full = join94(staging, path9);
94572
+ mkdirSync54(dirname34(full), { recursive: true, mode: 493 });
94371
94573
  const fd = openSync17(full, "wx");
94372
94574
  try {
94373
- writeFileSync34(fd, content);
94575
+ writeFileSync35(fd, content);
94374
94576
  } finally {
94375
94577
  closeSync17(fd);
94376
94578
  }
@@ -94386,9 +94588,9 @@ function writePersonalSkill(targetDir, files) {
94386
94588
  } catch {}
94387
94589
  if (targetExists) {
94388
94590
  oldRename = `${targetDir}.personal-old-${Date.now()}`;
94389
- renameSync24(targetDir, oldRename);
94591
+ renameSync25(targetDir, oldRename);
94390
94592
  }
94391
- renameSync24(staging, targetDir);
94593
+ renameSync25(staging, targetDir);
94392
94594
  if (oldRename) {
94393
94595
  rmSync19(oldRename, { recursive: true, force: true });
94394
94596
  oldRename = null;
@@ -94397,12 +94599,12 @@ function writePersonalSkill(targetDir, files) {
94397
94599
  try {
94398
94600
  rmSync19(staging, { recursive: true, force: true });
94399
94601
  } catch {}
94400
- if (oldRename && existsSync93(oldRename)) {
94602
+ if (oldRename && existsSync94(oldRename)) {
94401
94603
  try {
94402
- if (existsSync93(targetDir)) {
94604
+ if (existsSync94(targetDir)) {
94403
94605
  rmSync19(targetDir, { recursive: true, force: true });
94404
94606
  }
94405
- renameSync24(oldRename, targetDir);
94607
+ renameSync25(oldRename, targetDir);
94406
94608
  } catch {}
94407
94609
  }
94408
94610
  throw err2;
@@ -94465,7 +94667,7 @@ function loadFiles(opts) {
94465
94667
  return loadFromStdin2();
94466
94668
  }
94467
94669
  const p = resolve55(opts.from);
94468
- if (!existsSync93(p)) {
94670
+ if (!existsSync94(p)) {
94469
94671
  fail4(`--from path does not exist: ${opts.from}`);
94470
94672
  }
94471
94673
  const st = statSync50(p);
@@ -94473,7 +94675,7 @@ function loadFiles(opts) {
94473
94675
  return loadFromDir2(p);
94474
94676
  }
94475
94677
  if (p.endsWith(".md")) {
94476
- return { "SKILL.md": readFileSync80(p, "utf-8") };
94678
+ return { "SKILL.md": readFileSync81(p, "utf-8") };
94477
94679
  }
94478
94680
  fail4(`--from must be a directory or a .md file. Got: ${opts.from}`);
94479
94681
  }
@@ -94513,10 +94715,10 @@ function editPersonalAction(name, opts) {
94513
94715
  }
94514
94716
  var CLONE_SOURCE_RE = /^(shared|bundled):([a-z0-9][a-z0-9_-]{0,62})$/;
94515
94717
  function defaultSharedRoot() {
94516
- return join93(homedir52(), ".switchroom", "skills");
94718
+ return join94(homedir52(), ".switchroom", "skills");
94517
94719
  }
94518
94720
  function defaultBundledRoot() {
94519
- return join93(homedir52(), ".switchroom", "skills", "_bundled");
94721
+ return join94(homedir52(), ".switchroom", "skills", "_bundled");
94520
94722
  }
94521
94723
  function resolveCloneSource(source, opts) {
94522
94724
  const m = CLONE_SOURCE_RE.exec(source);
@@ -94526,8 +94728,8 @@ function resolveCloneSource(source, opts) {
94526
94728
  const tier = m[1];
94527
94729
  const slug = m[2];
94528
94730
  const root = tier === "bundled" ? opts.bundledRoot ?? defaultBundledRoot() : opts.sharedRoot ?? defaultSharedRoot();
94529
- const dir = join93(root, slug);
94530
- if (!existsSync93(dir)) {
94731
+ const dir = join94(root, slug);
94732
+ if (!existsSync94(dir)) {
94531
94733
  fail4(`clone source ${JSON.stringify(source)} not found at ${dir}; ` + `check \`switchroom skill search --tier ${tier}\``, 1);
94532
94734
  }
94533
94735
  const st = lstatSync12(dir);
@@ -94541,8 +94743,8 @@ function readSourceFiles(dir) {
94541
94743
  const files = {};
94542
94744
  const skipped = [];
94543
94745
  const walk2 = (sub) => {
94544
- for (const ent of readdirSync35(sub, { withFileTypes: true })) {
94545
- const full = join93(sub, ent.name);
94746
+ for (const ent of readdirSync36(sub, { withFileTypes: true })) {
94747
+ const full = join94(sub, ent.name);
94546
94748
  if (ent.isSymbolicLink()) {
94547
94749
  continue;
94548
94750
  }
@@ -94551,7 +94753,7 @@ function readSourceFiles(dir) {
94551
94753
  continue;
94552
94754
  }
94553
94755
  if (ent.isFile()) {
94554
- const rel = relative3(dir, full).replace(/\\/g, "/");
94756
+ const rel = relative5(dir, full).replace(/\\/g, "/");
94555
94757
  if (!validateRelPath(rel)) {
94556
94758
  skipped.push(rel);
94557
94759
  continue;
@@ -94562,7 +94764,7 @@ function readSourceFiles(dir) {
94562
94764
  fail4(`clone source has oversized file ${rel} (${st.size} bytes > ${CLONE_MAX_FILE_BYTES}); ` + `refuse to read`, 3);
94563
94765
  }
94564
94766
  } catch {}
94565
- files[rel] = readFileSync80(full, "utf-8");
94767
+ files[rel] = readFileSync81(full, "utf-8");
94566
94768
  }
94567
94769
  }
94568
94770
  };
@@ -94651,10 +94853,10 @@ function removePersonalAction(name, opts) {
94651
94853
  throw err2;
94652
94854
  }
94653
94855
  const trashRoot2 = trashDir(agentsRoot, agent);
94654
- mkdirSync53(trashRoot2, { recursive: true, mode: 493 });
94856
+ mkdirSync54(trashRoot2, { recursive: true, mode: 493 });
94655
94857
  const ts = Date.now();
94656
- const trashTarget = join93(trashRoot2, `${name}-${ts}`);
94657
- renameSync24(target, trashTarget);
94858
+ const trashTarget = join94(trashRoot2, `${name}-${ts}`);
94859
+ renameSync25(target, trashTarget);
94658
94860
  const now = new Date(ts);
94659
94861
  utimesSync(trashTarget, now, now);
94660
94862
  mirrorToConfigRepo(agent, name, null);
@@ -94672,27 +94874,27 @@ function listPersonalAction(opts) {
94672
94874
  const agent = resolveAgent(opts);
94673
94875
  const agentsRoot = resolveAgentsRoot(opts);
94674
94876
  sweepTrash(agentsRoot, agent);
94675
- const skillsDir = join93(agentsRoot, agent, ".claude", "skills");
94877
+ const skillsDir = join94(agentsRoot, agent, ".claude", "skills");
94676
94878
  const personal = [];
94677
- if (existsSync93(skillsDir)) {
94678
- for (const ent of readdirSync35(skillsDir, { withFileTypes: true })) {
94879
+ if (existsSync94(skillsDir)) {
94880
+ for (const ent of readdirSync36(skillsDir, { withFileTypes: true })) {
94679
94881
  if (!ent.isDirectory())
94680
94882
  continue;
94681
94883
  if (!ent.name.startsWith(PERSONAL_PREFIX))
94682
94884
  continue;
94683
94885
  const skillName = ent.name.slice(PERSONAL_PREFIX.length);
94684
- const skillPath = join93(skillsDir, ent.name);
94886
+ const skillPath = join94(skillsDir, ent.name);
94685
94887
  let fileCount = 0;
94686
94888
  let totalBytes = 0;
94687
94889
  const walk2 = (sub) => {
94688
- for (const e of readdirSync35(sub, { withFileTypes: true })) {
94890
+ for (const e of readdirSync36(sub, { withFileTypes: true })) {
94689
94891
  if (e.isFile()) {
94690
94892
  fileCount += 1;
94691
94893
  try {
94692
- totalBytes += statSync50(join93(sub, e.name)).size;
94894
+ totalBytes += statSync50(join94(sub, e.name)).size;
94693
94895
  } catch {}
94694
94896
  } else if (e.isDirectory()) {
94695
- walk2(join93(sub, e.name));
94897
+ walk2(join94(sub, e.name));
94696
94898
  }
94697
94899
  }
94698
94900
  };
@@ -94731,11 +94933,11 @@ function registerSkillPersonalCommands(program3) {
94731
94933
  // src/cli/self-improve-propose-skill.ts
94732
94934
  import { createConnection as createConnection4 } from "node:net";
94733
94935
  import { homedir as homedir53 } from "node:os";
94734
- import { join as join94 } from "node:path";
94735
- import { readFileSync as readFileSync81 } from "node:fs";
94936
+ import { join as join95 } from "node:path";
94937
+ import { readFileSync as readFileSync82 } from "node:fs";
94736
94938
  var IPC_CONNECT_TIMEOUT_MS = 5000;
94737
94939
  function gatewaySocketPath() {
94738
- return process.env.SWITCHROOM_GATEWAY_SOCKET ?? (process.env.TELEGRAM_STATE_DIR ? join94(process.env.TELEGRAM_STATE_DIR, "gateway.sock") : join94(homedir53(), ".claude", "channels", "telegram", "gateway.sock"));
94940
+ return process.env.SWITCHROOM_GATEWAY_SOCKET ?? (process.env.TELEGRAM_STATE_DIR ? join95(process.env.TELEGRAM_STATE_DIR, "gateway.sock") : join95(homedir53(), ".claude", "channels", "telegram", "gateway.sock"));
94739
94941
  }
94740
94942
  function fail5(msg, code = 1) {
94741
94943
  console.error(msg);
@@ -94770,7 +94972,7 @@ function registerSelfImproveProposeSkillCommand(program3) {
94770
94972
  fail5("agent name required (--agent or $SWITCHROOM_AGENT_NAME)");
94771
94973
  let draft;
94772
94974
  try {
94773
- draft = JSON.parse(readFileSync81(opts.draft, "utf-8"));
94975
+ draft = JSON.parse(readFileSync82(opts.draft, "utf-8"));
94774
94976
  } catch (e) {
94775
94977
  fail5(`failed to read/parse --draft: ${e.message}`);
94776
94978
  }
@@ -94807,9 +95009,9 @@ function registerSelfImproveProposeSkillCommand(program3) {
94807
95009
  init_esm();
94808
95010
  init_helpers();
94809
95011
  var import_yaml25 = __toESM(require_dist(), 1);
94810
- import { existsSync as existsSync94, readdirSync as readdirSync36, readFileSync as readFileSync82, statSync as statSync51 } from "node:fs";
95012
+ import { existsSync as existsSync95, readdirSync as readdirSync37, readFileSync as readFileSync83, statSync as statSync51 } from "node:fs";
94811
95013
  import { homedir as homedir54 } from "node:os";
94812
- import { join as join95, resolve as resolve56 } from "node:path";
95014
+ import { join as join96, resolve as resolve56 } from "node:path";
94813
95015
  var PERSONAL_PREFIX2 = "personal-";
94814
95016
  var BUNDLED_SUBDIR = "_bundled";
94815
95017
  var AGENT_NAME_RE3 = /^[a-z][a-z0-9_-]{0,62}$/;
@@ -94823,12 +95025,12 @@ function defaultBundledRoot2() {
94823
95025
  return resolve56(homedir54(), ".switchroom/skills/_bundled");
94824
95026
  }
94825
95027
  function readSkillFrontmatter(skillDir) {
94826
- const mdPath = join95(skillDir, "SKILL.md");
94827
- if (!existsSync94(mdPath))
95028
+ const mdPath = join96(skillDir, "SKILL.md");
95029
+ if (!existsSync95(mdPath))
94828
95030
  return null;
94829
95031
  let content;
94830
95032
  try {
94831
- content = readFileSync82(mdPath, "utf-8");
95033
+ content = readFileSync83(mdPath, "utf-8");
94832
95034
  } catch {
94833
95035
  return null;
94834
95036
  }
@@ -94856,7 +95058,7 @@ function readSkillFrontmatter(skillDir) {
94856
95058
  return { fm: parsed };
94857
95059
  }
94858
95060
  function statSkillMd(skillDir) {
94859
- const mdPath = join95(skillDir, "SKILL.md");
95061
+ const mdPath = join96(skillDir, "SKILL.md");
94860
95062
  try {
94861
95063
  const st = statSync51(mdPath);
94862
95064
  return { size: st.size, mtime: st.mtime.toISOString() };
@@ -94867,20 +95069,20 @@ function statSkillMd(skillDir) {
94867
95069
  function listPersonalSkills(agent, agentsRoot = defaultAgentsRoot()) {
94868
95070
  if (!AGENT_NAME_RE3.test(agent))
94869
95071
  return [];
94870
- const skillsDir = join95(agentsRoot, agent, ".claude/skills");
94871
- if (!existsSync94(skillsDir))
95072
+ const skillsDir = join96(agentsRoot, agent, ".claude/skills");
95073
+ if (!existsSync95(skillsDir))
94872
95074
  return [];
94873
95075
  const out = [];
94874
95076
  let entries;
94875
95077
  try {
94876
- entries = readdirSync36(skillsDir);
95078
+ entries = readdirSync37(skillsDir);
94877
95079
  } catch {
94878
95080
  return [];
94879
95081
  }
94880
95082
  for (const ent of entries) {
94881
95083
  if (!ent.startsWith(PERSONAL_PREFIX2))
94882
95084
  continue;
94883
- const dirPath = join95(skillsDir, ent);
95085
+ const dirPath = join96(skillsDir, ent);
94884
95086
  try {
94885
95087
  if (!statSync51(dirPath).isDirectory())
94886
95088
  continue;
@@ -94906,12 +95108,12 @@ function listPersonalSkills(agent, agentsRoot = defaultAgentsRoot()) {
94906
95108
  return out;
94907
95109
  }
94908
95110
  function listSharedSkills(sharedRoot = defaultSharedRoot2()) {
94909
- if (!existsSync94(sharedRoot))
95111
+ if (!existsSync95(sharedRoot))
94910
95112
  return [];
94911
95113
  const out = [];
94912
95114
  let entries;
94913
95115
  try {
94914
- entries = readdirSync36(sharedRoot);
95116
+ entries = readdirSync37(sharedRoot);
94915
95117
  } catch {
94916
95118
  return [];
94917
95119
  }
@@ -94920,7 +95122,7 @@ function listSharedSkills(sharedRoot = defaultSharedRoot2()) {
94920
95122
  continue;
94921
95123
  if (ent.startsWith("."))
94922
95124
  continue;
94923
- const dirPath = join95(sharedRoot, ent);
95125
+ const dirPath = join96(sharedRoot, ent);
94924
95126
  try {
94925
95127
  if (!statSync51(dirPath).isDirectory())
94926
95128
  continue;
@@ -94944,19 +95146,19 @@ function listSharedSkills(sharedRoot = defaultSharedRoot2()) {
94944
95146
  return out;
94945
95147
  }
94946
95148
  function listBundledSkills(bundledRoot = defaultBundledRoot2()) {
94947
- if (!existsSync94(bundledRoot))
95149
+ if (!existsSync95(bundledRoot))
94948
95150
  return [];
94949
95151
  const out = [];
94950
95152
  let entries;
94951
95153
  try {
94952
- entries = readdirSync36(bundledRoot);
95154
+ entries = readdirSync37(bundledRoot);
94953
95155
  } catch {
94954
95156
  return [];
94955
95157
  }
94956
95158
  for (const ent of entries) {
94957
95159
  if (ent.startsWith("."))
94958
95160
  continue;
94959
- const dirPath = join95(bundledRoot, ent);
95161
+ const dirPath = join96(bundledRoot, ent);
94960
95162
  try {
94961
95163
  if (!statSync51(dirPath).isDirectory())
94962
95164
  continue;
@@ -95102,18 +95304,18 @@ init_source();
95102
95304
  init_helpers();
95103
95305
  init_operator_uid();
95104
95306
  import {
95105
- existsSync as existsSync96,
95106
- mkdirSync as mkdirSync54,
95107
- readdirSync as readdirSync37,
95108
- readFileSync as readFileSync84,
95109
- writeFileSync as writeFileSync35,
95307
+ existsSync as existsSync97,
95308
+ mkdirSync as mkdirSync55,
95309
+ readdirSync as readdirSync38,
95310
+ readFileSync as readFileSync85,
95311
+ writeFileSync as writeFileSync36,
95110
95312
  statSync as statSync52,
95111
95313
  lstatSync as lstatSync13,
95112
95314
  realpathSync as realpathSync8,
95113
95315
  copyFileSync as copyFileSync13
95114
95316
  } from "node:fs";
95115
95317
  import { homedir as homedir55 } from "node:os";
95116
- import { join as join96 } from "node:path";
95318
+ import { join as join97 } from "node:path";
95117
95319
  import { spawnSync as spawnSync20 } from "node:child_process";
95118
95320
 
95119
95321
  // src/cli/singleton-stale-cleanup.ts
@@ -95462,7 +95664,7 @@ function resolveHostdHostHome(env2 = process.env, home2 = homedir55()) {
95462
95664
  return resolved;
95463
95665
  }
95464
95666
  function resolveHostdSkillsTarget(hostHome) {
95465
- const skillsPath = join96(hostHome, ".switchroom", "skills");
95667
+ const skillsPath = join97(hostHome, ".switchroom", "skills");
95466
95668
  let st;
95467
95669
  try {
95468
95670
  st = lstatSync13(skillsPath);
@@ -95479,21 +95681,21 @@ function resolveHostdSkillsTarget(hostHome) {
95479
95681
  console.warn(`switchroom hostd install: ~/.switchroom/skills is a symlink whose target ` + `does not resolve (dangling) \u2014 skipping the skills bind mount. Bundled ` + `skills will be unavailable to rollout/update until the symlink is fixed.`);
95480
95682
  return;
95481
95683
  }
95482
- if (!existsSync96(target)) {
95684
+ if (!existsSync97(target)) {
95483
95685
  console.warn(`switchroom hostd install: ~/.switchroom/skills resolves to "${target}", ` + `which does not exist \u2014 skipping the skills bind mount. Bundled skills ` + `will be unavailable to rollout/update until the symlink target exists.`);
95484
95686
  return;
95485
95687
  }
95486
95688
  return target;
95487
95689
  }
95488
95690
  function hostdDir() {
95489
- return join96(homedir55(), ".switchroom", "hostd");
95691
+ return join97(homedir55(), ".switchroom", "hostd");
95490
95692
  }
95491
95693
  function hostdComposePath() {
95492
- return join96(hostdDir(), "docker-compose.yml");
95694
+ return join97(hostdDir(), "docker-compose.yml");
95493
95695
  }
95494
95696
  function backupExistingCompose() {
95495
95697
  const p = hostdComposePath();
95496
- if (!existsSync96(p))
95698
+ if (!existsSync97(p))
95497
95699
  return null;
95498
95700
  const ts = new Date().toISOString().replace(/[:.]/g, "-");
95499
95701
  const bak = `${p}.bak-${ts}`;
@@ -95526,7 +95728,7 @@ async function doInstall(opts, program3) {
95526
95728
  }
95527
95729
  const dir = hostdDir();
95528
95730
  const composePath = hostdComposePath();
95529
- mkdirSync54(dir, { recursive: true });
95731
+ mkdirSync55(dir, { recursive: true });
95530
95732
  const imageTag = resolveHostdImageTag(opts.tag, cfg.release);
95531
95733
  const guard = checkDowngrade({
95532
95734
  container: "switchroom-hostd",
@@ -95559,7 +95761,7 @@ async function doInstall(opts, program3) {
95559
95761
  const bak = backupExistingCompose();
95560
95762
  if (bak)
95561
95763
  console.log(source_default.dim(` Backed up existing compose to ${bak}`));
95562
- writeFileSync35(composePath, yaml, "utf8");
95764
+ writeFileSync36(composePath, yaml, "utf8");
95563
95765
  console.log(source_default.green(` \u2713 Wrote ${composePath}`));
95564
95766
  const adminAgents = Object.entries(cfg.agents ?? {}).filter(([, a]) => a?.admin === true).map(([name]) => name);
95565
95767
  console.log(source_default.dim(` agents served (one socket each): ${allAgents.length === 0 ? "(none)" : allAgents.join(", ")}`));
@@ -95591,7 +95793,7 @@ function doStatus() {
95591
95793
  const composeYml = hostdComposePath();
95592
95794
  console.log(source_default.bold("switchroom-hostd"));
95593
95795
  console.log("");
95594
- if (!existsSync96(composeYml)) {
95796
+ if (!existsSync97(composeYml)) {
95595
95797
  console.log(source_default.yellow(" compose: not installed"));
95596
95798
  console.log(source_default.dim(" run `switchroom hostd install` to set up."));
95597
95799
  return;
@@ -95612,14 +95814,14 @@ function doStatus() {
95612
95814
  } else {
95613
95815
  console.log(source_default.green(` container: ${ps.stdout.trim()}`));
95614
95816
  }
95615
- if (existsSync96(dir)) {
95817
+ if (existsSync97(dir)) {
95616
95818
  const entries = [];
95617
95819
  try {
95618
- for (const name of readdirSync37(dir)) {
95820
+ for (const name of readdirSync38(dir)) {
95619
95821
  if (name === "docker-compose.yml" || name.startsWith("docker-compose.yml."))
95620
95822
  continue;
95621
- const sockPath = join96(dir, name, "sock");
95622
- if (existsSync96(sockPath)) {
95823
+ const sockPath = join97(dir, name, "sock");
95824
+ if (existsSync97(sockPath)) {
95623
95825
  const st = statSync52(sockPath);
95624
95826
  if ((st.mode & 61440) === 49152) {
95625
95827
  entries.push(`${name} \u2192 ${sockPath}`);
@@ -95638,7 +95840,7 @@ function doStatus() {
95638
95840
  }
95639
95841
  function doUninstall() {
95640
95842
  const composeYml = hostdComposePath();
95641
- if (!existsSync96(composeYml)) {
95843
+ if (!existsSync97(composeYml)) {
95642
95844
  console.log(source_default.yellow(" No hostd install detected (no compose file at this path)."));
95643
95845
  return;
95644
95846
  }
@@ -95662,12 +95864,12 @@ function registerHostdCommand(program3) {
95662
95864
  hostd.command("uninstall").description("Stop the hostd container. Leaves the compose file in place for re-install.").action(() => doUninstall());
95663
95865
  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) => {
95664
95866
  const logPath = opts.path ?? defaultAuditLogPath2();
95665
- if (!existsSync96(logPath)) {
95867
+ if (!existsSync97(logPath)) {
95666
95868
  console.error(source_default.yellow(`Audit log not found at ${logPath}.`) + source_default.gray(`
95667
95869
  The log is created when hostd handles its first privileged-verb request.`));
95668
95870
  return;
95669
95871
  }
95670
- const raw = readFileSync84(logPath, "utf-8");
95872
+ const raw = readFileSync85(logPath, "utf-8");
95671
95873
  const limit = Math.max(1, parseInt(opts.tail ?? "50", 10) || 50);
95672
95874
  const filters = {
95673
95875
  agent: opts.agent,
@@ -95710,9 +95912,9 @@ The log is created when hostd handles its first privileged-verb request.`));
95710
95912
  init_source();
95711
95913
  init_helpers();
95712
95914
  init_operator_uid();
95713
- import { chownSync as chownSync9, existsSync as existsSync97, mkdirSync as mkdirSync55, writeFileSync as writeFileSync36, copyFileSync as copyFileSync14 } from "node:fs";
95915
+ import { chownSync as chownSync9, existsSync as existsSync98, mkdirSync as mkdirSync56, writeFileSync as writeFileSync37, copyFileSync as copyFileSync14 } from "node:fs";
95714
95916
  import { homedir as homedir56 } from "node:os";
95715
- import { join as join97 } from "node:path";
95917
+ import { join as join98 } from "node:path";
95716
95918
  import { spawnSync as spawnSync21 } from "node:child_process";
95717
95919
  function resolveWebImageTag(explicitTag, release) {
95718
95920
  if (explicitTag)
@@ -95812,14 +96014,14 @@ services:
95812
96014
  `;
95813
96015
  }
95814
96016
  function webdDir() {
95815
- return join97(homedir56(), ".switchroom", "web");
96017
+ return join98(homedir56(), ".switchroom", "web");
95816
96018
  }
95817
96019
  function webdComposePath() {
95818
- return join97(webdDir(), "docker-compose.yml");
96020
+ return join98(webdDir(), "docker-compose.yml");
95819
96021
  }
95820
96022
  function backupExistingCompose2() {
95821
96023
  const p = webdComposePath();
95822
- if (!existsSync97(p))
96024
+ if (!existsSync98(p))
95823
96025
  return null;
95824
96026
  const ts = new Date().toISOString().replace(/[:.]/g, "-");
95825
96027
  const bak = `${p}.bak-${ts}`;
@@ -95844,7 +96046,7 @@ async function doInstall2(opts, program3) {
95844
96046
  }
95845
96047
  const dir = webdDir();
95846
96048
  const composePath = webdComposePath();
95847
- mkdirSync55(dir, { recursive: true });
96049
+ mkdirSync56(dir, { recursive: true });
95848
96050
  const cfg = getConfig(program3);
95849
96051
  const imageTag = resolveWebImageTag(opts.tag, cfg.release);
95850
96052
  const port = cfg.web_service?.port ?? 8080;
@@ -95879,7 +96081,7 @@ async function doInstall2(opts, program3) {
95879
96081
  const bak = backupExistingCompose2();
95880
96082
  if (bak)
95881
96083
  console.log(source_default.dim(` Backed up existing compose to ${bak}`));
95882
- writeFileSync36(composePath, yaml, "utf8");
96084
+ writeFileSync37(composePath, yaml, "utf8");
95883
96085
  try {
95884
96086
  if (typeof process.geteuid === "function" && process.geteuid() === 0) {
95885
96087
  chownSync9(dir, operatorUid, operatorUid);
@@ -95921,7 +96123,7 @@ function doStatus2() {
95921
96123
  const composeYml = webdComposePath();
95922
96124
  console.log(source_default.bold("switchroom-web"));
95923
96125
  console.log("");
95924
- if (!existsSync97(composeYml)) {
96126
+ if (!existsSync98(composeYml)) {
95925
96127
  console.log(source_default.yellow(" compose: not installed"));
95926
96128
  console.log(source_default.dim(" run `switchroom webd install` to set up."));
95927
96129
  return;
@@ -95945,7 +96147,7 @@ function doStatus2() {
95945
96147
  }
95946
96148
  function doUninstall2() {
95947
96149
  const composeYml = webdComposePath();
95948
- if (!existsSync97(composeYml)) {
96150
+ if (!existsSync98(composeYml)) {
95949
96151
  console.log(source_default.yellow(" No web-service install detected (no compose file at this path)."));
95950
96152
  return;
95951
96153
  }
@@ -95975,9 +96177,9 @@ function registerWebdCommand(program3) {
95975
96177
  // src/cli/host-repair.ts
95976
96178
  init_source();
95977
96179
  import { homedir as homedir57 } from "node:os";
95978
- import { join as join98 } from "node:path";
96180
+ import { join as join99 } from "node:path";
95979
96181
  var ARTIFACT_ALLOWLIST = {
95980
- dockerComposePluginDir: (home2) => join98(home2, ".docker", "cli-plugins", "docker-compose"),
96182
+ dockerComposePluginDir: (home2) => join99(home2, ".docker", "cli-plugins", "docker-compose"),
95981
96183
  stateSentinel: "/state"
95982
96184
  };
95983
96185
  function isStateBogusAutoDir(probe2) {
@@ -96131,7 +96333,7 @@ function applyMountRepairs(items, deps) {
96131
96333
  function registerHostCommand(program3) {
96132
96334
  const host = program3.command("host").description("Host-level maintenance operations for switchroom");
96133
96335
  host.command("repair-mounts").description("Detect and remove known auto-dir artifacts left by a container-context deploy " + "(2026-06-23 outage class). Default: dry-run. Pass --yes to apply.").option("--yes", "Actually perform the removals (default is dry-run)").action(async (opts) => {
96134
- const { rmdirSync: rmdirSync2, rmSync: rmSync20, lstatSync: lstatSync14, readdirSync: readdirSync38 } = await import("node:fs");
96336
+ const { rmdirSync: rmdirSync2, rmSync: rmSync20, lstatSync: lstatSync14, readdirSync: readdirSync39 } = await import("node:fs");
96135
96337
  const probe2 = {
96136
96338
  lstat(path9) {
96137
96339
  try {
@@ -96142,7 +96344,7 @@ function registerHostCommand(program3) {
96142
96344
  },
96143
96345
  readdir(path9) {
96144
96346
  try {
96145
- return readdirSync38(path9);
96347
+ return readdirSync39(path9);
96146
96348
  } catch {
96147
96349
  return null;
96148
96350
  }