switchroom 0.19.38 → 0.19.39

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.38", COMMIT_SHA = "9ec88983";
2123
+ var VERSION = "0.19.39", COMMIT_SHA = "4aff2bdd";
2124
2124
 
2125
2125
  // src/cli/resolve-version.ts
2126
2126
  import { existsSync, readFileSync } from "node:fs";
@@ -15830,7 +15830,7 @@ function hindsightPgEnv(overrides = new Map) {
15830
15830
  }
15831
15831
  return out;
15832
15832
  }
15833
- var HINDSIGHT_PG_MEM_LIMIT_MIB_FOR_DERIVATION, HINDSIGHT_PG_APP_ANON_MIB = 2560, HINDSIGHT_PG_PAGE_CACHE_FLOOR_MIB = 2048, HINDSIGHT_PG_SHARED_BUFFERS_BUDGET_MIB, HINDSIGHT_PG_DEFAULT_SHARED_BUFFERS_MIB = 3072, HINDSIGHT_PG_DEFAULT_EFFECTIVE_CACHE_SIZE_MIB = 7168, HINDSIGHT_PG_EFFECTIVE_CACHE_SIZE_ENV = "SWITCHROOM_HINDSIGHT_PG_EFFECTIVE_CACHE_SIZE", HINDSIGHT_PG_SHARED_BUFFERS_ENV = "SWITCHROOM_HINDSIGHT_PG_SHARED_BUFFERS", HINDSIGHT_PG_FSYNC_ENV = "SWITCHROOM_HINDSIGHT_PG_FSYNC", HINDSIGHT_PG_DEFAULT_FSYNC = "on", HINDSIGHT_PG_DEFAULTS, HINDSIGHT_PG_ENV_KEYS;
15833
+ var HINDSIGHT_PG_MEM_LIMIT_MIB_FOR_DERIVATION, HINDSIGHT_PG_APP_ANON_MIB = 2560, HINDSIGHT_PG_PAGE_CACHE_FLOOR_MIB = 2048, HINDSIGHT_PG_SHARED_BUFFERS_BUDGET_MIB, HINDSIGHT_PG_DEFAULT_SHARED_BUFFERS_MIB = 6144, HINDSIGHT_PG_DEFAULT_EFFECTIVE_CACHE_SIZE_MIB = 12288, HINDSIGHT_PG_EFFECTIVE_CACHE_SIZE_ENV = "SWITCHROOM_HINDSIGHT_PG_EFFECTIVE_CACHE_SIZE", HINDSIGHT_PG_SHARED_BUFFERS_ENV = "SWITCHROOM_HINDSIGHT_PG_SHARED_BUFFERS", HINDSIGHT_PG_FSYNC_ENV = "SWITCHROOM_HINDSIGHT_PG_FSYNC", HINDSIGHT_PG_DEFAULT_FSYNC = "on", HINDSIGHT_PG_DEFAULTS, HINDSIGHT_PG_ENV_KEYS;
15834
15834
  var init_hindsight_pg_defaults = __esm(() => {
15835
15835
  HINDSIGHT_PG_MEM_LIMIT_MIB_FOR_DERIVATION = 16 * 1024;
15836
15836
  HINDSIGHT_PG_SHARED_BUFFERS_BUDGET_MIB = HINDSIGHT_PG_MEM_LIMIT_MIB_FOR_DERIVATION - HINDSIGHT_PG_APP_ANON_MIB - HINDSIGHT_PG_PAGE_CACHE_FLOOR_MIB;
@@ -15908,7 +15908,7 @@ function hindsightPerfEnv(caps, overrides = new Map) {
15908
15908
  function findUnmanagedHindsightEnvKeys(configEnv) {
15909
15909
  return Object.keys(configEnv ?? {}).filter((key) => !HINDSIGHT_PERF_ENV_KEYS.has(key) && !HINDSIGHT_PG_ENV_KEYS.has(key)).sort();
15910
15910
  }
15911
- var HINDSIGHT_RERANKER_MAX_CANDIDATES_FOR_DERIVATION = 150, HINDSIGHT_DEFAULT_RECALL_MAX_CANDIDATES_PER_SOURCE, HINDSIGHT_DEFAULT_LINK_EXPANSION_PER_ENTITY_LIMIT = 50, HINDSIGHT_DEFAULT_LINK_EXPANSION_TIMEOUT_S = 2, HINDSIGHT_DEFAULT_LLM_REASONING_EFFORT = "low", HINDSIGHT_DEFAULT_LLM_MAX_CONCURRENT = 4, HINDSIGHT_DEFAULT_RETAIN_LLM_MAX_CONCURRENT = 1, HINDSIGHT_DEFAULT_CONSOLIDATION_LLM_MAX_CONCURRENT, HINDSIGHT_DEFAULT_RERANKER_LOCAL_FP16 = "true", HINDSIGHT_DEFAULT_RERANKER_LOCAL_BATCH_SIZE = 128, HINDSIGHT_DEFAULT_LLM_STRICT_SCHEMA = "true", HINDSIGHT_DEFAULT_LLM_MAX_RETRIES = 2, HINDSIGHT_DEFAULT_CONSOLIDATION_LLM_PARALLELISM = 2, HINDSIGHT_DEFAULT_MAX_OBSERVATIONS_PER_SCOPE = 1000, HINDSIGHT_DEFAULT_RERANKER_BUCKET_BATCHING = "true", HINDSIGHT_DEFAULT_RERANKER_MAX_CANDIDATES = 150, HINDSIGHT_DEFAULT_RERANKER_LOCAL_MAX_CONCURRENT = 4, HINDSIGHT_DEFAULT_RECALL_MAX_CONCURRENT = 8, HINDSIGHT_DEFAULT_REFLECT_WALL_TIMEOUT_S = 600, HINDSIGHT_DEFAULT_CONSOLIDATION_MAX_MEMORIES_PER_ROUND = 500, HINDSIGHT_DEFAULT_CONSOLIDATION_SLOT_LIMIT = 6, HINDSIGHT_DEFAULT_CONSOLIDATION_MAX_SLOTS = 1, HINDSIGHT_DEFAULT_RECENCY_DECAY_FUNCTION = "exponential", HINDSIGHT_DEFAULT_RECENCY_DECAY_HALFLIFE_DAYS = 30, HINDSIGHT_PERF_DEFAULTS_UNGATED, HINDSIGHT_PERF_DEFAULTS_GPU, HINDSIGHT_PERF_DEFAULTS_LOCAL_LLM, HINDSIGHT_PERF_OVERRIDE_ONLY_KEYS, HINDSIGHT_PERF_ENV_KEYS;
15911
+ var HINDSIGHT_RERANKER_MAX_CANDIDATES_FOR_DERIVATION = 150, HINDSIGHT_DEFAULT_RECALL_MAX_CANDIDATES_PER_SOURCE, HINDSIGHT_DEFAULT_LINK_EXPANSION_PER_ENTITY_LIMIT = 50, HINDSIGHT_DEFAULT_LINK_EXPANSION_TIMEOUT_S = 2, HINDSIGHT_DEFAULT_LLM_REASONING_EFFORT = "low", HINDSIGHT_DEFAULT_LLM_MAX_CONCURRENT = 4, HINDSIGHT_DEFAULT_RETAIN_LLM_MAX_CONCURRENT = 1, HINDSIGHT_DEFAULT_CONSOLIDATION_LLM_MAX_CONCURRENT, HINDSIGHT_DEFAULT_RERANKER_LOCAL_FP16 = "true", HINDSIGHT_DEFAULT_RERANKER_LOCAL_BATCH_SIZE = 128, HINDSIGHT_DEFAULT_LLM_STRICT_SCHEMA = "true", HINDSIGHT_DEFAULT_LLM_MAX_RETRIES = 2, HINDSIGHT_DEFAULT_CONSOLIDATION_LLM_PARALLELISM = 2, HINDSIGHT_DEFAULT_MAX_OBSERVATIONS_PER_SCOPE = 1000, HINDSIGHT_DEFAULT_RERANKER_BUCKET_BATCHING = "true", HINDSIGHT_DEFAULT_RERANKER_MAX_CANDIDATES = 150, HINDSIGHT_DEFAULT_RERANKER_LOCAL_MAX_CONCURRENT = 4, HINDSIGHT_DEFAULT_RECALL_MAX_CONCURRENT = 8, HINDSIGHT_DEFAULT_REFLECT_WALL_TIMEOUT_S = 600, HINDSIGHT_DEFAULT_CONSOLIDATION_MAX_MEMORIES_PER_ROUND = 250, HINDSIGHT_DEFAULT_CONSOLIDATION_SLOT_LIMIT = 6, HINDSIGHT_DEFAULT_CONSOLIDATION_MAX_SLOTS = 1, HINDSIGHT_DEFAULT_RECENCY_DECAY_FUNCTION = "exponential", HINDSIGHT_DEFAULT_RECENCY_DECAY_HALFLIFE_DAYS = 30, HINDSIGHT_PERF_DEFAULTS_UNGATED, HINDSIGHT_PERF_DEFAULTS_GPU, HINDSIGHT_PERF_DEFAULTS_LOCAL_LLM, HINDSIGHT_PERF_OVERRIDE_ONLY_KEYS, HINDSIGHT_PERF_ENV_KEYS;
15912
15912
  var init_hindsight_perf_defaults = __esm(() => {
15913
15913
  init_hindsight_pg_defaults();
15914
15914
  HINDSIGHT_DEFAULT_RECALL_MAX_CANDIDATES_PER_SOURCE = Math.ceil(HINDSIGHT_RERANKER_MAX_CANDIDATES_FOR_DERIVATION * 0.4);
@@ -45987,6 +45987,38 @@ function installCron(opts) {
45987
45987
  renameSync15(tmp, path6);
45988
45988
  return { status: "installed", path: path6, content };
45989
45989
  }
45990
+ function parseCronUser(content) {
45991
+ for (const line of content.split(`
45992
+ `)) {
45993
+ const trimmed = line.trim();
45994
+ if (!trimmed || trimmed.startsWith("#"))
45995
+ continue;
45996
+ if (!trimmed.includes("hindsight-watch"))
45997
+ continue;
45998
+ const fields = trimmed.split(/\s+/);
45999
+ if (fields.length >= 7)
46000
+ return fields[5];
46001
+ }
46002
+ return null;
46003
+ }
46004
+ function reconcileCron(opts) {
46005
+ const path6 = opts.path ?? CRON_PATH;
46006
+ if (!existsSync63(path6))
46007
+ return { status: "absent", path: path6 };
46008
+ let user = opts.fallbackUser;
46009
+ try {
46010
+ user = parseCronUser(readFileSync60(path6, "utf8")) ?? opts.fallbackUser;
46011
+ } catch {}
46012
+ if (!user) {
46013
+ throw new Error(`cannot reconcile ${path6}: no cron-user parseable from the existing fragment and no fallback user available`);
46014
+ }
46015
+ const r = installCron({ user, binary: opts.binary, path: path6 });
46016
+ return {
46017
+ status: r.status === "installed" ? "reconciled" : "unchanged",
46018
+ path: path6,
46019
+ content: r.content
46020
+ };
46021
+ }
45990
46022
  var CRON_PATH = "/etc/cron.d/hindsight-watch", CRON_SCHEDULE = "*/15 * * * *", CRON_LOG_PATH = "/var/log/hindsight-watch.log", CRON_LOCK_PATH = "/run/lock/hindsight-watch.lock";
45991
46023
  var init_install_cron = () => {};
45992
46024
 
@@ -51689,6 +51721,9 @@ import { spawnSync as spawnSync12 } from "node:child_process";
51689
51721
  function fixFor(c, target) {
51690
51722
  return remediationFor(classifyComponent(c), target);
51691
51723
  }
51724
+ function hostCliBehindStatus(c) {
51725
+ return c.kind === "cli" ? "fail" : "warn";
51726
+ }
51692
51727
  function runComponentVersionChecks(config, opts = {}) {
51693
51728
  const exec = opts.exec ?? defaultExec2;
51694
51729
  const components = collectComponents(opts.cliVersion ?? SWITCHROOM_VERSION, exec);
@@ -51712,10 +51747,11 @@ function runComponentVersionChecks(config, opts = {}) {
51712
51747
  });
51713
51748
  }
51714
51749
  for (const c of report.behind) {
51750
+ const status = hostCliBehindStatus(c);
51715
51751
  results.push({
51716
51752
  name: `component behind: ${c.name}`,
51717
- status: "warn",
51718
- detail: `on ${c.version}, expected ${report.target} (${src})`,
51753
+ status,
51754
+ detail: status === "fail" ? `on ${c.version}, expected ${report.target} (${src}) \u2014 the host CLI must never trail the fleet; it self-heals in-band via \`switchroom update\`` : `on ${c.version}, expected ${report.target} (${src})`,
51719
51755
  fix: fixFor(c, report.target)
51720
51756
  });
51721
51757
  }
@@ -68980,9 +69016,9 @@ __export(exports_server, {
68980
69016
  dispatchTool: () => dispatchTool,
68981
69017
  TOOLS: () => TOOLS
68982
69018
  });
68983
- import { spawnSync as spawnSync22 } from "node:child_process";
69019
+ import { spawnSync as spawnSync23 } from "node:child_process";
68984
69020
  function execCli(args, stdin) {
68985
- const r = spawnSync22(CLI_BIN, args, {
69021
+ const r = spawnSync23(CLI_BIN, args, {
68986
69022
  encoding: "utf-8",
68987
69023
  env: process.env,
68988
69024
  timeout: 15000,
@@ -69491,7 +69527,7 @@ __export(exports_server2, {
69491
69527
  TOOLS: () => TOOLS2
69492
69528
  });
69493
69529
  import { randomBytes as randomBytes16 } from "node:crypto";
69494
- import { existsSync as existsSync105 } from "node:fs";
69530
+ import { existsSync as existsSync106 } from "node:fs";
69495
69531
  function selfSocketPath() {
69496
69532
  return `/run/switchroom/hostd/${SELF_AGENT}/sock`;
69497
69533
  }
@@ -69518,7 +69554,7 @@ async function dispatchTool2(name, args) {
69518
69554
  return errorText2("hostd MCP: SWITCHROOM_AGENT_NAME env var is not set \u2014 cannot " + "determine which per-agent socket to talk to.");
69519
69555
  }
69520
69556
  const sockPath = selfSocketPath();
69521
- if (!existsSync105(sockPath)) {
69557
+ if (!existsSync106(sockPath)) {
69522
69558
  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.`);
69523
69559
  }
69524
69560
  let req;
@@ -69769,13 +69805,13 @@ function resolveAuditLogPath() {
69769
69805
  if (process.env.HOSTD_AUDIT_LOG_PATH)
69770
69806
  return process.env.HOSTD_AUDIT_LOG_PATH;
69771
69807
  const bindMounted = "/host-home/.switchroom/host-control-audit.log";
69772
- if (existsSync105(bindMounted))
69808
+ if (existsSync106(bindMounted))
69773
69809
  return bindMounted;
69774
69810
  return defaultAuditLogPath2();
69775
69811
  }
69776
69812
  function getLastUpdateApplyStatus() {
69777
69813
  const path10 = resolveAuditLogPath();
69778
- if (!existsSync105(path10)) {
69814
+ if (!existsSync106(path10)) {
69779
69815
  return errorText2(`get_status: audit log not found at ${path10}. No update_apply has run yet?`);
69780
69816
  }
69781
69817
  let raw;
@@ -70494,11 +70530,11 @@ var init_test_agents = __esm(() => {
70494
70530
  });
70495
70531
 
70496
70532
  // src/litellm/header-passthrough-guard.ts
70497
- import { existsSync as existsSync108, readdirSync as readdirSync41 } from "node:fs";
70533
+ import { existsSync as existsSync109, readdirSync as readdirSync41 } from "node:fs";
70498
70534
  function discoverLiveLitellmConfigPath(opts) {
70499
70535
  const servicesDir = opts?.servicesDir ?? COOLIFY_SERVICES_DIR;
70500
70536
  const readdir2 = opts?.readdirFn ?? ((p) => readdirSync41(p));
70501
- const exists = opts?.existsFn ?? existsSync108;
70537
+ const exists = opts?.existsFn ?? existsSync109;
70502
70538
  let entries;
70503
70539
  try {
70504
70540
  entries = readdir2(servicesDir);
@@ -70588,7 +70624,7 @@ var init_header_passthrough_guard = __esm(() => {
70588
70624
  });
70589
70625
 
70590
70626
  // src/fleet-health/litellm-config-sensor.ts
70591
- import { readFileSync as readFileSync97, existsSync as existsSync109 } from "node:fs";
70627
+ import { readFileSync as readFileSync98, existsSync as existsSync110 } from "node:fs";
70592
70628
  function resolveLitellmConfigPath(explicit, discoverFn = () => discoverLiveLitellmConfigPath()) {
70593
70629
  if (explicit)
70594
70630
  return explicit;
@@ -70599,8 +70635,8 @@ function resolveLitellmConfigPath(explicit, discoverFn = () => discoverLiveLitel
70599
70635
  }
70600
70636
  function scanLitellmConfig(opts = {}) {
70601
70637
  const path10 = resolveLitellmConfigPath(opts.path, opts.discoverFn);
70602
- const exists = opts.existsFn ?? existsSync109;
70603
- const read = opts.readFn ?? ((p) => readFileSync97(p, "utf-8"));
70638
+ const exists = opts.existsFn ?? existsSync110;
70639
+ const read = opts.readFn ?? ((p) => readFileSync98(p, "utf-8"));
70604
70640
  const log = opts.log ?? (() => {});
70605
70641
  const nowIso = opts.nowIso ?? new Date().toISOString();
70606
70642
  if (path10 === null) {
@@ -70675,20 +70711,20 @@ __export(exports_scan, {
70675
70711
  ledgerPathForBase: () => ledgerPathForBase
70676
70712
  });
70677
70713
  import {
70678
- readFileSync as readFileSync98,
70714
+ readFileSync as readFileSync99,
70679
70715
  readdirSync as readdirSync42,
70680
- existsSync as existsSync110,
70681
- mkdirSync as mkdirSync63,
70682
- writeFileSync as writeFileSync46
70716
+ existsSync as existsSync111,
70717
+ mkdirSync as mkdirSync64,
70718
+ writeFileSync as writeFileSync47
70683
70719
  } from "node:fs";
70684
- import { resolve as resolve61, dirname as dirname42 } from "node:path";
70720
+ import { resolve as resolve61, dirname as dirname43 } from "node:path";
70685
70721
  import { homedir as homedir61 } from "node:os";
70686
70722
  function resolveSwitchroomBase(home2 = process.env.SWITCHROOM_HOME ?? process.env.HOME ?? homedir61()) {
70687
70723
  return resolve61(home2, ".switchroom");
70688
70724
  }
70689
70725
  function listAgents(base) {
70690
70726
  const dir = resolve61(base, "agents");
70691
- if (!existsSync110(dir))
70727
+ if (!existsSync111(dir))
70692
70728
  return [];
70693
70729
  try {
70694
70730
  return readdirSync42(dir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name).sort();
@@ -70717,16 +70753,16 @@ function runScan(opts = {}) {
70717
70753
  let gwText = "";
70718
70754
  let sawArtifact = false;
70719
70755
  try {
70720
- if (existsSync110(turnsPath)) {
70721
- turnsText = readFileSync98(turnsPath, "utf-8");
70756
+ if (existsSync111(turnsPath)) {
70757
+ turnsText = readFileSync99(turnsPath, "utf-8");
70722
70758
  sawArtifact = true;
70723
70759
  }
70724
70760
  } catch (e) {
70725
70761
  log(`fleet-health: WARN skipping ${agent} turns.jsonl unreadable: ${String(e)}`);
70726
70762
  }
70727
70763
  try {
70728
- if (existsSync110(gwPath)) {
70729
- gwText = readFileSync98(gwPath, "utf-8");
70764
+ if (existsSync111(gwPath)) {
70765
+ gwText = readFileSync99(gwPath, "utf-8");
70730
70766
  sawArtifact = true;
70731
70767
  }
70732
70768
  } catch (e) {
@@ -70768,20 +70804,20 @@ function runScan(opts = {}) {
70768
70804
  function readLedgerIfPresent(base) {
70769
70805
  const path10 = ledgerPathForBase(base);
70770
70806
  try {
70771
- if (!existsSync110(path10))
70807
+ if (!existsSync111(path10))
70772
70808
  return null;
70773
- return JSON.parse(readFileSync98(path10, "utf-8"));
70809
+ return JSON.parse(readFileSync99(path10, "utf-8"));
70774
70810
  } catch {
70775
70811
  return null;
70776
70812
  }
70777
70813
  }
70778
70814
  function ledgerPathForBase(base) {
70779
- return fleetHealthLedgerPath(dirname42(base));
70815
+ return fleetHealthLedgerPath(dirname43(base));
70780
70816
  }
70781
70817
  function writeLedger(base, ledger) {
70782
70818
  const path10 = ledgerPathForBase(base);
70783
- mkdirSync63(dirname42(path10), { recursive: true });
70784
- writeFileSync46(path10, JSON.stringify(ledger, null, 2) + `
70819
+ mkdirSync64(dirname43(path10), { recursive: true });
70820
+ writeFileSync47(path10, JSON.stringify(ledger, null, 2) + `
70785
70821
  `, "utf-8");
70786
70822
  return path10;
70787
70823
  }
@@ -92108,9 +92144,9 @@ init_source();
92108
92144
  init_loader();
92109
92145
  init_lifecycle();
92110
92146
  init_compose_env();
92111
- import { existsSync as existsSync80, mkdirSync as mkdirSync45, readFileSync as readFileSync74, realpathSync as realpathSync6, statSync as statSync45, chownSync as chownSync8 } from "node:fs";
92112
- import { spawnSync as spawnSync16 } from "node:child_process";
92113
- import { join as join84, dirname as dirname33, resolve as resolve45 } from "node:path";
92147
+ import { existsSync as existsSync81, mkdirSync as mkdirSync46, readFileSync as readFileSync75, realpathSync as realpathSync6, statSync as statSync45, chownSync as chownSync8 } from "node:fs";
92148
+ import { spawnSync as spawnSync17 } from "node:child_process";
92149
+ import { join as join84, dirname as dirname34, resolve as resolve45 } from "node:path";
92114
92150
  import { homedir as homedir44 } from "node:os";
92115
92151
 
92116
92152
  // src/cli/release-yaml.ts
@@ -92639,10 +92675,151 @@ function defaultSelfUpdateIO() {
92639
92675
  // src/cli/update.ts
92640
92676
  init_self_invoke();
92641
92677
  init_component_versions();
92678
+ init_install_cron();
92679
+
92680
+ // src/host-cli-self-heal/install-timer.ts
92681
+ import { spawnSync as spawnSync16 } from "node:child_process";
92682
+ import { existsSync as existsSync80, mkdirSync as mkdirSync45, readFileSync as readFileSync74, renameSync as renameSync20, writeFileSync as writeFileSync31 } from "node:fs";
92683
+ import { dirname as dirname33 } from "node:path";
92684
+ var SERVICE_PATH = "/etc/systemd/system/switchroom-self-heal.service";
92685
+ var TIMER_PATH = "/etc/systemd/system/switchroom-self-heal.timer";
92686
+ var TIMER_UNIT = "switchroom-self-heal.timer";
92687
+ var SYSTEMD_MARKER = "/run/systemd/system";
92688
+ var DOC_URL = "https://github.com/switchroom/switchroom/blob/main/docs/operators/host-cli-self-heal.md";
92689
+ function renderService(opts) {
92690
+ const homeLine = opts.home ? `Environment=HOME=${opts.home}
92691
+ ` : "";
92692
+ return `# switchroom host CLI self-heal \u2014 keeps /usr/local/bin/switchroom from silently
92693
+ ` + `# trailing the fleet. Managed by \`switchroom update\`; edits are overwritten.
92694
+ ` + `[Unit]
92695
+ ` + `Description=Switchroom host CLI self-heal (re-run \`switchroom update\` so the host binary can't silently trail the fleet)
92696
+ ` + `Documentation=${DOC_URL}
92697
+ ` + `After=network-online.target docker.service
92698
+ ` + `Wants=network-online.target
92699
+ ` + `
92700
+ ` + `[Service]
92701
+ ` + `Type=oneshot
92702
+ ` + `# Run as the operator whose ~/.switchroom holds the fleet config \u2014 NOT root.
92703
+ ` + `User=${opts.user}
92704
+ ` + homeLine + `# --skip-images keeps each tick cheap: self-update-cli (the host binary swap)
92705
+ ` + `# still runs; GHCR pulls and container recreation do not.
92706
+ ` + `ExecStart=${opts.binary} update --skip-images
92707
+ ` + `# Self-heal must never wedge the host: bound the run and run at low priority.
92708
+ ` + `TimeoutStartSec=600
92709
+ ` + `Nice=10
92710
+ `;
92711
+ }
92712
+ function renderTimer() {
92713
+ return `# switchroom host CLI self-heal timer. Managed by \`switchroom update\`.
92714
+ ` + `[Unit]
92715
+ ` + `Description=Run the Switchroom host CLI self-heal every 30 minutes
92716
+ ` + `Documentation=${DOC_URL}
92717
+ ` + `
92718
+ ` + `[Timer]
92719
+ ` + `OnBootSec=5min
92720
+ ` + `OnUnitActiveSec=30min
92721
+ ` + `RandomizedDelaySec=2min
92722
+ ` + `Persistent=true
92723
+ ` + `
92724
+ ` + `[Install]
92725
+ ` + `WantedBy=timers.target
92726
+ `;
92727
+ }
92728
+ function writeUnitIdempotent(path7, content) {
92729
+ if (existsSync80(path7)) {
92730
+ try {
92731
+ if (readFileSync74(path7, "utf8") === content)
92732
+ return "unchanged";
92733
+ } catch {}
92734
+ }
92735
+ mkdirSync45(dirname33(path7), { recursive: true });
92736
+ const tmp = `${path7}.${process.pid}.tmp`;
92737
+ writeFileSync31(tmp, content, { mode: 420 });
92738
+ renameSync20(tmp, path7);
92739
+ return "written";
92740
+ }
92741
+ function homeFromPasswd(user) {
92742
+ try {
92743
+ for (const line of readFileSync74("/etc/passwd", "utf8").split(`
92744
+ `)) {
92745
+ const f = line.split(":");
92746
+ if (f[0] === user && f[5])
92747
+ return f[5];
92748
+ }
92749
+ } catch {}
92750
+ return;
92751
+ }
92752
+ function resolveOperatorUser(env2) {
92753
+ const user = env2.SUDO_USER ?? env2.USER ?? env2.LOGNAME;
92754
+ if (!user || user === "root")
92755
+ return null;
92756
+ return user;
92757
+ }
92758
+ function installSelfHealTimer(deps = {}) {
92759
+ const env2 = deps.env ?? process.env;
92760
+ const systemdBooted = deps.systemdBooted ?? (() => existsSync80(SYSTEMD_MARKER));
92761
+ const geteuid = deps.geteuid ?? (() => typeof process.geteuid === "function" ? process.geteuid() : undefined);
92762
+ const homeForUser = deps.homeForUser ?? homeFromPasswd;
92763
+ const servicePath = deps.servicePath ?? SERVICE_PATH;
92764
+ const timerPath = deps.timerPath ?? TIMER_PATH;
92765
+ const binary = env2.SWITCHROOM_BINARY ?? "/usr/local/bin/switchroom";
92766
+ const user = resolveOperatorUser(env2);
92767
+ const renderUser = user ?? "OPERATOR";
92768
+ const home2 = user ? homeForUser(user) : undefined;
92769
+ const serviceContent = renderService({ binary, user: renderUser, ...home2 ? { home: home2 } : {} });
92770
+ const timerContent = renderTimer();
92771
+ const manualCommands = [
92772
+ "sudo systemctl daemon-reload",
92773
+ `sudo systemctl enable --now ${TIMER_UNIT}`
92774
+ ];
92775
+ const base = { servicePath, timerPath, serviceContent, timerContent, manualCommands };
92776
+ if (!binary.startsWith("/")) {
92777
+ return {
92778
+ status: "skipped",
92779
+ reason: `SWITCHROOM_BINARY must be an absolute path (got ${binary})`,
92780
+ ...base
92781
+ };
92782
+ }
92783
+ if (!systemdBooted()) {
92784
+ return {
92785
+ status: "skipped",
92786
+ reason: "host is not systemd-booted (/run/systemd/system absent)",
92787
+ ...base
92788
+ };
92789
+ }
92790
+ if (geteuid() !== 0) {
92791
+ return { status: "skipped", reason: "not privileged (euid != 0)", ...base };
92792
+ }
92793
+ if (!user) {
92794
+ return {
92795
+ status: "skipped",
92796
+ reason: "no non-root operator user resolvable (SUDO_USER / USER / LOGNAME all unset or root)",
92797
+ ...base
92798
+ };
92799
+ }
92800
+ const svc = writeUnitIdempotent(servicePath, serviceContent);
92801
+ const tim = writeUnitIdempotent(timerPath, timerContent);
92802
+ const changed = svc === "written" || tim === "written";
92803
+ const runner = deps.runner ?? ((cmd, args) => {
92804
+ const r = spawnSync16(cmd, args, { stdio: "inherit" });
92805
+ return { status: r.status ?? 1 };
92806
+ });
92807
+ const reload = runner("systemctl", ["daemon-reload"]);
92808
+ if (reload.status !== 0) {
92809
+ throw new Error(`systemctl daemon-reload failed (exit ${reload.status})`);
92810
+ }
92811
+ const enable = runner("systemctl", ["enable", "--now", TIMER_UNIT]);
92812
+ if (enable.status !== 0) {
92813
+ throw new Error(`systemctl enable --now ${TIMER_UNIT} failed (exit ${enable.status})`);
92814
+ }
92815
+ return { status: changed ? "installed" : "unchanged", ...base };
92816
+ }
92817
+
92818
+ // src/cli/update.ts
92642
92819
  function defaultPersistPin(configPath) {
92643
92820
  return (pin) => {
92644
92821
  const path7 = configPath ?? findConfigFile();
92645
- const before = readFileSync74(path7, "utf8");
92822
+ const before = readFileSync75(path7, "utf8");
92646
92823
  const after = setReleasePinInConfig(before, pin);
92647
92824
  if (after === before)
92648
92825
  return;
@@ -92658,16 +92835,16 @@ function defaultPersistPin(configPath) {
92658
92835
  }
92659
92836
  var DEFAULT_COMPOSE_PATH2 = join84(homedir44(), ".switchroom", "compose", "docker-compose.yml");
92660
92837
  function runningFromSwitchroomCheckout(scriptPath) {
92661
- let dir = dirname33(scriptPath);
92838
+ let dir = dirname34(scriptPath);
92662
92839
  for (let i = 0;i < 12; i++) {
92663
- if (existsSync80(join84(dir, ".git"))) {
92840
+ if (existsSync81(join84(dir, ".git"))) {
92664
92841
  try {
92665
- const pkg = JSON.parse(readFileSync74(join84(dir, "package.json"), "utf-8"));
92842
+ const pkg = JSON.parse(readFileSync75(join84(dir, "package.json"), "utf-8"));
92666
92843
  if (pkg.name === "switchroom")
92667
92844
  return true;
92668
92845
  } catch {}
92669
92846
  }
92670
- const parent = dirname33(dir);
92847
+ const parent = dirname34(dir);
92671
92848
  if (parent === dir)
92672
92849
  break;
92673
92850
  dir = parent;
@@ -92728,7 +92905,7 @@ function planUpdate(opts) {
92728
92905
  bundleDir: import.meta.dirname,
92729
92906
  execPath: process.execPath,
92730
92907
  scriptPath,
92731
- inContainer: process.env.SWITCHROOM_HOSTD_CONTEXT === "1" || existsSync80("/.dockerenv")
92908
+ inContainer: process.env.SWITCHROOM_HOSTD_CONTEXT === "1" || existsSync81("/.dockerenv")
92732
92909
  });
92733
92910
  if (detection.kind !== "static-binary") {
92734
92911
  say(source_default.gray(` host CLI not self-updated: ${detection.reason}
@@ -92801,7 +92978,7 @@ function planUpdate(opts) {
92801
92978
  steps.push({
92802
92979
  name: "pull-images",
92803
92980
  description: "Pull broker / kernel / agent images from GHCR",
92804
- skipReason: opts.skipImages ? "--skip-images flag set" : !existsSync80(composePath) ? `compose file not found at ${composePath} (run \`switchroom apply --compose-only\` first)` : undefined,
92981
+ skipReason: opts.skipImages ? "--skip-images flag set" : !existsSync81(composePath) ? `compose file not found at ${composePath} (run \`switchroom apply --compose-only\` first)` : undefined,
92805
92982
  run: () => {
92806
92983
  const r = runner("docker", [
92807
92984
  "compose",
@@ -92846,6 +93023,69 @@ function planUpdate(opts) {
92846
93023
  throw new Error("switchroom apply failed");
92847
93024
  }
92848
93025
  });
93026
+ steps.push({
93027
+ name: "reconcile-hindsight-watch-cron",
93028
+ description: "Reconcile /etc/cron.d/hindsight-watch (binary path / schedule / flags) on already-armed hosts \u2014 idempotent; no-op when unarmed or already current",
93029
+ skipReason: hostdContext ? "deferred (hostd-context): /etc/cron.d is on the host, not in the hostd container \u2014 finish host-side with `switchroom hindsight-watch --install-cron`" : undefined,
93030
+ isHostdDeferred: hostdContext,
93031
+ run: () => {
93032
+ const say = opts.stdout ?? ((t) => process.stdout.write(t));
93033
+ const binary = process.env.SWITCHROOM_BINARY ?? "/usr/local/bin/switchroom";
93034
+ const fallbackUser = process.env.SUDO_USER ?? process.env.USER ?? process.env.LOGNAME;
93035
+ let res;
93036
+ try {
93037
+ res = reconcileCron({
93038
+ binary,
93039
+ fallbackUser,
93040
+ ...opts.watchCronPath ? { path: opts.watchCronPath } : {}
93041
+ });
93042
+ } catch (e) {
93043
+ say(source_default.yellow(` hindsight-watch cron not reconciled: ${e.message}
93044
+ `));
93045
+ return;
93046
+ }
93047
+ if (res.status === "absent") {
93048
+ say(source_default.gray(" hindsight-watch cron not armed \u2014 skipping reconcile " + "(arm with `switchroom hindsight-watch --install-cron`; doctor FAILs while unarmed)\n"));
93049
+ } else if (res.status === "reconciled") {
93050
+ say(source_default.green(` hindsight-watch cron reconciled at ${res.path}
93051
+ `));
93052
+ } else {
93053
+ say(source_default.gray(` hindsight-watch cron already current at ${res.path}
93054
+ `));
93055
+ }
93056
+ }
93057
+ });
93058
+ steps.push({
93059
+ name: "install-self-heal-timer",
93060
+ description: "Install + enable the switchroom-self-heal systemd timer so a shipped release converges the host binary automatically \u2014 graceful no-op without systemd/privilege",
93061
+ skipReason: hostdContext ? "deferred (hostd-context): /etc/systemd/system is on the host, not in the hostd container \u2014 finish host-side by re-running `switchroom update` on the host" : undefined,
93062
+ isHostdDeferred: hostdContext,
93063
+ run: () => {
93064
+ const say = opts.stdout ?? ((t) => process.stdout.write(t));
93065
+ let res;
93066
+ try {
93067
+ res = installSelfHealTimer(opts.selfHealTimerDeps ?? {});
93068
+ } catch (e) {
93069
+ say(source_default.yellow(` self-heal timer not installed: ${e.message}
93070
+ `));
93071
+ return;
93072
+ }
93073
+ if (res.status === "installed") {
93074
+ say(source_default.green(` self-heal timer installed + enabled (${res.servicePath}, ${res.timerPath})
93075
+ `));
93076
+ } else if (res.status === "unchanged") {
93077
+ say(source_default.gray(` self-heal timer already current + enabled at ${res.timerPath}
93078
+ `));
93079
+ } else {
93080
+ say(source_default.gray(` self-heal timer not installed automatically: ${res.reason}
93081
+ `) + source_default.gray(` Install it by hand:
93082
+ `) + source_default.gray(` # ${res.servicePath}
93083
+ `) + res.serviceContent.replace(/^/gm, source_default.gray(" ")) + source_default.gray(` # ${res.timerPath}
93084
+ `) + res.timerContent.replace(/^/gm, source_default.gray(" ")) + res.manualCommands.map((c) => source_default.gray(` ${c}
93085
+ `)).join(""));
93086
+ }
93087
+ }
93088
+ });
92849
93089
  let hostControlEnabled;
92850
93090
  if (typeof opts.hostControlEnabled === "boolean") {
92851
93091
  hostControlEnabled = opts.hostControlEnabled;
@@ -92922,13 +93162,13 @@ function planUpdate(opts) {
92922
93162
  }
92923
93163
  const source = resolve45(import.meta.dirname, "../../skills");
92924
93164
  const dest = join84(homedir44(), ".switchroom", "skills", "_bundled");
92925
- if (!existsSync80(source)) {
93165
+ if (!existsSync81(source)) {
92926
93166
  process.stderr.write(`switchroom update: sync-bundled-skills \u2014 CLI bundle has no adjacent skills/ at ${source}; skipping.
92927
93167
  `);
92928
93168
  return;
92929
93169
  }
92930
93170
  try {
92931
- mkdirSync45(dirname33(dest), { recursive: true });
93171
+ mkdirSync46(dirname34(dest), { recursive: true });
92932
93172
  const r = syncBundledSkills({
92933
93173
  source,
92934
93174
  dest,
@@ -92954,10 +93194,10 @@ function planUpdate(opts) {
92954
93194
  if (opts.syncBundledSkillsFn)
92955
93195
  return;
92956
93196
  const dest = join84(homedir44(), ".switchroom", "skills", "_bundled");
92957
- if (!existsSync80(dest)) {
93197
+ if (!existsSync81(dest)) {
92958
93198
  return;
92959
93199
  }
92960
- const missing = getBuiltinDefaultSkillEntries().map((e) => e.key).filter((key) => !existsSync80(join84(dest, key)));
93200
+ const missing = getBuiltinDefaultSkillEntries().map((e) => e.key).filter((key) => !existsSync81(join84(dest, key)));
92961
93201
  if (missing.length > 0) {
92962
93202
  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.`);
92963
93203
  }
@@ -92992,7 +93232,7 @@ function planUpdate(opts) {
92992
93232
  description: "docker compose up -d --remove-orphans (recreates services with new images / compose)",
92993
93233
  run: () => {
92994
93234
  try {
92995
- const composeText = readFileSync74(composePath, "utf8");
93235
+ const composeText = readFileSync75(composePath, "utf8");
92996
93236
  const pf = validateBindSources(composeText);
92997
93237
  if (!pf.ok)
92998
93238
  throw new Error(formatPreflightError(pf));
@@ -93026,7 +93266,7 @@ function planUpdate(opts) {
93026
93266
  return steps;
93027
93267
  }
93028
93268
  function defaultRunner2(cmd, args) {
93029
- const r = spawnSync16(cmd, args, { stdio: "inherit" });
93269
+ const r = spawnSync17(cmd, args, { stdio: "inherit" });
93030
93270
  return { status: r.status ?? 1 };
93031
93271
  }
93032
93272
  function writeMarkerInPreferredLocation(agent, reason, runner) {
@@ -93069,12 +93309,12 @@ function defaultStatusProbe(composePath) {
93069
93309
  try {
93070
93310
  cliBuiltAt = new Date(statSync45(scriptPath).mtimeMs).toISOString();
93071
93311
  } catch {}
93072
- let dir = dirname33(scriptPath);
93312
+ let dir = dirname34(scriptPath);
93073
93313
  for (let i = 0;i < 8; i++) {
93074
93314
  const pkgPath = join84(dir, "package.json");
93075
- if (existsSync80(pkgPath)) {
93315
+ if (existsSync81(pkgPath)) {
93076
93316
  try {
93077
- const pkg = JSON.parse(readFileSync74(pkgPath, "utf-8"));
93317
+ const pkg = JSON.parse(readFileSync75(pkgPath, "utf-8"));
93078
93318
  if (typeof pkg.version === "string")
93079
93319
  cliVersion = pkg.version;
93080
93320
  } catch (err) {
@@ -93082,7 +93322,7 @@ function defaultStatusProbe(composePath) {
93082
93322
  }
93083
93323
  break;
93084
93324
  }
93085
- const parent = dirname33(dir);
93325
+ const parent = dirname34(dir);
93086
93326
  if (parent === dir)
93087
93327
  break;
93088
93328
  dir = parent;
@@ -93095,13 +93335,13 @@ function defaultStatusProbe(composePath) {
93095
93335
  warnings.push("could not resolve CLI version (no package.json found above the resolved script path)");
93096
93336
  }
93097
93337
  const services = [];
93098
- if (!existsSync80(composePath)) {
93338
+ if (!existsSync81(composePath)) {
93099
93339
  warnings.push(`compose file not found at ${composePath}; service status unknown`);
93100
93340
  return { cliVersion, cliBuiltAt, services, warnings };
93101
93341
  }
93102
93342
  let serviceList = [];
93103
93343
  try {
93104
- const r = spawnSync16("docker", ["compose", "-p", "switchroom", "-f", composePath, "config", "--services"], { encoding: "utf-8", timeout: 1e4 });
93344
+ const r = spawnSync17("docker", ["compose", "-p", "switchroom", "-f", composePath, "config", "--services"], { encoding: "utf-8", timeout: 1e4 });
93105
93345
  if (r.status !== 0) {
93106
93346
  warnings.push(`docker compose config --services failed: ${r.stderr?.trim() ?? r.error?.message ?? "unknown"}`);
93107
93347
  return { cliVersion, cliBuiltAt, services, warnings };
@@ -93118,7 +93358,7 @@ function defaultStatusProbe(composePath) {
93118
93358
  let containerCreatedAt = null;
93119
93359
  let status = "<unknown>";
93120
93360
  try {
93121
- const r = spawnSync16("docker", ["inspect", "-f", "{{.Config.Image}}|{{.Created}}|{{.State.Status}}", containerName2], { encoding: "utf-8", timeout: 5000 });
93361
+ const r = spawnSync17("docker", ["inspect", "-f", "{{.Config.Image}}|{{.Created}}|{{.State.Status}}", containerName2], { encoding: "utf-8", timeout: 5000 });
93122
93362
  if (r.status === 0) {
93123
93363
  const [img, created, st] = r.stdout.trim().split("|");
93124
93364
  image = img ?? null;
@@ -93134,7 +93374,7 @@ function defaultStatusProbe(composePath) {
93134
93374
  let imagePulledAt = null;
93135
93375
  if (image) {
93136
93376
  try {
93137
- const r = spawnSync16("docker", ["image", "inspect", "-f", "{{.Id}}|{{.Created}}|{{.Metadata.LastTagTime}}", image], { encoding: "utf-8", timeout: 5000 });
93377
+ const r = spawnSync17("docker", ["image", "inspect", "-f", "{{.Id}}|{{.Created}}|{{.Metadata.LastTagTime}}", image], { encoding: "utf-8", timeout: 5000 });
93138
93378
  if (r.status === 0) {
93139
93379
  const [id, created, lastTag] = r.stdout.trim().split("|");
93140
93380
  imageDigestShort = id?.replace(/^sha256:/, "").slice(0, 12) ?? null;
@@ -93209,7 +93449,7 @@ function buildReexecArgs(opts) {
93209
93449
  return args;
93210
93450
  }
93211
93451
  function defaultReexec(binaryPath, args) {
93212
- const r = spawnSync16(binaryPath, args, {
93452
+ const r = spawnSync17(binaryPath, args, {
93213
93453
  stdio: "inherit",
93214
93454
  env: { ...process.env, [SELF_UPDATE_ENV_SENTINEL]: "1" }
93215
93455
  });
@@ -93218,7 +93458,7 @@ function defaultReexec(binaryPath, args) {
93218
93458
  function renderDriftPreamble(opts) {
93219
93459
  try {
93220
93460
  const exec = opts.componentExec ?? ((cmd, args) => {
93221
- const r = spawnSync16(cmd, args, { encoding: "utf-8", timeout: 1e4 });
93461
+ const r = spawnSync17(cmd, args, { encoding: "utf-8", timeout: 1e4 });
93222
93462
  return { status: r.status ?? 1, stdout: r.stdout ?? "" };
93223
93463
  });
93224
93464
  let pin;
@@ -93342,23 +93582,23 @@ function registerUpdateCommand(program3) {
93342
93582
 
93343
93583
  // src/cli/rollout.ts
93344
93584
  init_helpers();
93345
- import { spawnSync as spawnSync18 } from "node:child_process";
93346
- import { readFileSync as readFileSync76, chownSync as chownSync9, statSync as statSync47 } from "node:fs";
93585
+ import { spawnSync as spawnSync19 } from "node:child_process";
93586
+ import { readFileSync as readFileSync77, chownSync as chownSync9, statSync as statSync47 } from "node:fs";
93347
93587
  import { homedir as homedir46 } from "node:os";
93348
93588
 
93349
93589
  // src/cli/rollout-pin-journal.ts
93350
93590
  import {
93351
- existsSync as existsSync81,
93352
- readFileSync as readFileSync75,
93353
- writeFileSync as writeFileSync31,
93354
- renameSync as renameSync20,
93591
+ existsSync as existsSync82,
93592
+ readFileSync as readFileSync76,
93593
+ writeFileSync as writeFileSync32,
93594
+ renameSync as renameSync21,
93355
93595
  unlinkSync as unlinkSync15,
93356
93596
  statSync as statSync46,
93357
- mkdirSync as mkdirSync46
93597
+ mkdirSync as mkdirSync47
93358
93598
  } from "node:fs";
93359
93599
  import { homedir as homedir45 } from "node:os";
93360
93600
  import { createHash as createHash17 } from "node:crypto";
93361
- import { join as join85, basename as basename9, resolve as resolve46, dirname as dirname34 } from "node:path";
93601
+ import { join as join85, basename as basename9, resolve as resolve46, dirname as dirname35 } from "node:path";
93362
93602
  init_flock();
93363
93603
  var PIN_JOURNAL_MAX_AGE_MS = 15 * 60 * 1000;
93364
93604
  var STATE_DIR_NAME = ".switchroom";
@@ -93367,7 +93607,7 @@ function pinJournalDir(configPath) {
93367
93607
  if (override && override.trim().length > 0)
93368
93608
  return override.trim();
93369
93609
  if (configPath) {
93370
- const dir = dirname34(resolve46(configPath));
93610
+ const dir = dirname35(resolve46(configPath));
93371
93611
  if (basename9(dir) === STATE_DIR_NAME)
93372
93612
  return dir;
93373
93613
  }
@@ -93410,9 +93650,9 @@ function readPinJournal(configPath, warn = (m) => process.stderr.write(m)) {
93410
93650
  const p = pinJournalPath(configPath);
93411
93651
  let raw;
93412
93652
  try {
93413
- raw = readFileSync75(p, "utf8");
93653
+ raw = readFileSync76(p, "utf8");
93414
93654
  } catch (e) {
93415
- if (existsSync81(p)) {
93655
+ if (existsSync82(p)) {
93416
93656
  warn(`\u26a0\ufe0f rollout pin journal: ${p} exists but could not be read ` + `(${e.message}). A provisional \`release.pin\` may be ` + `uncommitted \u2014 verify it host-side before the next reconcile.
93417
93657
  `);
93418
93658
  }
@@ -93463,7 +93703,7 @@ function beginPinPersist(configPath, pin, opts = {}) {
93463
93703
  warn(`\u26a0\ufe0f rollout pin journal: overwriting an ABANDONED journal at ${p} ` + `(pid ${existing.pid} recorded ${existing.at}, provisional pin ` + `${existing.pin}). Its roll never committed or reverted; \`release.pin\` ` + `in ${configPath} may still name that unproven build \u2014 verify it.
93464
93704
  `);
93465
93705
  }
93466
- const priorPin = getReleasePinFromConfig(readFileSync75(configPath, "utf8"));
93706
+ const priorPin = getReleasePinFromConfig(readFileSync76(configPath, "utf8"));
93467
93707
  const journal = {
93468
93708
  v: 1,
93469
93709
  configPath,
@@ -93472,10 +93712,10 @@ function beginPinPersist(configPath, pin, opts = {}) {
93472
93712
  pid: process.pid,
93473
93713
  at: new Date().toISOString()
93474
93714
  };
93475
- mkdirSync46(dirname34(p), { recursive: true });
93715
+ mkdirSync47(dirname35(p), { recursive: true });
93476
93716
  const tmp = `${p}.${process.pid}.tmp`;
93477
- writeFileSync31(tmp, JSON.stringify(journal), { encoding: "utf8", mode: 384 });
93478
- renameSync20(tmp, p);
93717
+ writeFileSync32(tmp, JSON.stringify(journal), { encoding: "utf8", mode: 384 });
93718
+ renameSync21(tmp, p);
93479
93719
  return journal;
93480
93720
  }
93481
93721
  function commitPinPersist(configPath) {
@@ -93484,7 +93724,7 @@ function commitPinPersist(configPath) {
93484
93724
  unlinkSync15(p);
93485
93725
  return null;
93486
93726
  } catch (e) {
93487
- if (!existsSync81(p))
93727
+ if (!existsSync82(p))
93488
93728
  return null;
93489
93729
  return `rollout pin journal: FAILED to clear ${p} after a SUCCESSFUL roll ` + `(${e.message}). Delete it host-side \u2014 while it exists, ` + `recovery may revert a proven \`release.pin\`.`;
93490
93730
  }
@@ -93506,7 +93746,7 @@ function rollbackPinPersist(configPath, opts = {}) {
93506
93746
  }
93507
93747
  }
93508
93748
  try {
93509
- const current = readFileSync75(configPath, "utf8");
93749
+ const current = readFileSync76(configPath, "utf8");
93510
93750
  const next = journal.priorPin ? setReleasePinInConfig(current, journal.priorPin) : deleteReleasePinInConfig(current);
93511
93751
  let mode = 384;
93512
93752
  try {
@@ -93515,7 +93755,7 @@ function rollbackPinPersist(configPath, opts = {}) {
93515
93755
  if (opts.writeConfig) {
93516
93756
  opts.writeConfig(configPath, next, mode);
93517
93757
  } else {
93518
- writeFileSync31(configPath, next, { encoding: "utf8", mode });
93758
+ writeFileSync32(configPath, next, { encoding: "utf8", mode });
93519
93759
  }
93520
93760
  } catch (e) {
93521
93761
  return {
@@ -93563,10 +93803,10 @@ init_audit_reader();
93563
93803
  init_hindsight();
93564
93804
 
93565
93805
  // src/cli/deploy-version-guard.ts
93566
- import { spawnSync as spawnSync17 } from "node:child_process";
93806
+ import { spawnSync as spawnSync18 } from "node:child_process";
93567
93807
  var DOCKER_INSPECT_TIMEOUT_MS = 60 * 1000;
93568
93808
  var defaultRunner3 = (args) => {
93569
- const r = spawnSync17("docker", args, {
93809
+ const r = spawnSync18("docker", args, {
93570
93810
  encoding: "utf8",
93571
93811
  timeout: DOCKER_INSPECT_TIMEOUT_MS,
93572
93812
  killSignal: "SIGKILL"
@@ -93990,7 +94230,7 @@ function isSpawnTimeout(r, killSignal) {
93990
94230
  var ROLLOUT_KILL_SIGNAL = "SIGKILL";
93991
94231
  function createRolloutDeps(params) {
93992
94232
  const { configPath, scriptPath, hostdCtx } = params;
93993
- const spawn6 = params.spawn ?? spawnSync18;
94233
+ const spawn6 = params.spawn ?? spawnSync19;
93994
94234
  const warn = params.warn ?? ((line) => process.stderr.write(line));
93995
94235
  const self = resolveSelfInvocation({
93996
94236
  execPath: params.execPath ?? process.execPath,
@@ -94075,7 +94315,7 @@ function createRolloutDeps(params) {
94075
94315
  return { status: r.ok ? 0 : 1, stdout: r.stdout };
94076
94316
  }),
94077
94317
  persistPin: (pin) => {
94078
- const before = readFileSync76(configPath, "utf8");
94318
+ const before = readFileSync77(configPath, "utf8");
94079
94319
  const after = setReleasePinInConfig(before, pin);
94080
94320
  if (after === before)
94081
94321
  return false;
@@ -94263,8 +94503,8 @@ init_helpers();
94263
94503
  init_lifecycle();
94264
94504
  init_resolve_version();
94265
94505
  import { execSync as execSync3 } from "node:child_process";
94266
- import { existsSync as existsSync82, readFileSync as readFileSync77 } from "node:fs";
94267
- import { dirname as dirname35, join as join86 } from "node:path";
94506
+ import { existsSync as existsSync83, readFileSync as readFileSync78 } from "node:fs";
94507
+ import { dirname as dirname36, join as join86 } from "node:path";
94268
94508
  function getClaudeCodeVersion() {
94269
94509
  try {
94270
94510
  const out = execSync3("claude --version 2>/dev/null", {
@@ -94315,15 +94555,15 @@ function locateSwitchroomInstallDir() {
94315
94555
  let dir = import.meta.dirname;
94316
94556
  for (let i = 0;i < 10 && dir && dir !== "/"; i++) {
94317
94557
  const pkgPath = join86(dir, "package.json");
94318
- if (existsSync82(pkgPath)) {
94558
+ if (existsSync83(pkgPath)) {
94319
94559
  try {
94320
- const pkg = JSON.parse(readFileSync77(pkgPath, "utf-8"));
94321
- if (pkg.name === "switchroom" && existsSync82(join86(dir, ".git"))) {
94560
+ const pkg = JSON.parse(readFileSync78(pkgPath, "utf-8"));
94561
+ if (pkg.name === "switchroom" && existsSync83(join86(dir, ".git"))) {
94322
94562
  return dir;
94323
94563
  }
94324
94564
  } catch {}
94325
94565
  }
94326
- dir = dirname35(dir);
94566
+ dir = dirname36(dir);
94327
94567
  }
94328
94568
  return null;
94329
94569
  }
@@ -94497,7 +94737,7 @@ init_merge();
94497
94737
 
94498
94738
  // src/agents/session-retention.ts
94499
94739
  import {
94500
- existsSync as existsSync83,
94740
+ existsSync as existsSync84,
94501
94741
  readdirSync as readdirSync28,
94502
94742
  statSync as statSync48,
94503
94743
  unlinkSync as unlinkSync16
@@ -94508,7 +94748,7 @@ var DEFAULT_SESSION_RETENTION_MAX_AGE_DAYS = 30;
94508
94748
  var MIN_KEEP = 2;
94509
94749
  function collectSessionJsonl(claudeConfigDir) {
94510
94750
  const projects = join87(claudeConfigDir, "projects");
94511
- if (!existsSync83(projects))
94751
+ if (!existsSync84(projects))
94512
94752
  return [];
94513
94753
  const found = [];
94514
94754
  const walk2 = (dir) => {
@@ -94644,15 +94884,15 @@ function registerHandoffCommand(program3) {
94644
94884
  // src/issues/store.ts
94645
94885
  import {
94646
94886
  closeSync as closeSync16,
94647
- existsSync as existsSync84,
94648
- mkdirSync as mkdirSync47,
94887
+ existsSync as existsSync85,
94888
+ mkdirSync as mkdirSync48,
94649
94889
  openSync as openSync16,
94650
94890
  readdirSync as readdirSync29,
94651
- readFileSync as readFileSync78,
94652
- renameSync as renameSync21,
94891
+ readFileSync as readFileSync79,
94892
+ renameSync as renameSync22,
94653
94893
  statSync as statSync49,
94654
94894
  unlinkSync as unlinkSync17,
94655
- writeFileSync as writeFileSync32,
94895
+ writeFileSync as writeFileSync33,
94656
94896
  writeSync as writeSync9
94657
94897
  } from "node:fs";
94658
94898
  import { join as join88 } from "node:path";
@@ -94683,11 +94923,11 @@ var ISSUES_FILE = "issues.jsonl";
94683
94923
  var ISSUES_LOCK = "issues.lock";
94684
94924
  function readAll(stateDir) {
94685
94925
  const path7 = join88(stateDir, ISSUES_FILE);
94686
- if (!existsSync84(path7))
94926
+ if (!existsSync85(path7))
94687
94927
  return [];
94688
94928
  let raw;
94689
94929
  try {
94690
- raw = readFileSync78(path7, "utf-8");
94930
+ raw = readFileSync79(path7, "utf-8");
94691
94931
  } catch {
94692
94932
  return [];
94693
94933
  }
@@ -94760,7 +95000,7 @@ function record(stateDir, input, nowFn = Date.now) {
94760
95000
  });
94761
95001
  }
94762
95002
  function resolve49(stateDir, fingerprint, nowFn = Date.now) {
94763
- if (!existsSync84(join88(stateDir, ISSUES_FILE)))
95003
+ if (!existsSync85(join88(stateDir, ISSUES_FILE)))
94764
95004
  return 0;
94765
95005
  return withLock(stateDir, () => {
94766
95006
  const all = readAll(stateDir);
@@ -94778,7 +95018,7 @@ function resolve49(stateDir, fingerprint, nowFn = Date.now) {
94778
95018
  });
94779
95019
  }
94780
95020
  function resolveAllBySource(stateDir, source, nowFn = Date.now) {
94781
- if (!existsSync84(join88(stateDir, ISSUES_FILE)))
95021
+ if (!existsSync85(join88(stateDir, ISSUES_FILE)))
94782
95022
  return 0;
94783
95023
  return withLock(stateDir, () => {
94784
95024
  const all = readAll(stateDir);
@@ -94796,7 +95036,7 @@ function resolveAllBySource(stateDir, source, nowFn = Date.now) {
94796
95036
  });
94797
95037
  }
94798
95038
  function prune(stateDir, opts = {}) {
94799
- if (!existsSync84(join88(stateDir, ISSUES_FILE)))
95039
+ if (!existsSync85(join88(stateDir, ISSUES_FILE)))
94800
95040
  return 0;
94801
95041
  return withLock(stateDir, () => {
94802
95042
  const all = readAll(stateDir);
@@ -94826,7 +95066,7 @@ function prune(stateDir, opts = {}) {
94826
95066
  });
94827
95067
  }
94828
95068
  function ensureDir(stateDir) {
94829
- mkdirSync47(stateDir, { recursive: true });
95069
+ mkdirSync48(stateDir, { recursive: true });
94830
95070
  }
94831
95071
  function writeAll(stateDir, events) {
94832
95072
  const path7 = join88(stateDir, ISSUES_FILE);
@@ -94835,8 +95075,8 @@ function writeAll(stateDir, events) {
94835
95075
  const body = events.length === 0 ? "" : events.map((e) => JSON.stringify(e)).join(`
94836
95076
  `) + `
94837
95077
  `;
94838
- writeFileSync32(tmp, body, "utf-8");
94839
- renameSync21(tmp, path7);
95078
+ writeFileSync33(tmp, body, "utf-8");
95079
+ renameSync22(tmp, path7);
94840
95080
  }
94841
95081
  var ORPHAN_TMP_TTL_MS = 60000;
94842
95082
  var TMP_PREFIX = `${ISSUES_FILE}.tmp-`;
@@ -94898,7 +95138,7 @@ function withLock(stateDir, fn) {
94898
95138
  function tryStealStaleLock(lockPath) {
94899
95139
  let pidStr;
94900
95140
  try {
94901
- pidStr = readFileSync78(lockPath, "utf-8").trim();
95141
+ pidStr = readFileSync79(lockPath, "utf-8").trim();
94902
95142
  } catch {
94903
95143
  return true;
94904
95144
  }
@@ -95146,20 +95386,20 @@ function relTime(deltaMs) {
95146
95386
 
95147
95387
  // src/cli/deps.ts
95148
95388
  init_source();
95149
- import { existsSync as existsSync87 } from "node:fs";
95389
+ import { existsSync as existsSync88 } from "node:fs";
95150
95390
  import { homedir as homedir49 } from "node:os";
95151
95391
  import { join as join91, resolve as resolve50 } from "node:path";
95152
95392
 
95153
95393
  // src/deps/python.ts
95154
95394
  import { createHash as createHash18 } from "node:crypto";
95155
95395
  import {
95156
- existsSync as existsSync85,
95157
- mkdirSync as mkdirSync48,
95158
- readFileSync as readFileSync79,
95396
+ existsSync as existsSync86,
95397
+ mkdirSync as mkdirSync49,
95398
+ readFileSync as readFileSync80,
95159
95399
  rmSync as rmSync15,
95160
- writeFileSync as writeFileSync33
95400
+ writeFileSync as writeFileSync34
95161
95401
  } from "node:fs";
95162
- import { dirname as dirname36, join as join89 } from "node:path";
95402
+ import { dirname as dirname37, join as join89 } from "node:path";
95163
95403
  import { homedir as homedir47 } from "node:os";
95164
95404
  import { execFileSync as execFileSync24 } from "node:child_process";
95165
95405
 
@@ -95175,13 +95415,13 @@ function defaultPythonCacheRoot() {
95175
95415
  return join89(homedir47(), ".switchroom", "deps", "python");
95176
95416
  }
95177
95417
  function hashFile(path7) {
95178
- return createHash18("sha256").update(readFileSync79(path7)).digest("hex");
95418
+ return createHash18("sha256").update(readFileSync80(path7)).digest("hex");
95179
95419
  }
95180
95420
  function ensurePythonEnv(opts) {
95181
95421
  const { skillName, requirementsPath, force = false } = opts;
95182
95422
  const cacheRoot = opts.cacheRoot ?? defaultPythonCacheRoot();
95183
95423
  const hostPython = opts.pythonBin ?? "python3";
95184
- if (!existsSync85(requirementsPath)) {
95424
+ if (!existsSync86(requirementsPath)) {
95185
95425
  throw new PythonEnvError(`requirements file not found: ${requirementsPath}`);
95186
95426
  }
95187
95427
  const venvDir = join89(cacheRoot, skillName);
@@ -95190,8 +95430,8 @@ function ensurePythonEnv(opts) {
95190
95430
  const pythonBin = join89(binDir, "python");
95191
95431
  const pipBin = join89(binDir, "pip");
95192
95432
  const targetHash = hashFile(requirementsPath);
95193
- if (!force && existsSync85(stampPath) && existsSync85(pythonBin)) {
95194
- const existingHash = readFileSync79(stampPath, "utf8").trim();
95433
+ if (!force && existsSync86(stampPath) && existsSync86(pythonBin)) {
95434
+ const existingHash = readFileSync80(stampPath, "utf8").trim();
95195
95435
  if (existingHash === targetHash) {
95196
95436
  return {
95197
95437
  skillName,
@@ -95203,10 +95443,10 @@ function ensurePythonEnv(opts) {
95203
95443
  };
95204
95444
  }
95205
95445
  }
95206
- if (existsSync85(venvDir)) {
95446
+ if (existsSync86(venvDir)) {
95207
95447
  rmSync15(venvDir, { recursive: true, force: true });
95208
95448
  }
95209
- mkdirSync48(dirname36(venvDir), { recursive: true });
95449
+ mkdirSync49(dirname37(venvDir), { recursive: true });
95210
95450
  try {
95211
95451
  execFileSync24(hostPython, ["-m", "venv", venvDir], { stdio: "pipe" });
95212
95452
  } catch (err) {
@@ -95225,7 +95465,7 @@ function ensurePythonEnv(opts) {
95225
95465
  const e = err;
95226
95466
  throw new PythonEnvError(`Failed to install requirements for skill "${skillName}": ${e.message}`, e.stderr?.toString());
95227
95467
  }
95228
- writeFileSync33(stampPath, targetHash + `
95468
+ writeFileSync34(stampPath, targetHash + `
95229
95469
  `);
95230
95470
  return {
95231
95471
  skillName,
@@ -95241,13 +95481,13 @@ function ensurePythonEnv(opts) {
95241
95481
  import { createHash as createHash19 } from "node:crypto";
95242
95482
  import {
95243
95483
  copyFileSync as copyFileSync12,
95244
- existsSync as existsSync86,
95245
- mkdirSync as mkdirSync49,
95246
- readFileSync as readFileSync80,
95484
+ existsSync as existsSync87,
95485
+ mkdirSync as mkdirSync50,
95486
+ readFileSync as readFileSync81,
95247
95487
  rmSync as rmSync16,
95248
- writeFileSync as writeFileSync34
95488
+ writeFileSync as writeFileSync35
95249
95489
  } from "node:fs";
95250
- import { dirname as dirname37, join as join90 } from "node:path";
95490
+ import { dirname as dirname38, join as join90 } from "node:path";
95251
95491
  import { homedir as homedir48 } from "node:os";
95252
95492
  import { execFileSync as execFileSync25 } from "node:child_process";
95253
95493
 
@@ -95274,20 +95514,20 @@ function defaultNodeCacheRoot() {
95274
95514
  return join90(homedir48(), ".switchroom", "deps", "node");
95275
95515
  }
95276
95516
  function hashDepInputs(packageJsonPath) {
95277
- const sourceDir = dirname37(packageJsonPath);
95517
+ const sourceDir = dirname38(packageJsonPath);
95278
95518
  const hasher = createHash19("sha256");
95279
95519
  hasher.update(`package.json
95280
95520
  `);
95281
- hasher.update(readFileSync80(packageJsonPath));
95521
+ hasher.update(readFileSync81(packageJsonPath));
95282
95522
  for (const lockName of ALL_LOCKFILES) {
95283
95523
  const lockPath = join90(sourceDir, lockName);
95284
- if (existsSync86(lockPath)) {
95524
+ if (existsSync87(lockPath)) {
95285
95525
  hasher.update(`
95286
95526
  `);
95287
95527
  hasher.update(lockName);
95288
95528
  hasher.update(`
95289
95529
  `);
95290
- hasher.update(readFileSync80(lockPath));
95530
+ hasher.update(readFileSync81(lockPath));
95291
95531
  }
95292
95532
  }
95293
95533
  return hasher.digest("hex");
@@ -95296,17 +95536,17 @@ function ensureNodeEnv(opts) {
95296
95536
  const { skillName, packageJsonPath, force = false } = opts;
95297
95537
  const cacheRoot = opts.cacheRoot ?? defaultNodeCacheRoot();
95298
95538
  const installer = opts.installer ?? "bun";
95299
- if (!existsSync86(packageJsonPath)) {
95539
+ if (!existsSync87(packageJsonPath)) {
95300
95540
  throw new NodeEnvError(`package.json not found: ${packageJsonPath}`);
95301
95541
  }
95302
- const sourceDir = dirname37(packageJsonPath);
95542
+ const sourceDir = dirname38(packageJsonPath);
95303
95543
  const envDir = join90(cacheRoot, skillName);
95304
95544
  const stampPath = join90(envDir, ".package.sha256");
95305
95545
  const nodeModulesDir = join90(envDir, "node_modules");
95306
95546
  const binDir = join90(nodeModulesDir, ".bin");
95307
95547
  const targetHash = hashDepInputs(packageJsonPath);
95308
- if (!force && existsSync86(stampPath) && existsSync86(nodeModulesDir)) {
95309
- const existingHash = readFileSync80(stampPath, "utf8").trim();
95548
+ if (!force && existsSync87(stampPath) && existsSync87(nodeModulesDir)) {
95549
+ const existingHash = readFileSync81(stampPath, "utf8").trim();
95310
95550
  if (existingHash === targetHash) {
95311
95551
  return {
95312
95552
  skillName,
@@ -95317,15 +95557,15 @@ function ensureNodeEnv(opts) {
95317
95557
  };
95318
95558
  }
95319
95559
  }
95320
- if (existsSync86(envDir)) {
95560
+ if (existsSync87(envDir)) {
95321
95561
  rmSync16(envDir, { recursive: true, force: true });
95322
95562
  }
95323
- mkdirSync49(envDir, { recursive: true });
95563
+ mkdirSync50(envDir, { recursive: true });
95324
95564
  copyFileSync12(packageJsonPath, join90(envDir, "package.json"));
95325
95565
  let copiedLockfile = false;
95326
95566
  for (const lockName of LOCKFILES_FOR[installer]) {
95327
95567
  const lockPath = join90(sourceDir, lockName);
95328
- if (existsSync86(lockPath)) {
95568
+ if (existsSync87(lockPath)) {
95329
95569
  copyFileSync12(lockPath, join90(envDir, lockName));
95330
95570
  copiedLockfile = true;
95331
95571
  }
@@ -95342,7 +95582,7 @@ function ensureNodeEnv(opts) {
95342
95582
  const e = err;
95343
95583
  throw new NodeEnvError(`Failed to install node deps for skill "${skillName}" with ${installer}: ${e.message}`, e.stderr?.toString());
95344
95584
  }
95345
- writeFileSync34(stampPath, targetHash + `
95585
+ writeFileSync35(stampPath, targetHash + `
95346
95586
  `);
95347
95587
  return {
95348
95588
  skillName,
@@ -95361,22 +95601,22 @@ function registerDepsCommand(program3) {
95361
95601
  const deps = program3.command("deps").description("Manage cached per-skill dependency environments");
95362
95602
  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) => {
95363
95603
  const skillsRoot = builtinSkillsRoot();
95364
- if (!existsSync87(skillsRoot)) {
95604
+ if (!existsSync88(skillsRoot)) {
95365
95605
  console.error(source_default.red(`Bundled skills pool dir not found at ${skillsRoot} \u2014 run \`switchroom update\` to install it.`));
95366
95606
  process.exit(1);
95367
95607
  }
95368
95608
  const skillDir = join91(skillsRoot, skill);
95369
- if (!existsSync87(skillDir)) {
95609
+ if (!existsSync88(skillDir)) {
95370
95610
  console.error(source_default.red(`Unknown skill: ${skill} (no dir at ${skillDir})`));
95371
95611
  process.exit(1);
95372
95612
  }
95373
95613
  const requirementsPath = join91(skillDir, "requirements.txt");
95374
95614
  const packageJsonPath = join91(skillDir, "package.json");
95375
- const wantPython = opts.python ?? (!opts.python && !opts.node && existsSync87(requirementsPath));
95376
- const wantNode = opts.node ?? (!opts.python && !opts.node && existsSync87(packageJsonPath));
95615
+ const wantPython = opts.python ?? (!opts.python && !opts.node && existsSync88(requirementsPath));
95616
+ const wantNode = opts.node ?? (!opts.python && !opts.node && existsSync88(packageJsonPath));
95377
95617
  let did = 0;
95378
95618
  if (wantPython) {
95379
- if (!existsSync87(requirementsPath)) {
95619
+ if (!existsSync88(requirementsPath)) {
95380
95620
  console.error(source_default.red(`Skill "${skill}" has no requirements.txt at ${requirementsPath}`));
95381
95621
  process.exit(1);
95382
95622
  }
@@ -95400,7 +95640,7 @@ function registerDepsCommand(program3) {
95400
95640
  }
95401
95641
  }
95402
95642
  if (wantNode) {
95403
- if (!existsSync87(packageJsonPath)) {
95643
+ if (!existsSync88(packageJsonPath)) {
95404
95644
  console.error(source_default.red(`Skill "${skill}" has no package.json at ${packageJsonPath}`));
95405
95645
  process.exit(1);
95406
95646
  }
@@ -95433,9 +95673,9 @@ function registerDepsCommand(program3) {
95433
95673
  // src/cli/workspace.ts
95434
95674
  init_helpers();
95435
95675
  init_loader();
95436
- import { existsSync as existsSync88 } from "node:fs";
95676
+ import { existsSync as existsSync89 } from "node:fs";
95437
95677
  import { resolve as resolve51, sep as sep4 } from "node:path";
95438
- import { spawnSync as spawnSync19 } from "node:child_process";
95678
+ import { spawnSync as spawnSync20 } from "node:child_process";
95439
95679
 
95440
95680
  // src/agents/workspace.ts
95441
95681
  import { readFile as readFile2, stat } from "node:fs/promises";
@@ -96148,7 +96388,7 @@ function registerWorkspaceCommand(program3) {
96148
96388
  process.exit(1);
96149
96389
  }
96150
96390
  const editor = process.env["EDITOR"] ?? process.env["VISUAL"] ?? "vi";
96151
- const child = spawnSync19(editor, [target], { stdio: "inherit" });
96391
+ const child = spawnSync20(editor, [target], { stdio: "inherit" });
96152
96392
  if (child.status !== 0 && child.status !== null) {
96153
96393
  process.exit(child.status);
96154
96394
  }
@@ -96210,12 +96450,12 @@ function registerWorkspaceCommand(program3) {
96210
96450
  if (!dir)
96211
96451
  return;
96212
96452
  const gitDir = resolve51(dir, ".git");
96213
- if (!existsSync88(gitDir)) {
96453
+ if (!existsSync89(gitDir)) {
96214
96454
  process.stdout.write(`Workspace is not a git repository. Re-run \`switchroom agent create ${agentName}\` ` + `or manually \`git init\` in ${dir} to enable versioning.
96215
96455
  `);
96216
96456
  return;
96217
96457
  }
96218
- const statusResult = spawnSync19("git", ["status", "--short"], {
96458
+ const statusResult = spawnSync20("git", ["status", "--short"], {
96219
96459
  cwd: dir,
96220
96460
  encoding: "utf-8"
96221
96461
  });
@@ -96230,7 +96470,7 @@ function registerWorkspaceCommand(program3) {
96230
96470
  return;
96231
96471
  }
96232
96472
  const message = opts.message || `checkpoint: ${new Date().toISOString()}`;
96233
- const addResult = spawnSync19("git", ["add", "-A"], {
96473
+ const addResult = spawnSync20("git", ["add", "-A"], {
96234
96474
  cwd: dir,
96235
96475
  encoding: "utf-8"
96236
96476
  });
@@ -96239,7 +96479,7 @@ function registerWorkspaceCommand(program3) {
96239
96479
  `);
96240
96480
  process.exit(1);
96241
96481
  }
96242
- const commitResult = spawnSync19("git", ["commit", "-m", message], {
96482
+ const commitResult = spawnSync20("git", ["commit", "-m", message], {
96243
96483
  cwd: dir,
96244
96484
  encoding: "utf-8"
96245
96485
  });
@@ -96248,7 +96488,7 @@ function registerWorkspaceCommand(program3) {
96248
96488
  `);
96249
96489
  process.exit(1);
96250
96490
  }
96251
- const shaResult = spawnSync19("git", ["rev-parse", "--short", "HEAD"], {
96491
+ const shaResult = spawnSync20("git", ["rev-parse", "--short", "HEAD"], {
96252
96492
  cwd: dir,
96253
96493
  encoding: "utf-8"
96254
96494
  });
@@ -96264,12 +96504,12 @@ function registerWorkspaceCommand(program3) {
96264
96504
  if (!dir)
96265
96505
  return;
96266
96506
  const gitDir = resolve51(dir, ".git");
96267
- if (!existsSync88(gitDir)) {
96507
+ if (!existsSync89(gitDir)) {
96268
96508
  process.stdout.write(`Workspace is not a git repository.
96269
96509
  `);
96270
96510
  return;
96271
96511
  }
96272
- const child = spawnSync19("git", ["status", "--short"], {
96512
+ const child = spawnSync20("git", ["status", "--short"], {
96273
96513
  cwd: dir,
96274
96514
  stdio: "inherit"
96275
96515
  });
@@ -96289,7 +96529,7 @@ function resolveAgentWorkspaceDirOrExit(program3, agentName) {
96289
96529
  const agentsDir = resolveAgentsDir(config);
96290
96530
  const agentDir = resolve51(agentsDir, agentName);
96291
96531
  const dir = resolveAgentWorkspaceDir(agentDir);
96292
- if (!existsSync88(dir)) {
96532
+ if (!existsSync89(dir)) {
96293
96533
  process.stderr.write(`workspace: ${dir} does not exist yet. Run \`switchroom setup\` or \`switchroom agent scaffold ${agentName}\` to seed it.
96294
96534
  `);
96295
96535
  return;
@@ -96325,7 +96565,7 @@ function safeParseInt(value, fallback) {
96325
96565
  init_helpers();
96326
96566
  init_loader();
96327
96567
  init_merge();
96328
- import { copyFileSync as copyFileSync13, existsSync as existsSync89, readFileSync as readFileSync81, writeFileSync as writeFileSync35 } from "node:fs";
96568
+ import { copyFileSync as copyFileSync13, existsSync as existsSync90, readFileSync as readFileSync82, writeFileSync as writeFileSync36 } from "node:fs";
96329
96569
  import { join as join92, resolve as resolve52 } from "node:path";
96330
96570
  init_scaffold();
96331
96571
  init_profiles();
@@ -96343,7 +96583,7 @@ function resolveSoulTargetOrExit(program3, agentName) {
96343
96583
  const agentsDir = resolveAgentsDir(config);
96344
96584
  const agentDir = resolve52(agentsDir, agentName);
96345
96585
  const workspaceDir = resolveAgentWorkspaceDir(agentDir);
96346
- if (!existsSync89(workspaceDir)) {
96586
+ if (!existsSync90(workspaceDir)) {
96347
96587
  console.error(`soul: ${workspaceDir} does not exist yet. Run \`switchroom setup\` ` + `or \`switchroom agent scaffold ${agentName}\` to seed it.`);
96348
96588
  process.exit(1);
96349
96589
  }
@@ -96369,11 +96609,11 @@ function registerSoulCommand(program3) {
96369
96609
  const t = resolveSoulTargetOrExit(program3, agentName);
96370
96610
  if (!t)
96371
96611
  return;
96372
- if (!existsSync89(t.soulPath)) {
96612
+ if (!existsSync90(t.soulPath)) {
96373
96613
  console.error(`soul: ${t.soulPath} does not exist yet \u2014 run ` + `\`switchroom soul reset ${agentName}\` to seed it.`);
96374
96614
  process.exit(1);
96375
96615
  }
96376
- process.stdout.write(readFileSync81(t.soulPath, "utf-8"));
96616
+ process.stdout.write(readFileSync82(t.soulPath, "utf-8"));
96377
96617
  }));
96378
96618
  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) => {
96379
96619
  const t = resolveSoulTargetOrExit(program3, agentName);
@@ -96384,7 +96624,7 @@ function registerSoulCommand(program3) {
96384
96624
  console.error(`soul: profile "${t.profileName}" ships no SOUL.md.hbs \u2014 ` + `nothing to re-seed from.`);
96385
96625
  process.exit(1);
96386
96626
  }
96387
- const exists = existsSync89(t.soulPath);
96627
+ const exists = existsSync90(t.soulPath);
96388
96628
  if (exists && !opts.yes) {
96389
96629
  if (!isInteractive()) {
96390
96630
  console.error(`soul: ${t.soulPath} already exists. Re-run with --yes to ` + `replace it (the current file is backed up to SOUL.md.bak).`);
@@ -96399,12 +96639,12 @@ function registerSoulCommand(program3) {
96399
96639
  let backupPath;
96400
96640
  if (exists) {
96401
96641
  backupPath = `${t.soulPath}.bak`;
96402
- if (existsSync89(backupPath)) {
96642
+ if (existsSync90(backupPath)) {
96403
96643
  backupPath = `${t.soulPath}.bak.${Date.now()}`;
96404
96644
  }
96405
96645
  copyFileSync13(t.soulPath, backupPath);
96406
96646
  }
96407
- writeFileSync35(t.soulPath, content, "utf-8");
96647
+ writeFileSync36(t.soulPath, content, "utf-8");
96408
96648
  if (backupPath) {
96409
96649
  console.log(`soul: re-seeded ${agentName}'s SOUL.md from profile ` + `"${t.profileName}".
96410
96650
  ` + ` Previous version saved to ${backupPath}`);
@@ -96418,7 +96658,7 @@ function registerSoulCommand(program3) {
96418
96658
  // src/cli/debug.ts
96419
96659
  init_helpers();
96420
96660
  init_loader();
96421
- import { existsSync as existsSync90, readFileSync as readFileSync82, readdirSync as readdirSync30, statSync as statSync50 } from "node:fs";
96661
+ import { existsSync as existsSync91, readFileSync as readFileSync83, readdirSync as readdirSync30, statSync as statSync50 } from "node:fs";
96422
96662
  import { resolve as resolve53, join as join93 } from "node:path";
96423
96663
  import { createHash as createHash20 } from "node:crypto";
96424
96664
  init_merge();
@@ -96431,10 +96671,10 @@ function estimateTokens(bytes) {
96431
96671
  }
96432
96672
  function readMcpServerNames(agentDir) {
96433
96673
  const mcpPath = join93(agentDir, ".mcp.json");
96434
- if (!existsSync90(mcpPath))
96674
+ if (!existsSync91(mcpPath))
96435
96675
  return [];
96436
96676
  try {
96437
- const parsed = JSON.parse(readFileSync82(mcpPath, "utf-8"));
96677
+ const parsed = JSON.parse(readFileSync83(mcpPath, "utf-8"));
96438
96678
  return Object.keys(parsed.mcpServers ?? {});
96439
96679
  } catch {
96440
96680
  return null;
@@ -96445,7 +96685,7 @@ function sha256(content) {
96445
96685
  }
96446
96686
  function findLatestTranscriptJsonl(claudeConfigDir) {
96447
96687
  const projectsDir = join93(claudeConfigDir, "projects");
96448
- if (!existsSync90(projectsDir))
96688
+ if (!existsSync91(projectsDir))
96449
96689
  return;
96450
96690
  try {
96451
96691
  const entries = readdirSync30(projectsDir, { withFileTypes: true });
@@ -96455,7 +96695,7 @@ function findLatestTranscriptJsonl(claudeConfigDir) {
96455
96695
  continue;
96456
96696
  const projectPath = join93(projectsDir, entry.name);
96457
96697
  const transcriptPath = join93(projectPath, "transcript.jsonl");
96458
- if (!existsSync90(transcriptPath))
96698
+ if (!existsSync91(transcriptPath))
96459
96699
  continue;
96460
96700
  const stat3 = statSync50(transcriptPath);
96461
96701
  if (!latest || stat3.mtimeMs > latest.mtime) {
@@ -96469,7 +96709,7 @@ function findLatestTranscriptJsonl(claudeConfigDir) {
96469
96709
  }
96470
96710
  function extractLatestUserMessage(transcriptPath) {
96471
96711
  try {
96472
- const content = readFileSync82(transcriptPath, "utf-8");
96712
+ const content = readFileSync83(transcriptPath, "utf-8");
96473
96713
  const lines = content.trim().split(`
96474
96714
  `).filter(Boolean);
96475
96715
  for (let i = lines.length - 1;i >= 0; i--) {
@@ -96518,7 +96758,7 @@ function registerDebugCommand(program3) {
96518
96758
  }
96519
96759
  const agentsDir = resolveAgentsDir(config);
96520
96760
  const agentDir = resolve53(agentsDir, agentName);
96521
- if (!existsSync90(agentDir)) {
96761
+ if (!existsSync91(agentDir)) {
96522
96762
  console.error(`Agent directory not found: ${agentDir}`);
96523
96763
  process.exit(1);
96524
96764
  }
@@ -96573,7 +96813,7 @@ function registerDebugCommand(program3) {
96573
96813
  }
96574
96814
  console.log(`=== Append System Prompt (per-session) ===
96575
96815
  `);
96576
- const handoffContent = existsSync90(handoffPath) ? readFileSync82(handoffPath, "utf-8") : "";
96816
+ const handoffContent = existsSync91(handoffPath) ? readFileSync83(handoffPath, "utf-8") : "";
96577
96817
  if (handoffContent.trim().length > 0) {
96578
96818
  console.log(`-- Handoff Briefing (${formatBytes(handoffContent.length)}) --`);
96579
96819
  console.log(handoffContent);
@@ -96584,7 +96824,7 @@ function registerDebugCommand(program3) {
96584
96824
  }
96585
96825
  console.log(`=== CLAUDE.md (auto-loaded by Claude Code) ===
96586
96826
  `);
96587
- const claudeMdContent = existsSync90(claudeMdPath) ? readFileSync82(claudeMdPath, "utf-8") : "";
96827
+ const claudeMdContent = existsSync91(claudeMdPath) ? readFileSync83(claudeMdPath, "utf-8") : "";
96588
96828
  if (claudeMdContent.trim().length > 0) {
96589
96829
  console.log(`(${formatBytes(claudeMdContent.length)})`);
96590
96830
  console.log(claudeMdContent);
@@ -96595,7 +96835,7 @@ function registerDebugCommand(program3) {
96595
96835
  }
96596
96836
  console.log(`=== Persona (SOUL.md) ===
96597
96837
  `);
96598
- const soulMdContent = existsSync90(soulMdPath) ? readFileSync82(soulMdPath, "utf-8") : existsSync90(workspaceSoulMdPath) ? readFileSync82(workspaceSoulMdPath, "utf-8") : "";
96838
+ const soulMdContent = existsSync91(soulMdPath) ? readFileSync83(soulMdPath, "utf-8") : existsSync91(workspaceSoulMdPath) ? readFileSync83(workspaceSoulMdPath, "utf-8") : "";
96599
96839
  if (soulMdContent.trim().length > 0) {
96600
96840
  console.log(`(${formatBytes(soulMdContent.length)})`);
96601
96841
  console.log(soulMdContent);
@@ -96659,8 +96899,8 @@ function registerDebugCommand(program3) {
96659
96899
  const fleetDir = join93(agentsDir, "..", "fleet");
96660
96900
  const fleetInvPath = join93(fleetDir, "switchroom-invariants.md");
96661
96901
  const fleetClaudePath = join93(fleetDir, "CLAUDE.md");
96662
- const fleetInvBytes = existsSync90(fleetInvPath) ? readFileSync82(fleetInvPath, "utf-8").length : 0;
96663
- const fleetClaudeBytes = existsSync90(fleetClaudePath) ? readFileSync82(fleetClaudePath, "utf-8").length : 0;
96902
+ const fleetInvBytes = existsSync91(fleetInvPath) ? readFileSync83(fleetInvPath, "utf-8").length : 0;
96903
+ const fleetClaudeBytes = existsSync91(fleetClaudePath) ? readFileSync83(fleetClaudePath, "utf-8").length : 0;
96664
96904
  const fleetBytes = fleetInvBytes + fleetClaudeBytes;
96665
96905
  const totalBytes = stableBytes + perSessionBytes + claudeMdBytes + fleetBytes + perTurnBytes + userBytes;
96666
96906
  console.log(`Stable prefix: ${formatBytes(stableBytes).padEnd(20)} (cache-hot; includes SOUL.md ${soulMdBytes.toLocaleString()}B)`);
@@ -96693,20 +96933,20 @@ init_source();
96693
96933
 
96694
96934
  // src/worktree/claim.ts
96695
96935
  import { execFileSync as execFileSync26 } from "node:child_process";
96696
- import { closeSync as closeSync17, mkdirSync as mkdirSync51, openSync as openSync17, existsSync as existsSync92, unlinkSync as unlinkSync19 } from "node:fs";
96936
+ import { closeSync as closeSync17, mkdirSync as mkdirSync52, openSync as openSync17, existsSync as existsSync93, unlinkSync as unlinkSync19 } from "node:fs";
96697
96937
  import { join as join95, resolve as resolve55 } from "node:path";
96698
96938
  import { homedir as homedir51 } from "node:os";
96699
96939
  import { randomBytes as randomBytes14 } from "node:crypto";
96700
96940
 
96701
96941
  // src/worktree/registry.ts
96702
96942
  import {
96703
- mkdirSync as mkdirSync50,
96704
- writeFileSync as writeFileSync36,
96705
- readFileSync as readFileSync83,
96943
+ mkdirSync as mkdirSync51,
96944
+ writeFileSync as writeFileSync37,
96945
+ readFileSync as readFileSync84,
96706
96946
  readdirSync as readdirSync31,
96707
96947
  unlinkSync as unlinkSync18,
96708
- existsSync as existsSync91,
96709
- renameSync as renameSync22
96948
+ existsSync as existsSync92,
96949
+ renameSync as renameSync23
96710
96950
  } from "node:fs";
96711
96951
  import { join as join94, resolve as resolve54 } from "node:path";
96712
96952
  import { homedir as homedir50 } from "node:os";
@@ -96717,20 +96957,20 @@ function recordPath(id) {
96717
96957
  return join94(registryDir(), `${id}.json`);
96718
96958
  }
96719
96959
  function ensureDir2() {
96720
- mkdirSync50(registryDir(), { recursive: true });
96960
+ mkdirSync51(registryDir(), { recursive: true });
96721
96961
  }
96722
96962
  function writeRecord(record2) {
96723
96963
  ensureDir2();
96724
96964
  const target = recordPath(record2.id);
96725
96965
  const tmp = `${target}.tmp${process.pid}`;
96726
- writeFileSync36(tmp, JSON.stringify(record2, null, 2) + `
96966
+ writeFileSync37(tmp, JSON.stringify(record2, null, 2) + `
96727
96967
  `, { mode: 384 });
96728
- renameSync22(tmp, target);
96968
+ renameSync23(tmp, target);
96729
96969
  }
96730
96970
  function readRecord(id) {
96731
96971
  const path10 = recordPath(id);
96732
96972
  try {
96733
- const raw = readFileSync83(path10, "utf8");
96973
+ const raw = readFileSync84(path10, "utf8");
96734
96974
  return JSON.parse(raw);
96735
96975
  } catch {
96736
96976
  return null;
@@ -96763,7 +97003,7 @@ function countByRepo(repoPath) {
96763
97003
  // src/worktree/claim.ts
96764
97004
  function acquireRepoLock(repoPath) {
96765
97005
  const lockDir = registryDir();
96766
- mkdirSync51(lockDir, { recursive: true });
97006
+ mkdirSync52(lockDir, { recursive: true });
96767
97007
  const lockName = repoPath.replace(/[^A-Za-z0-9]/g, "_");
96768
97008
  const lockPath = join95(lockDir, `.lock-${lockName}`);
96769
97009
  const deadline = Date.now() + 5000;
@@ -96819,7 +97059,7 @@ function expandHome(p) {
96819
97059
  }
96820
97060
  async function claimWorktree(input, codeRepos) {
96821
97061
  const repoPath = resolveRepoPath(input.repo, codeRepos);
96822
- if (!existsSync92(repoPath)) {
97062
+ if (!existsSync93(repoPath)) {
96823
97063
  throw new Error(`Repository path does not exist: ${repoPath}`);
96824
97064
  }
96825
97065
  let concurrencyCap = DEFAULT_CONCURRENCY;
@@ -96841,7 +97081,7 @@ async function claimWorktree(input, codeRepos) {
96841
97081
  const taskSuffix = input.taskName ? sanitizeTaskName(input.taskName) : "task";
96842
97082
  branch = `task/${taskSuffix}-${id}`;
96843
97083
  const baseDir = worktreesBaseDir();
96844
- mkdirSync51(baseDir, { recursive: true });
97084
+ mkdirSync52(baseDir, { recursive: true });
96845
97085
  worktreePath = join95(baseDir, `${id}-${taskSuffix}`);
96846
97086
  const ambientOwner = process.env.SWITCHROOM_AGENT_NAME;
96847
97087
  const ownerAgent = input.ownerAgent ?? (ambientOwner != null && ambientOwner !== "" ? ambientOwner : undefined);
@@ -96875,7 +97115,7 @@ async function claimWorktree(input, codeRepos) {
96875
97115
 
96876
97116
  // src/worktree/release.ts
96877
97117
  import { execFileSync as execFileSync27 } from "node:child_process";
96878
- import { existsSync as existsSync93 } from "node:fs";
97118
+ import { existsSync as existsSync94 } from "node:fs";
96879
97119
  function releaseWorktree(input) {
96880
97120
  const { id } = input;
96881
97121
  const record2 = readRecord(id);
@@ -96883,7 +97123,7 @@ function releaseWorktree(input) {
96883
97123
  return { released: true };
96884
97124
  }
96885
97125
  let gitSuccess = true;
96886
- if (existsSync93(record2.path)) {
97126
+ if (existsSync94(record2.path)) {
96887
97127
  try {
96888
97128
  execFileSync27("git", ["worktree", "remove", "--force", record2.path], {
96889
97129
  cwd: record2.repo,
@@ -96922,7 +97162,7 @@ function listWorktrees() {
96922
97162
 
96923
97163
  // src/worktree/reaper.ts
96924
97164
  import { execFileSync as execFileSync28 } from "node:child_process";
96925
- import { existsSync as existsSync94 } from "node:fs";
97165
+ import { existsSync as existsSync95 } from "node:fs";
96926
97166
  var STALE_THRESHOLD_MS = 10 * 60 * 1000;
96927
97167
  function reapSkipReasonText(action) {
96928
97168
  switch (action) {
@@ -96983,7 +97223,7 @@ function planReaper(nowMs, deps = {}) {
96983
97223
  const plan = [];
96984
97224
  for (const record2 of listRecords()) {
96985
97225
  const heartbeatAge = now - new Date(record2.heartbeatAt).getTime();
96986
- const worktreeExists = existsSync94(record2.path);
97226
+ const worktreeExists = existsSync95(record2.path);
96987
97227
  if (!worktreeExists) {
96988
97228
  plan.push({
96989
97229
  record: record2,
@@ -97064,12 +97304,12 @@ function runReaper(nowMs, deps = {}) {
97064
97304
  // src/worktree/gc.ts
97065
97305
  import { execFileSync as execFileSync29 } from "node:child_process";
97066
97306
  import {
97067
- existsSync as existsSync95,
97068
- readFileSync as readFileSync84,
97307
+ existsSync as existsSync96,
97308
+ readFileSync as readFileSync85,
97069
97309
  readdirSync as readdirSync32,
97070
97310
  statSync as statSync51,
97071
- renameSync as renameSync23,
97072
- mkdirSync as mkdirSync52,
97311
+ renameSync as renameSync24,
97312
+ mkdirSync as mkdirSync53,
97073
97313
  rmSync as rmSync17
97074
97314
  } from "node:fs";
97075
97315
  import { homedir as homedir52 } from "node:os";
@@ -97191,9 +97431,9 @@ function trashRoot() {
97191
97431
  return resolve56(process.env.SWITCHROOM_WORKTREE_TRASH ?? join96(homedir52(), ".switchroom", "worktree-gc-trash"));
97192
97432
  }
97193
97433
  function planGc(roots, deps = {}) {
97194
- const exists = deps.existsSync ?? existsSync95;
97434
+ const exists = deps.existsSync ?? existsSync96;
97195
97435
  const readDir = deps.readDir ?? ((p) => readdirSync32(p));
97196
- const readFile4 = deps.readFile ?? ((p) => readFileSync84(p, "utf8"));
97436
+ const readFile4 = deps.readFile ?? ((p) => readFileSync85(p, "utf8"));
97197
97437
  const stat3 = deps.stat ?? ((p) => statSync51(p));
97198
97438
  const exec = deps.exec ?? defaultExec3;
97199
97439
  const prSignal = deps.prSignal ?? ((repo, branch) => defaultPrSignal(repo, branch, exec));
@@ -97321,10 +97561,10 @@ function planGc(roots, deps = {}) {
97321
97561
  }
97322
97562
  function applyGc(plan, deps = {}) {
97323
97563
  const exec = deps.exec ?? defaultExec3;
97324
- const mkdirp = deps.mkdirp ?? ((p) => void mkdirSync52(p, { recursive: true }));
97564
+ const mkdirp = deps.mkdirp ?? ((p) => void mkdirSync53(p, { recursive: true }));
97325
97565
  const move = deps.move ?? ((src, dest) => {
97326
97566
  try {
97327
- renameSync23(src, dest);
97567
+ renameSync24(src, dest);
97328
97568
  } catch {
97329
97569
  exec("mv", [src, dest]);
97330
97570
  }
@@ -97370,7 +97610,7 @@ function selectPurgeTargets(entries, olderThanDays) {
97370
97610
  return entries.filter((e) => e.ageDays >= olderThanDays).map((e) => e.path);
97371
97611
  }
97372
97612
  function listTrashEntries(nowMs, deps = {}) {
97373
- const exists = deps.existsSync ?? existsSync95;
97613
+ const exists = deps.existsSync ?? existsSync96;
97374
97614
  const readDir = deps.readDir ?? ((p) => readdirSync32(p));
97375
97615
  const root = trashRoot();
97376
97616
  if (!exists(root))
@@ -97632,10 +97872,10 @@ init_drive();
97632
97872
  init_scaffold_integration();
97633
97873
  import {
97634
97874
  chmodSync as chmodSync16,
97635
- mkdirSync as mkdirSync53,
97875
+ mkdirSync as mkdirSync54,
97636
97876
  readdirSync as readdirSync33,
97637
97877
  rmSync as rmSync18,
97638
- writeFileSync as writeFileSync37
97878
+ writeFileSync as writeFileSync38
97639
97879
  } from "node:fs";
97640
97880
  import { join as join97 } from "node:path";
97641
97881
  function encodeCredentialsFilename(email) {
@@ -97830,14 +98070,14 @@ function resolveCredentialsDir(env2) {
97830
98070
  return join97(stateBase, "google-workspace-mcp", "credentials");
97831
98071
  }
97832
98072
  function writeSeedFile(dir, email, seed) {
97833
- mkdirSync53(dir, { recursive: true, mode: 448 });
98073
+ mkdirSync54(dir, { recursive: true, mode: 448 });
97834
98074
  chmodSync16(dir, 448);
97835
98075
  for (const name of readdirSync33(dir)) {
97836
98076
  rmSync18(join97(dir, name), { force: true, recursive: true });
97837
98077
  }
97838
98078
  const filename = encodeCredentialsFilename(email);
97839
98079
  const filePath = join97(dir, filename);
97840
- writeFileSync37(filePath, JSON.stringify(seed), { mode: 384 });
98080
+ writeFileSync38(filePath, JSON.stringify(seed), { mode: 384 });
97841
98081
  chmodSync16(filePath, 384);
97842
98082
  return filePath;
97843
98083
  }
@@ -97995,8 +98235,8 @@ function registerDriveMcpLauncherCommand(program3) {
97995
98235
  // src/cli/m365-mcp-launcher.ts
97996
98236
  init_scaffold_integration();
97997
98237
  import { spawn as spawn6 } from "node:child_process";
97998
- import { writeFileSync as writeFileSync38, mkdirSync as mkdirSync54 } from "node:fs";
97999
- import { dirname as dirname38, join as join98 } from "node:path";
98238
+ import { writeFileSync as writeFileSync39, mkdirSync as mkdirSync55 } from "node:fs";
98239
+ import { dirname as dirname39, join as join98 } from "node:path";
98000
98240
  var SOFTERIA_TOKEN_ENV = "MS365_MCP_OAUTH_TOKEN";
98001
98241
  var DEFAULT_REFRESH_LEAD_MS = 5 * 60 * 1000;
98002
98242
  var MAX_REFRESH_INTERVAL_MS = 60 * 60 * 1000;
@@ -98032,8 +98272,8 @@ function computeRefreshDelayMs(expiresAt, now, leadMs = DEFAULT_REFRESH_LEAD_MS)
98032
98272
  function writeRefreshHeartbeat(agentName, data, account) {
98033
98273
  const path10 = heartbeatPath(agentName, account);
98034
98274
  try {
98035
- mkdirSync54(dirname38(path10), { recursive: true });
98036
- writeFileSync38(path10, JSON.stringify(data, null, 2), { mode: 420 });
98275
+ mkdirSync55(dirname39(path10), { recursive: true });
98276
+ writeFileSync39(path10, JSON.stringify(data, null, 2), { mode: 420 });
98037
98277
  } catch {}
98038
98278
  }
98039
98279
  function heartbeatPath(agentName, account) {
@@ -98273,8 +98513,8 @@ function registerM365McpLauncherCommand(program3) {
98273
98513
  // src/cli/notion-mcp-launcher.ts
98274
98514
  init_scaffold_integration();
98275
98515
  import { spawn as spawn7 } from "node:child_process";
98276
- import { existsSync as existsSync96, mkdirSync as mkdirSync55, writeFileSync as writeFileSync39 } from "node:fs";
98277
- import { dirname as dirname39 } from "node:path";
98516
+ import { existsSync as existsSync97, mkdirSync as mkdirSync56, writeFileSync as writeFileSync40 } from "node:fs";
98517
+ import { dirname as dirname40 } from "node:path";
98278
98518
  var HEARTBEAT_WRITE_INTERVAL_MS = 30 * 1000;
98279
98519
  var DEFAULT_HEARTBEAT_PATH = "/state/agent/notion-launcher.heartbeat.json";
98280
98520
  var DEFAULT_VAULT_KEY = "notion/integration-token";
@@ -98284,10 +98524,10 @@ function buildNotionMcpArgs(opts) {
98284
98524
  }
98285
98525
  function defaultWriteHeartbeat(path10, contents) {
98286
98526
  try {
98287
- const dir = dirname39(path10);
98288
- if (!existsSync96(dir))
98289
- mkdirSync55(dir, { recursive: true });
98290
- writeFileSync39(path10, contents);
98527
+ const dir = dirname40(path10);
98528
+ if (!existsSync97(dir))
98529
+ mkdirSync56(dir, { recursive: true });
98530
+ writeFileSync40(path10, contents);
98291
98531
  } catch {}
98292
98532
  }
98293
98533
  async function runNotionMcpLauncher(opts, runtime) {
@@ -98396,7 +98636,7 @@ function registerNotionMcpLauncherCommand(program3) {
98396
98636
  }
98397
98637
 
98398
98638
  // src/cli/hindsight-mcp-shim.ts
98399
- import { mkdirSync as mkdirSync56, readFileSync as readFileSync85, renameSync as renameSync24, writeFileSync as writeFileSync40 } from "node:fs";
98639
+ import { mkdirSync as mkdirSync57, readFileSync as readFileSync86, renameSync as renameSync25, writeFileSync as writeFileSync41 } from "node:fs";
98400
98640
  import { tmpdir as tmpdir5 } from "node:os";
98401
98641
  import { join as join99 } from "node:path";
98402
98642
  import { createInterface as createInterface6 } from "node:readline";
@@ -98848,18 +99088,18 @@ class HindsightShim {
98848
99088
  }
98849
99089
  writeCache(result) {
98850
99090
  try {
98851
- mkdirSync56(this.opts.cacheDir, { recursive: true });
99091
+ mkdirSync57(this.opts.cacheDir, { recursive: true });
98852
99092
  const tmp = join99(this.opts.cacheDir, `.${TOOLS_CACHE_FILENAME}.${process.pid}.tmp`);
98853
- writeFileSync40(tmp, JSON.stringify(result, null, 2) + `
99093
+ writeFileSync41(tmp, JSON.stringify(result, null, 2) + `
98854
99094
  `);
98855
- renameSync24(tmp, this.cachePath);
99095
+ renameSync25(tmp, this.cachePath);
98856
99096
  } catch (err) {
98857
99097
  this.log(`[hindsight-shim] cache write failed: ${String(err)}`);
98858
99098
  }
98859
99099
  }
98860
99100
  readCache() {
98861
99101
  try {
98862
- const parsed = JSON.parse(readFileSync85(this.cachePath, "utf-8"));
99102
+ const parsed = JSON.parse(readFileSync86(this.cachePath, "utf-8"));
98863
99103
  if (Array.isArray(parsed.tools))
98864
99104
  return parsed;
98865
99105
  return null;
@@ -99092,7 +99332,7 @@ function registerHindsightMcpShimCommand(program3) {
99092
99332
 
99093
99333
  // src/cli/deliver-file.ts
99094
99334
  init_client2();
99095
- import { readFileSync as readFileSync86, statSync as statSync52 } from "node:fs";
99335
+ import { readFileSync as readFileSync87, statSync as statSync52 } from "node:fs";
99096
99336
  import { basename as basename13 } from "node:path";
99097
99337
 
99098
99338
  // src/delivery/onedrive.ts
@@ -99432,7 +99672,7 @@ async function defaultResolveProvider() {
99432
99672
  async function runDeliverFile(localPath, deps = {}) {
99433
99673
  const agentName = safeAgentName(deps.agentName ?? process.env.SWITCHROOM_AGENT_NAME);
99434
99674
  const sizeOf = deps.fileSize ?? ((p) => statSync52(p).size);
99435
- const read = deps.readFile ?? ((p) => new Uint8Array(readFileSync86(p)));
99675
+ const read = deps.readFile ?? ((p) => new Uint8Array(readFileSync87(p)));
99436
99676
  const resolveProvider = deps.resolveProvider ?? defaultResolveProvider;
99437
99677
  let size;
99438
99678
  try {
@@ -99753,7 +99993,7 @@ function runRedactStdin() {
99753
99993
  }
99754
99994
 
99755
99995
  // src/cli/status-ask.ts
99756
- import { readFileSync as readFileSync87, existsSync as existsSync97, readdirSync as readdirSync34 } from "node:fs";
99996
+ import { readFileSync as readFileSync88, existsSync as existsSync98, readdirSync as readdirSync34 } from "node:fs";
99757
99997
  import { join as join100 } from "node:path";
99758
99998
  import { homedir as homedir53 } from "node:os";
99759
99999
 
@@ -100029,7 +100269,7 @@ function runReport(opts) {
100029
100269
  for (const src of sources) {
100030
100270
  let content;
100031
100271
  try {
100032
- content = readFileSync87(src.path, "utf-8");
100272
+ content = readFileSync88(src.path, "utf-8");
100033
100273
  } catch (err) {
100034
100274
  process.stderr.write(`status-ask report: cannot read ${src.path}: ${err instanceof Error ? err.message : String(err)}
100035
100275
  `);
@@ -100076,7 +100316,7 @@ function runReport(opts) {
100076
100316
  function resolveSources(explicitPath) {
100077
100317
  if (explicitPath != null && explicitPath.trim() !== "") {
100078
100318
  const trimmed = explicitPath.trim();
100079
- if (!existsSync97(trimmed)) {
100319
+ if (!existsSync98(trimmed)) {
100080
100320
  process.stderr.write(`status-ask report: ${trimmed}: file not found
100081
100321
  `);
100082
100322
  process.exit(1);
@@ -100092,7 +100332,7 @@ function resolveSources(explicitPath) {
100092
100332
  } catch {
100093
100333
  agentsDir = join100(homedir53(), ".switchroom", "agents");
100094
100334
  }
100095
- if (!existsSync97(agentsDir))
100335
+ if (!existsSync98(agentsDir))
100096
100336
  return [];
100097
100337
  const sources = [];
100098
100338
  let entries;
@@ -100103,7 +100343,7 @@ function resolveSources(explicitPath) {
100103
100343
  }
100104
100344
  for (const name of entries) {
100105
100345
  const path10 = join100(agentsDir, name, "runtime-metrics.jsonl");
100106
- if (existsSync97(path10)) {
100346
+ if (existsSync98(path10)) {
100107
100347
  sources.push({ path: path10, agent: name });
100108
100348
  }
100109
100349
  }
@@ -100133,13 +100373,13 @@ var import_yaml21 = __toESM(require_dist(), 1);
100133
100373
  init_paths();
100134
100374
  import {
100135
100375
  closeSync as closeSync18,
100136
- existsSync as existsSync98,
100376
+ existsSync as existsSync99,
100137
100377
  fsyncSync as fsyncSync8,
100138
- mkdirSync as mkdirSync57,
100378
+ mkdirSync as mkdirSync58,
100139
100379
  openSync as openSync18,
100140
100380
  readdirSync as readdirSync35,
100141
- readFileSync as readFileSync88,
100142
- renameSync as renameSync25,
100381
+ readFileSync as readFileSync89,
100382
+ renameSync as renameSync26,
100143
100383
  statSync as statSync53,
100144
100384
  unlinkSync as unlinkSync20,
100145
100385
  writeSync as writeSync10
@@ -100163,15 +100403,15 @@ function overlayPathsFor(agent, opts = {}) {
100163
100403
  };
100164
100404
  }
100165
100405
  function ensureDirs(paths) {
100166
- mkdirSync57(paths.scheduleDir, { recursive: true });
100167
- mkdirSync57(paths.scheduleStagingDir, { recursive: true });
100406
+ mkdirSync58(paths.scheduleDir, { recursive: true });
100407
+ mkdirSync58(paths.scheduleStagingDir, { recursive: true });
100168
100408
  }
100169
100409
  function ensureSkillsDirs(paths) {
100170
- mkdirSync57(paths.skillsDir, { recursive: true });
100171
- mkdirSync57(paths.skillsStagingDir, { recursive: true });
100410
+ mkdirSync58(paths.skillsDir, { recursive: true });
100411
+ mkdirSync58(paths.skillsStagingDir, { recursive: true });
100172
100412
  }
100173
100413
  function withAgentLock(paths, fn) {
100174
- mkdirSync57(paths.agentRoot, { recursive: true });
100414
+ mkdirSync58(paths.agentRoot, { recursive: true });
100175
100415
  const start = Date.now();
100176
100416
  const TIMEOUT_MS = 5000;
100177
100417
  let fd = null;
@@ -100221,7 +100461,7 @@ function writeOverlayEntry(agent, slug, yamlText, opts = {}) {
100221
100461
  } finally {
100222
100462
  closeSync18(fd);
100223
100463
  }
100224
- renameSync25(stagingPath, finalPath);
100464
+ renameSync26(stagingPath, finalPath);
100225
100465
  return finalPath;
100226
100466
  });
100227
100467
  }
@@ -100238,7 +100478,7 @@ function writeSkillsOverlayEntry(agent, slug, yamlText, opts = {}) {
100238
100478
  } finally {
100239
100479
  closeSync18(fd);
100240
100480
  }
100241
- renameSync25(stagingPath, finalPath);
100481
+ renameSync26(stagingPath, finalPath);
100242
100482
  return finalPath;
100243
100483
  });
100244
100484
  }
@@ -100246,7 +100486,7 @@ function deleteSkillsOverlayEntry(agent, slug, opts = {}) {
100246
100486
  const paths = overlayPathsFor(agent, opts);
100247
100487
  return withAgentLock(paths, () => {
100248
100488
  const finalPath = join101(paths.skillsDir, `${slug}.yaml`);
100249
- if (!existsSync98(finalPath))
100489
+ if (!existsSync99(finalPath))
100250
100490
  return false;
100251
100491
  unlinkSync20(finalPath);
100252
100492
  return true;
@@ -100254,7 +100494,7 @@ function deleteSkillsOverlayEntry(agent, slug, opts = {}) {
100254
100494
  }
100255
100495
  function listSkillsOverlayEntries(agent, opts = {}) {
100256
100496
  const paths = overlayPathsFor(agent, opts);
100257
- if (!existsSync98(paths.skillsDir))
100497
+ if (!existsSync99(paths.skillsDir))
100258
100498
  return [];
100259
100499
  const out = [];
100260
100500
  for (const name of readdirSync35(paths.skillsDir)) {
@@ -100262,7 +100502,7 @@ function listSkillsOverlayEntries(agent, opts = {}) {
100262
100502
  continue;
100263
100503
  const full = join101(paths.skillsDir, name);
100264
100504
  try {
100265
- const raw = readFileSync88(full, "utf-8");
100505
+ const raw = readFileSync89(full, "utf-8");
100266
100506
  const slug = name.replace(/\.ya?ml$/i, "");
100267
100507
  out.push({ slug, path: full, raw });
100268
100508
  } catch {}
@@ -100273,7 +100513,7 @@ function deleteOverlayEntry(agent, slug, opts = {}) {
100273
100513
  const paths = overlayPathsFor(agent, opts);
100274
100514
  return withAgentLock(paths, () => {
100275
100515
  const finalPath = join101(paths.scheduleDir, `${slug}.yaml`);
100276
- if (!existsSync98(finalPath))
100516
+ if (!existsSync99(finalPath))
100277
100517
  return false;
100278
100518
  unlinkSync20(finalPath);
100279
100519
  return true;
@@ -100281,7 +100521,7 @@ function deleteOverlayEntry(agent, slug, opts = {}) {
100281
100521
  }
100282
100522
  function listOverlayEntries(agent, opts = {}) {
100283
100523
  const paths = overlayPathsFor(agent, opts);
100284
- if (!existsSync98(paths.scheduleDir))
100524
+ if (!existsSync99(paths.scheduleDir))
100285
100525
  return [];
100286
100526
  const out = [];
100287
100527
  for (const name of readdirSync35(paths.scheduleDir)) {
@@ -100289,7 +100529,7 @@ function listOverlayEntries(agent, opts = {}) {
100289
100529
  continue;
100290
100530
  const full = join101(paths.scheduleDir, name);
100291
100531
  try {
100292
- const raw = readFileSync88(full, "utf-8");
100532
+ const raw = readFileSync89(full, "utf-8");
100293
100533
  const slug = name.replace(/\.ya?ml$/i, "");
100294
100534
  out.push({ slug, path: full, raw });
100295
100535
  } catch {}
@@ -100509,15 +100749,15 @@ function reconcileAgentCronOnly(agent) {
100509
100749
  // src/cli/agent-config-pending.ts
100510
100750
  import {
100511
100751
  closeSync as closeSync19,
100512
- existsSync as existsSync99,
100752
+ existsSync as existsSync100,
100513
100753
  fsyncSync as fsyncSync9,
100514
- mkdirSync as mkdirSync58,
100754
+ mkdirSync as mkdirSync59,
100515
100755
  openSync as openSync19,
100516
100756
  readdirSync as readdirSync36,
100517
- readFileSync as readFileSync89,
100518
- renameSync as renameSync26,
100757
+ readFileSync as readFileSync90,
100758
+ renameSync as renameSync27,
100519
100759
  unlinkSync as unlinkSync21,
100520
- writeFileSync as writeFileSync41,
100760
+ writeFileSync as writeFileSync42,
100521
100761
  writeSync as writeSync11
100522
100762
  } from "node:fs";
100523
100763
  import { join as join102 } from "node:path";
@@ -100529,7 +100769,7 @@ function pendingDir(agent, opts = {}) {
100529
100769
  }
100530
100770
  function ensurePendingDir(agent, opts = {}) {
100531
100771
  const dir = pendingDir(agent, opts);
100532
- mkdirSync58(dir, { recursive: true });
100772
+ mkdirSync59(dir, { recursive: true });
100533
100773
  return dir;
100534
100774
  }
100535
100775
  function newStageId() {
@@ -100558,15 +100798,15 @@ function stagePendingScheduleEntry(opts) {
100558
100798
  } finally {
100559
100799
  closeSync19(fd);
100560
100800
  }
100561
- renameSync26(yamlTmp, yamlPath);
100801
+ renameSync27(yamlTmp, yamlPath);
100562
100802
  }
100563
- writeFileSync41(metaPath, JSON.stringify(meta, null, 2) + `
100803
+ writeFileSync42(metaPath, JSON.stringify(meta, null, 2) + `
100564
100804
  `, { mode: 384 });
100565
100805
  return { stageId, yamlPath, metaPath };
100566
100806
  }
100567
100807
  function listPendingScheduleEntries(agent, opts = {}) {
100568
100808
  const dir = pendingDir(agent, opts);
100569
- if (!existsSync99(dir))
100809
+ if (!existsSync100(dir))
100570
100810
  return [];
100571
100811
  const out = [];
100572
100812
  for (const name of readdirSync36(dir).sort()) {
@@ -100575,10 +100815,10 @@ function listPendingScheduleEntries(agent, opts = {}) {
100575
100815
  const stageId = name.slice(0, -".meta.json".length);
100576
100816
  const metaPath = join102(dir, name);
100577
100817
  const yamlPath = join102(dir, `${stageId}.yaml`);
100578
- if (!existsSync99(yamlPath))
100818
+ if (!existsSync100(yamlPath))
100579
100819
  continue;
100580
100820
  try {
100581
- const meta = JSON.parse(readFileSync89(metaPath, "utf-8"));
100821
+ const meta = JSON.parse(readFileSync90(metaPath, "utf-8"));
100582
100822
  if (meta?.v !== 1 || typeof meta.stage_id !== "string")
100583
100823
  continue;
100584
100824
  out.push({ stageId: meta.stage_id, agent: meta.agent, yamlPath, metaPath, meta });
@@ -100594,10 +100834,10 @@ function commitPendingScheduleEntry(opts) {
100594
100834
  const slug = match.meta.entry.name ?? match.stageId;
100595
100835
  const paths = overlayPathsFor(opts.agent, { root: opts.root });
100596
100836
  const finalPath = join102(paths.scheduleDir, `${slug}.yaml`);
100597
- if (existsSync99(finalPath)) {
100837
+ if (existsSync100(finalPath)) {
100598
100838
  return { committed: false, reason: "slug_collision" };
100599
100839
  }
100600
- renameSync26(match.yamlPath, finalPath);
100840
+ renameSync27(match.yamlPath, finalPath);
100601
100841
  unlinkSync21(match.metaPath);
100602
100842
  return { committed: true, path: finalPath, slug };
100603
100843
  }
@@ -100616,7 +100856,7 @@ function denyPendingScheduleEntry(opts) {
100616
100856
  }
100617
100857
 
100618
100858
  // src/cli/agent-config-write.ts
100619
- import { existsSync as existsSync100, readFileSync as readFileSync90 } from "node:fs";
100859
+ import { existsSync as existsSync101, readFileSync as readFileSync91 } from "node:fs";
100620
100860
  import { execFileSync as execFileSync30 } from "node:child_process";
100621
100861
 
100622
100862
  // src/scheduler/schedule-report.ts
@@ -101006,8 +101246,8 @@ function scheduleRemove(opts) {
101006
101246
  }
101007
101247
  let priorContent = null;
101008
101248
  try {
101009
- if (existsSync100(match.path))
101010
- priorContent = readFileSync90(match.path, "utf-8");
101249
+ if (existsSync101(match.path))
101250
+ priorContent = readFileSync91(match.path, "utf-8");
101011
101251
  } catch {}
101012
101252
  deleteOverlayEntry(agent, match.slug, { root: opts.root });
101013
101253
  const reconcileFn = opts.reconcile === undefined ? opts.root ? null : reconcileAgentCronOnly : opts.reconcile;
@@ -101210,7 +101450,7 @@ function registerAgentConfigWriteCommands(program3) {
101210
101450
  }
101211
101451
  let blob;
101212
101452
  if (opts.jsonl) {
101213
- blob = existsSync100(opts.jsonl) ? readFileSync90(opts.jsonl, "utf-8") : "";
101453
+ blob = existsSync101(opts.jsonl) ? readFileSync91(opts.jsonl, "utf-8") : "";
101214
101454
  } else {
101215
101455
  try {
101216
101456
  blob = execFileSync30("docker", ["exec", `switchroom-${agent}`, "cat", "/state/agent/scheduler.jsonl"], {
@@ -101242,7 +101482,7 @@ function registerAgentConfigWriteCommands(program3) {
101242
101482
 
101243
101483
  // src/cli/agent-config-skill-write.ts
101244
101484
  var import_yaml22 = __toESM(require_dist(), 1);
101245
- import { existsSync as existsSync101 } from "node:fs";
101485
+ import { existsSync as existsSync102 } from "node:fs";
101246
101486
  init_reconcile_default_skills();
101247
101487
  init_agent_config();
101248
101488
  var import_yaml23 = __toESM(require_dist(), 1);
@@ -101322,7 +101562,7 @@ function skillInstall(opts) {
101322
101562
  }
101323
101563
  const poolDir = opts.bundledSkillsPoolDir ?? getBundledSkillsPoolDir();
101324
101564
  const skillPath = join103(poolDir, skillName);
101325
- if (!existsSync101(skillPath)) {
101565
+ if (!existsSync102(skillPath)) {
101326
101566
  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.`);
101327
101567
  }
101328
101568
  const yamlText = import_yaml22.stringify({ skills: [skillName] });
@@ -101486,22 +101726,22 @@ function registerAgentConfigSkillWriteCommands(program3) {
101486
101726
  // src/cli/skill.ts
101487
101727
  import {
101488
101728
  closeSync as closeSync20,
101489
- existsSync as existsSync102,
101729
+ existsSync as existsSync103,
101490
101730
  lstatSync as lstatSync12,
101491
- mkdirSync as mkdirSync59,
101731
+ mkdirSync as mkdirSync60,
101492
101732
  mkdtempSync as mkdtempSync5,
101493
101733
  openSync as openSync20,
101494
- readFileSync as readFileSync91,
101734
+ readFileSync as readFileSync92,
101495
101735
  readdirSync as readdirSync37,
101496
101736
  realpathSync as realpathSync7,
101497
- renameSync as renameSync27,
101737
+ renameSync as renameSync28,
101498
101738
  rmSync as rmSync19,
101499
101739
  statSync as statSync54,
101500
- writeFileSync as writeFileSync42
101740
+ writeFileSync as writeFileSync43
101501
101741
  } from "node:fs";
101502
101742
  import { tmpdir as tmpdir6, homedir as homedir54 } from "node:os";
101503
- import { dirname as dirname40, join as join104, relative as relative4, resolve as resolve58 } from "node:path";
101504
- import { spawnSync as spawnSync20 } from "node:child_process";
101743
+ import { dirname as dirname41, join as join104, relative as relative4, resolve as resolve58 } from "node:path";
101744
+ import { spawnSync as spawnSync21 } from "node:child_process";
101505
101745
 
101506
101746
  // src/cli/skill-common.ts
101507
101747
  var import_yaml24 = __toESM(require_dist(), 1);
@@ -101784,7 +102024,7 @@ function loadFromDir(dir) {
101784
102024
  continue;
101785
102025
  }
101786
102026
  if (ent.isFile()) {
101787
- const buf = readFileSync91(full);
102027
+ const buf = readFileSync92(full);
101788
102028
  files[rel.replace(/\\/g, "/")] = buf.toString("utf-8");
101789
102029
  }
101790
102030
  }
@@ -101795,7 +102035,7 @@ function loadFromDir(dir) {
101795
102035
  function loadFromTarball(tarPath) {
101796
102036
  const isGz = tarPath.endsWith(".gz") || tarPath.endsWith(".tgz");
101797
102037
  const listFlags = isGz ? ["-tzf"] : ["-tf"];
101798
- const list2 = spawnSync20("tar", [...listFlags, tarPath], {
102038
+ const list2 = spawnSync21("tar", [...listFlags, tarPath], {
101799
102039
  encoding: "utf-8",
101800
102040
  stdio: ["ignore", "pipe", "pipe"]
101801
102041
  });
@@ -101812,7 +102052,7 @@ function loadFromTarball(tarPath) {
101812
102052
  const staging = mkdtempSync5(join104(tmpdir6(), "skill-apply-extract-"));
101813
102053
  try {
101814
102054
  const flags = isGz ? ["-xzf"] : ["-xf"];
101815
- const r = spawnSync20("tar", [
102055
+ const r = spawnSync21("tar", [
101816
102056
  ...flags,
101817
102057
  tarPath,
101818
102058
  "-C",
@@ -101833,7 +102073,7 @@ function loadFromTarball(tarPath) {
101833
102073
  }
101834
102074
  }
101835
102075
  function loadSingleFile(filePath) {
101836
- const content = readFileSync91(filePath, "utf-8");
102076
+ const content = readFileSync92(filePath, "utf-8");
101837
102077
  return { "SKILL.md": content };
101838
102078
  }
101839
102079
  function loadFromStdin() {
@@ -101887,7 +102127,7 @@ function validatePayload(name, files) {
101887
102127
  if (errors2.length === 0) {
101888
102128
  for (const [path10, content] of Object.entries(files)) {
101889
102129
  if (SH_SCRIPT_RE2.test(path10)) {
101890
- const r = spawnSync20("bash", ["-n"], {
102130
+ const r = spawnSync21("bash", ["-n"], {
101891
102131
  input: content,
101892
102132
  encoding: "utf-8"
101893
102133
  });
@@ -101898,8 +102138,8 @@ function validatePayload(name, files) {
101898
102138
  const tmp = mkdtempSync5(join104(tmpdir6(), "skill-apply-py-"));
101899
102139
  const tmpPy = join104(tmp, "check.py");
101900
102140
  try {
101901
- writeFileSync42(tmpPy, content);
101902
- const r = spawnSync20("python3", ["-m", "py_compile", tmpPy], {
102141
+ writeFileSync43(tmpPy, content);
102142
+ const r = spawnSync21("python3", ["-m", "py_compile", tmpPy], {
101903
102143
  encoding: "utf-8"
101904
102144
  });
101905
102145
  if (r.status !== 0) {
@@ -101916,7 +102156,7 @@ function validatePayload(name, files) {
101916
102156
  function diffSummary(currentDir, files) {
101917
102157
  const lines = [];
101918
102158
  const currentFiles = {};
101919
- if (existsSync102(currentDir)) {
102159
+ if (existsSync103(currentDir)) {
101920
102160
  const walk2 = (sub) => {
101921
102161
  for (const ent of readdirSync37(sub, { withFileTypes: true })) {
101922
102162
  const full = join104(sub, ent.name);
@@ -101924,7 +102164,7 @@ function diffSummary(currentDir, files) {
101924
102164
  if (ent.isDirectory()) {
101925
102165
  walk2(full);
101926
102166
  } else if (ent.isFile()) {
101927
- currentFiles[rel.replace(/\\/g, "/")] = readFileSync91(full, "utf-8");
102167
+ currentFiles[rel.replace(/\\/g, "/")] = readFileSync92(full, "utf-8");
101928
102168
  }
101929
102169
  }
101930
102170
  };
@@ -101952,8 +102192,8 @@ function diffSummary(currentDir, files) {
101952
102192
  `);
101953
102193
  }
101954
102194
  function writePayload(poolDir, name, files) {
101955
- if (!existsSync102(poolDir)) {
101956
- mkdirSync59(poolDir, { recursive: true, mode: 493 });
102195
+ if (!existsSync103(poolDir)) {
102196
+ mkdirSync60(poolDir, { recursive: true, mode: 493 });
101957
102197
  }
101958
102198
  const target = join104(poolDir, name);
101959
102199
  let targetIsSymlink = false;
@@ -101971,10 +102211,10 @@ function writePayload(poolDir, name, files) {
101971
102211
  try {
101972
102212
  for (const [path10, content] of Object.entries(files)) {
101973
102213
  const full = join104(staging, path10);
101974
- mkdirSync59(dirname40(full), { recursive: true, mode: 493 });
102214
+ mkdirSync60(dirname41(full), { recursive: true, mode: 493 });
101975
102215
  const fd = openSync20(full, "wx");
101976
102216
  try {
101977
- writeFileSync42(fd, content);
102217
+ writeFileSync43(fd, content);
101978
102218
  } finally {
101979
102219
  closeSync20(fd);
101980
102220
  }
@@ -101990,9 +102230,9 @@ function writePayload(poolDir, name, files) {
101990
102230
  } catch {}
101991
102231
  if (targetExists) {
101992
102232
  oldRename = `${target}.skill-apply-old-${Date.now()}`;
101993
- renameSync27(target, oldRename);
102233
+ renameSync28(target, oldRename);
101994
102234
  }
101995
- renameSync27(staging, target);
102235
+ renameSync28(staging, target);
101996
102236
  if (oldRename) {
101997
102237
  rmSync19(oldRename, { recursive: true, force: true });
101998
102238
  oldRename = null;
@@ -102001,12 +102241,12 @@ function writePayload(poolDir, name, files) {
102001
102241
  try {
102002
102242
  rmSync19(staging, { recursive: true, force: true });
102003
102243
  } catch {}
102004
- if (oldRename && existsSync102(oldRename)) {
102244
+ if (oldRename && existsSync103(oldRename)) {
102005
102245
  try {
102006
- if (existsSync102(target)) {
102246
+ if (existsSync103(target)) {
102007
102247
  rmSync19(target, { recursive: true, force: true });
102008
102248
  }
102009
- renameSync27(oldRename, target);
102249
+ renameSync28(oldRename, target);
102010
102250
  } catch {}
102011
102251
  }
102012
102252
  throw err2;
@@ -102024,7 +102264,7 @@ function registerSkillCommand(program3) {
102024
102264
  files = loadFromStdin();
102025
102265
  } else {
102026
102266
  const fromPath = resolve58(opts.from);
102027
- if (!existsSync102(fromPath)) {
102267
+ if (!existsSync103(fromPath)) {
102028
102268
  fail4(`--from path does not exist: ${opts.from}`);
102029
102269
  }
102030
102270
  const st = statSync54(fromPath);
@@ -102062,7 +102302,7 @@ function registerSkillCommand(program3) {
102062
102302
  \u2713 Wrote ${name} to ${currentDir}`));
102063
102303
  const self = selfInvokeArgv(["apply", "--non-interactive"]);
102064
102304
  console.log(source_default.gray(`Running \`switchroom apply --non-interactive\`...`));
102065
- const r = spawnSync20(self.command, self.argv, { stdio: "inherit" });
102305
+ const r = spawnSync21(self.command, self.argv, { stdio: "inherit" });
102066
102306
  if (r.status !== 0) {
102067
102307
  console.error(source_default.yellow(`(warning: \`switchroom apply\` exited ${r.status} \u2014 skill is ` + `in the pool but symlinks may not be refreshed. Re-run manually.)`));
102068
102308
  }
@@ -102080,22 +102320,22 @@ function sumBytes(files) {
102080
102320
  init_esm();
102081
102321
  import {
102082
102322
  closeSync as closeSync21,
102083
- existsSync as existsSync103,
102323
+ existsSync as existsSync104,
102084
102324
  lstatSync as lstatSync13,
102085
- mkdirSync as mkdirSync60,
102325
+ mkdirSync as mkdirSync61,
102086
102326
  mkdtempSync as mkdtempSync6,
102087
102327
  openSync as openSync21,
102088
- readFileSync as readFileSync92,
102328
+ readFileSync as readFileSync93,
102089
102329
  readdirSync as readdirSync38,
102090
- renameSync as renameSync28,
102330
+ renameSync as renameSync29,
102091
102331
  rmSync as rmSync20,
102092
102332
  statSync as statSync55,
102093
102333
  utimesSync,
102094
- writeFileSync as writeFileSync43
102334
+ writeFileSync as writeFileSync44
102095
102335
  } from "node:fs";
102096
- import { dirname as dirname41, join as join105, relative as relative5, resolve as resolve59 } from "node:path";
102336
+ import { dirname as dirname42, join as join105, relative as relative5, resolve as resolve59 } from "node:path";
102097
102337
  import { homedir as homedir55, tmpdir as tmpdir7 } from "node:os";
102098
- import { spawnSync as spawnSync21 } from "node:child_process";
102338
+ import { spawnSync as spawnSync22 } from "node:child_process";
102099
102339
  init_helpers();
102100
102340
  init_agent_config();
102101
102341
  init_source();
@@ -102106,14 +102346,14 @@ var PERSONAL_SKILLS_SUBPATH = "personal-skills";
102106
102346
  function resolveConfigSkillsDir(agent) {
102107
102347
  const override = process.env.SWITCHROOM_CONFIG_DIR;
102108
102348
  const candidate = override ? resolve59(override) : join105(homedir55(), ".switchroom-config");
102109
- if (!existsSync103(candidate))
102349
+ if (!existsSync104(candidate))
102110
102350
  return null;
102111
102351
  return join105(candidate, "agents", agent, PERSONAL_SKILLS_SUBPATH);
102112
102352
  }
102113
102353
  var MIRROR_PRIOR_TTL_MS = 24 * 60 * 60 * 1000;
102114
102354
  function sweepMirrorPriors(configSkillsRoot) {
102115
102355
  try {
102116
- if (!existsSync103(configSkillsRoot))
102356
+ if (!existsSync104(configSkillsRoot))
102117
102357
  return;
102118
102358
  const now = Date.now();
102119
102359
  for (const ent of readdirSync38(configSkillsRoot)) {
@@ -102149,17 +102389,17 @@ function mirrorToConfigRepo(agent, name, liveSkillDir) {
102149
102389
  }
102150
102390
  if (liveSkillDir === null) {
102151
102391
  sweepMirrorPriors(configSkillsRoot);
102152
- if (existsSync103(dest)) {
102392
+ if (existsSync104(dest)) {
102153
102393
  const trash = join105(configSkillsRoot, `.${name}-trash-${Date.now()}`);
102154
- renameSync28(dest, trash);
102394
+ renameSync29(dest, trash);
102155
102395
  }
102156
102396
  return;
102157
102397
  }
102158
- mkdirSync60(configSkillsRoot, { recursive: true, mode: 493 });
102398
+ mkdirSync61(configSkillsRoot, { recursive: true, mode: 493 });
102159
102399
  sweepMirrorPriors(configSkillsRoot);
102160
102400
  const staging = mkdtempSync6(join105(configSkillsRoot, `.${name}-staging-`));
102161
102401
  const walk2 = (src, dst) => {
102162
- mkdirSync60(dst, { recursive: true, mode: 493 });
102402
+ mkdirSync61(dst, { recursive: true, mode: 493 });
102163
102403
  for (const ent of readdirSync38(src, { withFileTypes: true })) {
102164
102404
  const s = join105(src, ent.name);
102165
102405
  const d = join105(dst, ent.name);
@@ -102168,16 +102408,16 @@ function mirrorToConfigRepo(agent, name, liveSkillDir) {
102168
102408
  if (ent.isDirectory())
102169
102409
  walk2(s, d);
102170
102410
  else if (ent.isFile()) {
102171
- writeFileSync43(d, readFileSync92(s));
102411
+ writeFileSync44(d, readFileSync93(s));
102172
102412
  }
102173
102413
  }
102174
102414
  };
102175
102415
  walk2(liveSkillDir, staging);
102176
- if (existsSync103(dest)) {
102416
+ if (existsSync104(dest)) {
102177
102417
  const prior = join105(configSkillsRoot, `.${name}-prior-${Date.now()}`);
102178
- renameSync28(dest, prior);
102418
+ renameSync29(dest, prior);
102179
102419
  }
102180
- renameSync28(staging, dest);
102420
+ renameSync29(staging, dest);
102181
102421
  } catch (err2) {
102182
102422
  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.
102183
102423
  `));
@@ -102214,7 +102454,7 @@ function trashDir(agentsRoot, agent) {
102214
102454
  }
102215
102455
  function countPersonalSkills(agentsRoot, agent) {
102216
102456
  const skillsDir = join105(agentsRoot, agent, ".claude", "skills");
102217
- if (!existsSync103(skillsDir))
102457
+ if (!existsSync104(skillsDir))
102218
102458
  return 0;
102219
102459
  let n = 0;
102220
102460
  for (const ent of readdirSync38(skillsDir, { withFileTypes: true })) {
@@ -102261,7 +102501,7 @@ function loadFromDir2(dir) {
102261
102501
  }
102262
102502
  if (ent.isFile()) {
102263
102503
  const rel = relative5(abs, full).replace(/\\/g, "/");
102264
- files[rel] = readFileSync92(full, "utf-8");
102504
+ files[rel] = readFileSync93(full, "utf-8");
102265
102505
  }
102266
102506
  }
102267
102507
  };
@@ -102299,7 +102539,7 @@ function behavioralValidate(files) {
102299
102539
  const errors2 = [];
102300
102540
  for (const [path10, content] of Object.entries(files)) {
102301
102541
  if (SH_SCRIPT_RE.test(path10)) {
102302
- const r = spawnSync21("bash", ["-n"], { input: content, encoding: "utf-8" });
102542
+ const r = spawnSync22("bash", ["-n"], { input: content, encoding: "utf-8" });
102303
102543
  if (r.status !== 0) {
102304
102544
  errors2.push(`${path10} fails \`bash -n\`: ${(r.stderr ?? "").trim()}`);
102305
102545
  }
@@ -102307,8 +102547,8 @@ function behavioralValidate(files) {
102307
102547
  const tmp = mkdtempSync6(join105(tmpdir7(), "skill-personal-py-"));
102308
102548
  const tmpPy = join105(tmp, "check.py");
102309
102549
  try {
102310
- writeFileSync43(tmpPy, content);
102311
- const r = spawnSync21("python3", ["-m", "py_compile", tmpPy], {
102550
+ writeFileSync44(tmpPy, content);
102551
+ const r = spawnSync22("python3", ["-m", "py_compile", tmpPy], {
102312
102552
  encoding: "utf-8"
102313
102553
  });
102314
102554
  if (r.status !== 0) {
@@ -102323,7 +102563,7 @@ function behavioralValidate(files) {
102323
102563
  }
102324
102564
  function sweepTrash(agentsRoot, agent) {
102325
102565
  const trash = trashDir(agentsRoot, agent);
102326
- if (!existsSync103(trash))
102566
+ if (!existsSync104(trash))
102327
102567
  return;
102328
102568
  const now = Date.now();
102329
102569
  for (const ent of readdirSync38(trash, { withFileTypes: true })) {
@@ -102349,16 +102589,16 @@ function writePersonalSkill(targetDir, files) {
102349
102589
  if (targetIsSymlink) {
102350
102590
  fail5(`refusing to overwrite symlink at ${targetDir}; investigate manually`);
102351
102591
  }
102352
- mkdirSync60(dirname41(targetDir), { recursive: true, mode: 493 });
102353
- const staging = mkdtempSync6(join105(dirname41(targetDir), `.skill-personal-stage-`));
102592
+ mkdirSync61(dirname42(targetDir), { recursive: true, mode: 493 });
102593
+ const staging = mkdtempSync6(join105(dirname42(targetDir), `.skill-personal-stage-`));
102354
102594
  let oldRename = null;
102355
102595
  try {
102356
102596
  for (const [path10, content] of Object.entries(files)) {
102357
102597
  const full = join105(staging, path10);
102358
- mkdirSync60(dirname41(full), { recursive: true, mode: 493 });
102598
+ mkdirSync61(dirname42(full), { recursive: true, mode: 493 });
102359
102599
  const fd = openSync21(full, "wx");
102360
102600
  try {
102361
- writeFileSync43(fd, content);
102601
+ writeFileSync44(fd, content);
102362
102602
  } finally {
102363
102603
  closeSync21(fd);
102364
102604
  }
@@ -102374,9 +102614,9 @@ function writePersonalSkill(targetDir, files) {
102374
102614
  } catch {}
102375
102615
  if (targetExists) {
102376
102616
  oldRename = `${targetDir}.personal-old-${Date.now()}`;
102377
- renameSync28(targetDir, oldRename);
102617
+ renameSync29(targetDir, oldRename);
102378
102618
  }
102379
- renameSync28(staging, targetDir);
102619
+ renameSync29(staging, targetDir);
102380
102620
  if (oldRename) {
102381
102621
  rmSync20(oldRename, { recursive: true, force: true });
102382
102622
  oldRename = null;
@@ -102385,12 +102625,12 @@ function writePersonalSkill(targetDir, files) {
102385
102625
  try {
102386
102626
  rmSync20(staging, { recursive: true, force: true });
102387
102627
  } catch {}
102388
- if (oldRename && existsSync103(oldRename)) {
102628
+ if (oldRename && existsSync104(oldRename)) {
102389
102629
  try {
102390
- if (existsSync103(targetDir)) {
102630
+ if (existsSync104(targetDir)) {
102391
102631
  rmSync20(targetDir, { recursive: true, force: true });
102392
102632
  }
102393
- renameSync28(oldRename, targetDir);
102633
+ renameSync29(oldRename, targetDir);
102394
102634
  } catch {}
102395
102635
  }
102396
102636
  throw err2;
@@ -102453,7 +102693,7 @@ function loadFiles(opts) {
102453
102693
  return loadFromStdin2();
102454
102694
  }
102455
102695
  const p = resolve59(opts.from);
102456
- if (!existsSync103(p)) {
102696
+ if (!existsSync104(p)) {
102457
102697
  fail5(`--from path does not exist: ${opts.from}`);
102458
102698
  }
102459
102699
  const st = statSync55(p);
@@ -102461,7 +102701,7 @@ function loadFiles(opts) {
102461
102701
  return loadFromDir2(p);
102462
102702
  }
102463
102703
  if (p.endsWith(".md")) {
102464
- return { "SKILL.md": readFileSync92(p, "utf-8") };
102704
+ return { "SKILL.md": readFileSync93(p, "utf-8") };
102465
102705
  }
102466
102706
  fail5(`--from must be a directory or a .md file. Got: ${opts.from}`);
102467
102707
  }
@@ -102515,7 +102755,7 @@ function resolveCloneSource(source, opts) {
102515
102755
  const slug = m[2];
102516
102756
  const root = tier === "bundled" ? opts.bundledRoot ?? defaultBundledRoot() : opts.sharedRoot ?? defaultSharedRoot();
102517
102757
  const dir = join105(root, slug);
102518
- if (!existsSync103(dir)) {
102758
+ if (!existsSync104(dir)) {
102519
102759
  fail5(`clone source ${JSON.stringify(source)} not found at ${dir}; ` + `check \`switchroom skill search --tier ${tier}\``, 1);
102520
102760
  }
102521
102761
  const st = lstatSync13(dir);
@@ -102550,7 +102790,7 @@ function readSourceFiles(dir) {
102550
102790
  fail5(`clone source has oversized file ${rel} (${st.size} bytes > ${CLONE_MAX_FILE_BYTES}); ` + `refuse to read`, 3);
102551
102791
  }
102552
102792
  } catch {}
102553
- files[rel] = readFileSync92(full, "utf-8");
102793
+ files[rel] = readFileSync93(full, "utf-8");
102554
102794
  }
102555
102795
  }
102556
102796
  };
@@ -102639,10 +102879,10 @@ function removePersonalAction(name, opts) {
102639
102879
  throw err2;
102640
102880
  }
102641
102881
  const trashRoot2 = trashDir(agentsRoot, agent);
102642
- mkdirSync60(trashRoot2, { recursive: true, mode: 493 });
102882
+ mkdirSync61(trashRoot2, { recursive: true, mode: 493 });
102643
102883
  const ts = Date.now();
102644
102884
  const trashTarget = join105(trashRoot2, `${name}-${ts}`);
102645
- renameSync28(target, trashTarget);
102885
+ renameSync29(target, trashTarget);
102646
102886
  const now = new Date(ts);
102647
102887
  utimesSync(trashTarget, now, now);
102648
102888
  mirrorToConfigRepo(agent, name, null);
@@ -102662,7 +102902,7 @@ function listPersonalAction(opts) {
102662
102902
  sweepTrash(agentsRoot, agent);
102663
102903
  const skillsDir = join105(agentsRoot, agent, ".claude", "skills");
102664
102904
  const personal = [];
102665
- if (existsSync103(skillsDir)) {
102905
+ if (existsSync104(skillsDir)) {
102666
102906
  for (const ent of readdirSync38(skillsDir, { withFileTypes: true })) {
102667
102907
  if (!ent.isDirectory())
102668
102908
  continue;
@@ -102720,7 +102960,7 @@ function registerSkillPersonalCommands(program3) {
102720
102960
  import { createConnection as createConnection4 } from "node:net";
102721
102961
  import { homedir as homedir56 } from "node:os";
102722
102962
  import { join as join106 } from "node:path";
102723
- import { readFileSync as readFileSync93 } from "node:fs";
102963
+ import { readFileSync as readFileSync94 } from "node:fs";
102724
102964
  var IPC_CONNECT_TIMEOUT_MS = 5000;
102725
102965
  function gatewaySocketPath() {
102726
102966
  return process.env.SWITCHROOM_GATEWAY_SOCKET ?? (process.env.TELEGRAM_STATE_DIR ? join106(process.env.TELEGRAM_STATE_DIR, "gateway.sock") : join106(homedir56(), ".claude", "channels", "telegram", "gateway.sock"));
@@ -102758,7 +102998,7 @@ function registerSelfImproveProposeSkillCommand(program3) {
102758
102998
  fail6("agent name required (--agent or $SWITCHROOM_AGENT_NAME)");
102759
102999
  let draft;
102760
103000
  try {
102761
- draft = JSON.parse(readFileSync93(opts.draft, "utf-8"));
103001
+ draft = JSON.parse(readFileSync94(opts.draft, "utf-8"));
102762
103002
  } catch (e) {
102763
103003
  fail6(`failed to read/parse --draft: ${e.message}`);
102764
103004
  }
@@ -102795,7 +103035,7 @@ function registerSelfImproveProposeSkillCommand(program3) {
102795
103035
  init_esm();
102796
103036
  init_helpers();
102797
103037
  var import_yaml25 = __toESM(require_dist(), 1);
102798
- import { existsSync as existsSync104, readdirSync as readdirSync39, readFileSync as readFileSync94, statSync as statSync56 } from "node:fs";
103038
+ import { existsSync as existsSync105, readdirSync as readdirSync39, readFileSync as readFileSync95, statSync as statSync56 } from "node:fs";
102799
103039
  import { homedir as homedir57 } from "node:os";
102800
103040
  import { join as join107, resolve as resolve60 } from "node:path";
102801
103041
  var PERSONAL_PREFIX2 = "personal-";
@@ -102812,11 +103052,11 @@ function defaultBundledRoot2() {
102812
103052
  }
102813
103053
  function readSkillFrontmatter(skillDir) {
102814
103054
  const mdPath = join107(skillDir, "SKILL.md");
102815
- if (!existsSync104(mdPath))
103055
+ if (!existsSync105(mdPath))
102816
103056
  return null;
102817
103057
  let content;
102818
103058
  try {
102819
- content = readFileSync94(mdPath, "utf-8");
103059
+ content = readFileSync95(mdPath, "utf-8");
102820
103060
  } catch {
102821
103061
  return null;
102822
103062
  }
@@ -102856,7 +103096,7 @@ function listPersonalSkills(agent, agentsRoot = defaultAgentsRoot()) {
102856
103096
  if (!AGENT_NAME_RE3.test(agent))
102857
103097
  return [];
102858
103098
  const skillsDir = join107(agentsRoot, agent, ".claude/skills");
102859
- if (!existsSync104(skillsDir))
103099
+ if (!existsSync105(skillsDir))
102860
103100
  return [];
102861
103101
  const out = [];
102862
103102
  let entries;
@@ -102894,7 +103134,7 @@ function listPersonalSkills(agent, agentsRoot = defaultAgentsRoot()) {
102894
103134
  return out;
102895
103135
  }
102896
103136
  function listSharedSkills(sharedRoot = defaultSharedRoot2()) {
102897
- if (!existsSync104(sharedRoot))
103137
+ if (!existsSync105(sharedRoot))
102898
103138
  return [];
102899
103139
  const out = [];
102900
103140
  let entries;
@@ -102932,7 +103172,7 @@ function listSharedSkills(sharedRoot = defaultSharedRoot2()) {
102932
103172
  return out;
102933
103173
  }
102934
103174
  function listBundledSkills(bundledRoot = defaultBundledRoot2()) {
102935
- if (!existsSync104(bundledRoot))
103175
+ if (!existsSync105(bundledRoot))
102936
103176
  return [];
102937
103177
  const out = [];
102938
103178
  let entries;
@@ -103090,10 +103330,10 @@ init_source();
103090
103330
  init_helpers();
103091
103331
  init_operator_uid();
103092
103332
  import {
103093
- existsSync as existsSync106,
103094
- mkdirSync as mkdirSync61,
103333
+ existsSync as existsSync107,
103334
+ mkdirSync as mkdirSync62,
103095
103335
  readdirSync as readdirSync40,
103096
- writeFileSync as writeFileSync44,
103336
+ writeFileSync as writeFileSync45,
103097
103337
  statSync as statSync57,
103098
103338
  lstatSync as lstatSync14,
103099
103339
  realpathSync as realpathSync8,
@@ -103101,13 +103341,13 @@ import {
103101
103341
  } from "node:fs";
103102
103342
  import { homedir as homedir58 } from "node:os";
103103
103343
  import { join as join108 } from "node:path";
103104
- import { spawnSync as spawnSync24 } from "node:child_process";
103344
+ import { spawnSync as spawnSync25 } from "node:child_process";
103105
103345
 
103106
103346
  // src/cli/singleton-stale-cleanup.ts
103107
- import { spawnSync as spawnSync23 } from "node:child_process";
103347
+ import { spawnSync as spawnSync24 } from "node:child_process";
103108
103348
  function makeDockerRunner() {
103109
103349
  return (args) => {
103110
- const r = spawnSync23("docker", args, { encoding: "utf8" });
103350
+ const r = spawnSync24("docker", args, { encoding: "utf8" });
103111
103351
  return {
103112
103352
  ok: r.status === 0,
103113
103353
  stdout: r.stdout ?? "",
@@ -103466,7 +103706,7 @@ function resolveHostdSkillsTarget(hostHome) {
103466
103706
  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.`);
103467
103707
  return;
103468
103708
  }
103469
- if (!existsSync106(target)) {
103709
+ if (!existsSync107(target)) {
103470
103710
  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.`);
103471
103711
  return;
103472
103712
  }
@@ -103480,7 +103720,7 @@ function hostdComposePath() {
103480
103720
  }
103481
103721
  function backupExistingCompose() {
103482
103722
  const p = hostdComposePath();
103483
- if (!existsSync106(p))
103723
+ if (!existsSync107(p))
103484
103724
  return null;
103485
103725
  const ts = new Date().toISOString().replace(/[:.]/g, "-");
103486
103726
  const bak = `${p}.bak-${ts}`;
@@ -103488,7 +103728,7 @@ function backupExistingCompose() {
103488
103728
  return bak;
103489
103729
  }
103490
103730
  function runDocker(args) {
103491
- const r = spawnSync24("docker", args, { encoding: "utf8" });
103731
+ const r = spawnSync25("docker", args, { encoding: "utf8" });
103492
103732
  return {
103493
103733
  ok: r.status === 0,
103494
103734
  stdout: r.stdout ?? "",
@@ -103513,7 +103753,7 @@ async function doInstall(opts, program3) {
103513
103753
  }
103514
103754
  const dir = hostdDir();
103515
103755
  const composePath = hostdComposePath();
103516
- mkdirSync61(dir, { recursive: true });
103756
+ mkdirSync62(dir, { recursive: true });
103517
103757
  const imageTag = resolveHostdImageTag(opts.tag, cfg.release);
103518
103758
  const guard = checkDowngrade({
103519
103759
  container: "switchroom-hostd",
@@ -103546,7 +103786,7 @@ async function doInstall(opts, program3) {
103546
103786
  const bak = backupExistingCompose();
103547
103787
  if (bak)
103548
103788
  console.log(source_default.dim(` Backed up existing compose to ${bak}`));
103549
- writeFileSync44(composePath, yaml, "utf8");
103789
+ writeFileSync45(composePath, yaml, "utf8");
103550
103790
  console.log(source_default.green(` \u2713 Wrote ${composePath}`));
103551
103791
  const adminAgents = Object.entries(cfg.agents ?? {}).filter(([, a]) => a?.admin === true).map(([name]) => name);
103552
103792
  console.log(source_default.dim(` agents served (one socket each): ${allAgents.length === 0 ? "(none)" : allAgents.join(", ")}`));
@@ -103578,7 +103818,7 @@ function doStatus() {
103578
103818
  const composeYml = hostdComposePath();
103579
103819
  console.log(source_default.bold("switchroom-hostd"));
103580
103820
  console.log("");
103581
- if (!existsSync106(composeYml)) {
103821
+ if (!existsSync107(composeYml)) {
103582
103822
  console.log(source_default.yellow(" compose: not installed"));
103583
103823
  console.log(source_default.dim(" run `switchroom hostd install` to set up."));
103584
103824
  return;
@@ -103599,14 +103839,14 @@ function doStatus() {
103599
103839
  } else {
103600
103840
  console.log(source_default.green(` container: ${ps.stdout.trim()}`));
103601
103841
  }
103602
- if (existsSync106(dir)) {
103842
+ if (existsSync107(dir)) {
103603
103843
  const entries = [];
103604
103844
  try {
103605
103845
  for (const name of readdirSync40(dir)) {
103606
103846
  if (name === "docker-compose.yml" || name.startsWith("docker-compose.yml."))
103607
103847
  continue;
103608
103848
  const sockPath = join108(dir, name, "sock");
103609
- if (existsSync106(sockPath)) {
103849
+ if (existsSync107(sockPath)) {
103610
103850
  const st = statSync57(sockPath);
103611
103851
  if ((st.mode & 61440) === 49152) {
103612
103852
  entries.push(`${name} \u2192 ${sockPath}`);
@@ -103625,7 +103865,7 @@ function doStatus() {
103625
103865
  }
103626
103866
  function doUninstall() {
103627
103867
  const composeYml = hostdComposePath();
103628
- if (!existsSync106(composeYml)) {
103868
+ if (!existsSync107(composeYml)) {
103629
103869
  console.log(source_default.yellow(" No hostd install detected (no compose file at this path)."));
103630
103870
  return;
103631
103871
  }
@@ -103649,7 +103889,7 @@ function registerHostdCommand(program3) {
103649
103889
  hostd.command("uninstall").description("Stop the hostd container. Leaves the compose file in place for re-install.").action(() => doUninstall());
103650
103890
  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) => {
103651
103891
  const logPath = opts.path ?? defaultAuditLogPath2();
103652
- if (!existsSync106(logPath)) {
103892
+ if (!existsSync107(logPath)) {
103653
103893
  console.error(source_default.yellow(`Audit log not found at ${logPath}.`) + source_default.gray(`
103654
103894
  The log is created when hostd handles its first privileged-verb request.`));
103655
103895
  return;
@@ -103698,10 +103938,10 @@ init_source();
103698
103938
  init_helpers();
103699
103939
  init_operator_uid();
103700
103940
  init_compose();
103701
- import { chownSync as chownSync10, existsSync as existsSync107, mkdirSync as mkdirSync62, writeFileSync as writeFileSync45, copyFileSync as copyFileSync15 } from "node:fs";
103941
+ import { chownSync as chownSync10, existsSync as existsSync108, mkdirSync as mkdirSync63, writeFileSync as writeFileSync46, copyFileSync as copyFileSync15 } from "node:fs";
103702
103942
  import { homedir as homedir59 } from "node:os";
103703
103943
  import { join as join109 } from "node:path";
103704
- import { spawnSync as spawnSync25 } from "node:child_process";
103944
+ import { spawnSync as spawnSync26 } from "node:child_process";
103705
103945
  function resolveWebImageTag(explicitTag, release) {
103706
103946
  if (explicitTag)
103707
103947
  return explicitTag;
@@ -103809,7 +104049,7 @@ function webdComposePath() {
103809
104049
  }
103810
104050
  function backupExistingCompose2() {
103811
104051
  const p = webdComposePath();
103812
- if (!existsSync107(p))
104052
+ if (!existsSync108(p))
103813
104053
  return null;
103814
104054
  const ts = new Date().toISOString().replace(/[:.]/g, "-");
103815
104055
  const bak = `${p}.bak-${ts}`;
@@ -103817,7 +104057,7 @@ function backupExistingCompose2() {
103817
104057
  return bak;
103818
104058
  }
103819
104059
  function runDocker2(args) {
103820
- const r = spawnSync25("docker", args, { encoding: "utf8" });
104060
+ const r = spawnSync26("docker", args, { encoding: "utf8" });
103821
104061
  return {
103822
104062
  ok: r.status === 0,
103823
104063
  stdout: r.stdout ?? "",
@@ -103840,7 +104080,7 @@ async function doInstall2(opts, program3) {
103840
104080
  }
103841
104081
  const dir = webdDir();
103842
104082
  const composePath = webdComposePath();
103843
- mkdirSync62(dir, { recursive: true });
104083
+ mkdirSync63(dir, { recursive: true });
103844
104084
  const cfg = getConfig(program3);
103845
104085
  const imageTag = resolveWebImageTag(opts.tag, cfg.release);
103846
104086
  const port = cfg.web_service?.port ?? 8080;
@@ -103875,7 +104115,7 @@ async function doInstall2(opts, program3) {
103875
104115
  const bak = backupExistingCompose2();
103876
104116
  if (bak)
103877
104117
  console.log(source_default.dim(` Backed up existing compose to ${bak}`));
103878
- writeFileSync45(composePath, yaml, "utf8");
104118
+ writeFileSync46(composePath, yaml, "utf8");
103879
104119
  try {
103880
104120
  if (typeof process.geteuid === "function" && process.geteuid() === 0) {
103881
104121
  chownSync10(dir, operatorUid, operatorUid);
@@ -103917,7 +104157,7 @@ function doStatus2() {
103917
104157
  const composeYml = webdComposePath();
103918
104158
  console.log(source_default.bold("switchroom-web"));
103919
104159
  console.log("");
103920
- if (!existsSync107(composeYml)) {
104160
+ if (!existsSync108(composeYml)) {
103921
104161
  console.log(source_default.yellow(" compose: not installed"));
103922
104162
  console.log(source_default.dim(" run `switchroom webd install` to set up."));
103923
104163
  return;
@@ -103941,7 +104181,7 @@ function doStatus2() {
103941
104181
  }
103942
104182
  function doUninstall2() {
103943
104183
  const composeYml = webdComposePath();
103944
- if (!existsSync107(composeYml)) {
104184
+ if (!existsSync108(composeYml)) {
103945
104185
  console.log(source_default.yellow(" No web-service install detected (no compose file at this path)."));
103946
104186
  return;
103947
104187
  }
@@ -104216,13 +104456,13 @@ init_helpers();
104216
104456
  init_scan();
104217
104457
 
104218
104458
  // src/fleet-health/gh-sync.ts
104219
- import { spawnSync as spawnSync26 } from "node:child_process";
104459
+ import { spawnSync as spawnSync27 } from "node:child_process";
104220
104460
  var LABEL = "fleet-health";
104221
104461
  function defaultGhDeps(log) {
104222
104462
  return {
104223
104463
  log,
104224
104464
  run: (args) => {
104225
- const r = spawnSync26("gh", args, { encoding: "utf-8" });
104465
+ const r = spawnSync27("gh", args, { encoding: "utf-8" });
104226
104466
  return {
104227
104467
  ok: r.status === 0,
104228
104468
  stdout: (r.stdout ?? "").trim(),
@@ -104427,7 +104667,7 @@ function printDeepDiveBrief(targets) {
104427
104667
 
104428
104668
  // src/cli/hindsight-watch.ts
104429
104669
  init_source();
104430
- import { existsSync as existsSync112, readdirSync as readdirSync45 } from "node:fs";
104670
+ import { existsSync as existsSync113, readdirSync as readdirSync45 } from "node:fs";
104431
104671
  import { homedir as homedir63 } from "node:os";
104432
104672
  import { join as join112, resolve as resolve63 } from "node:path";
104433
104673
 
@@ -104497,8 +104737,8 @@ function postOperatorNoticeViaGateways(candidates, text, log, connectTimeoutMs =
104497
104737
  init_install_cron();
104498
104738
 
104499
104739
  // src/hindsight-watch/probe.ts
104500
- import { spawnSync as spawnSync27 } from "node:child_process";
104501
- import { readFileSync as readFileSync99, readdirSync as readdirSync44, statSync as statSync59 } from "node:fs";
104740
+ import { spawnSync as spawnSync28 } from "node:child_process";
104741
+ import { readFileSync as readFileSync100, readdirSync as readdirSync44, statSync as statSync59 } from "node:fs";
104502
104742
  import { homedir as homedir62 } from "node:os";
104503
104743
  import { resolve as resolve62 } from "node:path";
104504
104744
 
@@ -104626,7 +104866,7 @@ function readLlmSignals(series) {
104626
104866
  }
104627
104867
 
104628
104868
  // src/hindsight-watch/recall-log.ts
104629
- import { closeSync as closeSync22, existsSync as existsSync111, openSync as openSync22, readdirSync as readdirSync43, readSync as readSync6, statSync as statSync58 } from "node:fs";
104869
+ import { closeSync as closeSync22, existsSync as existsSync112, openSync as openSync22, readdirSync as readdirSync43, readSync as readSync6, statSync as statSync58 } from "node:fs";
104630
104870
  import { join as join111 } from "node:path";
104631
104871
  var RECALL_WINDOW_ROWS = 200;
104632
104872
  var RECALL_MAX_TAIL_BYTES = 1024 * 1024;
@@ -104635,7 +104875,7 @@ function recallLogPath2(agentDir) {
104635
104875
  return join111(agentDir, ".claude", "plugins", "data", "hindsight-memory-inline", "state", "recall_log.jsonl");
104636
104876
  }
104637
104877
  function readRecallLogTail2(path10, windowRows = RECALL_WINDOW_ROWS) {
104638
- if (!existsSync111(path10))
104878
+ if (!existsSync112(path10))
104639
104879
  return [];
104640
104880
  let text;
104641
104881
  let truncatedHead = false;
@@ -104847,7 +105087,7 @@ async function probeMetrics(url = DEFAULT_METRICS_URL, fetchImpl = fetch) {
104847
105087
  }
104848
105088
  }
104849
105089
  var defaultRunner4 = (cmd, args) => {
104850
- const r = spawnSync27(cmd, args, { stdio: "pipe", timeout: 1e4, encoding: "utf8" });
105090
+ const r = spawnSync28(cmd, args, { stdio: "pipe", timeout: 1e4, encoding: "utf8" });
104851
105091
  if (r.error)
104852
105092
  return { status: null, stdout: "", stderr: r.error.message };
104853
105093
  return { status: r.status, stdout: r.stdout ?? "", stderr: r.stderr ?? "" };
@@ -104875,7 +105115,7 @@ function readDropCount(hindsightDir) {
104875
105115
  try {
104876
105116
  if (statSync59(path10).size > DROPS_LEDGER_MAX_BYTES)
104877
105117
  return 0;
104878
- parsed = JSON.parse(readFileSync99(path10, "utf8"));
105118
+ parsed = JSON.parse(readFileSync100(path10, "utf8"));
104879
105119
  } catch {
104880
105120
  return 0;
104881
105121
  }
@@ -105923,7 +106163,7 @@ function collectRelayCandidates(agentsDir) {
105923
106163
  const candidates = [];
105924
106164
  for (const name of readdirSync45(agentsDir).sort()) {
105925
106165
  const sock = resolve63(agentsDir, name, "telegram", "gateway.sock");
105926
- if (existsSync112(sock))
106166
+ if (existsSync113(sock))
105927
106167
  candidates.push({ agent: name, sock });
105928
106168
  }
105929
106169
  return orderRelayCandidates(candidates);
@@ -105945,13 +106185,13 @@ async function notifyOperator(agentsDir, text, log) {
105945
106185
 
105946
106186
  // src/cli/openrouter-watch.ts
105947
106187
  init_source();
105948
- import { existsSync as existsSync114, readdirSync as readdirSync46 } from "node:fs";
106188
+ import { existsSync as existsSync115, readdirSync as readdirSync46 } from "node:fs";
105949
106189
  import { homedir as homedir65 } from "node:os";
105950
106190
  import { join as join113, resolve as resolve65 } from "node:path";
105951
106191
 
105952
106192
  // src/openrouter/install-cron.ts
105953
- import { existsSync as existsSync113, mkdirSync as mkdirSync64, readFileSync as readFileSync100, renameSync as renameSync29, writeFileSync as writeFileSync47 } from "node:fs";
105954
- import { dirname as dirname43 } from "node:path";
106193
+ import { existsSync as existsSync114, mkdirSync as mkdirSync65, readFileSync as readFileSync101, renameSync as renameSync30, writeFileSync as writeFileSync48 } from "node:fs";
106194
+ import { dirname as dirname44 } from "node:path";
105955
106195
  var CRON_PATH2 = "/etc/cron.d/openrouter-watch";
105956
106196
  var CRON_SCHEDULE2 = "17 * * * *";
105957
106197
  var CRON_LOG_PATH2 = "/var/log/openrouter-watch.log";
@@ -105968,30 +106208,30 @@ function renderCron2(opts) {
105968
106208
  function installCron2(opts) {
105969
106209
  const path10 = opts.path ?? CRON_PATH2;
105970
106210
  const content = renderCron2(opts);
105971
- if (existsSync113(path10)) {
106211
+ if (existsSync114(path10)) {
105972
106212
  try {
105973
- if (readFileSync100(path10, "utf8") === content) {
106213
+ if (readFileSync101(path10, "utf8") === content) {
105974
106214
  return { status: "unchanged", path: path10, content };
105975
106215
  }
105976
106216
  } catch {}
105977
106217
  }
105978
- mkdirSync64(dirname43(path10), { recursive: true });
106218
+ mkdirSync65(dirname44(path10), { recursive: true });
105979
106219
  const tmp = `${path10}.${process.pid}.tmp`;
105980
- writeFileSync47(tmp, content, { mode: 420 });
105981
- renameSync29(tmp, path10);
106220
+ writeFileSync48(tmp, content, { mode: 420 });
106221
+ renameSync30(tmp, path10);
105982
106222
  return { status: "installed", path: path10, content };
105983
106223
  }
105984
106224
  // src/openrouter/state.ts
105985
- import { mkdirSync as mkdirSync65, readFileSync as readFileSync101, renameSync as renameSync30, writeFileSync as writeFileSync48 } from "node:fs";
106225
+ import { mkdirSync as mkdirSync66, readFileSync as readFileSync102, renameSync as renameSync31, writeFileSync as writeFileSync49 } from "node:fs";
105986
106226
  import { homedir as homedir64 } from "node:os";
105987
- import { dirname as dirname44, resolve as resolve64 } from "node:path";
106227
+ import { dirname as dirname45, resolve as resolve64 } from "node:path";
105988
106228
  function defaultStatePath3(home2 = process.env.SWITCHROOM_HOME ?? process.env.HOME ?? homedir64()) {
105989
106229
  return resolve64(home2, ".switchroom", "openrouter-watch", "state.json");
105990
106230
  }
105991
106231
  function loadState2(path10) {
105992
106232
  let parsed;
105993
106233
  try {
105994
- parsed = JSON.parse(readFileSync101(path10, "utf8"));
106234
+ parsed = JSON.parse(readFileSync102(path10, "utf8"));
105995
106235
  } catch {
105996
106236
  return {};
105997
106237
  }
@@ -106011,12 +106251,12 @@ function loadState2(path10) {
106011
106251
  return out;
106012
106252
  }
106013
106253
  function saveState2(path10, state) {
106014
- mkdirSync65(dirname44(path10), { recursive: true, mode: 448 });
106254
+ mkdirSync66(dirname45(path10), { recursive: true, mode: 448 });
106015
106255
  const tmp = `${path10}.${process.pid}.tmp`;
106016
106256
  const payload = { v: 1, ...state };
106017
- writeFileSync48(tmp, JSON.stringify(payload, null, 2) + `
106257
+ writeFileSync49(tmp, JSON.stringify(payload, null, 2) + `
106018
106258
  `, { mode: 384 });
106019
- renameSync30(tmp, path10);
106259
+ renameSync31(tmp, path10);
106020
106260
  }
106021
106261
 
106022
106262
  // src/openrouter/watch.ts
@@ -106201,7 +106441,7 @@ async function notifyOperator2(agentsDir, text, log) {
106201
106441
  try {
106202
106442
  for (const name of readdirSync46(agentsDir).sort()) {
106203
106443
  const sock = resolve65(agentsDir, name, "telegram", "gateway.sock");
106204
- if (existsSync114(sock))
106444
+ if (existsSync115(sock))
106205
106445
  candidates.push({ agent: name, sock });
106206
106446
  }
106207
106447
  } catch (e) {