switchroom 0.19.8 → 0.19.10

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.10", COMMIT_SHA = "d88584dd";
2124
2124
 
2125
2125
  // src/cli/resolve-version.ts
2126
2126
  import { existsSync, readFileSync } from "node:fs";
@@ -23861,8 +23861,7 @@ function getBuiltinDefaultSkillEntries() {
23861
23861
  "switchroom-health",
23862
23862
  "switchroom-runtime",
23863
23863
  "mental-model-curator",
23864
- "dev-protocol",
23865
- "telegram-formatting"
23864
+ "dev-protocol"
23866
23865
  ];
23867
23866
  return [
23868
23867
  ...anthropic.map((key) => ({ key, optOutKey: key, source: "anthropic" })),
@@ -23939,7 +23938,7 @@ function bindingsForAgent(agentName, mw, microsoftAccounts) {
23939
23938
  // src/agents/reconcile-default-skills.ts
23940
23939
  import { existsSync as existsSync8, lstatSync as lstatSync2, mkdirSync as mkdirSync3, readdirSync as readdirSync4, readlinkSync as readlinkSync3, rmSync as rmSync2, symlinkSync } from "node:fs";
23941
23940
  import { homedir as homedir3 } from "node:os";
23942
- import { join as join6, resolve as resolve5 } from "node:path";
23941
+ import { dirname as dirname2, isAbsolute, join as join6, relative, resolve as resolve5 } from "node:path";
23943
23942
  function warnMissingPoolDir(poolDir) {
23944
23943
  if (warnedMissingPool.has(poolDir))
23945
23944
  return;
@@ -23947,6 +23946,14 @@ function warnMissingPoolDir(poolDir) {
23947
23946
  process.stderr.write(`switchroom: bundled skills pool dir not found at ${poolDir} \u2014 run \`switchroom update\` to install it.
23948
23947
  `);
23949
23948
  }
23949
+ function warnMissingBuiltinDefault(poolDir, key) {
23950
+ const marker = `${poolDir} ${key}`;
23951
+ if (warnedMissingDefault.has(marker))
23952
+ return;
23953
+ warnedMissingDefault.add(marker);
23954
+ 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.
23955
+ `);
23956
+ }
23950
23957
  function getBundledSkillsPoolDir() {
23951
23958
  return resolve5(homedir3(), ".switchroom/skills/_bundled");
23952
23959
  }
@@ -23961,6 +23968,27 @@ function isOwnedStaleLink(target, poolDir) {
23961
23968
  return true;
23962
23969
  return false;
23963
23970
  }
23971
+ function absoluteLinkTarget(linkPath, storedTarget) {
23972
+ return isAbsolute(storedTarget) ? storedTarget : resolve5(dirname2(linkPath), storedTarget);
23973
+ }
23974
+ function linkTargetFor(dest, src) {
23975
+ return relative(dirname2(dest), src);
23976
+ }
23977
+ function isOwnedBundledLink(dest, poolDir) {
23978
+ let stored = null;
23979
+ try {
23980
+ if (!lstatSync2(dest).isSymbolicLink())
23981
+ return false;
23982
+ stored = readlinkSync3(dest);
23983
+ } catch {
23984
+ return false;
23985
+ }
23986
+ if (!stored)
23987
+ return false;
23988
+ const resolved = isAbsolute(stored) ? stored : resolve5(dirname2(dest), stored);
23989
+ const poolPrefix = poolDir.endsWith("/") ? poolDir : poolDir + "/";
23990
+ return resolved === poolDir || resolved.startsWith(poolPrefix);
23991
+ }
23964
23992
  function reconcileAgentDefaultSkills(agentDir, optOuts = {}, defaults = getBuiltinDefaultSkillEntries(), poolDir = getBundledSkillsPoolDir()) {
23965
23993
  const name = agentDir.split("/").pop() ?? agentDir;
23966
23994
  const result = {
@@ -23969,6 +23997,8 @@ function reconcileAgentDefaultSkills(agentDir, optOuts = {}, defaults = getBuilt
23969
23997
  alreadyPresent: [],
23970
23998
  optedOut: [],
23971
23999
  conflicts: [],
24000
+ missingFromPool: [],
24001
+ pruned: [],
23972
24002
  changed: false
23973
24003
  };
23974
24004
  const claudeDir = join6(agentDir, ".claude");
@@ -23982,15 +24012,32 @@ function reconcileAgentDefaultSkills(agentDir, optOuts = {}, defaults = getBuilt
23982
24012
  return result;
23983
24013
  }
23984
24014
  for (const entry of defaults) {
24015
+ const dest = join6(targetDir, entry.key);
23985
24016
  if (optOuts[entry.optOutKey] === false) {
23986
24017
  result.optedOut.push(entry.key);
24018
+ if (isOwnedBundledLink(dest, poolDir)) {
24019
+ try {
24020
+ rmSync2(dest, { force: true });
24021
+ result.pruned.push(entry.key);
24022
+ result.changed = true;
24023
+ } catch {}
24024
+ }
23987
24025
  continue;
23988
24026
  }
23989
24027
  const src = join6(poolDir, entry.key);
23990
24028
  if (!existsSync8(src)) {
24029
+ result.missingFromPool.push(entry.key);
24030
+ warnMissingBuiltinDefault(poolDir, entry.key);
24031
+ if (isOwnedBundledLink(dest, poolDir)) {
24032
+ try {
24033
+ rmSync2(dest, { force: true });
24034
+ result.pruned.push(entry.key);
24035
+ result.changed = true;
24036
+ } catch {}
24037
+ }
23991
24038
  continue;
23992
24039
  }
23993
- const dest = join6(targetDir, entry.key);
24040
+ const relTarget = linkTargetFor(dest, src);
23994
24041
  let existing;
23995
24042
  try {
23996
24043
  existing = lstatSync2(dest);
@@ -24003,11 +24050,12 @@ function reconcileAgentDefaultSkills(agentDir, optOuts = {}, defaults = getBuilt
24003
24050
  try {
24004
24051
  currentTarget = readlinkSync3(dest);
24005
24052
  } catch {}
24006
- if (currentTarget === src) {
24053
+ if (currentTarget === relTarget) {
24007
24054
  result.alreadyPresent.push(entry.key);
24008
24055
  continue;
24009
24056
  }
24010
- if (currentTarget && isOwnedStaleLink(currentTarget, poolDir)) {
24057
+ const resolvedTarget = currentTarget ? absoluteLinkTarget(dest, currentTarget) : null;
24058
+ if (resolvedTarget && isOwnedStaleLink(resolvedTarget, poolDir)) {
24011
24059
  try {
24012
24060
  rmSync2(dest, { force: true });
24013
24061
  } catch {}
@@ -24021,19 +24069,52 @@ function reconcileAgentDefaultSkills(agentDir, optOuts = {}, defaults = getBuilt
24021
24069
  }
24022
24070
  }
24023
24071
  try {
24024
- symlinkSync(src, dest);
24072
+ symlinkSync(relTarget, dest);
24025
24073
  result.added.push(entry.key);
24026
24074
  result.changed = true;
24027
24075
  } catch (err) {
24028
24076
  result.conflicts.push(entry.key);
24029
24077
  }
24030
24078
  }
24079
+ const defaultKeys = new Set(defaults.map((d) => d.key));
24080
+ const legitimate = new Set(defaultKeys);
24081
+ try {
24082
+ for (const poolName of readdirSync4(poolDir)) {
24083
+ if (!poolName.startsWith("switchroom-"))
24084
+ continue;
24085
+ if (defaultKeys.has(poolName))
24086
+ continue;
24087
+ try {
24088
+ const st = lstatSync2(join6(poolDir, poolName));
24089
+ if (st.isDirectory() && existsSync8(join6(poolDir, poolName, "SKILL.md"))) {
24090
+ legitimate.add(poolName);
24091
+ }
24092
+ } catch {}
24093
+ }
24094
+ } catch {}
24095
+ let dirEntries = [];
24096
+ try {
24097
+ dirEntries = readdirSync4(targetDir);
24098
+ } catch {}
24099
+ for (const linkName of dirEntries) {
24100
+ if (legitimate.has(linkName))
24101
+ continue;
24102
+ const dest = join6(targetDir, linkName);
24103
+ if (!isOwnedBundledLink(dest, poolDir))
24104
+ continue;
24105
+ try {
24106
+ rmSync2(dest, { force: true });
24107
+ result.pruned.push(linkName);
24108
+ result.changed = true;
24109
+ } catch {}
24110
+ }
24031
24111
  return result;
24032
24112
  }
24033
- var warnedMissingPool;
24113
+ var warnedMissingPool, warnedMissingDefault;
24034
24114
  var init_reconcile_default_skills = __esm(() => {
24035
24115
  init_scaffold_integration();
24036
24116
  warnedMissingPool = new Set;
24117
+ warnedMissingDefault = new Set;
24037
24118
  });
24038
24119
 
24039
24120
  // src/agents/sub-agent-telegram-prompt.ts
@@ -24089,7 +24170,7 @@ import {
24089
24170
  copyFileSync as copyFileSync2,
24090
24171
  unlinkSync
24091
24172
  } from "node:fs";
24092
- import { basename as basename2, dirname as dirname2, resolve as resolve6 } from "node:path";
24173
+ import { basename as basename2, dirname as dirname3, resolve as resolve6 } from "node:path";
24093
24174
  function defaultStatePath() {
24094
24175
  return resolveStatePath("topics.json");
24095
24176
  }
@@ -24116,7 +24197,7 @@ function loadTopicState(statePath) {
24116
24197
  }
24117
24198
  function saveTopicState(state, statePath) {
24118
24199
  const path = statePath ?? defaultStatePath();
24119
- const dir = dirname2(path);
24200
+ const dir = dirname3(path);
24120
24201
  if (!existsSync9(dir)) {
24121
24202
  mkdirSync4(dir, { recursive: true });
24122
24203
  }
@@ -24388,7 +24469,7 @@ import {
24388
24469
  lstatSync as lstatSync3,
24389
24470
  realpathSync as realpathSync2
24390
24471
  } from "node:fs";
24391
- import { dirname as dirname3, basename as basename3, resolve as resolve7 } from "node:path";
24472
+ import { dirname as dirname4, basename as basename3, resolve as resolve7 } from "node:path";
24392
24473
  function atomicWriteFileSync2(path, data, mode) {
24393
24474
  let effectivePath = path;
24394
24475
  try {
@@ -24396,7 +24477,7 @@ function atomicWriteFileSync2(path, data, mode) {
24396
24477
  effectivePath = realpathSync2(path);
24397
24478
  }
24398
24479
  } catch {}
24399
- const dir = dirname3(resolve7(effectivePath));
24480
+ const dir = dirname4(resolve7(effectivePath));
24400
24481
  const tmp = resolve7(dir, `.${basename3(effectivePath)}.${process.pid}.${Date.now()}.tmp`);
24401
24482
  try {
24402
24483
  const fd = openSync4(tmp, "wx", mode);
@@ -24533,7 +24614,7 @@ function createVault(passphrase, vaultPath) {
24533
24614
  if (existsSync11(vaultPath)) {
24534
24615
  throw new VaultError(`Vault file already exists: ${vaultPath}`);
24535
24616
  }
24536
- const dir = dirname3(vaultPath);
24617
+ const dir = dirname4(vaultPath);
24537
24618
  if (!existsSync11(dir)) {
24538
24619
  mkdirSync5(dir, { recursive: true, mode: 448 });
24539
24620
  }
@@ -26141,7 +26222,7 @@ import {
26141
26222
  } from "node:fs";
26142
26223
  import { homedir as homedir5 } from "node:os";
26143
26224
  import { execSync, execFileSync as execFileSync6 } from "node:child_process";
26144
- import { join as join11, resolve as resolve11 } from "node:path";
26225
+ import { dirname as dirname5, isAbsolute as isAbsolute2, join as join11, relative as relative2, resolve as resolve11 } from "node:path";
26145
26226
  import { createHash as createHash3 } from "node:crypto";
26146
26227
  function prependReplyDiscipline(rendered, context) {
26147
26228
  const replyDiscipline = renderReplyDisciplineFragment(context);
@@ -26527,7 +26608,8 @@ function migrateLegacySkillsDir(agentDir, skillsPool) {
26527
26608
  } catch {
26528
26609
  continue;
26529
26610
  }
26530
- if (target && target.startsWith(skillsPool)) {
26611
+ const resolved = target ? isAbsolute2(target) ? target : resolve11(dirname5(entryPath), target) : null;
26612
+ if (resolved && resolved.startsWith(skillsPool)) {
26531
26613
  try {
26532
26614
  rmSync4(entryPath, { force: true });
26533
26615
  } catch {}
@@ -26550,6 +26632,7 @@ function syncGlobalSkills(agentDir, declared, skillsDirOverride) {
26550
26632
  console.warn(` WARNING: skill "${name}" not found in pool (${skillsPool}) \u2014 skipping`);
26551
26633
  continue;
26552
26634
  }
26635
+ const relTarget = relative2(dirname5(dest), src);
26553
26636
  let linkStat;
26554
26637
  try {
26555
26638
  linkStat = lstatSync4(dest);
@@ -26562,7 +26645,11 @@ function syncGlobalSkills(agentDir, declared, skillsDirOverride) {
26562
26645
  try {
26563
26646
  target = readlinkSync4(dest);
26564
26647
  } catch {}
26565
- if (target && target.startsWith(skillsPool)) {
26648
+ if (target === relTarget) {
26649
+ continue;
26650
+ }
26651
+ const resolved = target ? isAbsolute2(target) ? target : resolve11(dirname5(dest), target) : null;
26652
+ if (resolved && resolved.startsWith(skillsPool)) {
26566
26653
  try {
26567
26654
  rmSync4(dest, { force: true });
26568
26655
  } catch {}
@@ -26574,7 +26661,7 @@ function syncGlobalSkills(agentDir, declared, skillsDirOverride) {
26574
26661
  }
26575
26662
  }
26576
26663
  try {
26577
- symlinkSync2(src, dest);
26664
+ symlinkSync2(relTarget, dest);
26578
26665
  } catch (err) {
26579
26666
  console.warn(` WARNING: failed to symlink skill "${name}": ${err.message}`);
26580
26667
  }
@@ -26590,10 +26677,11 @@ function syncGlobalSkills(agentDir, declared, skillsDirOverride) {
26590
26677
  } catch {
26591
26678
  continue;
26592
26679
  }
26593
- if (linkTarget && linkTarget.includes("/.switchroom/skills/_bundled/")) {
26680
+ const resolved = linkTarget ? isAbsolute2(linkTarget) ? linkTarget : resolve11(dirname5(entryPath), linkTarget) : null;
26681
+ if (resolved && resolved.includes("/.switchroom/skills/_bundled/")) {
26594
26682
  continue;
26595
26683
  }
26596
- if (linkTarget && linkTarget.startsWith(skillsPool)) {
26684
+ if (resolved && resolved.startsWith(skillsPool)) {
26597
26685
  rmSync4(entryPath, { force: true });
26598
26686
  }
26599
26687
  }
@@ -26646,7 +26734,10 @@ function installSwitchroomSkills(agentDir, opts = {}) {
26646
26734
  try {
26647
26735
  currentTarget = readlinkSync4(dest);
26648
26736
  } catch {}
26649
- if (currentTarget !== join11(builtinSkillsDir, name))
26737
+ if (!currentTarget)
26738
+ continue;
26739
+ const resolvedTarget = isAbsolute2(currentTarget) ? currentTarget : resolve11(dirname5(dest), currentTarget);
26740
+ if (resolvedTarget !== join11(builtinSkillsDir, name))
26650
26741
  continue;
26651
26742
  try {
26652
26743
  rmSync4(dest, { force: true });
@@ -26657,6 +26748,7 @@ function installSwitchroomSkills(agentDir, opts = {}) {
26657
26748
  for (const name of switchroomSkillNames) {
26658
26749
  const src = join11(builtinSkillsDir, name);
26659
26750
  const dest = join11(targetDir, name);
26751
+ const relTarget = relative2(dirname5(dest), src);
26660
26752
  let existing;
26661
26753
  try {
26662
26754
  existing = lstatSync4(dest);
@@ -26669,7 +26761,7 @@ function installSwitchroomSkills(agentDir, opts = {}) {
26669
26761
  try {
26670
26762
  currentTarget = readlinkSync4(dest);
26671
26763
  } catch {}
26672
- if (currentTarget === src)
26764
+ if (currentTarget === relTarget)
26673
26765
  continue;
26674
26766
  try {
26675
26767
  rmSync4(dest, { force: true });
@@ -26679,7 +26771,7 @@ function installSwitchroomSkills(agentDir, opts = {}) {
26679
26771
  }
26680
26772
  }
26681
26773
  try {
26682
- symlinkSync2(src, dest);
26774
+ symlinkSync2(relTarget, dest);
26683
26775
  } catch (err) {
26684
26776
  console.warn(` WARNING: failed to symlink switchroom skill "${name}": ${err.message}`);
26685
26777
  }
@@ -27381,6 +27473,24 @@ function resolveWebkiteMcpEntry(_agentName, agentConfig, _switchroomConfig) {
27381
27473
  }
27382
27474
  };
27383
27475
  }
27476
+ function computeDesiredPermissionAllow(agentConfig, hindsightEnabled) {
27477
+ const tools = agentConfig.tools ?? { allow: [], deny: [] };
27478
+ const rawAllow = tools.allow ?? [];
27479
+ const hasAllWildcard = rawAllow.includes("all");
27480
+ const baseAllow = hasAllWildcard ? [...ALL_BUILTIN_TOOLS, ...rawAllow.filter((t) => t !== "all")] : rawAllow.filter((t) => t !== "all");
27481
+ const dangerousMode = agentConfig.dangerous_mode === true;
27482
+ const hadExplicitAllow = rawAllow.length > 0;
27483
+ const readOnlyDefaults = !dangerousMode && !hadExplicitAllow ? DEFAULT_READ_ONLY_PREAPPROVED_TOOLS : [];
27484
+ return dedupe2([
27485
+ ...baseAllow,
27486
+ ...readOnlyDefaults,
27487
+ ...usesSwitchroomTelegramPlugin(agentConfig) ? SWITCHROOM_TELEGRAM_MCP_TOOLS : [],
27488
+ ...hindsightEnabled ? HINDSIGHT_MCP_TOOLS : [],
27489
+ ...AGENT_CONFIG_MCP_TOOLS,
27490
+ ...HOSTD_MCP_TOOLS,
27491
+ ...agentConfig.mcp_servers?.["webkite"] === false ? [] : WEBKITE_MCP_TOOLS
27492
+ ]);
27493
+ }
27384
27494
  function scaffoldAgent(name, agentConfigRaw, agentsDir, telegramConfig, switchroomConfig, userIdOverride, switchroomConfigPath) {
27385
27495
  const agentConfig = resolveAgentConfig(switchroomConfig?.defaults, switchroomConfig?.profiles, agentConfigRaw);
27386
27496
  const agentDir = resolve11(agentsDir, name);
@@ -27403,20 +27513,8 @@ function scaffoldAgent(name, agentConfigRaw, agentsDir, telegramConfig, switchro
27403
27513
  const tools = agentConfig.tools ?? { allow: [], deny: [] };
27404
27514
  const rawAllow = tools.allow ?? [];
27405
27515
  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
27516
  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
- ]);
27517
+ const permissionAllow = computeDesiredPermissionAllow(agentConfig, hindsightEnabled);
27420
27518
  const hindsightAutoRecallEnabled = hindsightEnabled && agentConfig.memory?.auto_recall !== false;
27421
27519
  const hindsightBankId = agentConfig.memory?.collection ?? name;
27422
27520
  const hindsightApiBaseUrl = switchroomConfig?.memory?.config?.url ? switchroomConfig.memory.config.url.replace(/\/mcp\/?$/, "").replace(/\/$/, "") : HINDSIGHT_DEFAULT_API_BASE_URL;
@@ -28332,23 +28430,11 @@ function reconcileAgentInner(name, agentConfigRaw, agentsDir, telegramConfig, sw
28332
28430
  const tools = agentConfig.tools ?? { allow: [], deny: [] };
28333
28431
  const rawAllow = tools.allow ?? [];
28334
28432
  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
28433
  const hindsightEnabled = isHindsightEnabled(switchroomConfig);
28434
+ const desiredAllow = computeDesiredPermissionAllow(agentConfig, hindsightEnabled);
28340
28435
  if (Array.isArray(tools.allow)) {
28341
28436
  tools.allow = tools.allow.filter((p) => !LEGACY_SWITCHROOM_MCP_TOKENS.includes(p) && !LEGACY_HOSTD_BLANKET_TOKENS.includes(p));
28342
28437
  }
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
28438
  const desiredDeny = dedupe2([
28353
28439
  ...tools.deny ?? [],
28354
28440
  ...webkiteDenyForAgent(agentConfig),
@@ -29420,31 +29506,34 @@ You're writing for a phone screen in Telegram. Every reply renders as rich Markd
29420
29506
 
29421
29507
  - **Short answers (a line or two): plain prose, no formatting.** "on it, pulling the
29422
29508
  logs now" is already perfect. No bold, no bullets, no headings.
29423
- - **Default: light structure.** Bold ONLY the one key fact or answer, never more. Use
29424
- a list only for 3+ genuinely parallel items the reader will scan or compare; two
29425
- items or a flowing thought stay prose. \`code spans\` for identifiers: filenames,
29426
- commands, config keys, error codes (tap-to-copy).
29427
- - **Long answers may add tables / headings / blockquotes, but only when they genuinely
29428
- aid scanning**: a table for real 2-D data (rows x columns), headings only in a
29429
- multi-section answer, \`>\` for quoted text. If the structure doesn't cut the
29430
- reader's effort, drop it.
29431
-
29432
- The framework normalizes mechanics in code on every outbound message: block spacing
29433
- (one blank line between distinct blocks), em/en dashes, and \`\u2022\` bullet markers are
29434
- rewritten deterministically at send time. Don't fight it or hand-tune spacing; write
29435
- the content, the gateway makes the typography consistent. Over-bolded messages (most
29436
- of the text bold, or whole paragraphs/lists bolded) have their bold stripped at send
29437
- time, so bold sparingly.
29438
-
29439
- Hard cap is 32768 characters. Long before that, ask whether a wall of text is the
29440
- right answer at all. Structure exists for the reader, not the writer: a two-item
29441
- bullet list is worse than a sentence, a heading on a three-line reply is noise. When
29442
- in doubt, shorter and plainer wins.
29443
-
29444
- Full palette when a rich or long message earns it \u2014 expandable blockquotes, spoilers,
29445
- highlight, code-fence language hints, tables, escaping and chunking rules: load the
29446
- \`telegram-formatting\` skill. Reach for it only when you're actually composing that
29447
- message, never for everyday replies.
29509
+ - **Default: light structure.** Bold ONLY the one key fact or answer, never more. A
29510
+ list only for 3+ genuinely parallel items the reader will scan or compare; two items
29511
+ or a flowing thought stay prose. \`code spans\` for identifiers: filenames, commands,
29512
+ config keys, error codes (tap-to-copy). Wrap dynamic identifiers in backticks:
29513
+ code-span content is literal, so it never needs escaping. Links as \`[label](url)\`,
29514
+ never bare pasted URLs mid-prose.
29515
+ - **Long answers may add the rich constructs, but only when they cut the reader's
29516
+ effort:** a GFM pipe table for real 2-D data (rows x columns); headings only in a
29517
+ multi-section answer; \`>\` for quoted text; fenced code blocks ALWAYS with a language
29518
+ hint (\`\`\`diff, \`\`\`json, \`\`\`bash \u2014 bare fence only for non-code fixed-width output);
29519
+ and the flagship \u2014 the **expandable blockquote** \`**> first line\` + \`> continuation\`
29520
+ for a long quote, stack trace, or detailed aside the reader can collapse. Use it
29521
+ whenever a bulky supporting block would otherwise dominate the message.
29522
+
29523
+ Renders wrong on this path \u2014 never emit: underline (\`__x__\` renders as bold),
29524
+ \`^sup^\`/\`~sub~\`, \`$math$\`, \`<details>\`, footnotes \`[^1]\`. Write "squared", not \`x^2^\`.
29525
+
29526
+ The framework normalizes mechanics in code on every outbound message: block spacing,
29527
+ em/en dashes, and \`\u2022\` bullet markers are
29528
+ rewritten deterministically; unsupported tokens (\`^highlight^\`, \`$math$\`, \`<details>\`,
29529
+ footnotes) are repaired; long messages are chunked safely at 32768 chars (fences and
29530
+ table rows never bisected); over-bolded messages get their bold stripped. Don't
29531
+ hand-tune spacing or fight it \u2014 write the content, the gateway makes typography
29532
+ consistent. Long before the cap, ask whether a wall of text is the right answer at all.
29533
+
29534
+ Structure exists for the reader, not the writer: a two-item bullet list is worse than
29535
+ a sentence, a heading on a three-line reply is noise. When in doubt, shorter and
29536
+ plainer wins.
29448
29537
 
29449
29538
  Every turn that answers a user message ends with a user-visible \`reply\`
29450
29539
  \u2014 Telegram is all the user sees; your terminal output
@@ -29606,7 +29695,7 @@ var init_scaffold = __esm(() => {
29606
29695
 
29607
29696
  // src/setup/host-capabilities.ts
29608
29697
  import { existsSync as existsSync17, mkdirSync as mkdirSync11, readFileSync as readFileSync14, writeFileSync as writeFileSync5 } from "node:fs";
29609
- import { dirname as dirname4 } from "node:path";
29698
+ import { dirname as dirname6 } from "node:path";
29610
29699
  function hostCapabilitiesPath() {
29611
29700
  return resolveStatePath("host-capabilities.json");
29612
29701
  }
@@ -29621,7 +29710,7 @@ function saveVoiceCapability(caps, now = () => new Date) {
29621
29710
  }
29622
29711
  };
29623
29712
  const path = hostCapabilitiesPath();
29624
- mkdirSync11(dirname4(path), { recursive: true });
29713
+ mkdirSync11(dirname6(path), { recursive: true });
29625
29714
  writeFileSync5(path, JSON.stringify(doc, null, 2) + `
29626
29715
  `, {
29627
29716
  encoding: "utf-8",
@@ -29728,11 +29817,11 @@ var init_grants_db_path = __esm(() => {
29728
29817
 
29729
29818
  // src/agents/compose.ts
29730
29819
  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";
29820
+ import { join as join13, isAbsolute as isAbsolute3, dirname as dirname8, resolve as resolve13 } from "node:path";
29732
29821
  function assertPlausibleHostHome(homePrefix) {
29733
29822
  if (homePrefix === "${HOME}")
29734
29823
  return;
29735
- const bad = !isAbsolute(homePrefix) || CONTAINER_ROOT_PREFIXES.some((p) => homePrefix === p || homePrefix.startsWith(p + "/"));
29824
+ const bad = !isAbsolute3(homePrefix) || CONTAINER_ROOT_PREFIXES.some((p) => homePrefix === p || homePrefix.startsWith(p + "/"));
29736
29825
  if (!bad)
29737
29826
  return;
29738
29827
  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 +30065,8 @@ function conditionalMountPresent(probePath, hostHome, probeHome) {
29976
30065
  if (!lstatSync5(probePath).isSymbolicLink())
29977
30066
  return false;
29978
30067
  let target = readlinkSync5(probePath);
29979
- if (!isAbsolute(target))
29980
- target = resolve13(dirname6(probePath), target);
30068
+ if (!isAbsolute3(target))
30069
+ target = resolve13(dirname8(probePath), target);
29981
30070
  if (hostHome && probeHome && hostHome !== probeHome) {
29982
30071
  if (target.startsWith(hostHome + "/")) {
29983
30072
  return true;
@@ -30026,7 +30115,7 @@ function generateCompose(opts) {
30026
30115
  const lines = [];
30027
30116
  lines.push("# generated by switchroom \u2014 do not edit by hand.");
30028
30117
  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");
30118
+ lines.push("# or `switchroom apply`. To customise an agent, edit");
30030
30119
  lines.push("# switchroom.yaml and re-run the regenerating command.");
30031
30120
  lines.push("");
30032
30121
  lines.push(`# image tag: ${imageTag}`);
@@ -30698,7 +30787,7 @@ var init_operator_uid = () => {};
30698
30787
  import { chownSync as chownSync2 } from "node:fs";
30699
30788
  import { mkdir, readFile, writeFile, rename, copyFile } from "node:fs/promises";
30700
30789
  import { homedir as homedir7 } from "node:os";
30701
- import { basename as basename4, dirname as dirname7, join as join15 } from "node:path";
30790
+ import { basename as basename4, dirname as dirname9, join as join15 } from "node:path";
30702
30791
  function agentHadLiteLLMRouting(composeContent, agentName) {
30703
30792
  const lines = composeContent.split(`
30704
30793
  `);
@@ -30839,7 +30928,7 @@ async function computeComposeContent(opts) {
30839
30928
  async function writeComposeFile(opts) {
30840
30929
  const { content, imageTag, previous, previousImageTag } = await computeComposeContent(opts);
30841
30930
  const operatorUid = resolveOperatorUid();
30842
- await mkdir(dirname7(opts.composePath), { recursive: true });
30931
+ await mkdir(dirname9(opts.composePath), { recursive: true });
30843
30932
  if (previous !== null) {
30844
30933
  try {
30845
30934
  await copyFile(opts.composePath, opts.composePath + ".bak");
@@ -30908,9 +30997,9 @@ var init_tmux = __esm(() => {
30908
30997
 
30909
30998
  // src/agents/compose-env.ts
30910
30999
  import { existsSync as existsSync21 } from "node:fs";
30911
- import { dirname as dirname8 } from "node:path";
31000
+ import { dirname as dirname10 } from "node:path";
30912
31001
  function composeEnvPath(composePath) {
30913
- return dirname8(composePath) + "/.env";
31002
+ return dirname10(composePath) + "/.env";
30914
31003
  }
30915
31004
  function composeEnvFileArgs(composePath) {
30916
31005
  const envPath = composeEnvPath(composePath);
@@ -35578,7 +35667,7 @@ import {
35578
35667
  unlinkSync as unlinkSync7
35579
35668
  } from "node:fs";
35580
35669
  import { createHash as createHash6 } from "node:crypto";
35581
- import { basename as basename5, dirname as dirname9, join as join31 } from "node:path";
35670
+ import { basename as basename5, dirname as dirname11, join as join31 } from "node:path";
35582
35671
  function vaultLayoutPaths(home2) {
35583
35672
  const switchroomRoot = join31(home2, ".switchroom");
35584
35673
  return {
@@ -35731,7 +35820,7 @@ function sha256File(path2) {
35731
35820
  return createHash6("sha256").update(data).digest("hex");
35732
35821
  }
35733
35822
  function atomicReplaceWithSymlink(target, linkTarget) {
35734
- const tmp = join31(dirname9(target), `.${basename5(target)}.symlink-tmp`);
35823
+ const tmp = join31(dirname11(target), `.${basename5(target)}.symlink-tmp`);
35735
35824
  if (existsSync39(tmp)) {
35736
35825
  try {
35737
35826
  unlinkSync7(tmp);
@@ -35785,7 +35874,7 @@ import {
35785
35874
  unlinkSync as unlinkSync8,
35786
35875
  writeSync as writeSync5
35787
35876
  } from "node:fs";
35788
- import { basename as basename6, dirname as dirname10, resolve as resolve27 } from "node:path";
35877
+ import { basename as basename6, dirname as dirname12, resolve as resolve27 } from "node:path";
35789
35878
  function readMachineId() {
35790
35879
  const vitestVal = process.env.VITEST;
35791
35880
  const isTestEnv = vitestVal !== undefined && vitestVal.length > 0;
@@ -35850,7 +35939,7 @@ function decryptAutoUnlock(blob, machineId) {
35850
35939
  }
35851
35940
  function writeAutoUnlockFile(passphrase, filePath) {
35852
35941
  const blob = encryptAutoUnlock(passphrase);
35853
- const dir = dirname10(filePath);
35942
+ const dir = dirname12(filePath);
35854
35943
  mkdirSync23(dir, { recursive: true, mode: 448 });
35855
35944
  const tmp = resolve27(dir, `.${basename6(filePath)}.${process.pid}.${Date.now()}.tmp`);
35856
35945
  try {
@@ -36957,7 +37046,7 @@ function formatForCli(entries, opts = {}) {
36957
37046
  var init_audit_reader = () => {};
36958
37047
 
36959
37048
  // 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";
37049
+ import { dirname as dirname16, posix, sep as sep2 } from "path";
36961
37050
  function createModulerModifier() {
36962
37051
  const getModuleFromFileName = createGetModuleFromFilename();
36963
37052
  return async (frames) => {
@@ -36966,7 +37055,7 @@ function createModulerModifier() {
36966
37055
  return frames;
36967
37056
  };
36968
37057
  }
36969
- function createGetModuleFromFilename(basePath = process.argv[1] ? dirname14(process.argv[1]) : process.cwd(), isWindows = sep2 === "\\") {
37058
+ function createGetModuleFromFilename(basePath = process.argv[1] ? dirname16(process.argv[1]) : process.cwd(), isWindows = sep2 === "\\") {
36970
37059
  const normalizedBase = isWindows ? normalizeWindowsPath(basePath) : basePath;
36971
37060
  return (filename) => {
36972
37061
  if (!filename)
@@ -41582,7 +41671,7 @@ import {
41582
41671
  readFileSync as readFileSync45,
41583
41672
  writeFileSync as writeFileSync15
41584
41673
  } from "node:fs";
41585
- import { dirname as dirname15 } from "node:path";
41674
+ import { dirname as dirname17 } from "node:path";
41586
41675
  import { randomUUID as randomUUID3 } from "node:crypto";
41587
41676
  function telemetryDisabled() {
41588
41677
  const v = process.env.SWITCHROOM_TELEMETRY_DISABLED;
@@ -41604,7 +41693,7 @@ function getDistinctId() {
41604
41693
  const id = randomUUID3();
41605
41694
  cachedDistinctId = id;
41606
41695
  try {
41607
- mkdirSync27(dirname15(path5), { recursive: true });
41696
+ mkdirSync27(dirname17(path5), { recursive: true });
41608
41697
  writeFileSync15(path5, id, "utf-8");
41609
41698
  } catch {}
41610
41699
  return id;
@@ -41851,7 +41940,7 @@ import {
41851
41940
  readFileSync as readFileSync55,
41852
41941
  readdirSync as readdirSync21
41853
41942
  } from "node:fs";
41854
- import { dirname as dirname19, join as join53 } from "node:path";
41943
+ import { dirname as dirname21, join as join53 } from "node:path";
41855
41944
  import { execSync as execSync2 } from "node:child_process";
41856
41945
  function locateManifestPath() {
41857
41946
  let dir = import.meta.dirname;
@@ -41859,7 +41948,7 @@ function locateManifestPath() {
41859
41948
  const candidate = join53(dir, "dependencies.json");
41860
41949
  if (existsSync60(candidate))
41861
41950
  return candidate;
41862
- dir = dirname19(dir);
41951
+ dir = dirname21(dir);
41863
41952
  }
41864
41953
  return null;
41865
41954
  }
@@ -42713,7 +42802,7 @@ function checkAgentSocketMounts(composeYaml) {
42713
42802
  name: "agent socket-volume isolation",
42714
42803
  status: "fail",
42715
42804
  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."
42805
+ 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
42806
  };
42718
42807
  }
42719
42808
  function checkAgentCaps(config) {
@@ -42911,7 +43000,7 @@ function runDockerChecks(args) {
42911
43000
  name: "compose file present",
42912
43001
  status: "warn",
42913
43002
  detail: "Docker mode active but no docker-compose.yml found at ~/.switchroom/compose/docker-compose.yml",
42914
- fix: "Run `switchroom reconcile` to generate it."
43003
+ fix: "Run `switchroom apply` to generate it."
42915
43004
  });
42916
43005
  }
42917
43006
  out.push(...checkContainerRuntimeHealth(args.config, args.dockerPsDeps));
@@ -45933,7 +46022,7 @@ import {
45933
46022
  readdirSync as readdirSync23,
45934
46023
  statSync as statSync38
45935
46024
  } from "node:fs";
45936
- import { dirname as dirname20, join as join68, resolve as resolve39 } from "node:path";
46025
+ import { dirname as dirname22, join as join68, resolve as resolve39 } from "node:path";
45937
46026
  import { createPublicKey, createPrivateKey } from "node:crypto";
45938
46027
  function findInNvm(bin) {
45939
46028
  const nvmRoot = join68(process.env.HOME ?? "", ".nvm", "versions", "node");
@@ -47530,7 +47619,7 @@ async function checkMffAuthFlow(envPath = mffEnvPath(), timeoutMs = 8000) {
47530
47619
  detail: "skipped (MFF_API_URL not set)"
47531
47620
  };
47532
47621
  }
47533
- const credDir = dirname20(envPath);
47622
+ const credDir = dirname22(envPath);
47534
47623
  const authScript = join68(credDir, "claude-auth.py");
47535
47624
  if (!existsSync66(authScript)) {
47536
47625
  return {
@@ -48590,8 +48679,8 @@ var init_fleet_defaults = __esm(() => {
48590
48679
  });
48591
48680
 
48592
48681
  // src/agents/connection-health.ts
48593
- import { mkdirSync as mkdirSync46, writeFileSync as writeFileSync28 } from "node:fs";
48594
- import { join as join84 } from "node:path";
48682
+ import { mkdirSync as mkdirSync47, writeFileSync as writeFileSync29 } from "node:fs";
48683
+ import { join as join85 } from "node:path";
48595
48684
  async function computeAgentConnectionIssues(config, agentName, vaultAclReader) {
48596
48685
  const reqs = computeMcpSecretRequirements(config).filter((r) => r.agent === agentName);
48597
48686
  if (reqs.length === 0)
@@ -48648,10 +48737,10 @@ async function computeAgentConnectionIssues(config, agentName, vaultAclReader) {
48648
48737
  return issues;
48649
48738
  }
48650
48739
  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) + `
48740
+ const dir = join85(agentDir, ".claude");
48741
+ const path8 = join85(dir, CONNECTION_HEALTH_FILENAME);
48742
+ (deps?.mkdir ?? ((p, o) => mkdirSync47(p, o)))(dir, { recursive: true });
48743
+ (deps?.writeFile ?? ((p, d) => writeFileSync29(p, d)))(path8, JSON.stringify(health, null, 2) + `
48655
48744
  `);
48656
48745
  }
48657
48746
  async function refreshAgentConnectionHealth(config, agentName, agentDir, deps) {
@@ -48672,10 +48761,10 @@ var CONNECTION_HEALTH_FILENAME = "connection-health.json";
48672
48761
  var init_connection_health = () => {};
48673
48762
 
48674
48763
  // 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";
48764
+ import { existsSync as existsSync84, readFileSync as readFileSync73, writeFileSync as writeFileSync30, chmodSync as chmodSync12, mkdirSync as mkdirSync48 } from "node:fs";
48765
+ import { join as join86 } from "node:path";
48677
48766
  function containerHookCommand() {
48678
- return join85(CONTAINER_AGENT_DIR, ".claude", "hooks", HOOK_FILENAME);
48767
+ return join86(CONTAINER_AGENT_DIR, ".claude", "hooks", HOOK_FILENAME);
48679
48768
  }
48680
48769
  function updatePromptHookScript() {
48681
48770
  return `#!/bin/bash
@@ -48741,14 +48830,14 @@ exit 0
48741
48830
  `;
48742
48831
  }
48743
48832
  function installUpdatePromptHook(agentDir) {
48744
- const hooksDir = join85(agentDir, ".claude", "hooks");
48745
- mkdirSync47(hooksDir, { recursive: true });
48746
- const scriptPath = join85(hooksDir, HOOK_FILENAME);
48833
+ const hooksDir = join86(agentDir, ".claude", "hooks");
48834
+ mkdirSync48(hooksDir, { recursive: true });
48835
+ const scriptPath = join86(hooksDir, HOOK_FILENAME);
48747
48836
  const desired = updatePromptHookScript();
48748
48837
  let installed = false;
48749
- const existing = existsSync83(scriptPath) ? readFileSync72(scriptPath, "utf-8") : "";
48838
+ const existing = existsSync84(scriptPath) ? readFileSync73(scriptPath, "utf-8") : "";
48750
48839
  if (existing !== desired) {
48751
- writeFileSync29(scriptPath, desired, { mode: 493 });
48840
+ writeFileSync30(scriptPath, desired, { mode: 493 });
48752
48841
  chmodSync12(scriptPath, 493);
48753
48842
  installed = true;
48754
48843
  } else {
@@ -48756,11 +48845,11 @@ function installUpdatePromptHook(agentDir) {
48756
48845
  chmodSync12(scriptPath, 493);
48757
48846
  } catch {}
48758
48847
  }
48759
- const settingsPath = join85(agentDir, ".claude", "settings.json");
48760
- if (!existsSync83(settingsPath)) {
48848
+ const settingsPath = join86(agentDir, ".claude", "settings.json");
48849
+ if (!existsSync84(settingsPath)) {
48761
48850
  return { scriptPath, settingsPath, installed };
48762
48851
  }
48763
- const raw = readFileSync72(settingsPath, "utf-8");
48852
+ const raw = readFileSync73(settingsPath, "utf-8");
48764
48853
  let parsed;
48765
48854
  try {
48766
48855
  parsed = JSON.parse(raw);
@@ -48796,7 +48885,7 @@ function installUpdatePromptHook(agentDir) {
48796
48885
  if (mutated) {
48797
48886
  hooks.UserPromptSubmit = list2;
48798
48887
  parsed.hooks = hooks;
48799
- writeFileSync29(settingsPath, JSON.stringify(parsed, null, 2) + `
48888
+ writeFileSync30(settingsPath, JSON.stringify(parsed, null, 2) + `
48800
48889
  `, { mode: 384 });
48801
48890
  installed = true;
48802
48891
  } else if (!alreadyCorrect) {
@@ -48805,7 +48894,7 @@ function installUpdatePromptHook(agentDir) {
48805
48894
  });
48806
48895
  hooks.UserPromptSubmit = list2;
48807
48896
  parsed.hooks = hooks;
48808
- writeFileSync29(settingsPath, JSON.stringify(parsed, null, 2) + `
48897
+ writeFileSync30(settingsPath, JSON.stringify(parsed, null, 2) + `
48809
48898
  `, { mode: 384 });
48810
48899
  installed = true;
48811
48900
  }
@@ -49189,8 +49278,8 @@ __export(exports_voice_sidecar_token, {
49189
49278
  VOICE_SIDECAR_TOKEN_ENV: () => VOICE_SIDECAR_TOKEN_ENV
49190
49279
  });
49191
49280
  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";
49281
+ 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";
49282
+ import { dirname as dirname31 } from "node:path";
49194
49283
  async function defaultResolveOrSeedToken(home2, writeErr) {
49195
49284
  const [{ getViaBrokerStructured: getViaBrokerStructured2, putViaBroker: putViaBroker2 }, { resolveOperatorVaultPassphrase }] = await Promise.all([
49196
49285
  Promise.resolve().then(() => (init_client(), exports_client)),
@@ -49224,8 +49313,8 @@ async function provisionVoiceSidecarToken(composePath, home2, ctx) {
49224
49313
  const envPath = composeEnvPath(composePath);
49225
49314
  if (engine !== "local") {
49226
49315
  try {
49227
- if (existsSync85(envPath)) {
49228
- const body = readFileSync73(envPath, "utf-8");
49316
+ if (existsSync86(envPath)) {
49317
+ const body = readFileSync74(envPath, "utf-8");
49229
49318
  if (body.includes(`${VOICE_SIDECAR_TOKEN_ENV}=`))
49230
49319
  rmSync17(envPath);
49231
49320
  }
@@ -49244,11 +49333,11 @@ async function provisionVoiceSidecarToken(composePath, home2, ctx) {
49244
49333
  if (!token)
49245
49334
  return;
49246
49335
  try {
49247
- mkdirSync48(dirname29(envPath), { recursive: true });
49336
+ mkdirSync49(dirname31(envPath), { recursive: true });
49248
49337
  let body = "";
49249
49338
  try {
49250
- if (existsSync85(envPath))
49251
- body = readFileSync73(envPath, "utf-8");
49339
+ if (existsSync86(envPath))
49340
+ body = readFileSync74(envPath, "utf-8");
49252
49341
  } catch {}
49253
49342
  const line = `${VOICE_SIDECAR_TOKEN_ENV}=${token}`;
49254
49343
  const keyRe = new RegExp(`^${VOICE_SIDECAR_TOKEN_ENV}=.*$`, "m");
@@ -49256,7 +49345,7 @@ async function provisionVoiceSidecarToken(composePath, home2, ctx) {
49256
49345
  `) ? body + `
49257
49346
  ` : body) + line + `
49258
49347
  `;
49259
- writeFileSync30(envPath, next, {
49348
+ writeFileSync31(envPath, next, {
49260
49349
  encoding: "utf-8",
49261
49350
  mode: 384
49262
49351
  });
@@ -49308,11 +49397,11 @@ __export(exports_apply, {
49308
49397
  DEFAULT_COMPOSE_PATH: () => DEFAULT_COMPOSE_PATH2,
49309
49398
  COMPOSE_PROJECT: () => COMPOSE_PROJECT2
49310
49399
  });
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";
49400
+ 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
49401
  import { mkdir as mkdir2 } from "node:fs/promises";
49313
49402
  import { spawnSync as childSpawnSync } from "node:child_process";
49314
49403
  import readline from "node:readline";
49315
- import { dirname as dirname30, join as join87, resolve as resolve52 } from "node:path";
49404
+ import { dirname as dirname32, join as join88, resolve as resolve52 } from "node:path";
49316
49405
  import { homedir as homedir49 } from "node:os";
49317
49406
  import { execFileSync as execFileSync27 } from "node:child_process";
49318
49407
  function effectiveLiteLLMEnabled(config, agentResolvedLitellm) {
@@ -49324,7 +49413,7 @@ async function resolveOperatorVaultPassphrase(home2) {
49324
49413
  return envPass;
49325
49414
  try {
49326
49415
  const { readAutoUnlockFile: readAutoUnlockFile2 } = await Promise.resolve().then(() => (init_auto_unlock(), exports_auto_unlock));
49327
- const blobPath = join87(home2, ".switchroom", "vault-auto-unlock");
49416
+ const blobPath = join88(home2, ".switchroom", "vault-auto-unlock");
49328
49417
  const pass = readAutoUnlockFile2(blobPath);
49329
49418
  return pass && pass.length > 0 ? pass : null;
49330
49419
  } catch {
@@ -49333,10 +49422,10 @@ async function resolveOperatorVaultPassphrase(home2) {
49333
49422
  }
49334
49423
  function materializeLitellmMasterKeyForBroker(masterKey, home2 = process.env.HOME ?? "/root") {
49335
49424
  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() + `
49425
+ const stateDir = join88(home2, ".switchroom", "state", "auth-broker");
49426
+ mkdirSync50(stateDir, { recursive: true, mode: 448 });
49427
+ const path9 = join88(stateDir, LITELLM_MASTER_KEY_STATE_BASENAME);
49428
+ writeFileSync32(path9, masterKey.trim() + `
49340
49429
  `, { mode: 384 });
49341
49430
  try {
49342
49431
  chmodSync14(path9, 384);
@@ -49428,9 +49517,9 @@ async function provisionLiteLLMKeys(config, agentNames, switchroomConfigPath, ct
49428
49517
  const oauthAccount = config.auth?.active;
49429
49518
  let pendingConfigEdits = false;
49430
49519
  let configText = null;
49431
- if (switchroomConfigPath && existsSync86(switchroomConfigPath)) {
49520
+ if (switchroomConfigPath && existsSync87(switchroomConfigPath)) {
49432
49521
  try {
49433
- configText = readFileSync74(switchroomConfigPath, "utf-8");
49522
+ configText = readFileSync75(switchroomConfigPath, "utf-8");
49434
49523
  } catch (err) {
49435
49524
  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
49525
  `));
@@ -49659,14 +49748,14 @@ async function provisionLiteLLMKeys(config, agentNames, switchroomConfigPath, ct
49659
49748
  function resolveVaultBindMountDir(homeDir, ctx) {
49660
49749
  const isCustomPath = ctx.migrationKind === "custom-path-skipped";
49661
49750
  if (isCustomPath && ctx.customVaultPath) {
49662
- return dirname30(ctx.customVaultPath);
49751
+ return dirname32(ctx.customVaultPath);
49663
49752
  }
49664
- return join87(homeDir, ".switchroom", "vault");
49753
+ return join88(homeDir, ".switchroom", "vault");
49665
49754
  }
49666
49755
  function inspectVaultBindMountDir(vaultDir) {
49667
- if (!existsSync86(vaultDir))
49756
+ if (!existsSync87(vaultDir))
49668
49757
  return { kind: "missing" };
49669
- const entries = readdirSync30(vaultDir);
49758
+ const entries = readdirSync31(vaultDir);
49670
49759
  const unknown = [];
49671
49760
  for (const name of entries) {
49672
49761
  if (KNOWN_VAULT_ARTIFACT_NAMES.has(name))
@@ -49692,60 +49781,60 @@ function hasVaultRefs(value) {
49692
49781
  async function ensureHostMountSources(config) {
49693
49782
  const home2 = resolveHostHomeForCompose();
49694
49783
  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")
49784
+ join88(home2, ".switchroom", "approvals"),
49785
+ join88(home2, ".switchroom", "scheduler"),
49786
+ join88(home2, ".switchroom", "logs"),
49787
+ join88(home2, ".switchroom", "compose"),
49788
+ join88(home2, ".switchroom", "broker-operator")
49700
49789
  ];
49701
49790
  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"));
49791
+ dirs.push(join88(home2, ".switchroom", "agents", name));
49792
+ dirs.push(join88(home2, ".switchroom", "logs", name));
49793
+ dirs.push(join88(home2, ".claude", "projects", name));
49794
+ dirs.push(join88(home2, ".switchroom", "audit", name));
49795
+ if (existsSync87(join88(home2, ".switchroom-config"))) {
49796
+ dirs.push(join88(home2, ".switchroom-config", "agents", name, "personal-skills"));
49708
49797
  }
49709
49798
  }
49710
49799
  for (const dir of dirs) {
49711
49800
  await mkdir2(dir, { recursive: true });
49712
49801
  }
49713
- const autoUnlockPath = join87(home2, ".switchroom", "vault-auto-unlock");
49714
- if (!existsSync86(autoUnlockPath)) {
49715
- writeFileSync31(autoUnlockPath, "", { mode: 384 });
49802
+ const autoUnlockPath = join88(home2, ".switchroom", "vault-auto-unlock");
49803
+ if (!existsSync87(autoUnlockPath)) {
49804
+ writeFileSync32(autoUnlockPath, "", { mode: 384 });
49716
49805
  }
49717
- const auditLogPath = join87(home2, ".switchroom", "vault-audit.log");
49718
- if (!existsSync86(auditLogPath)) {
49719
- writeFileSync31(auditLogPath, "", { mode: 420 });
49806
+ const auditLogPath = join88(home2, ".switchroom", "vault-audit.log");
49807
+ if (!existsSync87(auditLogPath)) {
49808
+ writeFileSync32(auditLogPath, "", { mode: 420 });
49720
49809
  }
49721
49810
  const grantsDbDir = getGrantsDbDir(home2);
49722
- mkdirSync49(grantsDbDir, { recursive: true, mode: 448 });
49811
+ mkdirSync50(grantsDbDir, { recursive: true, mode: 448 });
49723
49812
  migrateLegacyGrantsDbLocation(getGrantsDbPath(home2));
49724
- const hostdAuditLogPath = join87(home2, ".switchroom", "host-control-audit.log");
49725
- if (!existsSync86(hostdAuditLogPath)) {
49726
- writeFileSync31(hostdAuditLogPath, "", { mode: 420 });
49813
+ const hostdAuditLogPath = join88(home2, ".switchroom", "host-control-audit.log");
49814
+ if (!existsSync87(hostdAuditLogPath)) {
49815
+ writeFileSync32(hostdAuditLogPath, "", { mode: 420 });
49727
49816
  }
49728
49817
  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 });
49818
+ const tokenPath = join88(home2, ".switchroom", "agents", name, ".vault-token");
49819
+ if (!existsSync87(tokenPath)) {
49820
+ writeFileSync32(tokenPath, "", { mode: 384 });
49732
49821
  }
49733
49822
  try {
49734
49823
  const uid = allocateAgentUid(name);
49735
49824
  chownSync8(tokenPath, uid, uid);
49736
49825
  } catch {}
49737
49826
  }
49738
- const fleetDir = join87(home2, ".switchroom", "fleet");
49827
+ const fleetDir = join88(home2, ".switchroom", "fleet");
49739
49828
  await mkdir2(fleetDir, { recursive: true });
49740
- const invariantsPath = join87(fleetDir, "switchroom-invariants.md");
49829
+ const invariantsPath = join88(fleetDir, "switchroom-invariants.md");
49741
49830
  const invariantsCanonical = renderFleetInvariants();
49742
- const invariantsCurrent = existsSync86(invariantsPath) ? readFileSync74(invariantsPath, "utf-8") : null;
49831
+ const invariantsCurrent = existsSync87(invariantsPath) ? readFileSync75(invariantsPath, "utf-8") : null;
49743
49832
  if (invariantsCurrent !== invariantsCanonical) {
49744
- writeFileSync31(invariantsPath, invariantsCanonical, { mode: 420 });
49833
+ writeFileSync32(invariantsPath, invariantsCanonical, { mode: 420 });
49745
49834
  }
49746
- const fleetClaudePath = join87(fleetDir, "CLAUDE.md");
49747
- if (!existsSync86(fleetClaudePath)) {
49748
- writeFileSync31(fleetClaudePath, renderFleetDefaultsClaudeMd(), {
49835
+ const fleetClaudePath = join88(fleetDir, "CLAUDE.md");
49836
+ if (!existsSync87(fleetClaudePath)) {
49837
+ writeFileSync32(fleetClaudePath, renderFleetDefaultsClaudeMd(), {
49749
49838
  mode: 420
49750
49839
  });
49751
49840
  }
@@ -49774,7 +49863,7 @@ function isInAgentContainer(vaultPresent, composeV2Present, env2 = process.env)
49774
49863
  function runApplyPreflight(config, opts = {}) {
49775
49864
  const vaultPath = resolvePath(config.vault?.path ?? "~/.switchroom/vault.enc");
49776
49865
  const detect = opts.detectComposeV2 ?? detectComposeV2;
49777
- const vaultMissing = hasVaultRefs(config) && !existsSync86(vaultPath);
49866
+ const vaultMissing = hasVaultRefs(config) && !existsSync87(vaultPath);
49778
49867
  const composeErr = detect();
49779
49868
  if ((vaultMissing || composeErr) && isInAgentContainer(!vaultMissing, composeErr === null)) {
49780
49869
  throw new Error(IN_AGENT_CONTAINER_APPLY_MSG);
@@ -49788,7 +49877,7 @@ function runApplyPreflight(config, opts = {}) {
49788
49877
  detectAndReportLegacyGdriveSlots(vaultPath);
49789
49878
  }
49790
49879
  function detectAndReportLegacyGdriveSlots(vaultPath) {
49791
- if (!existsSync86(vaultPath))
49880
+ if (!existsSync87(vaultPath))
49792
49881
  return;
49793
49882
  const passphrase = process.env.SWITCHROOM_VAULT_PASSPHRASE;
49794
49883
  if (!passphrase)
@@ -49829,17 +49918,17 @@ function detectAndReportLegacyGdriveSlots(vaultPath) {
49829
49918
  }
49830
49919
  function writeInstallTypeCache(homeDir = homedir49()) {
49831
49920
  const ctx = detectInstallType();
49832
- const dir = join87(homeDir, ".switchroom");
49833
- const out = join87(dir, "install-type.json");
49921
+ const dir = join88(homeDir, ".switchroom");
49922
+ const out = join88(dir, "install-type.json");
49834
49923
  const tmp = `${out}.tmp`;
49835
- mkdirSync49(dir, { recursive: true });
49924
+ mkdirSync50(dir, { recursive: true });
49836
49925
  const payload = {
49837
49926
  install_type: ctx.install_type,
49838
49927
  detected_at: new Date().toISOString(),
49839
49928
  source_paths: ctx.source_paths
49840
49929
  };
49841
- writeFileSync31(tmp, JSON.stringify(payload, null, 2), { mode: 420 });
49842
- renameSync20(tmp, out);
49930
+ writeFileSync32(tmp, JSON.stringify(payload, null, 2), { mode: 420 });
49931
+ renameSync21(tmp, out);
49843
49932
  return out;
49844
49933
  }
49845
49934
  async function runApply(config, options, deps = {}, switchroomConfigPath) {
@@ -49897,17 +49986,17 @@ Applying switchroom config...
49897
49986
  writeOut(source_default.green(` + ${name}`) + source_default.gray(` (${agentConfig.extends ?? "default"}) \u2014 ${detail}
49898
49987
  `));
49899
49988
  try {
49900
- installUpdatePromptHook(join87(agentsDir, name));
49989
+ installUpdatePromptHook(join88(agentsDir, name));
49901
49990
  } catch (hookErr) {
49902
49991
  writeOut(source_default.gray(` (update-prompt hook install failed for ${name}: ${hookErr.message})
49903
49992
  `));
49904
49993
  }
49905
- await refreshAgentConnectionHealth(config, name, join87(agentsDir, name), {
49994
+ await refreshAgentConnectionHealth(config, name, join88(agentsDir, name), {
49906
49995
  vaultAclReader: connHealthVaultAclReader
49907
49996
  });
49908
49997
  try {
49909
49998
  const uid = allocateAgentUid(name);
49910
- alignAgentUid(name, join87(agentsDir, name), uid, {
49999
+ alignAgentUid(name, join88(agentsDir, name), uid, {
49911
50000
  confirm: !options.nonInteractive,
49912
50001
  writeOut
49913
50002
  });
@@ -49952,7 +50041,7 @@ Applying switchroom config...
49952
50041
  for (const name of agentNames) {
49953
50042
  try {
49954
50043
  const uid = allocateAgentUid(name);
49955
- alignAgentUid(name, join87(agentsDir, name), uid, {
50044
+ alignAgentUid(name, join88(agentsDir, name), uid, {
49956
50045
  confirm: !options.nonInteractive,
49957
50046
  writeOut
49958
50047
  });
@@ -50290,18 +50379,18 @@ function copyExampleConfig2(name) {
50290
50379
  throw new Error(`Invalid example name: ${name} (must match /^[a-z0-9_-]+$/)`);
50291
50380
  }
50292
50381
  const dest = resolve52(process.cwd(), "switchroom.yaml");
50293
- if (existsSync86(dest)) {
50382
+ if (existsSync87(dest)) {
50294
50383
  console.error(source_default.yellow("switchroom.yaml already exists \u2014 skipping example copy"));
50295
50384
  return;
50296
50385
  }
50297
50386
  const embedded = EMBEDDED_EXAMPLES[name];
50298
50387
  if (embedded !== undefined) {
50299
- writeFileSync31(dest, embedded, { encoding: "utf8" });
50388
+ writeFileSync32(dest, embedded, { encoding: "utf8" });
50300
50389
  console.log(source_default.green(`Copied ${name}.yaml -> switchroom.yaml`));
50301
50390
  return;
50302
50391
  }
50303
50392
  const exampleFile = resolve52(import.meta.dirname, `../../examples/${name}.yaml`);
50304
- if (!existsSync86(exampleFile)) {
50393
+ if (!existsSync87(exampleFile)) {
50305
50394
  throw new Error(`Example config not found: ${name}.yaml (available: ${Object.keys(EMBEDDED_EXAMPLES).join(", ")})`);
50306
50395
  }
50307
50396
  copyFileSync12(exampleFile, dest);
@@ -50312,8 +50401,8 @@ function findUnwritableAgentDirs(config, opts) {
50312
50401
  const targets = opts.only ? [opts.only] : Object.keys(config.agents ?? {});
50313
50402
  const unwritable = [];
50314
50403
  for (const name of targets) {
50315
- const startSh = join87(agentsDir, name, "start.sh");
50316
- if (!existsSync86(startSh))
50404
+ const startSh = join88(agentsDir, name, "start.sh");
50405
+ if (!existsSync87(startSh))
50317
50406
  continue;
50318
50407
  try {
50319
50408
  accessSync3(startSh, fsConstants6.W_OK);
@@ -50518,7 +50607,7 @@ var init_apply = __esm(() => {
50518
50607
  switchroom: switchroom_default,
50519
50608
  minimal: minimal_default
50520
50609
  };
50521
- DEFAULT_COMPOSE_PATH2 = join87(homedir49(), ".switchroom", "compose", "docker-compose.yml");
50610
+ DEFAULT_COMPOSE_PATH2 = join88(homedir49(), ".switchroom", "compose", "docker-compose.yml");
50522
50611
  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
50612
  ` + "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
50613
  SELF_ELEVATE_PRESERVED_ENV = [
@@ -59829,49 +59918,49 @@ var require_fast_uri = __commonJS((exports2, module) => {
59829
59918
  schemelessOptions.skipEscape = true;
59830
59919
  return serialize(resolved, schemelessOptions);
59831
59920
  }
59832
- function resolveComponent(base, relative4, options, skipNormalization) {
59921
+ function resolveComponent(base, relative6, options, skipNormalization) {
59833
59922
  const target = {};
59834
59923
  if (!skipNormalization) {
59835
59924
  base = parse6(serialize(base, options), options);
59836
- relative4 = parse6(serialize(relative4, options), options);
59925
+ relative6 = parse6(serialize(relative6, options), options);
59837
59926
  }
59838
59927
  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;
59928
+ if (!options.tolerant && relative6.scheme) {
59929
+ target.scheme = relative6.scheme;
59930
+ target.userinfo = relative6.userinfo;
59931
+ target.host = relative6.host;
59932
+ target.port = relative6.port;
59933
+ target.path = removeDotSegments(relative6.path || "");
59934
+ target.query = relative6.query;
59846
59935
  } 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;
59936
+ if (relative6.userinfo !== undefined || relative6.host !== undefined || relative6.port !== undefined) {
59937
+ target.userinfo = relative6.userinfo;
59938
+ target.host = relative6.host;
59939
+ target.port = relative6.port;
59940
+ target.path = removeDotSegments(relative6.path || "");
59941
+ target.query = relative6.query;
59853
59942
  } else {
59854
- if (!relative4.path) {
59943
+ if (!relative6.path) {
59855
59944
  target.path = base.path;
59856
- if (relative4.query !== undefined) {
59857
- target.query = relative4.query;
59945
+ if (relative6.query !== undefined) {
59946
+ target.query = relative6.query;
59858
59947
  } else {
59859
59948
  target.query = base.query;
59860
59949
  }
59861
59950
  } else {
59862
- if (relative4.path[0] === "/") {
59863
- target.path = removeDotSegments(relative4.path);
59951
+ if (relative6.path[0] === "/") {
59952
+ target.path = removeDotSegments(relative6.path);
59864
59953
  } else {
59865
59954
  if ((base.userinfo !== undefined || base.host !== undefined || base.port !== undefined) && !base.path) {
59866
- target.path = "/" + relative4.path;
59955
+ target.path = "/" + relative6.path;
59867
59956
  } else if (!base.path) {
59868
- target.path = relative4.path;
59957
+ target.path = relative6.path;
59869
59958
  } else {
59870
- target.path = base.path.slice(0, base.path.lastIndexOf("/") + 1) + relative4.path;
59959
+ target.path = base.path.slice(0, base.path.lastIndexOf("/") + 1) + relative6.path;
59871
59960
  }
59872
59961
  target.path = removeDotSegments(target.path);
59873
59962
  }
59874
- target.query = relative4.query;
59963
+ target.query = relative6.query;
59875
59964
  }
59876
59965
  target.userinfo = base.userinfo;
59877
59966
  target.host = base.host;
@@ -59879,7 +59968,7 @@ var require_fast_uri = __commonJS((exports2, module) => {
59879
59968
  }
59880
59969
  target.scheme = base.scheme;
59881
59970
  }
59882
- target.fragment = relative4.fragment;
59971
+ target.fragment = relative6.fragment;
59883
59972
  return target;
59884
59973
  }
59885
59974
  function equal(uriA, uriB, options) {
@@ -63967,7 +64056,7 @@ __export(exports_server2, {
63967
64056
  TOOLS: () => TOOLS2
63968
64057
  });
63969
64058
  import { randomBytes as randomBytes16 } from "node:crypto";
63970
- import { existsSync as existsSync95, readFileSync as readFileSync83 } from "node:fs";
64059
+ import { existsSync as existsSync96, readFileSync as readFileSync84 } from "node:fs";
63971
64060
  function selfSocketPath() {
63972
64061
  return `/run/switchroom/hostd/${SELF_AGENT}/sock`;
63973
64062
  }
@@ -63994,7 +64083,7 @@ async function dispatchTool2(name, args) {
63994
64083
  return errorText2("hostd MCP: SWITCHROOM_AGENT_NAME env var is not set \u2014 cannot " + "determine which per-agent socket to talk to.");
63995
64084
  }
63996
64085
  const sockPath = selfSocketPath();
63997
- if (!existsSync95(sockPath)) {
64086
+ if (!existsSync96(sockPath)) {
63998
64087
  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
64088
  }
64000
64089
  let req;
@@ -64245,18 +64334,18 @@ function resolveAuditLogPath() {
64245
64334
  if (process.env.HOSTD_AUDIT_LOG_PATH)
64246
64335
  return process.env.HOSTD_AUDIT_LOG_PATH;
64247
64336
  const bindMounted = "/host-home/.switchroom/host-control-audit.log";
64248
- if (existsSync95(bindMounted))
64337
+ if (existsSync96(bindMounted))
64249
64338
  return bindMounted;
64250
64339
  return defaultAuditLogPath2();
64251
64340
  }
64252
64341
  function getLastUpdateApplyStatus() {
64253
64342
  const path9 = resolveAuditLogPath();
64254
- if (!existsSync95(path9)) {
64343
+ if (!existsSync96(path9)) {
64255
64344
  return errorText2(`get_status: audit log not found at ${path9}. No update_apply has run yet?`);
64256
64345
  }
64257
64346
  let raw;
64258
64347
  try {
64259
- raw = readFileSync83(path9, "utf-8");
64348
+ raw = readFileSync84(path9, "utf-8");
64260
64349
  } catch (err2) {
64261
64350
  return errorText2(`get_status: failed to read audit log at ${path9}: ${err2.message}`);
64262
64351
  }
@@ -65006,14 +65095,14 @@ var init_header_passthrough_guard = __esm(() => {
65006
65095
  });
65007
65096
 
65008
65097
  // src/fleet-health/litellm-config-sensor.ts
65009
- import { readFileSync as readFileSync85, existsSync as existsSync98 } from "node:fs";
65098
+ import { readFileSync as readFileSync86, existsSync as existsSync99 } from "node:fs";
65010
65099
  function resolveLitellmConfigPath(explicit) {
65011
65100
  return explicit ?? process.env.LITELLM_CONFIG_PATH ?? DEFAULT_LITELLM_CONFIG_PATH;
65012
65101
  }
65013
65102
  function scanLitellmConfig(opts = {}) {
65014
65103
  const path9 = resolveLitellmConfigPath(opts.path);
65015
- const exists = opts.existsFn ?? existsSync98;
65016
- const read = opts.readFn ?? ((p) => readFileSync85(p, "utf-8"));
65104
+ const exists = opts.existsFn ?? existsSync99;
65105
+ const read = opts.readFn ?? ((p) => readFileSync86(p, "utf-8"));
65017
65106
  const log = opts.log ?? (() => {});
65018
65107
  const nowIso = opts.nowIso ?? new Date().toISOString();
65019
65108
  if (!exists(path9)) {
@@ -65068,23 +65157,23 @@ __export(exports_scan, {
65068
65157
  ledgerPathForBase: () => ledgerPathForBase
65069
65158
  });
65070
65159
  import {
65071
- readFileSync as readFileSync86,
65072
- readdirSync as readdirSync38,
65073
- existsSync as existsSync99,
65074
- mkdirSync as mkdirSync56,
65075
- writeFileSync as writeFileSync37
65160
+ readFileSync as readFileSync87,
65161
+ readdirSync as readdirSync39,
65162
+ existsSync as existsSync100,
65163
+ mkdirSync as mkdirSync57,
65164
+ writeFileSync as writeFileSync38
65076
65165
  } from "node:fs";
65077
- import { resolve as resolve57, dirname as dirname33 } from "node:path";
65166
+ import { resolve as resolve57, dirname as dirname35 } from "node:path";
65078
65167
  import { homedir as homedir58 } from "node:os";
65079
65168
  function resolveSwitchroomBase(home2 = process.env.SWITCHROOM_HOME ?? process.env.HOME ?? homedir58()) {
65080
65169
  return resolve57(home2, ".switchroom");
65081
65170
  }
65082
65171
  function listAgents(base) {
65083
65172
  const dir = resolve57(base, "agents");
65084
- if (!existsSync99(dir))
65173
+ if (!existsSync100(dir))
65085
65174
  return [];
65086
65175
  try {
65087
- return readdirSync38(dir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name).sort();
65176
+ return readdirSync39(dir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name).sort();
65088
65177
  } catch {
65089
65178
  return [];
65090
65179
  }
@@ -65110,16 +65199,16 @@ function runScan(opts = {}) {
65110
65199
  let gwText = "";
65111
65200
  let sawArtifact = false;
65112
65201
  try {
65113
- if (existsSync99(turnsPath)) {
65114
- turnsText = readFileSync86(turnsPath, "utf-8");
65202
+ if (existsSync100(turnsPath)) {
65203
+ turnsText = readFileSync87(turnsPath, "utf-8");
65115
65204
  sawArtifact = true;
65116
65205
  }
65117
65206
  } catch (e) {
65118
65207
  log(`fleet-health: WARN skipping ${agent} turns.jsonl unreadable: ${String(e)}`);
65119
65208
  }
65120
65209
  try {
65121
- if (existsSync99(gwPath)) {
65122
- gwText = readFileSync86(gwPath, "utf-8");
65210
+ if (existsSync100(gwPath)) {
65211
+ gwText = readFileSync87(gwPath, "utf-8");
65123
65212
  sawArtifact = true;
65124
65213
  }
65125
65214
  } catch (e) {
@@ -65161,20 +65250,20 @@ function runScan(opts = {}) {
65161
65250
  function readLedgerIfPresent(base) {
65162
65251
  const path9 = ledgerPathForBase(base);
65163
65252
  try {
65164
- if (!existsSync99(path9))
65253
+ if (!existsSync100(path9))
65165
65254
  return null;
65166
- return JSON.parse(readFileSync86(path9, "utf-8"));
65255
+ return JSON.parse(readFileSync87(path9, "utf-8"));
65167
65256
  } catch {
65168
65257
  return null;
65169
65258
  }
65170
65259
  }
65171
65260
  function ledgerPathForBase(base) {
65172
- return fleetHealthLedgerPath(dirname33(base));
65261
+ return fleetHealthLedgerPath(dirname35(base));
65173
65262
  }
65174
65263
  function writeLedger(base, ledger) {
65175
65264
  const path9 = ledgerPathForBase(base);
65176
- mkdirSync56(dirname33(path9), { recursive: true });
65177
- writeFileSync37(path9, JSON.stringify(ledger, null, 2) + `
65265
+ mkdirSync57(dirname35(path9), { recursive: true });
65266
+ writeFileSync38(path9, JSON.stringify(ledger, null, 2) + `
65178
65267
  `, "utf-8");
65179
65268
  return path9;
65180
65269
  }
@@ -72180,7 +72269,7 @@ init_audit_log();
72180
72269
  init_test_isolation_guard();
72181
72270
  import * as net3 from "node:net";
72182
72271
  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";
72272
+ import { dirname as dirname15, resolve as resolve29, basename as basename7 } from "node:path";
72184
72273
  import * as os4 from "node:os";
72185
72274
  import * as path4 from "node:path";
72186
72275
 
@@ -74556,7 +74645,7 @@ class VaultBroker {
74556
74645
  this.passphrase = this.testOpts._testPassphrase;
74557
74646
  }
74558
74647
  process.umask(63);
74559
- const parentDir = dirname13(this.socketPath);
74648
+ const parentDir = dirname15(this.socketPath);
74560
74649
  mkdirSync25(parentDir, { recursive: true, mode: 448 });
74561
74650
  try {
74562
74651
  chmodSync9(parentDir, 448);
@@ -76101,15 +76190,15 @@ class VaultBroker {
76101
76190
  }
76102
76191
  }
76103
76192
  function detectVaultLayoutDrift(vaultPath) {
76104
- const dir = dirname13(vaultPath);
76193
+ const dir = dirname15(vaultPath);
76105
76194
  if (basename7(dir) !== "vault")
76106
76195
  return;
76107
76196
  if (basename7(vaultPath) !== "vault.enc")
76108
76197
  return;
76109
- const switchroomDir = dirname13(dir);
76198
+ const switchroomDir = dirname15(dir);
76110
76199
  if (basename7(switchroomDir) !== ".switchroom")
76111
76200
  return;
76112
- const home2 = dirname13(switchroomDir);
76201
+ const home2 = dirname15(switchroomDir);
76113
76202
  const result = inspectVaultLayout(home2);
76114
76203
  if (result.kind === "divergent") {
76115
76204
  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 +79679,7 @@ import {
79590
79679
  writeSync as writeSync8,
79591
79680
  constants as fsConstants3
79592
79681
  } from "node:fs";
79593
- import { resolve as resolve34, extname, join as join51, relative, dirname as dirname16 } from "node:path";
79682
+ import { resolve as resolve34, extname, join as join51, relative as relative3, dirname as dirname18 } from "node:path";
79594
79683
  import { homedir as homedir28 } from "node:os";
79595
79684
  import { timingSafeEqual as timingSafeEqual3, randomBytes as randomBytes11 } from "node:crypto";
79596
79685
 
@@ -83051,7 +83140,7 @@ function resolveWebToken() {
83051
83140
  return existing;
83052
83141
  }
83053
83142
  const token = randomBytes11(32).toString("hex");
83054
- mkdirSync31(dirname16(tokenPath), { recursive: true, mode: 448 });
83143
+ mkdirSync31(dirname18(tokenPath), { recursive: true, mode: 448 });
83055
83144
  try {
83056
83145
  const fd = openSync11(tokenPath, fsConstants3.O_WRONLY | fsConstants3.O_CREAT | fsConstants3.O_EXCL, 384);
83057
83146
  try {
@@ -83638,7 +83727,7 @@ function startWebServer(config, port, hostname = "127.0.0.1", configPath) {
83638
83727
  } catch {
83639
83728
  return new Response("Not Found", { status: 404 });
83640
83729
  }
83641
- const rel = relative(uiDir, realFullPath);
83730
+ const rel = relative3(uiDir, realFullPath);
83642
83731
  if (rel.startsWith("..") || resolve34(uiDir, rel) !== realFullPath) {
83643
83732
  return new Response("Forbidden", { status: 403 });
83644
83733
  }
@@ -83768,7 +83857,7 @@ init_loader();
83768
83857
 
83769
83858
  // src/web/startup-guard.ts
83770
83859
  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";
83860
+ import { dirname as dirname19 } from "node:path";
83772
83861
  function detectConfigMountFault(configPath, deps = {}) {
83773
83862
  const stat = deps.stat ?? ((p) => statSync33(p));
83774
83863
  let st;
@@ -83815,7 +83904,7 @@ function readCrashState(statePath) {
83815
83904
  }
83816
83905
  function writeCrashState(statePath, state) {
83817
83906
  try {
83818
- mkdirSync32(dirname17(statePath), { recursive: true });
83907
+ mkdirSync32(dirname19(statePath), { recursive: true });
83819
83908
  writeFileSync18(statePath, JSON.stringify(state), { mode: 384 });
83820
83909
  } catch {}
83821
83910
  }
@@ -83911,7 +84000,7 @@ init_atomic();
83911
84000
  init_loader();
83912
84001
  init_scaffold();
83913
84002
  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";
84003
+ import { resolve as resolve35, dirname as dirname20 } from "node:path";
83915
84004
  init_state();
83916
84005
  init_vault();
83917
84006
  init_manager();
@@ -84223,7 +84312,7 @@ async function copyExampleConfig(nonInteractive) {
84223
84312
  if (!existsSync59(srcFile)) {
84224
84313
  throw new ConfigError(`Example config not found: ${choice}.yaml`);
84225
84314
  }
84226
- mkdirSync33(dirname18(destFile), { recursive: true });
84315
+ mkdirSync33(dirname20(destFile), { recursive: true });
84227
84316
  copyFileSync9(srcFile, destFile);
84228
84317
  console.log(source_default.green(` Copied ${choice}.yaml -> ${destFile}`));
84229
84318
  console.log(source_default.yellow(` Edit ${destFile} to customize, then re-run switchroom setup.`));
@@ -85003,9 +85092,9 @@ init_source();
85003
85092
  init_loader();
85004
85093
  init_lifecycle();
85005
85094
  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";
85095
+ import { existsSync as existsSync68, mkdirSync as mkdirSync36, readFileSync as readFileSync61, realpathSync as realpathSync6, statSync as statSync40, chownSync as chownSync5 } from "node:fs";
85007
85096
  import { spawnSync as spawnSync12 } from "node:child_process";
85008
- import { join as join69, dirname as dirname21, resolve as resolve40 } from "node:path";
85097
+ import { join as join70, dirname as dirname23, resolve as resolve40 } from "node:path";
85009
85098
  import { homedir as homedir40 } from "node:os";
85010
85099
 
85011
85100
  // src/cli/release-yaml.ts
@@ -85096,10 +85185,132 @@ ${lines.join(`
85096
85185
 
85097
85186
  // src/cli/update.ts
85098
85187
  init_hindsight();
85188
+ init_scaffold_integration();
85189
+
85190
+ // src/cli/sync-bundled-skills.ts
85191
+ import {
85192
+ cpSync as cpSync2,
85193
+ existsSync as existsSync67,
85194
+ mkdirSync as mkdirSync35,
85195
+ readFileSync as readFileSync60,
85196
+ readdirSync as readdirSync24,
85197
+ renameSync as renameSync16,
85198
+ rmSync as rmSync12,
85199
+ writeFileSync as writeFileSync19
85200
+ } from "node:fs";
85201
+ import { join as join69 } from "node:path";
85202
+ var BUNDLED_SKILL_MANIFEST_NAME = ".switchroom-manifest.json";
85203
+ function listSkillDirs(dir) {
85204
+ if (!existsSync67(dir))
85205
+ return [];
85206
+ return readdirSync24(dir, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name);
85207
+ }
85208
+ function readBundledSkillManifest(poolDir) {
85209
+ const path5 = join69(poolDir, BUNDLED_SKILL_MANIFEST_NAME);
85210
+ if (!existsSync67(path5))
85211
+ return { firstRun: true };
85212
+ try {
85213
+ const parsed = JSON.parse(readFileSync60(path5, "utf8"));
85214
+ if (!parsed || typeof parsed !== "object" || !Array.isArray(parsed.skills) || !parsed.skills.every((s) => typeof s === "string")) {
85215
+ return { corrupt: true };
85216
+ }
85217
+ const m = parsed;
85218
+ return { manifest: { version: String(m.version ?? ""), skills: m.skills, updatedAt: String(m.updatedAt ?? "") } };
85219
+ } catch {
85220
+ return { corrupt: true };
85221
+ }
85222
+ }
85223
+ function stageAndSwap(srcSkill, destSkill, poolDir, name) {
85224
+ const staging = join69(poolDir, `.tmp-${name}-${process.pid}-${Date.now()}`);
85225
+ try {
85226
+ rmSync12(staging, { recursive: true, force: true });
85227
+ cpSync2(srcSkill, staging, { recursive: true, dereference: false });
85228
+ rmSync12(destSkill, { recursive: true, force: true });
85229
+ renameSync16(staging, destSkill);
85230
+ } finally {
85231
+ rmSync12(staging, { recursive: true, force: true });
85232
+ }
85233
+ }
85234
+ function syncBundledSkills(opts) {
85235
+ const { source, dest, version: version2 } = opts;
85236
+ const result = {
85237
+ added: [],
85238
+ updated: [],
85239
+ removed: [],
85240
+ preserved: [],
85241
+ ownershipTransferred: [],
85242
+ firstRun: false,
85243
+ manifestCorrupt: false
85244
+ };
85245
+ mkdirSync35(dest, { recursive: true });
85246
+ const prior = readBundledSkillManifest(dest);
85247
+ const priorSkills = new Set("manifest" in prior ? prior.manifest.skills : []);
85248
+ result.firstRun = "firstRun" in prior;
85249
+ result.manifestCorrupt = "corrupt" in prior;
85250
+ const shipped = listSkillDirs(source).sort();
85251
+ const shippedSet = new Set(shipped);
85252
+ for (const name of shipped) {
85253
+ const destSkill = join69(dest, name);
85254
+ const existed = existsSync67(destSkill);
85255
+ let transferred = false;
85256
+ if (existed && !priorSkills.has(name) && !result.firstRun) {
85257
+ const backup = join69(dest, `${name}.operator-backup-${process.pid}-${Date.now()}`);
85258
+ try {
85259
+ renameSync16(destSkill, backup);
85260
+ transferred = true;
85261
+ result.ownershipTransferred.push(name);
85262
+ 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.
85263
+ `);
85264
+ } catch {
85265
+ result.ownershipTransferred.push(name);
85266
+ 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.
85267
+ `);
85268
+ continue;
85269
+ }
85270
+ }
85271
+ stageAndSwap(join69(source, name), destSkill, dest, name);
85272
+ if (!transferred && (priorSkills.has(name) || existed))
85273
+ result.updated.push(name);
85274
+ else
85275
+ result.added.push(name);
85276
+ }
85277
+ if (!result.firstRun && !result.manifestCorrupt) {
85278
+ for (const name of priorSkills) {
85279
+ if (shippedSet.has(name))
85280
+ continue;
85281
+ const target = join69(dest, name);
85282
+ if (existsSync67(target)) {
85283
+ rmSync12(target, { recursive: true, force: true });
85284
+ result.removed.push(name);
85285
+ }
85286
+ }
85287
+ }
85288
+ for (const name of listSkillDirs(dest)) {
85289
+ if (!shippedSet.has(name) && !priorSkills.has(name)) {
85290
+ result.preserved.push(name);
85291
+ }
85292
+ }
85293
+ result.removed.sort();
85294
+ result.preserved.sort();
85295
+ const manifest = {
85296
+ version: version2,
85297
+ skills: shipped,
85298
+ updatedAt: new Date().toISOString()
85299
+ };
85300
+ const manifestPath = join69(dest, BUNDLED_SKILL_MANIFEST_NAME);
85301
+ const manifestTmp = join69(dest, `${BUNDLED_SKILL_MANIFEST_NAME}.tmp-${process.pid}-${Date.now()}`);
85302
+ writeFileSync19(manifestTmp, JSON.stringify(manifest, null, 2) + `
85303
+ `, "utf8");
85304
+ renameSync16(manifestTmp, manifestPath);
85305
+ return result;
85306
+ }
85307
+
85308
+ // src/cli/update.ts
85309
+ init_resolve_version();
85099
85310
  function defaultPersistPin(configPath) {
85100
85311
  return (pin) => {
85101
85312
  const path5 = configPath ?? findConfigFile();
85102
- const before = readFileSync60(path5, "utf8");
85313
+ const before = readFileSync61(path5, "utf8");
85103
85314
  const after = setReleasePinInConfig(before, pin);
85104
85315
  if (after === before)
85105
85316
  return;
@@ -85113,18 +85324,18 @@ function defaultPersistPin(configPath) {
85113
85324
  } catch {}
85114
85325
  };
85115
85326
  }
85116
- var DEFAULT_COMPOSE_PATH = join69(homedir40(), ".switchroom", "compose", "docker-compose.yml");
85327
+ var DEFAULT_COMPOSE_PATH = join70(homedir40(), ".switchroom", "compose", "docker-compose.yml");
85117
85328
  function runningFromSwitchroomCheckout(scriptPath) {
85118
- let dir = dirname21(scriptPath);
85329
+ let dir = dirname23(scriptPath);
85119
85330
  for (let i = 0;i < 12; i++) {
85120
- if (existsSync67(join69(dir, ".git"))) {
85331
+ if (existsSync68(join70(dir, ".git"))) {
85121
85332
  try {
85122
- const pkg = JSON.parse(readFileSync60(join69(dir, "package.json"), "utf-8"));
85333
+ const pkg = JSON.parse(readFileSync61(join70(dir, "package.json"), "utf-8"));
85123
85334
  if (pkg.name === "switchroom")
85124
85335
  return true;
85125
85336
  } catch {}
85126
85337
  }
85127
- const parent = dirname21(dir);
85338
+ const parent = dirname23(dir);
85128
85339
  if (parent === dir)
85129
85340
  break;
85130
85341
  dir = parent;
@@ -85204,7 +85415,7 @@ function planUpdate(opts) {
85204
85415
  steps.push({
85205
85416
  name: "pull-images",
85206
85417
  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,
85418
+ skipReason: opts.skipImages ? "--skip-images flag set" : !existsSync68(composePath) ? `compose file not found at ${composePath} (run \`switchroom apply --compose-only\` first)` : undefined,
85208
85419
  run: () => {
85209
85420
  const r = runner("docker", [
85210
85421
  "compose",
@@ -85330,23 +85541,48 @@ function planUpdate(opts) {
85330
85541
  return;
85331
85542
  }
85332
85543
  const source = resolve40(import.meta.dirname, "../../skills");
85333
- const dest = join69(homedir40(), ".switchroom", "skills", "_bundled");
85334
- if (!existsSync67(source)) {
85544
+ const dest = join70(homedir40(), ".switchroom", "skills", "_bundled");
85545
+ if (!existsSync68(source)) {
85335
85546
  process.stderr.write(`switchroom update: sync-bundled-skills \u2014 CLI bundle has no adjacent skills/ at ${source}; skipping.
85336
85547
  `);
85337
85548
  return;
85338
85549
  }
85339
85550
  try {
85340
- if (existsSync67(dest)) {
85341
- rmSync12(dest, { recursive: true, force: true });
85551
+ mkdirSync36(dirname23(dest), { recursive: true });
85552
+ const r = syncBundledSkills({
85553
+ source,
85554
+ dest,
85555
+ version: SWITCHROOM_VERSION
85556
+ });
85557
+ if (r.manifestCorrupt) {
85558
+ process.stderr.write(`switchroom update: sync-bundled-skills \u2014 pool manifest was unreadable; ` + `deleted nothing (fail-closed) and rewrote a clean manifest.
85559
+ `);
85560
+ }
85561
+ if (r.removed.length > 0) {
85562
+ process.stderr.write(`switchroom update: sync-bundled-skills \u2014 removed ${r.removed.length} retired ` + `bundled skill(s): ${r.removed.join(", ")}.
85563
+ `);
85342
85564
  }
85343
- mkdirSync35(dirname21(dest), { recursive: true });
85344
- cpSync2(source, dest, { recursive: true, dereference: false });
85345
85565
  } catch (err) {
85346
85566
  throw new Error(`sync-bundled-skills failed: ${err.message}`);
85347
85567
  }
85348
85568
  }
85349
85569
  });
85570
+ steps.push({
85571
+ name: "verify-bundled-skills",
85572
+ description: "Assert every builtin default skill is present in ~/.switchroom/skills/_bundled/ after sync.",
85573
+ run: () => {
85574
+ if (opts.syncBundledSkillsFn)
85575
+ return;
85576
+ const dest = join70(homedir40(), ".switchroom", "skills", "_bundled");
85577
+ if (!existsSync68(dest)) {
85578
+ return;
85579
+ }
85580
+ const missing = getBuiltinDefaultSkillEntries().map((e) => e.key).filter((key) => !existsSync68(join70(dest, key)));
85581
+ if (missing.length > 0) {
85582
+ 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.`);
85583
+ }
85584
+ }
85585
+ });
85350
85586
  steps.push({
85351
85587
  name: "stamp-restart-marker",
85352
85588
  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 +85612,7 @@ function planUpdate(opts) {
85376
85612
  description: "docker compose up -d --remove-orphans (recreates services with new images / compose)",
85377
85613
  run: () => {
85378
85614
  try {
85379
- const composeText = readFileSync60(composePath, "utf8");
85615
+ const composeText = readFileSync61(composePath, "utf8");
85380
85616
  const pf = validateBindSources(composeText);
85381
85617
  if (!pf.ok)
85382
85618
  throw new Error(formatPreflightError(pf));
@@ -85453,12 +85689,12 @@ function defaultStatusProbe(composePath) {
85453
85689
  try {
85454
85690
  cliBuiltAt = new Date(statSync40(scriptPath).mtimeMs).toISOString();
85455
85691
  } catch {}
85456
- let dir = dirname21(scriptPath);
85692
+ let dir = dirname23(scriptPath);
85457
85693
  for (let i = 0;i < 8; i++) {
85458
- const pkgPath = join69(dir, "package.json");
85459
- if (existsSync67(pkgPath)) {
85694
+ const pkgPath = join70(dir, "package.json");
85695
+ if (existsSync68(pkgPath)) {
85460
85696
  try {
85461
- const pkg = JSON.parse(readFileSync60(pkgPath, "utf-8"));
85697
+ const pkg = JSON.parse(readFileSync61(pkgPath, "utf-8"));
85462
85698
  if (typeof pkg.version === "string")
85463
85699
  cliVersion = pkg.version;
85464
85700
  } catch (err) {
@@ -85466,7 +85702,7 @@ function defaultStatusProbe(composePath) {
85466
85702
  }
85467
85703
  break;
85468
85704
  }
85469
- const parent = dirname21(dir);
85705
+ const parent = dirname23(dir);
85470
85706
  if (parent === dir)
85471
85707
  break;
85472
85708
  dir = parent;
@@ -85479,7 +85715,7 @@ function defaultStatusProbe(composePath) {
85479
85715
  warnings.push("could not resolve CLI version (no package.json found above the resolved script path)");
85480
85716
  }
85481
85717
  const services = [];
85482
- if (!existsSync67(composePath)) {
85718
+ if (!existsSync68(composePath)) {
85483
85719
  warnings.push(`compose file not found at ${composePath}; service status unknown`);
85484
85720
  return { cliVersion, cliBuiltAt, services, warnings };
85485
85721
  }
@@ -85675,7 +85911,7 @@ function registerUpdateCommand(program3) {
85675
85911
  // src/cli/rollout.ts
85676
85912
  init_helpers();
85677
85913
  import { spawnSync as spawnSync14 } from "node:child_process";
85678
- import { readFileSync as readFileSync61, chownSync as chownSync6, statSync as statSync41 } from "node:fs";
85914
+ import { readFileSync as readFileSync62, chownSync as chownSync6, statSync as statSync41 } from "node:fs";
85679
85915
  import { homedir as homedir41 } from "node:os";
85680
85916
  init_operator_uid();
85681
85917
  init_atomic();
@@ -85961,7 +86197,7 @@ function resolveRollbackTarget(auditLogPath) {
85961
86197
  const logPath = auditLogPath ?? defaultAuditLogPath2(homedir41());
85962
86198
  let raw;
85963
86199
  try {
85964
- raw = readFileSync61(logPath, "utf8");
86200
+ raw = readFileSync62(logPath, "utf8");
85965
86201
  } catch {
85966
86202
  return null;
85967
86203
  }
@@ -86079,7 +86315,7 @@ function registerRolloutCommand(program3) {
86079
86315
  `),
86080
86316
  webImageTag: () => deployedImageTag("switchroom-web"),
86081
86317
  persistPin: (pin) => {
86082
- const before = readFileSync61(configPath, "utf8");
86318
+ const before = readFileSync62(configPath, "utf8");
86083
86319
  const after = setReleasePinInConfig(before, pin);
86084
86320
  if (after === before)
86085
86321
  return;
@@ -86157,8 +86393,8 @@ init_helpers();
86157
86393
  init_lifecycle();
86158
86394
  init_resolve_version();
86159
86395
  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";
86396
+ import { existsSync as existsSync69, readFileSync as readFileSync63 } from "node:fs";
86397
+ import { dirname as dirname24, join as join71 } from "node:path";
86162
86398
  function getClaudeCodeVersion() {
86163
86399
  try {
86164
86400
  const out = execSync3("claude --version 2>/dev/null", {
@@ -86208,16 +86444,16 @@ function formatUptime3(timestamp) {
86208
86444
  function locateSwitchroomInstallDir() {
86209
86445
  let dir = import.meta.dirname;
86210
86446
  for (let i = 0;i < 10 && dir && dir !== "/"; i++) {
86211
- const pkgPath = join70(dir, "package.json");
86212
- if (existsSync68(pkgPath)) {
86447
+ const pkgPath = join71(dir, "package.json");
86448
+ if (existsSync69(pkgPath)) {
86213
86449
  try {
86214
- const pkg = JSON.parse(readFileSync62(pkgPath, "utf-8"));
86215
- if (pkg.name === "switchroom" && existsSync68(join70(dir, ".git"))) {
86450
+ const pkg = JSON.parse(readFileSync63(pkgPath, "utf-8"));
86451
+ if (pkg.name === "switchroom" && existsSync69(join71(dir, ".git"))) {
86216
86452
  return dir;
86217
86453
  }
86218
86454
  } catch {}
86219
86455
  }
86220
- dir = dirname22(dir);
86456
+ dir = dirname24(dir);
86221
86457
  }
86222
86458
  return null;
86223
86459
  }
@@ -86390,29 +86626,29 @@ import { resolve as resolve42 } from "node:path";
86390
86626
 
86391
86627
  // src/agents/session-retention.ts
86392
86628
  import {
86393
- existsSync as existsSync69,
86394
- readdirSync as readdirSync24,
86629
+ existsSync as existsSync70,
86630
+ readdirSync as readdirSync25,
86395
86631
  statSync as statSync42,
86396
86632
  unlinkSync as unlinkSync14
86397
86633
  } from "node:fs";
86398
- import { join as join71 } from "node:path";
86634
+ import { join as join72 } from "node:path";
86399
86635
  var DEFAULT_SESSION_RETENTION_MAX_COUNT = 20;
86400
86636
  var DEFAULT_SESSION_RETENTION_MAX_AGE_DAYS = 30;
86401
86637
  var MIN_KEEP = 2;
86402
86638
  function collectSessionJsonl(claudeConfigDir) {
86403
- const projects = join71(claudeConfigDir, "projects");
86404
- if (!existsSync69(projects))
86639
+ const projects = join72(claudeConfigDir, "projects");
86640
+ if (!existsSync70(projects))
86405
86641
  return [];
86406
86642
  const found = [];
86407
86643
  const walk2 = (dir) => {
86408
86644
  let entries;
86409
86645
  try {
86410
- entries = readdirSync24(dir);
86646
+ entries = readdirSync25(dir);
86411
86647
  } catch {
86412
86648
  return;
86413
86649
  }
86414
86650
  for (const name of entries) {
86415
- const full = join71(dir, name);
86651
+ const full = join72(dir, name);
86416
86652
  let st;
86417
86653
  try {
86418
86654
  st = statSync42(full);
@@ -86532,18 +86768,18 @@ function registerHandoffCommand(program3) {
86532
86768
  // src/issues/store.ts
86533
86769
  import {
86534
86770
  closeSync as closeSync12,
86535
- existsSync as existsSync70,
86536
- mkdirSync as mkdirSync36,
86771
+ existsSync as existsSync71,
86772
+ mkdirSync as mkdirSync37,
86537
86773
  openSync as openSync12,
86538
- readdirSync as readdirSync25,
86539
- readFileSync as readFileSync63,
86540
- renameSync as renameSync16,
86774
+ readdirSync as readdirSync26,
86775
+ readFileSync as readFileSync64,
86776
+ renameSync as renameSync17,
86541
86777
  statSync as statSync43,
86542
86778
  unlinkSync as unlinkSync15,
86543
- writeFileSync as writeFileSync19,
86779
+ writeFileSync as writeFileSync20,
86544
86780
  writeSync as writeSync9
86545
86781
  } from "node:fs";
86546
- import { join as join72 } from "node:path";
86782
+ import { join as join73 } from "node:path";
86547
86783
  import { randomBytes as randomBytes12 } from "node:crypto";
86548
86784
  import { execSync as execSync4 } from "node:child_process";
86549
86785
 
@@ -86974,12 +87210,12 @@ function redactedMarker(ruleId) {
86974
87210
  var ISSUES_FILE = "issues.jsonl";
86975
87211
  var ISSUES_LOCK = "issues.lock";
86976
87212
  function readAll(stateDir) {
86977
- const path5 = join72(stateDir, ISSUES_FILE);
86978
- if (!existsSync70(path5))
87213
+ const path5 = join73(stateDir, ISSUES_FILE);
87214
+ if (!existsSync71(path5))
86979
87215
  return [];
86980
87216
  let raw;
86981
87217
  try {
86982
- raw = readFileSync63(path5, "utf-8");
87218
+ raw = readFileSync64(path5, "utf-8");
86983
87219
  } catch {
86984
87220
  return [];
86985
87221
  }
@@ -87052,7 +87288,7 @@ function record(stateDir, input, nowFn = Date.now) {
87052
87288
  });
87053
87289
  }
87054
87290
  function resolve43(stateDir, fingerprint, nowFn = Date.now) {
87055
- if (!existsSync70(join72(stateDir, ISSUES_FILE)))
87291
+ if (!existsSync71(join73(stateDir, ISSUES_FILE)))
87056
87292
  return 0;
87057
87293
  return withLock(stateDir, () => {
87058
87294
  const all = readAll(stateDir);
@@ -87070,7 +87306,7 @@ function resolve43(stateDir, fingerprint, nowFn = Date.now) {
87070
87306
  });
87071
87307
  }
87072
87308
  function resolveAllBySource(stateDir, source, nowFn = Date.now) {
87073
- if (!existsSync70(join72(stateDir, ISSUES_FILE)))
87309
+ if (!existsSync71(join73(stateDir, ISSUES_FILE)))
87074
87310
  return 0;
87075
87311
  return withLock(stateDir, () => {
87076
87312
  const all = readAll(stateDir);
@@ -87088,7 +87324,7 @@ function resolveAllBySource(stateDir, source, nowFn = Date.now) {
87088
87324
  });
87089
87325
  }
87090
87326
  function prune(stateDir, opts = {}) {
87091
- if (!existsSync70(join72(stateDir, ISSUES_FILE)))
87327
+ if (!existsSync71(join73(stateDir, ISSUES_FILE)))
87092
87328
  return 0;
87093
87329
  return withLock(stateDir, () => {
87094
87330
  const all = readAll(stateDir);
@@ -87118,24 +87354,24 @@ function prune(stateDir, opts = {}) {
87118
87354
  });
87119
87355
  }
87120
87356
  function ensureDir(stateDir) {
87121
- mkdirSync36(stateDir, { recursive: true });
87357
+ mkdirSync37(stateDir, { recursive: true });
87122
87358
  }
87123
87359
  function writeAll(stateDir, events) {
87124
- const path5 = join72(stateDir, ISSUES_FILE);
87360
+ const path5 = join73(stateDir, ISSUES_FILE);
87125
87361
  sweepOrphanTmpFiles(stateDir);
87126
87362
  const tmp = `${path5}.tmp-${process.pid}-${randomBytes12(4).toString("hex")}`;
87127
87363
  const body = events.length === 0 ? "" : events.map((e) => JSON.stringify(e)).join(`
87128
87364
  `) + `
87129
87365
  `;
87130
- writeFileSync19(tmp, body, "utf-8");
87131
- renameSync16(tmp, path5);
87366
+ writeFileSync20(tmp, body, "utf-8");
87367
+ renameSync17(tmp, path5);
87132
87368
  }
87133
87369
  var ORPHAN_TMP_TTL_MS = 60000;
87134
87370
  var TMP_PREFIX = `${ISSUES_FILE}.tmp-`;
87135
87371
  function sweepOrphanTmpFiles(stateDir) {
87136
87372
  let entries;
87137
87373
  try {
87138
- entries = readdirSync25(stateDir);
87374
+ entries = readdirSync26(stateDir);
87139
87375
  } catch {
87140
87376
  return;
87141
87377
  }
@@ -87143,7 +87379,7 @@ function sweepOrphanTmpFiles(stateDir) {
87143
87379
  for (const entry of entries) {
87144
87380
  if (!entry.startsWith(TMP_PREFIX))
87145
87381
  continue;
87146
- const tmpPath = join72(stateDir, entry);
87382
+ const tmpPath = join73(stateDir, entry);
87147
87383
  try {
87148
87384
  const stat = statSync43(tmpPath);
87149
87385
  if (stat.mtimeMs < cutoff) {
@@ -87155,7 +87391,7 @@ function sweepOrphanTmpFiles(stateDir) {
87155
87391
  var LOCK_RETRY_MS = 25;
87156
87392
  var LOCK_TIMEOUT_MS = 1e4;
87157
87393
  function withLock(stateDir, fn) {
87158
- const lockPath = join72(stateDir, ISSUES_LOCK);
87394
+ const lockPath = join73(stateDir, ISSUES_LOCK);
87159
87395
  const startedAt = Date.now();
87160
87396
  let fd = null;
87161
87397
  while (fd === null) {
@@ -87190,7 +87426,7 @@ function withLock(stateDir, fn) {
87190
87426
  function tryStealStaleLock(lockPath) {
87191
87427
  let pidStr;
87192
87428
  try {
87193
- pidStr = readFileSync63(lockPath, "utf-8").trim();
87429
+ pidStr = readFileSync64(lockPath, "utf-8").trim();
87194
87430
  } catch {
87195
87431
  return true;
87196
87432
  }
@@ -87438,20 +87674,20 @@ function relTime(deltaMs) {
87438
87674
 
87439
87675
  // src/cli/deps.ts
87440
87676
  init_source();
87441
- import { existsSync as existsSync73 } from "node:fs";
87677
+ import { existsSync as existsSync74 } from "node:fs";
87442
87678
  import { homedir as homedir44 } from "node:os";
87443
- import { join as join75, resolve as resolve44 } from "node:path";
87679
+ import { join as join76, resolve as resolve44 } from "node:path";
87444
87680
 
87445
87681
  // src/deps/python.ts
87446
87682
  import { createHash as createHash13 } from "node:crypto";
87447
87683
  import {
87448
- existsSync as existsSync71,
87449
- mkdirSync as mkdirSync37,
87450
- readFileSync as readFileSync64,
87684
+ existsSync as existsSync72,
87685
+ mkdirSync as mkdirSync38,
87686
+ readFileSync as readFileSync65,
87451
87687
  rmSync as rmSync13,
87452
- writeFileSync as writeFileSync20
87688
+ writeFileSync as writeFileSync21
87453
87689
  } from "node:fs";
87454
- import { dirname as dirname23, join as join73 } from "node:path";
87690
+ import { dirname as dirname25, join as join74 } from "node:path";
87455
87691
  import { homedir as homedir42 } from "node:os";
87456
87692
  import { execFileSync as execFileSync21 } from "node:child_process";
87457
87693
 
@@ -87464,26 +87700,26 @@ class PythonEnvError extends Error {
87464
87700
  }
87465
87701
  }
87466
87702
  function defaultPythonCacheRoot() {
87467
- return join73(homedir42(), ".switchroom", "deps", "python");
87703
+ return join74(homedir42(), ".switchroom", "deps", "python");
87468
87704
  }
87469
87705
  function hashFile(path5) {
87470
- return createHash13("sha256").update(readFileSync64(path5)).digest("hex");
87706
+ return createHash13("sha256").update(readFileSync65(path5)).digest("hex");
87471
87707
  }
87472
87708
  function ensurePythonEnv(opts) {
87473
87709
  const { skillName, requirementsPath, force = false } = opts;
87474
87710
  const cacheRoot = opts.cacheRoot ?? defaultPythonCacheRoot();
87475
87711
  const hostPython = opts.pythonBin ?? "python3";
87476
- if (!existsSync71(requirementsPath)) {
87712
+ if (!existsSync72(requirementsPath)) {
87477
87713
  throw new PythonEnvError(`requirements file not found: ${requirementsPath}`);
87478
87714
  }
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");
87715
+ const venvDir = join74(cacheRoot, skillName);
87716
+ const stampPath = join74(venvDir, ".requirements.sha256");
87717
+ const binDir = join74(venvDir, "bin");
87718
+ const pythonBin = join74(binDir, "python");
87719
+ const pipBin = join74(binDir, "pip");
87484
87720
  const targetHash = hashFile(requirementsPath);
87485
- if (!force && existsSync71(stampPath) && existsSync71(pythonBin)) {
87486
- const existingHash = readFileSync64(stampPath, "utf8").trim();
87721
+ if (!force && existsSync72(stampPath) && existsSync72(pythonBin)) {
87722
+ const existingHash = readFileSync65(stampPath, "utf8").trim();
87487
87723
  if (existingHash === targetHash) {
87488
87724
  return {
87489
87725
  skillName,
@@ -87495,10 +87731,10 @@ function ensurePythonEnv(opts) {
87495
87731
  };
87496
87732
  }
87497
87733
  }
87498
- if (existsSync71(venvDir)) {
87734
+ if (existsSync72(venvDir)) {
87499
87735
  rmSync13(venvDir, { recursive: true, force: true });
87500
87736
  }
87501
- mkdirSync37(dirname23(venvDir), { recursive: true });
87737
+ mkdirSync38(dirname25(venvDir), { recursive: true });
87502
87738
  try {
87503
87739
  execFileSync21(hostPython, ["-m", "venv", venvDir], { stdio: "pipe" });
87504
87740
  } catch (err) {
@@ -87517,7 +87753,7 @@ function ensurePythonEnv(opts) {
87517
87753
  const e = err;
87518
87754
  throw new PythonEnvError(`Failed to install requirements for skill "${skillName}": ${e.message}`, e.stderr?.toString());
87519
87755
  }
87520
- writeFileSync20(stampPath, targetHash + `
87756
+ writeFileSync21(stampPath, targetHash + `
87521
87757
  `);
87522
87758
  return {
87523
87759
  skillName,
@@ -87533,13 +87769,13 @@ function ensurePythonEnv(opts) {
87533
87769
  import { createHash as createHash14 } from "node:crypto";
87534
87770
  import {
87535
87771
  copyFileSync as copyFileSync10,
87536
- existsSync as existsSync72,
87537
- mkdirSync as mkdirSync38,
87538
- readFileSync as readFileSync65,
87772
+ existsSync as existsSync73,
87773
+ mkdirSync as mkdirSync39,
87774
+ readFileSync as readFileSync66,
87539
87775
  rmSync as rmSync14,
87540
- writeFileSync as writeFileSync21
87776
+ writeFileSync as writeFileSync22
87541
87777
  } from "node:fs";
87542
- import { dirname as dirname24, join as join74 } from "node:path";
87778
+ import { dirname as dirname26, join as join75 } from "node:path";
87543
87779
  import { homedir as homedir43 } from "node:os";
87544
87780
  import { execFileSync as execFileSync22 } from "node:child_process";
87545
87781
 
@@ -87563,23 +87799,23 @@ var LOCKFILES_FOR = {
87563
87799
  npm: ["package-lock.json"]
87564
87800
  };
87565
87801
  function defaultNodeCacheRoot() {
87566
- return join74(homedir43(), ".switchroom", "deps", "node");
87802
+ return join75(homedir43(), ".switchroom", "deps", "node");
87567
87803
  }
87568
87804
  function hashDepInputs(packageJsonPath) {
87569
- const sourceDir = dirname24(packageJsonPath);
87805
+ const sourceDir = dirname26(packageJsonPath);
87570
87806
  const hasher = createHash14("sha256");
87571
87807
  hasher.update(`package.json
87572
87808
  `);
87573
- hasher.update(readFileSync65(packageJsonPath));
87809
+ hasher.update(readFileSync66(packageJsonPath));
87574
87810
  for (const lockName of ALL_LOCKFILES) {
87575
- const lockPath = join74(sourceDir, lockName);
87576
- if (existsSync72(lockPath)) {
87811
+ const lockPath = join75(sourceDir, lockName);
87812
+ if (existsSync73(lockPath)) {
87577
87813
  hasher.update(`
87578
87814
  `);
87579
87815
  hasher.update(lockName);
87580
87816
  hasher.update(`
87581
87817
  `);
87582
- hasher.update(readFileSync65(lockPath));
87818
+ hasher.update(readFileSync66(lockPath));
87583
87819
  }
87584
87820
  }
87585
87821
  return hasher.digest("hex");
@@ -87588,17 +87824,17 @@ function ensureNodeEnv(opts) {
87588
87824
  const { skillName, packageJsonPath, force = false } = opts;
87589
87825
  const cacheRoot = opts.cacheRoot ?? defaultNodeCacheRoot();
87590
87826
  const installer = opts.installer ?? "bun";
87591
- if (!existsSync72(packageJsonPath)) {
87827
+ if (!existsSync73(packageJsonPath)) {
87592
87828
  throw new NodeEnvError(`package.json not found: ${packageJsonPath}`);
87593
87829
  }
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");
87830
+ const sourceDir = dirname26(packageJsonPath);
87831
+ const envDir = join75(cacheRoot, skillName);
87832
+ const stampPath = join75(envDir, ".package.sha256");
87833
+ const nodeModulesDir = join75(envDir, "node_modules");
87834
+ const binDir = join75(nodeModulesDir, ".bin");
87599
87835
  const targetHash = hashDepInputs(packageJsonPath);
87600
- if (!force && existsSync72(stampPath) && existsSync72(nodeModulesDir)) {
87601
- const existingHash = readFileSync65(stampPath, "utf8").trim();
87836
+ if (!force && existsSync73(stampPath) && existsSync73(nodeModulesDir)) {
87837
+ const existingHash = readFileSync66(stampPath, "utf8").trim();
87602
87838
  if (existingHash === targetHash) {
87603
87839
  return {
87604
87840
  skillName,
@@ -87609,16 +87845,16 @@ function ensureNodeEnv(opts) {
87609
87845
  };
87610
87846
  }
87611
87847
  }
87612
- if (existsSync72(envDir)) {
87848
+ if (existsSync73(envDir)) {
87613
87849
  rmSync14(envDir, { recursive: true, force: true });
87614
87850
  }
87615
- mkdirSync38(envDir, { recursive: true });
87616
- copyFileSync10(packageJsonPath, join74(envDir, "package.json"));
87851
+ mkdirSync39(envDir, { recursive: true });
87852
+ copyFileSync10(packageJsonPath, join75(envDir, "package.json"));
87617
87853
  let copiedLockfile = false;
87618
87854
  for (const lockName of LOCKFILES_FOR[installer]) {
87619
- const lockPath = join74(sourceDir, lockName);
87620
- if (existsSync72(lockPath)) {
87621
- copyFileSync10(lockPath, join74(envDir, lockName));
87855
+ const lockPath = join75(sourceDir, lockName);
87856
+ if (existsSync73(lockPath)) {
87857
+ copyFileSync10(lockPath, join75(envDir, lockName));
87622
87858
  copiedLockfile = true;
87623
87859
  }
87624
87860
  }
@@ -87634,7 +87870,7 @@ function ensureNodeEnv(opts) {
87634
87870
  const e = err;
87635
87871
  throw new NodeEnvError(`Failed to install node deps for skill "${skillName}" with ${installer}: ${e.message}`, e.stderr?.toString());
87636
87872
  }
87637
- writeFileSync21(stampPath, targetHash + `
87873
+ writeFileSync22(stampPath, targetHash + `
87638
87874
  `);
87639
87875
  return {
87640
87876
  skillName,
@@ -87653,22 +87889,22 @@ function registerDepsCommand(program3) {
87653
87889
  const deps = program3.command("deps").description("Manage cached per-skill dependency environments");
87654
87890
  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
87891
  const skillsRoot = builtinSkillsRoot();
87656
- if (!existsSync73(skillsRoot)) {
87892
+ if (!existsSync74(skillsRoot)) {
87657
87893
  console.error(source_default.red(`Bundled skills pool dir not found at ${skillsRoot} \u2014 run \`switchroom update\` to install it.`));
87658
87894
  process.exit(1);
87659
87895
  }
87660
- const skillDir = join75(skillsRoot, skill);
87661
- if (!existsSync73(skillDir)) {
87896
+ const skillDir = join76(skillsRoot, skill);
87897
+ if (!existsSync74(skillDir)) {
87662
87898
  console.error(source_default.red(`Unknown skill: ${skill} (no dir at ${skillDir})`));
87663
87899
  process.exit(1);
87664
87900
  }
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));
87901
+ const requirementsPath = join76(skillDir, "requirements.txt");
87902
+ const packageJsonPath = join76(skillDir, "package.json");
87903
+ const wantPython = opts.python ?? (!opts.python && !opts.node && existsSync74(requirementsPath));
87904
+ const wantNode = opts.node ?? (!opts.python && !opts.node && existsSync74(packageJsonPath));
87669
87905
  let did = 0;
87670
87906
  if (wantPython) {
87671
- if (!existsSync73(requirementsPath)) {
87907
+ if (!existsSync74(requirementsPath)) {
87672
87908
  console.error(source_default.red(`Skill "${skill}" has no requirements.txt at ${requirementsPath}`));
87673
87909
  process.exit(1);
87674
87910
  }
@@ -87692,7 +87928,7 @@ function registerDepsCommand(program3) {
87692
87928
  }
87693
87929
  }
87694
87930
  if (wantNode) {
87695
- if (!existsSync73(packageJsonPath)) {
87931
+ if (!existsSync74(packageJsonPath)) {
87696
87932
  console.error(source_default.red(`Skill "${skill}" has no package.json at ${packageJsonPath}`));
87697
87933
  process.exit(1);
87698
87934
  }
@@ -87725,7 +87961,7 @@ function registerDepsCommand(program3) {
87725
87961
  // src/cli/workspace.ts
87726
87962
  init_helpers();
87727
87963
  init_loader();
87728
- import { existsSync as existsSync74 } from "node:fs";
87964
+ import { existsSync as existsSync75 } from "node:fs";
87729
87965
  import { resolve as resolve45, sep as sep3 } from "node:path";
87730
87966
  import { spawnSync as spawnSync15 } from "node:child_process";
87731
87967
 
@@ -88502,7 +88738,7 @@ function registerWorkspaceCommand(program3) {
88502
88738
  if (!dir)
88503
88739
  return;
88504
88740
  const gitDir = resolve45(dir, ".git");
88505
- if (!existsSync74(gitDir)) {
88741
+ if (!existsSync75(gitDir)) {
88506
88742
  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
88743
  `);
88508
88744
  return;
@@ -88556,7 +88792,7 @@ function registerWorkspaceCommand(program3) {
88556
88792
  if (!dir)
88557
88793
  return;
88558
88794
  const gitDir = resolve45(dir, ".git");
88559
- if (!existsSync74(gitDir)) {
88795
+ if (!existsSync75(gitDir)) {
88560
88796
  process.stdout.write(`Workspace is not a git repository.
88561
88797
  `);
88562
88798
  return;
@@ -88581,7 +88817,7 @@ function resolveAgentWorkspaceDirOrExit(program3, agentName) {
88581
88817
  const agentsDir = resolveAgentsDir(config);
88582
88818
  const agentDir = resolve45(agentsDir, agentName);
88583
88819
  const dir = resolveAgentWorkspaceDir(agentDir);
88584
- if (!existsSync74(dir)) {
88820
+ if (!existsSync75(dir)) {
88585
88821
  process.stderr.write(`workspace: ${dir} does not exist yet. Run \`switchroom setup\` or \`switchroom agent scaffold ${agentName}\` to seed it.
88586
88822
  `);
88587
88823
  return;
@@ -88617,8 +88853,8 @@ function safeParseInt(value, fallback) {
88617
88853
  init_helpers();
88618
88854
  init_loader();
88619
88855
  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";
88856
+ import { copyFileSync as copyFileSync11, existsSync as existsSync76, readFileSync as readFileSync67, writeFileSync as writeFileSync23 } from "node:fs";
88857
+ import { join as join77, resolve as resolve46 } from "node:path";
88622
88858
  init_scaffold();
88623
88859
  init_profiles();
88624
88860
  init_schema();
@@ -88635,7 +88871,7 @@ function resolveSoulTargetOrExit(program3, agentName) {
88635
88871
  const agentsDir = resolveAgentsDir(config);
88636
88872
  const agentDir = resolve46(agentsDir, agentName);
88637
88873
  const workspaceDir = resolveAgentWorkspaceDir(agentDir);
88638
- if (!existsSync75(workspaceDir)) {
88874
+ if (!existsSync76(workspaceDir)) {
88639
88875
  console.error(`soul: ${workspaceDir} does not exist yet. Run \`switchroom setup\` ` + `or \`switchroom agent scaffold ${agentName}\` to seed it.`);
88640
88876
  process.exit(1);
88641
88877
  }
@@ -88644,7 +88880,7 @@ function resolveSoulTargetOrExit(program3, agentName) {
88644
88880
  profileName,
88645
88881
  profilePath,
88646
88882
  workspaceDir,
88647
- soulPath: join76(workspaceDir, "SOUL.md"),
88883
+ soulPath: join77(workspaceDir, "SOUL.md"),
88648
88884
  soul: merged.soul
88649
88885
  };
88650
88886
  }
@@ -88661,11 +88897,11 @@ function registerSoulCommand(program3) {
88661
88897
  const t = resolveSoulTargetOrExit(program3, agentName);
88662
88898
  if (!t)
88663
88899
  return;
88664
- if (!existsSync75(t.soulPath)) {
88900
+ if (!existsSync76(t.soulPath)) {
88665
88901
  console.error(`soul: ${t.soulPath} does not exist yet \u2014 run ` + `\`switchroom soul reset ${agentName}\` to seed it.`);
88666
88902
  process.exit(1);
88667
88903
  }
88668
- process.stdout.write(readFileSync66(t.soulPath, "utf-8"));
88904
+ process.stdout.write(readFileSync67(t.soulPath, "utf-8"));
88669
88905
  }));
88670
88906
  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
88907
  const t = resolveSoulTargetOrExit(program3, agentName);
@@ -88676,7 +88912,7 @@ function registerSoulCommand(program3) {
88676
88912
  console.error(`soul: profile "${t.profileName}" ships no SOUL.md.hbs \u2014 ` + `nothing to re-seed from.`);
88677
88913
  process.exit(1);
88678
88914
  }
88679
- const exists = existsSync75(t.soulPath);
88915
+ const exists = existsSync76(t.soulPath);
88680
88916
  if (exists && !opts.yes) {
88681
88917
  if (!isInteractive()) {
88682
88918
  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 +88927,12 @@ function registerSoulCommand(program3) {
88691
88927
  let backupPath;
88692
88928
  if (exists) {
88693
88929
  backupPath = `${t.soulPath}.bak`;
88694
- if (existsSync75(backupPath)) {
88930
+ if (existsSync76(backupPath)) {
88695
88931
  backupPath = `${t.soulPath}.bak.${Date.now()}`;
88696
88932
  }
88697
88933
  copyFileSync11(t.soulPath, backupPath);
88698
88934
  }
88699
- writeFileSync22(t.soulPath, content, "utf-8");
88935
+ writeFileSync23(t.soulPath, content, "utf-8");
88700
88936
  if (backupPath) {
88701
88937
  console.log(`soul: re-seeded ${agentName}'s SOUL.md from profile ` + `"${t.profileName}".
88702
88938
  ` + ` Previous version saved to ${backupPath}`);
@@ -88710,8 +88946,8 @@ function registerSoulCommand(program3) {
88710
88946
  // src/cli/debug.ts
88711
88947
  init_helpers();
88712
88948
  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";
88949
+ import { existsSync as existsSync77, readFileSync as readFileSync68, readdirSync as readdirSync27, statSync as statSync44 } from "node:fs";
88950
+ import { resolve as resolve47, join as join78 } from "node:path";
88715
88951
  import { createHash as createHash15 } from "node:crypto";
88716
88952
  init_merge();
88717
88953
  init_hindsight2();
@@ -88722,11 +88958,11 @@ function estimateTokens(bytes) {
88722
88958
  return Math.round(bytes / 3.7);
88723
88959
  }
88724
88960
  function readMcpServerNames(agentDir) {
88725
- const mcpPath = join77(agentDir, ".mcp.json");
88726
- if (!existsSync76(mcpPath))
88961
+ const mcpPath = join78(agentDir, ".mcp.json");
88962
+ if (!existsSync77(mcpPath))
88727
88963
  return [];
88728
88964
  try {
88729
- const parsed = JSON.parse(readFileSync67(mcpPath, "utf-8"));
88965
+ const parsed = JSON.parse(readFileSync68(mcpPath, "utf-8"));
88730
88966
  return Object.keys(parsed.mcpServers ?? {});
88731
88967
  } catch {
88732
88968
  return null;
@@ -88736,18 +88972,18 @@ function sha256(content) {
88736
88972
  return createHash15("sha256").update(content).digest("hex").slice(0, 16);
88737
88973
  }
88738
88974
  function findLatestTranscriptJsonl(claudeConfigDir) {
88739
- const projectsDir = join77(claudeConfigDir, "projects");
88740
- if (!existsSync76(projectsDir))
88975
+ const projectsDir = join78(claudeConfigDir, "projects");
88976
+ if (!existsSync77(projectsDir))
88741
88977
  return;
88742
88978
  try {
88743
- const entries = readdirSync26(projectsDir, { withFileTypes: true });
88979
+ const entries = readdirSync27(projectsDir, { withFileTypes: true });
88744
88980
  let latest;
88745
88981
  for (const entry of entries) {
88746
88982
  if (!entry.isDirectory())
88747
88983
  continue;
88748
- const projectPath = join77(projectsDir, entry.name);
88749
- const transcriptPath = join77(projectPath, "transcript.jsonl");
88750
- if (!existsSync76(transcriptPath))
88984
+ const projectPath = join78(projectsDir, entry.name);
88985
+ const transcriptPath = join78(projectPath, "transcript.jsonl");
88986
+ if (!existsSync77(transcriptPath))
88751
88987
  continue;
88752
88988
  const stat3 = statSync44(transcriptPath);
88753
88989
  if (!latest || stat3.mtimeMs > latest.mtime) {
@@ -88761,7 +88997,7 @@ function findLatestTranscriptJsonl(claudeConfigDir) {
88761
88997
  }
88762
88998
  function extractLatestUserMessage(transcriptPath) {
88763
88999
  try {
88764
- const content = readFileSync67(transcriptPath, "utf-8");
89000
+ const content = readFileSync68(transcriptPath, "utf-8");
88765
89001
  const lines = content.trim().split(`
88766
89002
  `).filter(Boolean);
88767
89003
  for (let i = lines.length - 1;i >= 0; i--) {
@@ -88810,16 +89046,16 @@ function registerDebugCommand(program3) {
88810
89046
  }
88811
89047
  const agentsDir = resolveAgentsDir(config);
88812
89048
  const agentDir = resolve47(agentsDir, agentName);
88813
- if (!existsSync76(agentDir)) {
89049
+ if (!existsSync77(agentDir)) {
88814
89050
  console.error(`Agent directory not found: ${agentDir}`);
88815
89051
  process.exit(1);
88816
89052
  }
88817
89053
  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");
89054
+ const claudeConfigDir = join78(agentDir, ".claude");
89055
+ const claudeMdPath = join78(agentDir, "CLAUDE.md");
89056
+ const soulMdPath = join78(agentDir, "SOUL.md");
89057
+ const workspaceSoulMdPath = join78(workspaceDir, "SOUL.md");
89058
+ const handoffPath = join78(agentDir, ".handoff.md");
88823
89059
  const lastN = parseInt(opts.last, 10);
88824
89060
  if (isNaN(lastN) || lastN < 1) {
88825
89061
  console.error("--last must be a positive integer");
@@ -88865,7 +89101,7 @@ function registerDebugCommand(program3) {
88865
89101
  }
88866
89102
  console.log(`=== Append System Prompt (per-session) ===
88867
89103
  `);
88868
- const handoffContent = existsSync76(handoffPath) ? readFileSync67(handoffPath, "utf-8") : "";
89104
+ const handoffContent = existsSync77(handoffPath) ? readFileSync68(handoffPath, "utf-8") : "";
88869
89105
  if (handoffContent.trim().length > 0) {
88870
89106
  console.log(`-- Handoff Briefing (${formatBytes(handoffContent.length)}) --`);
88871
89107
  console.log(handoffContent);
@@ -88876,7 +89112,7 @@ function registerDebugCommand(program3) {
88876
89112
  }
88877
89113
  console.log(`=== CLAUDE.md (auto-loaded by Claude Code) ===
88878
89114
  `);
88879
- const claudeMdContent = existsSync76(claudeMdPath) ? readFileSync67(claudeMdPath, "utf-8") : "";
89115
+ const claudeMdContent = existsSync77(claudeMdPath) ? readFileSync68(claudeMdPath, "utf-8") : "";
88880
89116
  if (claudeMdContent.trim().length > 0) {
88881
89117
  console.log(`(${formatBytes(claudeMdContent.length)})`);
88882
89118
  console.log(claudeMdContent);
@@ -88887,7 +89123,7 @@ function registerDebugCommand(program3) {
88887
89123
  }
88888
89124
  console.log(`=== Persona (SOUL.md) ===
88889
89125
  `);
88890
- const soulMdContent = existsSync76(soulMdPath) ? readFileSync67(soulMdPath, "utf-8") : existsSync76(workspaceSoulMdPath) ? readFileSync67(workspaceSoulMdPath, "utf-8") : "";
89126
+ const soulMdContent = existsSync77(soulMdPath) ? readFileSync68(soulMdPath, "utf-8") : existsSync77(workspaceSoulMdPath) ? readFileSync68(workspaceSoulMdPath, "utf-8") : "";
88891
89127
  if (soulMdContent.trim().length > 0) {
88892
89128
  console.log(`(${formatBytes(soulMdContent.length)})`);
88893
89129
  console.log(soulMdContent);
@@ -88948,11 +89184,11 @@ function registerDebugCommand(program3) {
88948
89184
  const soulMdBytes = soulMdContent.length;
88949
89185
  const perTurnBytes = dynamicResult.concatenated.length;
88950
89186
  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;
89187
+ const fleetDir = join78(agentsDir, "..", "fleet");
89188
+ const fleetInvPath = join78(fleetDir, "switchroom-invariants.md");
89189
+ const fleetClaudePath = join78(fleetDir, "CLAUDE.md");
89190
+ const fleetInvBytes = existsSync77(fleetInvPath) ? readFileSync68(fleetInvPath, "utf-8").length : 0;
89191
+ const fleetClaudeBytes = existsSync77(fleetClaudePath) ? readFileSync68(fleetClaudePath, "utf-8").length : 0;
88956
89192
  const fleetBytes = fleetInvBytes + fleetClaudeBytes;
88957
89193
  const totalBytes = stableBytes + perSessionBytes + claudeMdBytes + fleetBytes + perTurnBytes + userBytes;
88958
89194
  console.log(`Stable prefix: ${formatBytes(stableBytes).padEnd(20)} (cache-hot; includes SOUL.md ${soulMdBytes.toLocaleString()}B)`);
@@ -88985,44 +89221,44 @@ init_source();
88985
89221
 
88986
89222
  // src/worktree/claim.ts
88987
89223
  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";
89224
+ import { closeSync as closeSync13, mkdirSync as mkdirSync41, openSync as openSync13, existsSync as existsSync79, unlinkSync as unlinkSync17 } from "node:fs";
89225
+ import { join as join80, resolve as resolve49 } from "node:path";
88990
89226
  import { homedir as homedir46 } from "node:os";
88991
89227
  import { randomBytes as randomBytes13 } from "node:crypto";
88992
89228
 
88993
89229
  // src/worktree/registry.ts
88994
89230
  import {
88995
- mkdirSync as mkdirSync39,
88996
- writeFileSync as writeFileSync23,
88997
- readFileSync as readFileSync68,
88998
- readdirSync as readdirSync27,
89231
+ mkdirSync as mkdirSync40,
89232
+ writeFileSync as writeFileSync24,
89233
+ readFileSync as readFileSync69,
89234
+ readdirSync as readdirSync28,
88999
89235
  unlinkSync as unlinkSync16,
89000
- existsSync as existsSync77,
89001
- renameSync as renameSync17
89236
+ existsSync as existsSync78,
89237
+ renameSync as renameSync18
89002
89238
  } from "node:fs";
89003
- import { join as join78, resolve as resolve48 } from "node:path";
89239
+ import { join as join79, resolve as resolve48 } from "node:path";
89004
89240
  import { homedir as homedir45 } from "node:os";
89005
89241
  function registryDir() {
89006
- return resolve48(process.env.SWITCHROOM_WORKTREE_DIR ?? join78(homedir45(), ".switchroom", "worktrees"));
89242
+ return resolve48(process.env.SWITCHROOM_WORKTREE_DIR ?? join79(homedir45(), ".switchroom", "worktrees"));
89007
89243
  }
89008
89244
  function recordPath(id) {
89009
- return join78(registryDir(), `${id}.json`);
89245
+ return join79(registryDir(), `${id}.json`);
89010
89246
  }
89011
89247
  function ensureDir2() {
89012
- mkdirSync39(registryDir(), { recursive: true });
89248
+ mkdirSync40(registryDir(), { recursive: true });
89013
89249
  }
89014
89250
  function writeRecord(record2) {
89015
89251
  ensureDir2();
89016
89252
  const target = recordPath(record2.id);
89017
89253
  const tmp = `${target}.tmp${process.pid}`;
89018
- writeFileSync23(tmp, JSON.stringify(record2, null, 2) + `
89254
+ writeFileSync24(tmp, JSON.stringify(record2, null, 2) + `
89019
89255
  `, { mode: 384 });
89020
- renameSync17(tmp, target);
89256
+ renameSync18(tmp, target);
89021
89257
  }
89022
89258
  function readRecord(id) {
89023
89259
  const path8 = recordPath(id);
89024
89260
  try {
89025
- const raw = readFileSync68(path8, "utf8");
89261
+ const raw = readFileSync69(path8, "utf8");
89026
89262
  return JSON.parse(raw);
89027
89263
  } catch {
89028
89264
  return null;
@@ -89038,7 +89274,7 @@ function listRecords() {
89038
89274
  ensureDir2();
89039
89275
  const dir = registryDir();
89040
89276
  const records = [];
89041
- for (const entry of readdirSync27(dir)) {
89277
+ for (const entry of readdirSync28(dir)) {
89042
89278
  if (!entry.endsWith(".json"))
89043
89279
  continue;
89044
89280
  const id = entry.slice(0, -5);
@@ -89055,9 +89291,9 @@ function countByRepo(repoPath) {
89055
89291
  // src/worktree/claim.ts
89056
89292
  function acquireRepoLock(repoPath) {
89057
89293
  const lockDir = registryDir();
89058
- mkdirSync40(lockDir, { recursive: true });
89294
+ mkdirSync41(lockDir, { recursive: true });
89059
89295
  const lockName = repoPath.replace(/[^A-Za-z0-9]/g, "_");
89060
- const lockPath = join79(lockDir, `.lock-${lockName}`);
89296
+ const lockPath = join80(lockDir, `.lock-${lockName}`);
89061
89297
  const deadline = Date.now() + 5000;
89062
89298
  let fd = null;
89063
89299
  while (fd === null) {
@@ -89084,7 +89320,7 @@ function acquireRepoLock(repoPath) {
89084
89320
  }
89085
89321
  var DEFAULT_CONCURRENCY = 5;
89086
89322
  function worktreesBaseDir() {
89087
- return resolve49(process.env.SWITCHROOM_WORKTREE_BASE ?? join79(homedir46(), ".switchroom", "worktree-checkouts"));
89323
+ return resolve49(process.env.SWITCHROOM_WORKTREE_BASE ?? join80(homedir46(), ".switchroom", "worktree-checkouts"));
89088
89324
  }
89089
89325
  function shortId() {
89090
89326
  return randomBytes13(4).toString("hex");
@@ -89106,12 +89342,12 @@ function resolveRepoPath(repo, codeRepos) {
89106
89342
  }
89107
89343
  function expandHome(p) {
89108
89344
  if (p.startsWith("~/"))
89109
- return join79(homedir46(), p.slice(2));
89345
+ return join80(homedir46(), p.slice(2));
89110
89346
  return p;
89111
89347
  }
89112
89348
  async function claimWorktree(input, codeRepos) {
89113
89349
  const repoPath = resolveRepoPath(input.repo, codeRepos);
89114
- if (!existsSync78(repoPath)) {
89350
+ if (!existsSync79(repoPath)) {
89115
89351
  throw new Error(`Repository path does not exist: ${repoPath}`);
89116
89352
  }
89117
89353
  let concurrencyCap = DEFAULT_CONCURRENCY;
@@ -89133,8 +89369,8 @@ async function claimWorktree(input, codeRepos) {
89133
89369
  const taskSuffix = input.taskName ? sanitizeTaskName(input.taskName) : "task";
89134
89370
  branch = `task/${taskSuffix}-${id}`;
89135
89371
  const baseDir = worktreesBaseDir();
89136
- mkdirSync40(baseDir, { recursive: true });
89137
- worktreePath = join79(baseDir, `${id}-${taskSuffix}`);
89372
+ mkdirSync41(baseDir, { recursive: true });
89373
+ worktreePath = join80(baseDir, `${id}-${taskSuffix}`);
89138
89374
  const ambientOwner = process.env.SWITCHROOM_AGENT_NAME;
89139
89375
  const ownerAgent = input.ownerAgent ?? (ambientOwner != null && ambientOwner !== "" ? ambientOwner : undefined);
89140
89376
  const now = new Date().toISOString();
@@ -89167,7 +89403,7 @@ async function claimWorktree(input, codeRepos) {
89167
89403
 
89168
89404
  // src/worktree/release.ts
89169
89405
  import { execFileSync as execFileSync24 } from "node:child_process";
89170
- import { existsSync as existsSync79 } from "node:fs";
89406
+ import { existsSync as existsSync80 } from "node:fs";
89171
89407
  function releaseWorktree(input) {
89172
89408
  const { id } = input;
89173
89409
  const record2 = readRecord(id);
@@ -89175,7 +89411,7 @@ function releaseWorktree(input) {
89175
89411
  return { released: true };
89176
89412
  }
89177
89413
  let gitSuccess = true;
89178
- if (existsSync79(record2.path)) {
89414
+ if (existsSync80(record2.path)) {
89179
89415
  try {
89180
89416
  execFileSync24("git", ["worktree", "remove", "--force", record2.path], {
89181
89417
  cwd: record2.repo,
@@ -89214,7 +89450,7 @@ function listWorktrees() {
89214
89450
 
89215
89451
  // src/worktree/reaper.ts
89216
89452
  import { execFileSync as execFileSync25 } from "node:child_process";
89217
- import { existsSync as existsSync80 } from "node:fs";
89453
+ import { existsSync as existsSync81 } from "node:fs";
89218
89454
  var STALE_THRESHOLD_MS = 10 * 60 * 1000;
89219
89455
  function reapSkipReasonText(action) {
89220
89456
  switch (action) {
@@ -89275,7 +89511,7 @@ function planReaper(nowMs, deps = {}) {
89275
89511
  const plan = [];
89276
89512
  for (const record2 of listRecords()) {
89277
89513
  const heartbeatAge = now - new Date(record2.heartbeatAt).getTime();
89278
- const worktreeExists = existsSync80(record2.path);
89514
+ const worktreeExists = existsSync81(record2.path);
89279
89515
  if (!worktreeExists) {
89280
89516
  plan.push({
89281
89517
  record: record2,
@@ -89356,16 +89592,16 @@ function runReaper(nowMs, deps = {}) {
89356
89592
  // src/worktree/gc.ts
89357
89593
  import { execFileSync as execFileSync26 } from "node:child_process";
89358
89594
  import {
89359
- existsSync as existsSync81,
89360
- readFileSync as readFileSync69,
89361
- readdirSync as readdirSync28,
89595
+ existsSync as existsSync82,
89596
+ readFileSync as readFileSync70,
89597
+ readdirSync as readdirSync29,
89362
89598
  statSync as statSync45,
89363
- renameSync as renameSync18,
89364
- mkdirSync as mkdirSync41,
89599
+ renameSync as renameSync19,
89600
+ mkdirSync as mkdirSync42,
89365
89601
  rmSync as rmSync15
89366
89602
  } from "node:fs";
89367
89603
  import { homedir as homedir47 } from "node:os";
89368
- import { join as join80, resolve as resolve50 } from "node:path";
89604
+ import { join as join81, resolve as resolve50 } from "node:path";
89369
89605
  function parseGitdirPointer(dotGitFileContents) {
89370
89606
  const m = /^gitdir:\s*(.+?)\s*$/m.exec(dotGitFileContents);
89371
89607
  return m ? m[1] : null;
@@ -89480,17 +89716,17 @@ function defaultPrSignal(repo, branch, exec) {
89480
89716
  }
89481
89717
  }
89482
89718
  function trashRoot() {
89483
- return resolve50(process.env.SWITCHROOM_WORKTREE_TRASH ?? join80(homedir47(), ".switchroom", "worktree-gc-trash"));
89719
+ return resolve50(process.env.SWITCHROOM_WORKTREE_TRASH ?? join81(homedir47(), ".switchroom", "worktree-gc-trash"));
89484
89720
  }
89485
89721
  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"));
89722
+ const exists = deps.existsSync ?? existsSync82;
89723
+ const readDir = deps.readDir ?? ((p) => readdirSync29(p));
89724
+ const readFile4 = deps.readFile ?? ((p) => readFileSync70(p, "utf8"));
89489
89725
  const stat3 = deps.stat ?? ((p) => statSync45(p));
89490
89726
  const exec = deps.exec ?? defaultExec;
89491
89727
  const prSignal = deps.prSignal ?? ((repo, branch) => defaultPrSignal(repo, branch, exec));
89492
89728
  const stamp = deps.dateStamp ?? "undated";
89493
- const trash = join80(trashRoot(), stamp);
89729
+ const trash = join81(trashRoot(), stamp);
89494
89730
  let claimed;
89495
89731
  try {
89496
89732
  claimed = new Set(listRecords().map((r) => resolve50(r.path)));
@@ -89526,10 +89762,10 @@ function planGc(roots, deps = {}) {
89526
89762
  continue;
89527
89763
  }
89528
89764
  for (const name of entries) {
89529
- const dir = join80(root, name);
89765
+ const dir = join81(root, name);
89530
89766
  if (isEphemeralPath(dir))
89531
89767
  continue;
89532
- const dotGit = join80(dir, ".git");
89768
+ const dotGit = join81(dir, ".git");
89533
89769
  if (!exists(dotGit))
89534
89770
  continue;
89535
89771
  let st;
@@ -89558,7 +89794,7 @@ function planGc(roots, deps = {}) {
89558
89794
  ownerRepos.add(repoRoot);
89559
89795
  if (exists(ptr))
89560
89796
  continue;
89561
- orphans.push({ dir, owner: repoRoot, dest: join80(trash, name) });
89797
+ orphans.push({ dir, owner: repoRoot, dest: join81(trash, name) });
89562
89798
  }
89563
89799
  }
89564
89800
  const registered = [];
@@ -89613,10 +89849,10 @@ function planGc(roots, deps = {}) {
89613
89849
  }
89614
89850
  function applyGc(plan, deps = {}) {
89615
89851
  const exec = deps.exec ?? defaultExec;
89616
- const mkdirp = deps.mkdirp ?? ((p) => void mkdirSync41(p, { recursive: true }));
89852
+ const mkdirp = deps.mkdirp ?? ((p) => void mkdirSync42(p, { recursive: true }));
89617
89853
  const move = deps.move ?? ((src, dest) => {
89618
89854
  try {
89619
- renameSync18(src, dest);
89855
+ renameSync19(src, dest);
89620
89856
  } catch {
89621
89857
  exec("mv", [src, dest]);
89622
89858
  }
@@ -89662,14 +89898,14 @@ function selectPurgeTargets(entries, olderThanDays) {
89662
89898
  return entries.filter((e) => e.ageDays >= olderThanDays).map((e) => e.path);
89663
89899
  }
89664
89900
  function listTrashEntries(nowMs, deps = {}) {
89665
- const exists = deps.existsSync ?? existsSync81;
89666
- const readDir = deps.readDir ?? ((p) => readdirSync28(p));
89901
+ const exists = deps.existsSync ?? existsSync82;
89902
+ const readDir = deps.readDir ?? ((p) => readdirSync29(p));
89667
89903
  const root = trashRoot();
89668
89904
  if (!exists(root))
89669
89905
  return [];
89670
89906
  const out = [];
89671
89907
  for (const stamp of readDir(root)) {
89672
- const stampDir = join80(root, stamp);
89908
+ const stampDir = join81(root, stamp);
89673
89909
  let names;
89674
89910
  try {
89675
89911
  names = readDir(stampDir);
@@ -89677,7 +89913,7 @@ function listTrashEntries(nowMs, deps = {}) {
89677
89913
  continue;
89678
89914
  }
89679
89915
  for (const name of names) {
89680
- const p = join80(stampDir, name);
89916
+ const p = join81(stampDir, name);
89681
89917
  let mtimeMs = nowMs;
89682
89918
  try {
89683
89919
  mtimeMs = statSync45(p).mtimeMs;
@@ -89701,7 +89937,7 @@ function purgeTrash(paths) {
89701
89937
  return { deleted, errors: errors2 };
89702
89938
  }
89703
89939
  function defaultRoots() {
89704
- return [join80(homedir47(), "code")];
89940
+ return [join81(homedir47(), "code")];
89705
89941
  }
89706
89942
 
89707
89943
  // src/cli/worktree.ts
@@ -89924,12 +90160,12 @@ init_drive();
89924
90160
  init_scaffold_integration();
89925
90161
  import {
89926
90162
  chmodSync as chmodSync11,
89927
- mkdirSync as mkdirSync42,
89928
- readdirSync as readdirSync29,
90163
+ mkdirSync as mkdirSync43,
90164
+ readdirSync as readdirSync30,
89929
90165
  rmSync as rmSync16,
89930
- writeFileSync as writeFileSync24
90166
+ writeFileSync as writeFileSync25
89931
90167
  } from "node:fs";
89932
- import { join as join81 } from "node:path";
90168
+ import { join as join82 } from "node:path";
89933
90169
  function encodeCredentialsFilename(email) {
89934
90170
  const SAFE = new Set([
89935
90171
  ..."ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
@@ -90119,17 +90355,17 @@ function resolveCredentialsDir(env2) {
90119
90355
  if (explicit && explicit.length > 0)
90120
90356
  return explicit;
90121
90357
  const stateBase = env2.SWITCHROOM_CONTAINER === "1" ? "/state/agent" : env2.HOME ?? ".";
90122
- return join81(stateBase, "google-workspace-mcp", "credentials");
90358
+ return join82(stateBase, "google-workspace-mcp", "credentials");
90123
90359
  }
90124
90360
  function writeSeedFile(dir, email, seed) {
90125
- mkdirSync42(dir, { recursive: true, mode: 448 });
90361
+ mkdirSync43(dir, { recursive: true, mode: 448 });
90126
90362
  chmodSync11(dir, 448);
90127
- for (const name of readdirSync29(dir)) {
90128
- rmSync16(join81(dir, name), { force: true, recursive: true });
90363
+ for (const name of readdirSync30(dir)) {
90364
+ rmSync16(join82(dir, name), { force: true, recursive: true });
90129
90365
  }
90130
90366
  const filename = encodeCredentialsFilename(email);
90131
- const filePath = join81(dir, filename);
90132
- writeFileSync24(filePath, JSON.stringify(seed), { mode: 384 });
90367
+ const filePath = join82(dir, filename);
90368
+ writeFileSync25(filePath, JSON.stringify(seed), { mode: 384 });
90133
90369
  chmodSync11(filePath, 384);
90134
90370
  return filePath;
90135
90371
  }
@@ -90287,8 +90523,8 @@ function registerDriveMcpLauncherCommand(program3) {
90287
90523
  // src/cli/m365-mcp-launcher.ts
90288
90524
  init_scaffold_integration();
90289
90525
  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";
90526
+ import { writeFileSync as writeFileSync26, mkdirSync as mkdirSync44 } from "node:fs";
90527
+ import { dirname as dirname27, join as join83 } from "node:path";
90292
90528
  var SOFTERIA_TOKEN_ENV = "MS365_MCP_OAUTH_TOKEN";
90293
90529
  var DEFAULT_REFRESH_LEAD_MS = 5 * 60 * 1000;
90294
90530
  var MAX_REFRESH_INTERVAL_MS = 60 * 60 * 1000;
@@ -90324,8 +90560,8 @@ function computeRefreshDelayMs(expiresAt, now, leadMs = DEFAULT_REFRESH_LEAD_MS)
90324
90560
  function writeRefreshHeartbeat(agentName, data, account) {
90325
90561
  const path8 = heartbeatPath(agentName, account);
90326
90562
  try {
90327
- mkdirSync43(dirname25(path8), { recursive: true });
90328
- writeFileSync25(path8, JSON.stringify(data, null, 2), { mode: 420 });
90563
+ mkdirSync44(dirname27(path8), { recursive: true });
90564
+ writeFileSync26(path8, JSON.stringify(data, null, 2), { mode: 420 });
90329
90565
  } catch {}
90330
90566
  }
90331
90567
  function heartbeatPath(agentName, account) {
@@ -90333,7 +90569,7 @@ function heartbeatPath(agentName, account) {
90333
90569
  const override = process.env.SWITCHROOM_M365_HEARTBEAT_DIR;
90334
90570
  if (override) {
90335
90571
  const base = slug ? `m365-launcher-${agentName}-${slug}` : `m365-launcher-${agentName}`;
90336
- return join82(override, `${base}.heartbeat.json`);
90572
+ return join83(override, `${base}.heartbeat.json`);
90337
90573
  }
90338
90574
  return slug ? `/state/agent/m365-launcher-${slug}.heartbeat.json` : "/state/agent/m365-launcher.heartbeat.json";
90339
90575
  }
@@ -90565,8 +90801,8 @@ function registerM365McpLauncherCommand(program3) {
90565
90801
  // src/cli/notion-mcp-launcher.ts
90566
90802
  init_scaffold_integration();
90567
90803
  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";
90804
+ import { existsSync as existsSync83, mkdirSync as mkdirSync45, writeFileSync as writeFileSync27 } from "node:fs";
90805
+ import { dirname as dirname28 } from "node:path";
90570
90806
  var HEARTBEAT_WRITE_INTERVAL_MS = 30 * 1000;
90571
90807
  var DEFAULT_HEARTBEAT_PATH = "/state/agent/notion-launcher.heartbeat.json";
90572
90808
  var DEFAULT_VAULT_KEY = "notion/integration-token";
@@ -90576,10 +90812,10 @@ function buildNotionMcpArgs(opts) {
90576
90812
  }
90577
90813
  function defaultWriteHeartbeat(path8, contents) {
90578
90814
  try {
90579
- const dir = dirname26(path8);
90580
- if (!existsSync82(dir))
90581
- mkdirSync44(dir, { recursive: true });
90582
- writeFileSync26(path8, contents);
90815
+ const dir = dirname28(path8);
90816
+ if (!existsSync83(dir))
90817
+ mkdirSync45(dir, { recursive: true });
90818
+ writeFileSync27(path8, contents);
90583
90819
  } catch {}
90584
90820
  }
90585
90821
  async function runNotionMcpLauncher(opts, runtime) {
@@ -90689,9 +90925,9 @@ function registerNotionMcpLauncherCommand(program3) {
90689
90925
 
90690
90926
  // src/cli/hindsight-mcp-shim.ts
90691
90927
  init_hindsight();
90692
- import { mkdirSync as mkdirSync45, readFileSync as readFileSync70, renameSync as renameSync19, writeFileSync as writeFileSync27 } from "node:fs";
90928
+ import { mkdirSync as mkdirSync46, readFileSync as readFileSync71, renameSync as renameSync20, writeFileSync as writeFileSync28 } from "node:fs";
90693
90929
  import { tmpdir as tmpdir5 } from "node:os";
90694
- import { join as join83 } from "node:path";
90930
+ import { join as join84 } from "node:path";
90695
90931
  import { createInterface as createInterface6 } from "node:readline";
90696
90932
  var SHIM_SUPPORTED_PROTOCOL_VERSIONS = [
90697
90933
  "2025-06-18",
@@ -90914,22 +91150,22 @@ class HindsightShim {
90914
91150
  `));
90915
91151
  }
90916
91152
  get cachePath() {
90917
- return join83(this.opts.cacheDir, TOOLS_CACHE_FILENAME);
91153
+ return join84(this.opts.cacheDir, TOOLS_CACHE_FILENAME);
90918
91154
  }
90919
91155
  writeCache(result) {
90920
91156
  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) + `
91157
+ mkdirSync46(this.opts.cacheDir, { recursive: true });
91158
+ const tmp = join84(this.opts.cacheDir, `.${TOOLS_CACHE_FILENAME}.${process.pid}.tmp`);
91159
+ writeFileSync28(tmp, JSON.stringify(result, null, 2) + `
90924
91160
  `);
90925
- renameSync19(tmp, this.cachePath);
91161
+ renameSync20(tmp, this.cachePath);
90926
91162
  } catch (err) {
90927
91163
  this.log(`[hindsight-shim] cache write failed: ${String(err)}`);
90928
91164
  }
90929
91165
  }
90930
91166
  readCache() {
90931
91167
  try {
90932
- const parsed = JSON.parse(readFileSync70(this.cachePath, "utf-8"));
91168
+ const parsed = JSON.parse(readFileSync71(this.cachePath, "utf-8"));
90933
91169
  if (Array.isArray(parsed.tools))
90934
91170
  return parsed;
90935
91171
  return null;
@@ -91092,7 +91328,7 @@ function resolveShimOptionsFromEnv(env2) {
91092
91328
  return {
91093
91329
  url: env2.HINDSIGHT_MCP_URL || HINDSIGHT_DEFAULT_MCP_URL,
91094
91330
  bankId: env2.HINDSIGHT_BANK_ID || "",
91095
- cacheDir: env2.HINDSIGHT_SHIM_CACHE_DIR || join83(home2, ".hindsight-shim")
91331
+ cacheDir: env2.HINDSIGHT_SHIM_CACHE_DIR || join84(home2, ".hindsight-shim")
91096
91332
  };
91097
91333
  }
91098
91334
  function registerHindsightMcpShimCommand(program3) {
@@ -91105,7 +91341,7 @@ function registerHindsightMcpShimCommand(program3) {
91105
91341
 
91106
91342
  // src/cli/deliver-file.ts
91107
91343
  init_client2();
91108
- import { readFileSync as readFileSync71, statSync as statSync46 } from "node:fs";
91344
+ import { readFileSync as readFileSync72, statSync as statSync46 } from "node:fs";
91109
91345
  import { basename as basename11 } from "node:path";
91110
91346
 
91111
91347
  // src/delivery/onedrive.ts
@@ -91445,7 +91681,7 @@ async function defaultResolveProvider() {
91445
91681
  async function runDeliverFile(localPath, deps = {}) {
91446
91682
  const agentName = safeAgentName(deps.agentName ?? process.env.SWITCHROOM_AGENT_NAME);
91447
91683
  const sizeOf = deps.fileSize ?? ((p) => statSync46(p).size);
91448
- const read = deps.readFile ?? ((p) => new Uint8Array(readFileSync71(p)));
91684
+ const read = deps.readFile ?? ((p) => new Uint8Array(readFileSync72(p)));
91449
91685
  const resolveProvider = deps.resolveProvider ?? defaultResolveProvider;
91450
91686
  let size;
91451
91687
  try {
@@ -91766,8 +92002,8 @@ function runRedactStdin() {
91766
92002
  }
91767
92003
 
91768
92004
  // 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";
92005
+ import { readFileSync as readFileSync76, existsSync as existsSync88, readdirSync as readdirSync32 } from "node:fs";
92006
+ import { join as join89 } from "node:path";
91771
92007
  import { homedir as homedir50 } from "node:os";
91772
92008
 
91773
92009
  // src/status-ask/report.ts
@@ -92042,7 +92278,7 @@ function runReport(opts) {
92042
92278
  for (const src of sources) {
92043
92279
  let content;
92044
92280
  try {
92045
- content = readFileSync75(src.path, "utf-8");
92281
+ content = readFileSync76(src.path, "utf-8");
92046
92282
  } catch (err) {
92047
92283
  process.stderr.write(`status-ask report: cannot read ${src.path}: ${err instanceof Error ? err.message : String(err)}
92048
92284
  `);
@@ -92089,7 +92325,7 @@ function runReport(opts) {
92089
92325
  function resolveSources(explicitPath) {
92090
92326
  if (explicitPath != null && explicitPath.trim() !== "") {
92091
92327
  const trimmed = explicitPath.trim();
92092
- if (!existsSync87(trimmed)) {
92328
+ if (!existsSync88(trimmed)) {
92093
92329
  process.stderr.write(`status-ask report: ${trimmed}: file not found
92094
92330
  `);
92095
92331
  process.exit(1);
@@ -92103,20 +92339,20 @@ function resolveSources(explicitPath) {
92103
92339
  const config = loadConfig();
92104
92340
  agentsDir = resolveAgentsDir(config);
92105
92341
  } catch {
92106
- agentsDir = join88(homedir50(), ".switchroom", "agents");
92342
+ agentsDir = join89(homedir50(), ".switchroom", "agents");
92107
92343
  }
92108
- if (!existsSync87(agentsDir))
92344
+ if (!existsSync88(agentsDir))
92109
92345
  return [];
92110
92346
  const sources = [];
92111
92347
  let entries;
92112
92348
  try {
92113
- entries = readdirSync31(agentsDir);
92349
+ entries = readdirSync32(agentsDir);
92114
92350
  } catch {
92115
92351
  return [];
92116
92352
  }
92117
92353
  for (const name of entries) {
92118
- const path9 = join88(agentsDir, name, "runtime-metrics.jsonl");
92119
- if (existsSync87(path9)) {
92354
+ const path9 = join89(agentsDir, name, "runtime-metrics.jsonl");
92355
+ if (existsSync88(path9)) {
92120
92356
  sources.push({ path: path9, agent: name });
92121
92357
  }
92122
92358
  }
@@ -92146,45 +92382,45 @@ var import_yaml21 = __toESM(require_dist(), 1);
92146
92382
  init_paths();
92147
92383
  import {
92148
92384
  closeSync as closeSync14,
92149
- existsSync as existsSync88,
92385
+ existsSync as existsSync89,
92150
92386
  fsyncSync as fsyncSync8,
92151
- mkdirSync as mkdirSync50,
92387
+ mkdirSync as mkdirSync51,
92152
92388
  openSync as openSync14,
92153
- readdirSync as readdirSync32,
92154
- readFileSync as readFileSync76,
92155
- renameSync as renameSync21,
92389
+ readdirSync as readdirSync33,
92390
+ readFileSync as readFileSync77,
92391
+ renameSync as renameSync22,
92156
92392
  statSync as statSync48,
92157
92393
  unlinkSync as unlinkSync18,
92158
92394
  writeSync as writeSync10
92159
92395
  } from "node:fs";
92160
- import { join as join89, resolve as resolve53 } from "node:path";
92396
+ import { join as join90, resolve as resolve53 } from "node:path";
92161
92397
  var STAGING_SUBDIR = ".staging";
92162
92398
  function overlayPathsFor(agent, opts = {}) {
92163
92399
  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);
92400
+ const scheduleDir = join90(base, "schedule.d");
92401
+ const scheduleStagingDir = join90(scheduleDir, STAGING_SUBDIR);
92402
+ const skillsDir = join90(base, "skills.d");
92403
+ const skillsStagingDir = join90(skillsDir, STAGING_SUBDIR);
92168
92404
  return {
92169
92405
  agentRoot: base,
92170
92406
  scheduleDir,
92171
92407
  scheduleStagingDir,
92172
92408
  skillsDir,
92173
92409
  skillsStagingDir,
92174
- lockPath: join89(base, ".lock"),
92410
+ lockPath: join90(base, ".lock"),
92175
92411
  stagingDir: scheduleStagingDir
92176
92412
  };
92177
92413
  }
92178
92414
  function ensureDirs(paths) {
92179
- mkdirSync50(paths.scheduleDir, { recursive: true });
92180
- mkdirSync50(paths.scheduleStagingDir, { recursive: true });
92415
+ mkdirSync51(paths.scheduleDir, { recursive: true });
92416
+ mkdirSync51(paths.scheduleStagingDir, { recursive: true });
92181
92417
  }
92182
92418
  function ensureSkillsDirs(paths) {
92183
- mkdirSync50(paths.skillsDir, { recursive: true });
92184
- mkdirSync50(paths.skillsStagingDir, { recursive: true });
92419
+ mkdirSync51(paths.skillsDir, { recursive: true });
92420
+ mkdirSync51(paths.skillsStagingDir, { recursive: true });
92185
92421
  }
92186
92422
  function withAgentLock(paths, fn) {
92187
- mkdirSync50(paths.agentRoot, { recursive: true });
92423
+ mkdirSync51(paths.agentRoot, { recursive: true });
92188
92424
  const start = Date.now();
92189
92425
  const TIMEOUT_MS = 5000;
92190
92426
  let fd = null;
@@ -92225,8 +92461,8 @@ function writeOverlayEntry(agent, slug, yamlText, opts = {}) {
92225
92461
  const paths = overlayPathsFor(agent, opts);
92226
92462
  return withAgentLock(paths, () => {
92227
92463
  ensureDirs(paths);
92228
- const stagingPath = join89(paths.scheduleStagingDir, `${slug}.yaml`);
92229
- const finalPath = join89(paths.scheduleDir, `${slug}.yaml`);
92464
+ const stagingPath = join90(paths.scheduleStagingDir, `${slug}.yaml`);
92465
+ const finalPath = join90(paths.scheduleDir, `${slug}.yaml`);
92230
92466
  const fd = openSync14(stagingPath, "w", 384);
92231
92467
  try {
92232
92468
  writeSync10(fd, yamlText);
@@ -92234,7 +92470,7 @@ function writeOverlayEntry(agent, slug, yamlText, opts = {}) {
92234
92470
  } finally {
92235
92471
  closeSync14(fd);
92236
92472
  }
92237
- renameSync21(stagingPath, finalPath);
92473
+ renameSync22(stagingPath, finalPath);
92238
92474
  return finalPath;
92239
92475
  });
92240
92476
  }
@@ -92242,8 +92478,8 @@ function writeSkillsOverlayEntry(agent, slug, yamlText, opts = {}) {
92242
92478
  const paths = overlayPathsFor(agent, opts);
92243
92479
  return withAgentLock(paths, () => {
92244
92480
  ensureSkillsDirs(paths);
92245
- const stagingPath = join89(paths.skillsStagingDir, `${slug}.yaml`);
92246
- const finalPath = join89(paths.skillsDir, `${slug}.yaml`);
92481
+ const stagingPath = join90(paths.skillsStagingDir, `${slug}.yaml`);
92482
+ const finalPath = join90(paths.skillsDir, `${slug}.yaml`);
92247
92483
  const fd = openSync14(stagingPath, "w", 384);
92248
92484
  try {
92249
92485
  writeSync10(fd, yamlText);
@@ -92251,15 +92487,15 @@ function writeSkillsOverlayEntry(agent, slug, yamlText, opts = {}) {
92251
92487
  } finally {
92252
92488
  closeSync14(fd);
92253
92489
  }
92254
- renameSync21(stagingPath, finalPath);
92490
+ renameSync22(stagingPath, finalPath);
92255
92491
  return finalPath;
92256
92492
  });
92257
92493
  }
92258
92494
  function deleteSkillsOverlayEntry(agent, slug, opts = {}) {
92259
92495
  const paths = overlayPathsFor(agent, opts);
92260
92496
  return withAgentLock(paths, () => {
92261
- const finalPath = join89(paths.skillsDir, `${slug}.yaml`);
92262
- if (!existsSync88(finalPath))
92497
+ const finalPath = join90(paths.skillsDir, `${slug}.yaml`);
92498
+ if (!existsSync89(finalPath))
92263
92499
  return false;
92264
92500
  unlinkSync18(finalPath);
92265
92501
  return true;
@@ -92267,15 +92503,15 @@ function deleteSkillsOverlayEntry(agent, slug, opts = {}) {
92267
92503
  }
92268
92504
  function listSkillsOverlayEntries(agent, opts = {}) {
92269
92505
  const paths = overlayPathsFor(agent, opts);
92270
- if (!existsSync88(paths.skillsDir))
92506
+ if (!existsSync89(paths.skillsDir))
92271
92507
  return [];
92272
92508
  const out = [];
92273
- for (const name of readdirSync32(paths.skillsDir)) {
92509
+ for (const name of readdirSync33(paths.skillsDir)) {
92274
92510
  if (!/\.ya?ml$/i.test(name))
92275
92511
  continue;
92276
- const full = join89(paths.skillsDir, name);
92512
+ const full = join90(paths.skillsDir, name);
92277
92513
  try {
92278
- const raw = readFileSync76(full, "utf-8");
92514
+ const raw = readFileSync77(full, "utf-8");
92279
92515
  const slug = name.replace(/\.ya?ml$/i, "");
92280
92516
  out.push({ slug, path: full, raw });
92281
92517
  } catch {}
@@ -92285,8 +92521,8 @@ function listSkillsOverlayEntries(agent, opts = {}) {
92285
92521
  function deleteOverlayEntry(agent, slug, opts = {}) {
92286
92522
  const paths = overlayPathsFor(agent, opts);
92287
92523
  return withAgentLock(paths, () => {
92288
- const finalPath = join89(paths.scheduleDir, `${slug}.yaml`);
92289
- if (!existsSync88(finalPath))
92524
+ const finalPath = join90(paths.scheduleDir, `${slug}.yaml`);
92525
+ if (!existsSync89(finalPath))
92290
92526
  return false;
92291
92527
  unlinkSync18(finalPath);
92292
92528
  return true;
@@ -92294,15 +92530,15 @@ function deleteOverlayEntry(agent, slug, opts = {}) {
92294
92530
  }
92295
92531
  function listOverlayEntries(agent, opts = {}) {
92296
92532
  const paths = overlayPathsFor(agent, opts);
92297
- if (!existsSync88(paths.scheduleDir))
92533
+ if (!existsSync89(paths.scheduleDir))
92298
92534
  return [];
92299
92535
  const out = [];
92300
- for (const name of readdirSync32(paths.scheduleDir)) {
92536
+ for (const name of readdirSync33(paths.scheduleDir)) {
92301
92537
  if (!/\.ya?ml$/i.test(name))
92302
92538
  continue;
92303
- const full = join89(paths.scheduleDir, name);
92539
+ const full = join90(paths.scheduleDir, name);
92304
92540
  try {
92305
- const raw = readFileSync76(full, "utf-8");
92541
+ const raw = readFileSync77(full, "utf-8");
92306
92542
  const slug = name.replace(/\.ya?ml$/i, "");
92307
92543
  out.push({ slug, path: full, raw });
92308
92544
  } catch {}
@@ -92522,27 +92758,27 @@ function reconcileAgentCronOnly(agent) {
92522
92758
  // src/cli/agent-config-pending.ts
92523
92759
  import {
92524
92760
  closeSync as closeSync15,
92525
- existsSync as existsSync89,
92761
+ existsSync as existsSync90,
92526
92762
  fsyncSync as fsyncSync9,
92527
- mkdirSync as mkdirSync51,
92763
+ mkdirSync as mkdirSync52,
92528
92764
  openSync as openSync15,
92529
- readdirSync as readdirSync33,
92530
- readFileSync as readFileSync77,
92531
- renameSync as renameSync22,
92765
+ readdirSync as readdirSync34,
92766
+ readFileSync as readFileSync78,
92767
+ renameSync as renameSync23,
92532
92768
  unlinkSync as unlinkSync19,
92533
- writeFileSync as writeFileSync32,
92769
+ writeFileSync as writeFileSync33,
92534
92770
  writeSync as writeSync11
92535
92771
  } from "node:fs";
92536
- import { join as join90 } from "node:path";
92772
+ import { join as join91 } from "node:path";
92537
92773
  import { randomBytes as randomBytes15 } from "node:crypto";
92538
92774
  var STAGE_ID_PREFIX = "cap_";
92539
92775
  function pendingDir(agent, opts = {}) {
92540
92776
  const paths = overlayPathsFor(agent, opts);
92541
- return join90(paths.scheduleDir, ".pending");
92777
+ return join91(paths.scheduleDir, ".pending");
92542
92778
  }
92543
92779
  function ensurePendingDir(agent, opts = {}) {
92544
92780
  const dir = pendingDir(agent, opts);
92545
- mkdirSync51(dir, { recursive: true });
92781
+ mkdirSync52(dir, { recursive: true });
92546
92782
  return dir;
92547
92783
  }
92548
92784
  function newStageId() {
@@ -92551,8 +92787,8 @@ function newStageId() {
92551
92787
  function stagePendingScheduleEntry(opts) {
92552
92788
  const dir = ensurePendingDir(opts.agent, { root: opts.root });
92553
92789
  const stageId = opts.stageId ?? newStageId();
92554
- const yamlPath = join90(dir, `${stageId}.yaml`);
92555
- const metaPath = join90(dir, `${stageId}.meta.json`);
92790
+ const yamlPath = join91(dir, `${stageId}.yaml`);
92791
+ const metaPath = join91(dir, `${stageId}.meta.json`);
92556
92792
  const meta = {
92557
92793
  v: 1,
92558
92794
  stage_id: stageId,
@@ -92571,27 +92807,27 @@ function stagePendingScheduleEntry(opts) {
92571
92807
  } finally {
92572
92808
  closeSync15(fd);
92573
92809
  }
92574
- renameSync22(yamlTmp, yamlPath);
92810
+ renameSync23(yamlTmp, yamlPath);
92575
92811
  }
92576
- writeFileSync32(metaPath, JSON.stringify(meta, null, 2) + `
92812
+ writeFileSync33(metaPath, JSON.stringify(meta, null, 2) + `
92577
92813
  `, { mode: 384 });
92578
92814
  return { stageId, yamlPath, metaPath };
92579
92815
  }
92580
92816
  function listPendingScheduleEntries(agent, opts = {}) {
92581
92817
  const dir = pendingDir(agent, opts);
92582
- if (!existsSync89(dir))
92818
+ if (!existsSync90(dir))
92583
92819
  return [];
92584
92820
  const out = [];
92585
- for (const name of readdirSync33(dir).sort()) {
92821
+ for (const name of readdirSync34(dir).sort()) {
92586
92822
  if (!name.endsWith(".meta.json"))
92587
92823
  continue;
92588
92824
  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))
92825
+ const metaPath = join91(dir, name);
92826
+ const yamlPath = join91(dir, `${stageId}.yaml`);
92827
+ if (!existsSync90(yamlPath))
92592
92828
  continue;
92593
92829
  try {
92594
- const meta = JSON.parse(readFileSync77(metaPath, "utf-8"));
92830
+ const meta = JSON.parse(readFileSync78(metaPath, "utf-8"));
92595
92831
  if (meta?.v !== 1 || typeof meta.stage_id !== "string")
92596
92832
  continue;
92597
92833
  out.push({ stageId: meta.stage_id, agent: meta.agent, yamlPath, metaPath, meta });
@@ -92606,11 +92842,11 @@ function commitPendingScheduleEntry(opts) {
92606
92842
  return { committed: false, reason: "not_found" };
92607
92843
  const slug = match.meta.entry.name ?? match.stageId;
92608
92844
  const paths = overlayPathsFor(opts.agent, { root: opts.root });
92609
- const finalPath = join90(paths.scheduleDir, `${slug}.yaml`);
92610
- if (existsSync89(finalPath)) {
92845
+ const finalPath = join91(paths.scheduleDir, `${slug}.yaml`);
92846
+ if (existsSync90(finalPath)) {
92611
92847
  return { committed: false, reason: "slug_collision" };
92612
92848
  }
92613
- renameSync22(match.yamlPath, finalPath);
92849
+ renameSync23(match.yamlPath, finalPath);
92614
92850
  unlinkSync19(match.metaPath);
92615
92851
  return { committed: true, path: finalPath, slug };
92616
92852
  }
@@ -92629,7 +92865,7 @@ function denyPendingScheduleEntry(opts) {
92629
92865
  }
92630
92866
 
92631
92867
  // src/cli/agent-config-write.ts
92632
- import { existsSync as existsSync90, readFileSync as readFileSync78 } from "node:fs";
92868
+ import { existsSync as existsSync91, readFileSync as readFileSync79 } from "node:fs";
92633
92869
  import { execFileSync as execFileSync28 } from "node:child_process";
92634
92870
 
92635
92871
  // src/scheduler/schedule-report.ts
@@ -93019,8 +93255,8 @@ function scheduleRemove(opts) {
93019
93255
  }
93020
93256
  let priorContent = null;
93021
93257
  try {
93022
- if (existsSync90(match.path))
93023
- priorContent = readFileSync78(match.path, "utf-8");
93258
+ if (existsSync91(match.path))
93259
+ priorContent = readFileSync79(match.path, "utf-8");
93024
93260
  } catch {}
93025
93261
  deleteOverlayEntry(agent, match.slug, { root: opts.root });
93026
93262
  const reconcileFn = opts.reconcile === undefined ? opts.root ? null : reconcileAgentCronOnly : opts.reconcile;
@@ -93223,7 +93459,7 @@ function registerAgentConfigWriteCommands(program3) {
93223
93459
  }
93224
93460
  let blob;
93225
93461
  if (opts.jsonl) {
93226
- blob = existsSync90(opts.jsonl) ? readFileSync78(opts.jsonl, "utf-8") : "";
93462
+ blob = existsSync91(opts.jsonl) ? readFileSync79(opts.jsonl, "utf-8") : "";
93227
93463
  } else {
93228
93464
  try {
93229
93465
  blob = execFileSync28("docker", ["exec", `switchroom-${agent}`, "cat", "/state/agent/scheduler.jsonl"], {
@@ -93255,11 +93491,11 @@ function registerAgentConfigWriteCommands(program3) {
93255
93491
 
93256
93492
  // src/cli/agent-config-skill-write.ts
93257
93493
  var import_yaml22 = __toESM(require_dist(), 1);
93258
- import { existsSync as existsSync91 } from "node:fs";
93494
+ import { existsSync as existsSync92 } from "node:fs";
93259
93495
  init_reconcile_default_skills();
93260
93496
  init_agent_config();
93261
93497
  var import_yaml23 = __toESM(require_dist(), 1);
93262
- import { join as join91 } from "node:path";
93498
+ import { join as join92 } from "node:path";
93263
93499
  var MAX_SKILLS_PER_AGENT = 20;
93264
93500
  var V1_ALLOWED_SOURCE_PREFIX = "bundled:";
93265
93501
  function exitCodeFor2(code) {
@@ -93334,8 +93570,8 @@ function skillInstall(opts) {
93334
93570
  return err("E_SKILL_QUOTA_EXCEEDED", `agent ${agent} already has ${used} overlay-installed skills (cap ${MAX_SKILLS_PER_AGENT})`);
93335
93571
  }
93336
93572
  const poolDir = opts.bundledSkillsPoolDir ?? getBundledSkillsPoolDir();
93337
- const skillPath = join91(poolDir, skillName);
93338
- if (!existsSync91(skillPath)) {
93573
+ const skillPath = join92(poolDir, skillName);
93574
+ if (!existsSync92(skillPath)) {
93339
93575
  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
93576
  }
93341
93577
  const yamlText = import_yaml22.stringify({ skills: [skillName] });
@@ -93499,21 +93735,21 @@ function registerAgentConfigSkillWriteCommands(program3) {
93499
93735
  // src/cli/skill.ts
93500
93736
  import {
93501
93737
  closeSync as closeSync16,
93502
- existsSync as existsSync92,
93738
+ existsSync as existsSync93,
93503
93739
  lstatSync as lstatSync11,
93504
- mkdirSync as mkdirSync52,
93740
+ mkdirSync as mkdirSync53,
93505
93741
  mkdtempSync as mkdtempSync5,
93506
93742
  openSync as openSync16,
93507
- readFileSync as readFileSync79,
93508
- readdirSync as readdirSync34,
93743
+ readFileSync as readFileSync80,
93744
+ readdirSync as readdirSync35,
93509
93745
  realpathSync as realpathSync7,
93510
- renameSync as renameSync23,
93746
+ renameSync as renameSync24,
93511
93747
  rmSync as rmSync18,
93512
93748
  statSync as statSync49,
93513
- writeFileSync as writeFileSync33
93749
+ writeFileSync as writeFileSync34
93514
93750
  } from "node:fs";
93515
93751
  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";
93752
+ import { dirname as dirname33, join as join93, relative as relative4, resolve as resolve54 } from "node:path";
93517
93753
  import { spawnSync as spawnSync16 } from "node:child_process";
93518
93754
 
93519
93755
  // src/cli/skill-common.ts
@@ -93747,7 +93983,7 @@ function scanForClaudeP2(content) {
93747
93983
  function resolveSkillsPoolDir2(override) {
93748
93984
  const raw = override ?? "~/.switchroom/skills";
93749
93985
  if (raw.startsWith("~/")) {
93750
- return join92(homedir51(), raw.slice(2));
93986
+ return join93(homedir51(), raw.slice(2));
93751
93987
  }
93752
93988
  if (raw === "~")
93753
93989
  return homedir51();
@@ -93784,10 +94020,10 @@ function loadFromDir(dir) {
93784
94020
  }
93785
94021
  const files = {};
93786
94022
  const walk2 = (sub) => {
93787
- const entries = readdirSync34(sub, { withFileTypes: true });
94023
+ const entries = readdirSync35(sub, { withFileTypes: true });
93788
94024
  for (const ent of entries) {
93789
- const full = join92(sub, ent.name);
93790
- const rel = relative2(abs, full);
94025
+ const full = join93(sub, ent.name);
94026
+ const rel = relative4(abs, full);
93791
94027
  if (ent.isSymbolicLink()) {
93792
94028
  fail3(`refusing to read symlink inside --from dir: ${rel}`);
93793
94029
  }
@@ -93796,7 +94032,7 @@ function loadFromDir(dir) {
93796
94032
  continue;
93797
94033
  }
93798
94034
  if (ent.isFile()) {
93799
- const buf = readFileSync79(full);
94035
+ const buf = readFileSync80(full);
93800
94036
  files[rel.replace(/\\/g, "/")] = buf.toString("utf-8");
93801
94037
  }
93802
94038
  }
@@ -93821,7 +94057,7 @@ function loadFromTarball(tarPath) {
93821
94057
  fail3(`tarball contains disallowed path: ${JSON.stringify(entry)} \u2014 ` + `refusing to extract before any file is written`);
93822
94058
  }
93823
94059
  }
93824
- const staging = mkdtempSync5(join92(tmpdir6(), "skill-apply-extract-"));
94060
+ const staging = mkdtempSync5(join93(tmpdir6(), "skill-apply-extract-"));
93825
94061
  try {
93826
94062
  const flags = isGz ? ["-xzf"] : ["-xf"];
93827
94063
  const r = spawnSync16("tar", [
@@ -93845,7 +94081,7 @@ function loadFromTarball(tarPath) {
93845
94081
  }
93846
94082
  }
93847
94083
  function loadSingleFile(filePath) {
93848
- const content = readFileSync79(filePath, "utf-8");
94084
+ const content = readFileSync80(filePath, "utf-8");
93849
94085
  return { "SKILL.md": content };
93850
94086
  }
93851
94087
  function loadFromStdin() {
@@ -93907,10 +94143,10 @@ function validatePayload(name, files) {
93907
94143
  errors2.push(`${path9} fails \`bash -n\` syntax check: ${(r.stderr ?? "").trim()}`);
93908
94144
  }
93909
94145
  } else if (PY_SCRIPT_RE2.test(path9)) {
93910
- const tmp = mkdtempSync5(join92(tmpdir6(), "skill-apply-py-"));
93911
- const tmpPy = join92(tmp, "check.py");
94146
+ const tmp = mkdtempSync5(join93(tmpdir6(), "skill-apply-py-"));
94147
+ const tmpPy = join93(tmp, "check.py");
93912
94148
  try {
93913
- writeFileSync33(tmpPy, content);
94149
+ writeFileSync34(tmpPy, content);
93914
94150
  const r = spawnSync16("python3", ["-m", "py_compile", tmpPy], {
93915
94151
  encoding: "utf-8"
93916
94152
  });
@@ -93928,15 +94164,15 @@ function validatePayload(name, files) {
93928
94164
  function diffSummary(currentDir, files) {
93929
94165
  const lines = [];
93930
94166
  const currentFiles = {};
93931
- if (existsSync92(currentDir)) {
94167
+ if (existsSync93(currentDir)) {
93932
94168
  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);
94169
+ for (const ent of readdirSync35(sub, { withFileTypes: true })) {
94170
+ const full = join93(sub, ent.name);
94171
+ const rel = relative4(currentDir, full);
93936
94172
  if (ent.isDirectory()) {
93937
94173
  walk2(full);
93938
94174
  } else if (ent.isFile()) {
93939
- currentFiles[rel.replace(/\\/g, "/")] = readFileSync79(full, "utf-8");
94175
+ currentFiles[rel.replace(/\\/g, "/")] = readFileSync80(full, "utf-8");
93940
94176
  }
93941
94177
  }
93942
94178
  };
@@ -93964,10 +94200,10 @@ function diffSummary(currentDir, files) {
93964
94200
  `);
93965
94201
  }
93966
94202
  function writePayload(poolDir, name, files) {
93967
- if (!existsSync92(poolDir)) {
93968
- mkdirSync52(poolDir, { recursive: true, mode: 493 });
94203
+ if (!existsSync93(poolDir)) {
94204
+ mkdirSync53(poolDir, { recursive: true, mode: 493 });
93969
94205
  }
93970
- const target = join92(poolDir, name);
94206
+ const target = join93(poolDir, name);
93971
94207
  let targetIsSymlink = false;
93972
94208
  try {
93973
94209
  const st = lstatSync11(target);
@@ -93978,15 +94214,15 @@ function writePayload(poolDir, name, files) {
93978
94214
  if (targetIsSymlink) {
93979
94215
  fail3(`refusing to overwrite symlink at ${target}; investigate manually`);
93980
94216
  }
93981
- const staging = mkdtempSync5(join92(poolDir, `.skill-apply-stage-${name}-`));
94217
+ const staging = mkdtempSync5(join93(poolDir, `.skill-apply-stage-${name}-`));
93982
94218
  let oldRename = null;
93983
94219
  try {
93984
94220
  for (const [path9, content] of Object.entries(files)) {
93985
- const full = join92(staging, path9);
93986
- mkdirSync52(dirname31(full), { recursive: true, mode: 493 });
94221
+ const full = join93(staging, path9);
94222
+ mkdirSync53(dirname33(full), { recursive: true, mode: 493 });
93987
94223
  const fd = openSync16(full, "wx");
93988
94224
  try {
93989
- writeFileSync33(fd, content);
94225
+ writeFileSync34(fd, content);
93990
94226
  } finally {
93991
94227
  closeSync16(fd);
93992
94228
  }
@@ -94002,9 +94238,9 @@ function writePayload(poolDir, name, files) {
94002
94238
  } catch {}
94003
94239
  if (targetExists) {
94004
94240
  oldRename = `${target}.skill-apply-old-${Date.now()}`;
94005
- renameSync23(target, oldRename);
94241
+ renameSync24(target, oldRename);
94006
94242
  }
94007
- renameSync23(staging, target);
94243
+ renameSync24(staging, target);
94008
94244
  if (oldRename) {
94009
94245
  rmSync18(oldRename, { recursive: true, force: true });
94010
94246
  oldRename = null;
@@ -94013,12 +94249,12 @@ function writePayload(poolDir, name, files) {
94013
94249
  try {
94014
94250
  rmSync18(staging, { recursive: true, force: true });
94015
94251
  } catch {}
94016
- if (oldRename && existsSync92(oldRename)) {
94252
+ if (oldRename && existsSync93(oldRename)) {
94017
94253
  try {
94018
- if (existsSync92(target)) {
94254
+ if (existsSync93(target)) {
94019
94255
  rmSync18(target, { recursive: true, force: true });
94020
94256
  }
94021
- renameSync23(oldRename, target);
94257
+ renameSync24(oldRename, target);
94022
94258
  } catch {}
94023
94259
  }
94024
94260
  throw err2;
@@ -94036,7 +94272,7 @@ function registerSkillCommand(program3) {
94036
94272
  files = loadFromStdin();
94037
94273
  } else {
94038
94274
  const fromPath = resolve54(opts.from);
94039
- if (!existsSync92(fromPath)) {
94275
+ if (!existsSync93(fromPath)) {
94040
94276
  fail3(`--from path does not exist: ${opts.from}`);
94041
94277
  }
94042
94278
  const st = statSync49(fromPath);
@@ -94060,7 +94296,7 @@ function registerSkillCommand(program3) {
94060
94296
  }
94061
94297
  const config = loadConfig();
94062
94298
  const poolDir = resolveSkillsPoolDir2(config.switchroom?.skills_dir);
94063
- const currentDir = join92(poolDir, name);
94299
+ const currentDir = join93(poolDir, name);
94064
94300
  console.log(source_default.bold(`Skill: ${name}`) + source_default.gray(` (${Object.keys(files).length} files, ${sumBytes(files)} bytes)`));
94065
94301
  console.log(source_default.bold("Diff vs current pool content:"));
94066
94302
  console.log(diffSummary(currentDir, files));
@@ -94092,20 +94328,20 @@ function sumBytes(files) {
94092
94328
  init_esm();
94093
94329
  import {
94094
94330
  closeSync as closeSync17,
94095
- existsSync as existsSync93,
94331
+ existsSync as existsSync94,
94096
94332
  lstatSync as lstatSync12,
94097
- mkdirSync as mkdirSync53,
94333
+ mkdirSync as mkdirSync54,
94098
94334
  mkdtempSync as mkdtempSync6,
94099
94335
  openSync as openSync17,
94100
- readFileSync as readFileSync80,
94101
- readdirSync as readdirSync35,
94102
- renameSync as renameSync24,
94336
+ readFileSync as readFileSync81,
94337
+ readdirSync as readdirSync36,
94338
+ renameSync as renameSync25,
94103
94339
  rmSync as rmSync19,
94104
94340
  statSync as statSync50,
94105
94341
  utimesSync,
94106
- writeFileSync as writeFileSync34
94342
+ writeFileSync as writeFileSync35
94107
94343
  } from "node:fs";
94108
- import { dirname as dirname32, join as join93, relative as relative3, resolve as resolve55 } from "node:path";
94344
+ import { dirname as dirname34, join as join94, relative as relative5, resolve as resolve55 } from "node:path";
94109
94345
  import { homedir as homedir52, tmpdir as tmpdir7 } from "node:os";
94110
94346
  import { spawnSync as spawnSync17 } from "node:child_process";
94111
94347
  init_helpers();
@@ -94117,18 +94353,18 @@ var TRASH_TTL_MS = 24 * 60 * 60 * 1000;
94117
94353
  var PERSONAL_SKILLS_SUBPATH = "personal-skills";
94118
94354
  function resolveConfigSkillsDir(agent) {
94119
94355
  const override = process.env.SWITCHROOM_CONFIG_DIR;
94120
- const candidate = override ? resolve55(override) : join93(homedir52(), ".switchroom-config");
94121
- if (!existsSync93(candidate))
94356
+ const candidate = override ? resolve55(override) : join94(homedir52(), ".switchroom-config");
94357
+ if (!existsSync94(candidate))
94122
94358
  return null;
94123
- return join93(candidate, "agents", agent, PERSONAL_SKILLS_SUBPATH);
94359
+ return join94(candidate, "agents", agent, PERSONAL_SKILLS_SUBPATH);
94124
94360
  }
94125
94361
  var MIRROR_PRIOR_TTL_MS = 24 * 60 * 60 * 1000;
94126
94362
  function sweepMirrorPriors(configSkillsRoot) {
94127
94363
  try {
94128
- if (!existsSync93(configSkillsRoot))
94364
+ if (!existsSync94(configSkillsRoot))
94129
94365
  return;
94130
94366
  const now = Date.now();
94131
- for (const ent of readdirSync35(configSkillsRoot)) {
94367
+ for (const ent of readdirSync36(configSkillsRoot)) {
94132
94368
  const m = /^\.(?:.+)-(?:prior|trash)-(\d+)$/.exec(ent);
94133
94369
  if (!m)
94134
94370
  continue;
@@ -94138,7 +94374,7 @@ function sweepMirrorPriors(configSkillsRoot) {
94138
94374
  if (now - ts < MIRROR_PRIOR_TTL_MS)
94139
94375
  continue;
94140
94376
  try {
94141
- rmSync19(join93(configSkillsRoot, ent), { recursive: true, force: true });
94377
+ rmSync19(join94(configSkillsRoot, ent), { recursive: true, force: true });
94142
94378
  } catch {}
94143
94379
  }
94144
94380
  } catch {}
@@ -94147,7 +94383,7 @@ function mirrorToConfigRepo(agent, name, liveSkillDir) {
94147
94383
  const configSkillsRoot = resolveConfigSkillsDir(agent);
94148
94384
  if (!configSkillsRoot)
94149
94385
  return;
94150
- const dest = join93(configSkillsRoot, name);
94386
+ const dest = join94(configSkillsRoot, name);
94151
94387
  try {
94152
94388
  if (liveSkillDir !== null) {
94153
94389
  try {
@@ -94161,35 +94397,35 @@ function mirrorToConfigRepo(agent, name, liveSkillDir) {
94161
94397
  }
94162
94398
  if (liveSkillDir === null) {
94163
94399
  sweepMirrorPriors(configSkillsRoot);
94164
- if (existsSync93(dest)) {
94165
- const trash = join93(configSkillsRoot, `.${name}-trash-${Date.now()}`);
94166
- renameSync24(dest, trash);
94400
+ if (existsSync94(dest)) {
94401
+ const trash = join94(configSkillsRoot, `.${name}-trash-${Date.now()}`);
94402
+ renameSync25(dest, trash);
94167
94403
  }
94168
94404
  return;
94169
94405
  }
94170
- mkdirSync53(configSkillsRoot, { recursive: true, mode: 493 });
94406
+ mkdirSync54(configSkillsRoot, { recursive: true, mode: 493 });
94171
94407
  sweepMirrorPriors(configSkillsRoot);
94172
- const staging = mkdtempSync6(join93(configSkillsRoot, `.${name}-staging-`));
94408
+ const staging = mkdtempSync6(join94(configSkillsRoot, `.${name}-staging-`));
94173
94409
  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);
94410
+ mkdirSync54(dst, { recursive: true, mode: 493 });
94411
+ for (const ent of readdirSync36(src, { withFileTypes: true })) {
94412
+ const s = join94(src, ent.name);
94413
+ const d = join94(dst, ent.name);
94178
94414
  if (ent.isSymbolicLink())
94179
94415
  continue;
94180
94416
  if (ent.isDirectory())
94181
94417
  walk2(s, d);
94182
94418
  else if (ent.isFile()) {
94183
- writeFileSync34(d, readFileSync80(s));
94419
+ writeFileSync35(d, readFileSync81(s));
94184
94420
  }
94185
94421
  }
94186
94422
  };
94187
94423
  walk2(liveSkillDir, staging);
94188
- if (existsSync93(dest)) {
94189
- const prior = join93(configSkillsRoot, `.${name}-prior-${Date.now()}`);
94190
- renameSync24(dest, prior);
94424
+ if (existsSync94(dest)) {
94425
+ const prior = join94(configSkillsRoot, `.${name}-prior-${Date.now()}`);
94426
+ renameSync25(dest, prior);
94191
94427
  }
94192
- renameSync24(staging, dest);
94428
+ renameSync25(staging, dest);
94193
94429
  } catch (err2) {
94194
94430
  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
94431
  `));
@@ -94216,20 +94452,20 @@ function resolveAgent(opts) {
94216
94452
  function resolveAgentsRoot(opts) {
94217
94453
  if (opts.root)
94218
94454
  return resolve55(opts.root);
94219
- return join93(homedir52(), ".switchroom", "agents");
94455
+ return join94(homedir52(), ".switchroom", "agents");
94220
94456
  }
94221
94457
  function personalSkillDir(agentsRoot, agent, name) {
94222
- return join93(agentsRoot, agent, ".claude", "skills", PERSONAL_PREFIX + name);
94458
+ return join94(agentsRoot, agent, ".claude", "skills", PERSONAL_PREFIX + name);
94223
94459
  }
94224
94460
  function trashDir(agentsRoot, agent) {
94225
- return join93(agentsRoot, agent, ".claude", TRASH_DIRNAME);
94461
+ return join94(agentsRoot, agent, ".claude", TRASH_DIRNAME);
94226
94462
  }
94227
94463
  function countPersonalSkills(agentsRoot, agent) {
94228
- const skillsDir = join93(agentsRoot, agent, ".claude", "skills");
94229
- if (!existsSync93(skillsDir))
94464
+ const skillsDir = join94(agentsRoot, agent, ".claude", "skills");
94465
+ if (!existsSync94(skillsDir))
94230
94466
  return 0;
94231
94467
  let n = 0;
94232
- for (const ent of readdirSync35(skillsDir, { withFileTypes: true })) {
94468
+ for (const ent of readdirSync36(skillsDir, { withFileTypes: true })) {
94233
94469
  if (ent.isDirectory() && ent.name.startsWith(PERSONAL_PREFIX))
94234
94470
  n += 1;
94235
94471
  }
@@ -94262,18 +94498,18 @@ function loadFromDir2(dir) {
94262
94498
  }
94263
94499
  const files = {};
94264
94500
  const walk2 = (sub) => {
94265
- for (const ent of readdirSync35(sub, { withFileTypes: true })) {
94266
- const full = join93(sub, ent.name);
94501
+ for (const ent of readdirSync36(sub, { withFileTypes: true })) {
94502
+ const full = join94(sub, ent.name);
94267
94503
  if (ent.isSymbolicLink()) {
94268
- fail4(`refusing to read symlink in --from dir: ${relative3(abs, full)}`);
94504
+ fail4(`refusing to read symlink in --from dir: ${relative5(abs, full)}`);
94269
94505
  }
94270
94506
  if (ent.isDirectory()) {
94271
94507
  walk2(full);
94272
94508
  continue;
94273
94509
  }
94274
94510
  if (ent.isFile()) {
94275
- const rel = relative3(abs, full).replace(/\\/g, "/");
94276
- files[rel] = readFileSync80(full, "utf-8");
94511
+ const rel = relative5(abs, full).replace(/\\/g, "/");
94512
+ files[rel] = readFileSync81(full, "utf-8");
94277
94513
  }
94278
94514
  }
94279
94515
  };
@@ -94316,10 +94552,10 @@ function behavioralValidate(files) {
94316
94552
  errors2.push(`${path9} fails \`bash -n\`: ${(r.stderr ?? "").trim()}`);
94317
94553
  }
94318
94554
  } else if (PY_SCRIPT_RE.test(path9)) {
94319
- const tmp = mkdtempSync6(join93(tmpdir7(), "skill-personal-py-"));
94320
- const tmpPy = join93(tmp, "check.py");
94555
+ const tmp = mkdtempSync6(join94(tmpdir7(), "skill-personal-py-"));
94556
+ const tmpPy = join94(tmp, "check.py");
94321
94557
  try {
94322
- writeFileSync34(tmpPy, content);
94558
+ writeFileSync35(tmpPy, content);
94323
94559
  const r = spawnSync17("python3", ["-m", "py_compile", tmpPy], {
94324
94560
  encoding: "utf-8"
94325
94561
  });
@@ -94335,13 +94571,13 @@ function behavioralValidate(files) {
94335
94571
  }
94336
94572
  function sweepTrash(agentsRoot, agent) {
94337
94573
  const trash = trashDir(agentsRoot, agent);
94338
- if (!existsSync93(trash))
94574
+ if (!existsSync94(trash))
94339
94575
  return;
94340
94576
  const now = Date.now();
94341
- for (const ent of readdirSync35(trash, { withFileTypes: true })) {
94577
+ for (const ent of readdirSync36(trash, { withFileTypes: true })) {
94342
94578
  if (!ent.isDirectory())
94343
94579
  continue;
94344
- const entPath = join93(trash, ent.name);
94580
+ const entPath = join94(trash, ent.name);
94345
94581
  try {
94346
94582
  const st = statSync50(entPath);
94347
94583
  if (now - st.mtimeMs > TRASH_TTL_MS) {
@@ -94361,16 +94597,16 @@ function writePersonalSkill(targetDir, files) {
94361
94597
  if (targetIsSymlink) {
94362
94598
  fail4(`refusing to overwrite symlink at ${targetDir}; investigate manually`);
94363
94599
  }
94364
- mkdirSync53(dirname32(targetDir), { recursive: true, mode: 493 });
94365
- const staging = mkdtempSync6(join93(dirname32(targetDir), `.skill-personal-stage-`));
94600
+ mkdirSync54(dirname34(targetDir), { recursive: true, mode: 493 });
94601
+ const staging = mkdtempSync6(join94(dirname34(targetDir), `.skill-personal-stage-`));
94366
94602
  let oldRename = null;
94367
94603
  try {
94368
94604
  for (const [path9, content] of Object.entries(files)) {
94369
- const full = join93(staging, path9);
94370
- mkdirSync53(dirname32(full), { recursive: true, mode: 493 });
94605
+ const full = join94(staging, path9);
94606
+ mkdirSync54(dirname34(full), { recursive: true, mode: 493 });
94371
94607
  const fd = openSync17(full, "wx");
94372
94608
  try {
94373
- writeFileSync34(fd, content);
94609
+ writeFileSync35(fd, content);
94374
94610
  } finally {
94375
94611
  closeSync17(fd);
94376
94612
  }
@@ -94386,9 +94622,9 @@ function writePersonalSkill(targetDir, files) {
94386
94622
  } catch {}
94387
94623
  if (targetExists) {
94388
94624
  oldRename = `${targetDir}.personal-old-${Date.now()}`;
94389
- renameSync24(targetDir, oldRename);
94625
+ renameSync25(targetDir, oldRename);
94390
94626
  }
94391
- renameSync24(staging, targetDir);
94627
+ renameSync25(staging, targetDir);
94392
94628
  if (oldRename) {
94393
94629
  rmSync19(oldRename, { recursive: true, force: true });
94394
94630
  oldRename = null;
@@ -94397,12 +94633,12 @@ function writePersonalSkill(targetDir, files) {
94397
94633
  try {
94398
94634
  rmSync19(staging, { recursive: true, force: true });
94399
94635
  } catch {}
94400
- if (oldRename && existsSync93(oldRename)) {
94636
+ if (oldRename && existsSync94(oldRename)) {
94401
94637
  try {
94402
- if (existsSync93(targetDir)) {
94638
+ if (existsSync94(targetDir)) {
94403
94639
  rmSync19(targetDir, { recursive: true, force: true });
94404
94640
  }
94405
- renameSync24(oldRename, targetDir);
94641
+ renameSync25(oldRename, targetDir);
94406
94642
  } catch {}
94407
94643
  }
94408
94644
  throw err2;
@@ -94465,7 +94701,7 @@ function loadFiles(opts) {
94465
94701
  return loadFromStdin2();
94466
94702
  }
94467
94703
  const p = resolve55(opts.from);
94468
- if (!existsSync93(p)) {
94704
+ if (!existsSync94(p)) {
94469
94705
  fail4(`--from path does not exist: ${opts.from}`);
94470
94706
  }
94471
94707
  const st = statSync50(p);
@@ -94473,7 +94709,7 @@ function loadFiles(opts) {
94473
94709
  return loadFromDir2(p);
94474
94710
  }
94475
94711
  if (p.endsWith(".md")) {
94476
- return { "SKILL.md": readFileSync80(p, "utf-8") };
94712
+ return { "SKILL.md": readFileSync81(p, "utf-8") };
94477
94713
  }
94478
94714
  fail4(`--from must be a directory or a .md file. Got: ${opts.from}`);
94479
94715
  }
@@ -94513,10 +94749,10 @@ function editPersonalAction(name, opts) {
94513
94749
  }
94514
94750
  var CLONE_SOURCE_RE = /^(shared|bundled):([a-z0-9][a-z0-9_-]{0,62})$/;
94515
94751
  function defaultSharedRoot() {
94516
- return join93(homedir52(), ".switchroom", "skills");
94752
+ return join94(homedir52(), ".switchroom", "skills");
94517
94753
  }
94518
94754
  function defaultBundledRoot() {
94519
- return join93(homedir52(), ".switchroom", "skills", "_bundled");
94755
+ return join94(homedir52(), ".switchroom", "skills", "_bundled");
94520
94756
  }
94521
94757
  function resolveCloneSource(source, opts) {
94522
94758
  const m = CLONE_SOURCE_RE.exec(source);
@@ -94526,8 +94762,8 @@ function resolveCloneSource(source, opts) {
94526
94762
  const tier = m[1];
94527
94763
  const slug = m[2];
94528
94764
  const root = tier === "bundled" ? opts.bundledRoot ?? defaultBundledRoot() : opts.sharedRoot ?? defaultSharedRoot();
94529
- const dir = join93(root, slug);
94530
- if (!existsSync93(dir)) {
94765
+ const dir = join94(root, slug);
94766
+ if (!existsSync94(dir)) {
94531
94767
  fail4(`clone source ${JSON.stringify(source)} not found at ${dir}; ` + `check \`switchroom skill search --tier ${tier}\``, 1);
94532
94768
  }
94533
94769
  const st = lstatSync12(dir);
@@ -94541,8 +94777,8 @@ function readSourceFiles(dir) {
94541
94777
  const files = {};
94542
94778
  const skipped = [];
94543
94779
  const walk2 = (sub) => {
94544
- for (const ent of readdirSync35(sub, { withFileTypes: true })) {
94545
- const full = join93(sub, ent.name);
94780
+ for (const ent of readdirSync36(sub, { withFileTypes: true })) {
94781
+ const full = join94(sub, ent.name);
94546
94782
  if (ent.isSymbolicLink()) {
94547
94783
  continue;
94548
94784
  }
@@ -94551,7 +94787,7 @@ function readSourceFiles(dir) {
94551
94787
  continue;
94552
94788
  }
94553
94789
  if (ent.isFile()) {
94554
- const rel = relative3(dir, full).replace(/\\/g, "/");
94790
+ const rel = relative5(dir, full).replace(/\\/g, "/");
94555
94791
  if (!validateRelPath(rel)) {
94556
94792
  skipped.push(rel);
94557
94793
  continue;
@@ -94562,7 +94798,7 @@ function readSourceFiles(dir) {
94562
94798
  fail4(`clone source has oversized file ${rel} (${st.size} bytes > ${CLONE_MAX_FILE_BYTES}); ` + `refuse to read`, 3);
94563
94799
  }
94564
94800
  } catch {}
94565
- files[rel] = readFileSync80(full, "utf-8");
94801
+ files[rel] = readFileSync81(full, "utf-8");
94566
94802
  }
94567
94803
  }
94568
94804
  };
@@ -94651,10 +94887,10 @@ function removePersonalAction(name, opts) {
94651
94887
  throw err2;
94652
94888
  }
94653
94889
  const trashRoot2 = trashDir(agentsRoot, agent);
94654
- mkdirSync53(trashRoot2, { recursive: true, mode: 493 });
94890
+ mkdirSync54(trashRoot2, { recursive: true, mode: 493 });
94655
94891
  const ts = Date.now();
94656
- const trashTarget = join93(trashRoot2, `${name}-${ts}`);
94657
- renameSync24(target, trashTarget);
94892
+ const trashTarget = join94(trashRoot2, `${name}-${ts}`);
94893
+ renameSync25(target, trashTarget);
94658
94894
  const now = new Date(ts);
94659
94895
  utimesSync(trashTarget, now, now);
94660
94896
  mirrorToConfigRepo(agent, name, null);
@@ -94672,27 +94908,27 @@ function listPersonalAction(opts) {
94672
94908
  const agent = resolveAgent(opts);
94673
94909
  const agentsRoot = resolveAgentsRoot(opts);
94674
94910
  sweepTrash(agentsRoot, agent);
94675
- const skillsDir = join93(agentsRoot, agent, ".claude", "skills");
94911
+ const skillsDir = join94(agentsRoot, agent, ".claude", "skills");
94676
94912
  const personal = [];
94677
- if (existsSync93(skillsDir)) {
94678
- for (const ent of readdirSync35(skillsDir, { withFileTypes: true })) {
94913
+ if (existsSync94(skillsDir)) {
94914
+ for (const ent of readdirSync36(skillsDir, { withFileTypes: true })) {
94679
94915
  if (!ent.isDirectory())
94680
94916
  continue;
94681
94917
  if (!ent.name.startsWith(PERSONAL_PREFIX))
94682
94918
  continue;
94683
94919
  const skillName = ent.name.slice(PERSONAL_PREFIX.length);
94684
- const skillPath = join93(skillsDir, ent.name);
94920
+ const skillPath = join94(skillsDir, ent.name);
94685
94921
  let fileCount = 0;
94686
94922
  let totalBytes = 0;
94687
94923
  const walk2 = (sub) => {
94688
- for (const e of readdirSync35(sub, { withFileTypes: true })) {
94924
+ for (const e of readdirSync36(sub, { withFileTypes: true })) {
94689
94925
  if (e.isFile()) {
94690
94926
  fileCount += 1;
94691
94927
  try {
94692
- totalBytes += statSync50(join93(sub, e.name)).size;
94928
+ totalBytes += statSync50(join94(sub, e.name)).size;
94693
94929
  } catch {}
94694
94930
  } else if (e.isDirectory()) {
94695
- walk2(join93(sub, e.name));
94931
+ walk2(join94(sub, e.name));
94696
94932
  }
94697
94933
  }
94698
94934
  };
@@ -94731,11 +94967,11 @@ function registerSkillPersonalCommands(program3) {
94731
94967
  // src/cli/self-improve-propose-skill.ts
94732
94968
  import { createConnection as createConnection4 } from "node:net";
94733
94969
  import { homedir as homedir53 } from "node:os";
94734
- import { join as join94 } from "node:path";
94735
- import { readFileSync as readFileSync81 } from "node:fs";
94970
+ import { join as join95 } from "node:path";
94971
+ import { readFileSync as readFileSync82 } from "node:fs";
94736
94972
  var IPC_CONNECT_TIMEOUT_MS = 5000;
94737
94973
  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"));
94974
+ 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
94975
  }
94740
94976
  function fail5(msg, code = 1) {
94741
94977
  console.error(msg);
@@ -94770,7 +95006,7 @@ function registerSelfImproveProposeSkillCommand(program3) {
94770
95006
  fail5("agent name required (--agent or $SWITCHROOM_AGENT_NAME)");
94771
95007
  let draft;
94772
95008
  try {
94773
- draft = JSON.parse(readFileSync81(opts.draft, "utf-8"));
95009
+ draft = JSON.parse(readFileSync82(opts.draft, "utf-8"));
94774
95010
  } catch (e) {
94775
95011
  fail5(`failed to read/parse --draft: ${e.message}`);
94776
95012
  }
@@ -94807,9 +95043,9 @@ function registerSelfImproveProposeSkillCommand(program3) {
94807
95043
  init_esm();
94808
95044
  init_helpers();
94809
95045
  var import_yaml25 = __toESM(require_dist(), 1);
94810
- import { existsSync as existsSync94, readdirSync as readdirSync36, readFileSync as readFileSync82, statSync as statSync51 } from "node:fs";
95046
+ import { existsSync as existsSync95, readdirSync as readdirSync37, readFileSync as readFileSync83, statSync as statSync51 } from "node:fs";
94811
95047
  import { homedir as homedir54 } from "node:os";
94812
- import { join as join95, resolve as resolve56 } from "node:path";
95048
+ import { join as join96, resolve as resolve56 } from "node:path";
94813
95049
  var PERSONAL_PREFIX2 = "personal-";
94814
95050
  var BUNDLED_SUBDIR = "_bundled";
94815
95051
  var AGENT_NAME_RE3 = /^[a-z][a-z0-9_-]{0,62}$/;
@@ -94823,12 +95059,12 @@ function defaultBundledRoot2() {
94823
95059
  return resolve56(homedir54(), ".switchroom/skills/_bundled");
94824
95060
  }
94825
95061
  function readSkillFrontmatter(skillDir) {
94826
- const mdPath = join95(skillDir, "SKILL.md");
94827
- if (!existsSync94(mdPath))
95062
+ const mdPath = join96(skillDir, "SKILL.md");
95063
+ if (!existsSync95(mdPath))
94828
95064
  return null;
94829
95065
  let content;
94830
95066
  try {
94831
- content = readFileSync82(mdPath, "utf-8");
95067
+ content = readFileSync83(mdPath, "utf-8");
94832
95068
  } catch {
94833
95069
  return null;
94834
95070
  }
@@ -94856,7 +95092,7 @@ function readSkillFrontmatter(skillDir) {
94856
95092
  return { fm: parsed };
94857
95093
  }
94858
95094
  function statSkillMd(skillDir) {
94859
- const mdPath = join95(skillDir, "SKILL.md");
95095
+ const mdPath = join96(skillDir, "SKILL.md");
94860
95096
  try {
94861
95097
  const st = statSync51(mdPath);
94862
95098
  return { size: st.size, mtime: st.mtime.toISOString() };
@@ -94867,20 +95103,20 @@ function statSkillMd(skillDir) {
94867
95103
  function listPersonalSkills(agent, agentsRoot = defaultAgentsRoot()) {
94868
95104
  if (!AGENT_NAME_RE3.test(agent))
94869
95105
  return [];
94870
- const skillsDir = join95(agentsRoot, agent, ".claude/skills");
94871
- if (!existsSync94(skillsDir))
95106
+ const skillsDir = join96(agentsRoot, agent, ".claude/skills");
95107
+ if (!existsSync95(skillsDir))
94872
95108
  return [];
94873
95109
  const out = [];
94874
95110
  let entries;
94875
95111
  try {
94876
- entries = readdirSync36(skillsDir);
95112
+ entries = readdirSync37(skillsDir);
94877
95113
  } catch {
94878
95114
  return [];
94879
95115
  }
94880
95116
  for (const ent of entries) {
94881
95117
  if (!ent.startsWith(PERSONAL_PREFIX2))
94882
95118
  continue;
94883
- const dirPath = join95(skillsDir, ent);
95119
+ const dirPath = join96(skillsDir, ent);
94884
95120
  try {
94885
95121
  if (!statSync51(dirPath).isDirectory())
94886
95122
  continue;
@@ -94906,12 +95142,12 @@ function listPersonalSkills(agent, agentsRoot = defaultAgentsRoot()) {
94906
95142
  return out;
94907
95143
  }
94908
95144
  function listSharedSkills(sharedRoot = defaultSharedRoot2()) {
94909
- if (!existsSync94(sharedRoot))
95145
+ if (!existsSync95(sharedRoot))
94910
95146
  return [];
94911
95147
  const out = [];
94912
95148
  let entries;
94913
95149
  try {
94914
- entries = readdirSync36(sharedRoot);
95150
+ entries = readdirSync37(sharedRoot);
94915
95151
  } catch {
94916
95152
  return [];
94917
95153
  }
@@ -94920,7 +95156,7 @@ function listSharedSkills(sharedRoot = defaultSharedRoot2()) {
94920
95156
  continue;
94921
95157
  if (ent.startsWith("."))
94922
95158
  continue;
94923
- const dirPath = join95(sharedRoot, ent);
95159
+ const dirPath = join96(sharedRoot, ent);
94924
95160
  try {
94925
95161
  if (!statSync51(dirPath).isDirectory())
94926
95162
  continue;
@@ -94944,19 +95180,19 @@ function listSharedSkills(sharedRoot = defaultSharedRoot2()) {
94944
95180
  return out;
94945
95181
  }
94946
95182
  function listBundledSkills(bundledRoot = defaultBundledRoot2()) {
94947
- if (!existsSync94(bundledRoot))
95183
+ if (!existsSync95(bundledRoot))
94948
95184
  return [];
94949
95185
  const out = [];
94950
95186
  let entries;
94951
95187
  try {
94952
- entries = readdirSync36(bundledRoot);
95188
+ entries = readdirSync37(bundledRoot);
94953
95189
  } catch {
94954
95190
  return [];
94955
95191
  }
94956
95192
  for (const ent of entries) {
94957
95193
  if (ent.startsWith("."))
94958
95194
  continue;
94959
- const dirPath = join95(bundledRoot, ent);
95195
+ const dirPath = join96(bundledRoot, ent);
94960
95196
  try {
94961
95197
  if (!statSync51(dirPath).isDirectory())
94962
95198
  continue;
@@ -95102,18 +95338,18 @@ init_source();
95102
95338
  init_helpers();
95103
95339
  init_operator_uid();
95104
95340
  import {
95105
- existsSync as existsSync96,
95106
- mkdirSync as mkdirSync54,
95107
- readdirSync as readdirSync37,
95108
- readFileSync as readFileSync84,
95109
- writeFileSync as writeFileSync35,
95341
+ existsSync as existsSync97,
95342
+ mkdirSync as mkdirSync55,
95343
+ readdirSync as readdirSync38,
95344
+ readFileSync as readFileSync85,
95345
+ writeFileSync as writeFileSync36,
95110
95346
  statSync as statSync52,
95111
95347
  lstatSync as lstatSync13,
95112
95348
  realpathSync as realpathSync8,
95113
95349
  copyFileSync as copyFileSync13
95114
95350
  } from "node:fs";
95115
95351
  import { homedir as homedir55 } from "node:os";
95116
- import { join as join96 } from "node:path";
95352
+ import { join as join97 } from "node:path";
95117
95353
  import { spawnSync as spawnSync20 } from "node:child_process";
95118
95354
 
95119
95355
  // src/cli/singleton-stale-cleanup.ts
@@ -95462,7 +95698,7 @@ function resolveHostdHostHome(env2 = process.env, home2 = homedir55()) {
95462
95698
  return resolved;
95463
95699
  }
95464
95700
  function resolveHostdSkillsTarget(hostHome) {
95465
- const skillsPath = join96(hostHome, ".switchroom", "skills");
95701
+ const skillsPath = join97(hostHome, ".switchroom", "skills");
95466
95702
  let st;
95467
95703
  try {
95468
95704
  st = lstatSync13(skillsPath);
@@ -95479,21 +95715,21 @@ function resolveHostdSkillsTarget(hostHome) {
95479
95715
  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
95716
  return;
95481
95717
  }
95482
- if (!existsSync96(target)) {
95718
+ if (!existsSync97(target)) {
95483
95719
  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
95720
  return;
95485
95721
  }
95486
95722
  return target;
95487
95723
  }
95488
95724
  function hostdDir() {
95489
- return join96(homedir55(), ".switchroom", "hostd");
95725
+ return join97(homedir55(), ".switchroom", "hostd");
95490
95726
  }
95491
95727
  function hostdComposePath() {
95492
- return join96(hostdDir(), "docker-compose.yml");
95728
+ return join97(hostdDir(), "docker-compose.yml");
95493
95729
  }
95494
95730
  function backupExistingCompose() {
95495
95731
  const p = hostdComposePath();
95496
- if (!existsSync96(p))
95732
+ if (!existsSync97(p))
95497
95733
  return null;
95498
95734
  const ts = new Date().toISOString().replace(/[:.]/g, "-");
95499
95735
  const bak = `${p}.bak-${ts}`;
@@ -95526,7 +95762,7 @@ async function doInstall(opts, program3) {
95526
95762
  }
95527
95763
  const dir = hostdDir();
95528
95764
  const composePath = hostdComposePath();
95529
- mkdirSync54(dir, { recursive: true });
95765
+ mkdirSync55(dir, { recursive: true });
95530
95766
  const imageTag = resolveHostdImageTag(opts.tag, cfg.release);
95531
95767
  const guard = checkDowngrade({
95532
95768
  container: "switchroom-hostd",
@@ -95559,7 +95795,7 @@ async function doInstall(opts, program3) {
95559
95795
  const bak = backupExistingCompose();
95560
95796
  if (bak)
95561
95797
  console.log(source_default.dim(` Backed up existing compose to ${bak}`));
95562
- writeFileSync35(composePath, yaml, "utf8");
95798
+ writeFileSync36(composePath, yaml, "utf8");
95563
95799
  console.log(source_default.green(` \u2713 Wrote ${composePath}`));
95564
95800
  const adminAgents = Object.entries(cfg.agents ?? {}).filter(([, a]) => a?.admin === true).map(([name]) => name);
95565
95801
  console.log(source_default.dim(` agents served (one socket each): ${allAgents.length === 0 ? "(none)" : allAgents.join(", ")}`));
@@ -95591,7 +95827,7 @@ function doStatus() {
95591
95827
  const composeYml = hostdComposePath();
95592
95828
  console.log(source_default.bold("switchroom-hostd"));
95593
95829
  console.log("");
95594
- if (!existsSync96(composeYml)) {
95830
+ if (!existsSync97(composeYml)) {
95595
95831
  console.log(source_default.yellow(" compose: not installed"));
95596
95832
  console.log(source_default.dim(" run `switchroom hostd install` to set up."));
95597
95833
  return;
@@ -95612,14 +95848,14 @@ function doStatus() {
95612
95848
  } else {
95613
95849
  console.log(source_default.green(` container: ${ps.stdout.trim()}`));
95614
95850
  }
95615
- if (existsSync96(dir)) {
95851
+ if (existsSync97(dir)) {
95616
95852
  const entries = [];
95617
95853
  try {
95618
- for (const name of readdirSync37(dir)) {
95854
+ for (const name of readdirSync38(dir)) {
95619
95855
  if (name === "docker-compose.yml" || name.startsWith("docker-compose.yml."))
95620
95856
  continue;
95621
- const sockPath = join96(dir, name, "sock");
95622
- if (existsSync96(sockPath)) {
95857
+ const sockPath = join97(dir, name, "sock");
95858
+ if (existsSync97(sockPath)) {
95623
95859
  const st = statSync52(sockPath);
95624
95860
  if ((st.mode & 61440) === 49152) {
95625
95861
  entries.push(`${name} \u2192 ${sockPath}`);
@@ -95638,7 +95874,7 @@ function doStatus() {
95638
95874
  }
95639
95875
  function doUninstall() {
95640
95876
  const composeYml = hostdComposePath();
95641
- if (!existsSync96(composeYml)) {
95877
+ if (!existsSync97(composeYml)) {
95642
95878
  console.log(source_default.yellow(" No hostd install detected (no compose file at this path)."));
95643
95879
  return;
95644
95880
  }
@@ -95662,12 +95898,12 @@ function registerHostdCommand(program3) {
95662
95898
  hostd.command("uninstall").description("Stop the hostd container. Leaves the compose file in place for re-install.").action(() => doUninstall());
95663
95899
  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
95900
  const logPath = opts.path ?? defaultAuditLogPath2();
95665
- if (!existsSync96(logPath)) {
95901
+ if (!existsSync97(logPath)) {
95666
95902
  console.error(source_default.yellow(`Audit log not found at ${logPath}.`) + source_default.gray(`
95667
95903
  The log is created when hostd handles its first privileged-verb request.`));
95668
95904
  return;
95669
95905
  }
95670
- const raw = readFileSync84(logPath, "utf-8");
95906
+ const raw = readFileSync85(logPath, "utf-8");
95671
95907
  const limit = Math.max(1, parseInt(opts.tail ?? "50", 10) || 50);
95672
95908
  const filters = {
95673
95909
  agent: opts.agent,
@@ -95710,9 +95946,9 @@ The log is created when hostd handles its first privileged-verb request.`));
95710
95946
  init_source();
95711
95947
  init_helpers();
95712
95948
  init_operator_uid();
95713
- import { chownSync as chownSync9, existsSync as existsSync97, mkdirSync as mkdirSync55, writeFileSync as writeFileSync36, copyFileSync as copyFileSync14 } from "node:fs";
95949
+ import { chownSync as chownSync9, existsSync as existsSync98, mkdirSync as mkdirSync56, writeFileSync as writeFileSync37, copyFileSync as copyFileSync14 } from "node:fs";
95714
95950
  import { homedir as homedir56 } from "node:os";
95715
- import { join as join97 } from "node:path";
95951
+ import { join as join98 } from "node:path";
95716
95952
  import { spawnSync as spawnSync21 } from "node:child_process";
95717
95953
  function resolveWebImageTag(explicitTag, release) {
95718
95954
  if (explicitTag)
@@ -95812,14 +96048,14 @@ services:
95812
96048
  `;
95813
96049
  }
95814
96050
  function webdDir() {
95815
- return join97(homedir56(), ".switchroom", "web");
96051
+ return join98(homedir56(), ".switchroom", "web");
95816
96052
  }
95817
96053
  function webdComposePath() {
95818
- return join97(webdDir(), "docker-compose.yml");
96054
+ return join98(webdDir(), "docker-compose.yml");
95819
96055
  }
95820
96056
  function backupExistingCompose2() {
95821
96057
  const p = webdComposePath();
95822
- if (!existsSync97(p))
96058
+ if (!existsSync98(p))
95823
96059
  return null;
95824
96060
  const ts = new Date().toISOString().replace(/[:.]/g, "-");
95825
96061
  const bak = `${p}.bak-${ts}`;
@@ -95844,7 +96080,7 @@ async function doInstall2(opts, program3) {
95844
96080
  }
95845
96081
  const dir = webdDir();
95846
96082
  const composePath = webdComposePath();
95847
- mkdirSync55(dir, { recursive: true });
96083
+ mkdirSync56(dir, { recursive: true });
95848
96084
  const cfg = getConfig(program3);
95849
96085
  const imageTag = resolveWebImageTag(opts.tag, cfg.release);
95850
96086
  const port = cfg.web_service?.port ?? 8080;
@@ -95879,7 +96115,7 @@ async function doInstall2(opts, program3) {
95879
96115
  const bak = backupExistingCompose2();
95880
96116
  if (bak)
95881
96117
  console.log(source_default.dim(` Backed up existing compose to ${bak}`));
95882
- writeFileSync36(composePath, yaml, "utf8");
96118
+ writeFileSync37(composePath, yaml, "utf8");
95883
96119
  try {
95884
96120
  if (typeof process.geteuid === "function" && process.geteuid() === 0) {
95885
96121
  chownSync9(dir, operatorUid, operatorUid);
@@ -95921,7 +96157,7 @@ function doStatus2() {
95921
96157
  const composeYml = webdComposePath();
95922
96158
  console.log(source_default.bold("switchroom-web"));
95923
96159
  console.log("");
95924
- if (!existsSync97(composeYml)) {
96160
+ if (!existsSync98(composeYml)) {
95925
96161
  console.log(source_default.yellow(" compose: not installed"));
95926
96162
  console.log(source_default.dim(" run `switchroom webd install` to set up."));
95927
96163
  return;
@@ -95945,7 +96181,7 @@ function doStatus2() {
95945
96181
  }
95946
96182
  function doUninstall2() {
95947
96183
  const composeYml = webdComposePath();
95948
- if (!existsSync97(composeYml)) {
96184
+ if (!existsSync98(composeYml)) {
95949
96185
  console.log(source_default.yellow(" No web-service install detected (no compose file at this path)."));
95950
96186
  return;
95951
96187
  }
@@ -95975,9 +96211,9 @@ function registerWebdCommand(program3) {
95975
96211
  // src/cli/host-repair.ts
95976
96212
  init_source();
95977
96213
  import { homedir as homedir57 } from "node:os";
95978
- import { join as join98 } from "node:path";
96214
+ import { join as join99 } from "node:path";
95979
96215
  var ARTIFACT_ALLOWLIST = {
95980
- dockerComposePluginDir: (home2) => join98(home2, ".docker", "cli-plugins", "docker-compose"),
96216
+ dockerComposePluginDir: (home2) => join99(home2, ".docker", "cli-plugins", "docker-compose"),
95981
96217
  stateSentinel: "/state"
95982
96218
  };
95983
96219
  function isStateBogusAutoDir(probe2) {
@@ -96131,7 +96367,7 @@ function applyMountRepairs(items, deps) {
96131
96367
  function registerHostCommand(program3) {
96132
96368
  const host = program3.command("host").description("Host-level maintenance operations for switchroom");
96133
96369
  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");
96370
+ const { rmdirSync: rmdirSync2, rmSync: rmSync20, lstatSync: lstatSync14, readdirSync: readdirSync39 } = await import("node:fs");
96135
96371
  const probe2 = {
96136
96372
  lstat(path9) {
96137
96373
  try {
@@ -96142,7 +96378,7 @@ function registerHostCommand(program3) {
96142
96378
  },
96143
96379
  readdir(path9) {
96144
96380
  try {
96145
- return readdirSync38(path9);
96381
+ return readdirSync39(path9);
96146
96382
  } catch {
96147
96383
  return null;
96148
96384
  }