switchroom 0.19.37 → 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.37", COMMIT_SHA = "5d2f9a17";
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
 
@@ -45994,13 +46026,15 @@ var init_install_cron = () => {};
45994
46026
  function inParts(memories) {
45995
46027
  return Math.round(memories * PARTS_PER_MEMORY);
45996
46028
  }
45997
- var RING_MAX = 8, MAX_SAMPLE_AGE_MS, MIN_RETAIN_SAMPLES = 20, RETAIN_FAILURE_RATE = 0.1, PARTS_PER_MEMORY = 6, QUEUE_FLOOR_MEMORIES = 100, QUEUE_FLOOR, QUEUE_GROWTH_FRACTION = 0.1, QUEUE_GROWTH_MIN_ABS_MEMORIES = 20, QUEUE_GROWTH_MIN_ABS, BREACHES_TO_FIRE_LEVEL = 2, BREACHES_TO_FIRE_EDGE = 1, CLEARS_TO_RESOLVE = 2, RENOTIFY_MS, DEFAULT_METRICS_URL = "http://127.0.0.1:18888/metrics", DEFAULT_CONTAINER = "switchroom-hindsight", METRICS_MAX_BYTES, METRICS_TIMEOUT_MS = 1e4, RECALL_OWN_BANK_TIMEOUT_WARN = 0.05, RECALL_OWN_BANK_TIMEOUT_PAGE = 0.15, RECALL_ZERO_MEMORY_WARN = 0.25, RECALL_ZERO_MEMORY_PAGE = 0.4, RECALL_POOL_MEDIAN_WARN = 8, RECALL_POOL_MEDIAN_PAGE = 3, RECALL_SCORE_P50_WARN = 0.02, RECALL_SCORE_P50_PAGE = 0.01, CONSOLIDATION_AGE_WARN_S, CONSOLIDATION_AGE_PAGE_S, CONSOLIDATION_FAILURE_STREAK_WARN = 3, CONSOLIDATION_FAILURE_STREAK_PAGE = 10, CONSOLIDATION_STREAK_RECENCY_S, PENDING_CONSOLIDATION_FLOOR = 500, PENDING_CONSOLIDATION_GROWTH_FRACTION = 0.5, PENDING_CONSOLIDATION_GROWTH_WARN_ABS = 500, PENDING_CONSOLIDATION_GROWTH_PAGE_ABS = 5000, VECTOR_INDEX_SAMPLE_ROWS = 3, RECALL_MIN_SAMPLES = 30, LLM_FAILURE_RATE_WARN = 0.02, LLM_FAILURE_RATE_PAGE = 0.1, LLM_MIN_SAMPLES = 20;
46029
+ var RING_MAX = 8, MAX_SAMPLE_AGE_MS, MIN_RETAIN_SAMPLES = 20, RETAIN_FAILURE_RATE = 0.1, PARTS_PER_MEMORY = 6, QUEUE_FLOOR_MEMORIES = 100, QUEUE_FLOOR, QUEUE_GROWTH_FRACTION = 0.1, QUEUE_GROWTH_MIN_ABS_MEMORIES = 20, QUEUE_GROWTH_MIN_ABS, BREACHES_TO_FIRE_LEVEL = 2, BREACHES_TO_FIRE_EDGE = 1, CLEARS_TO_RESOLVE = 2, RENOTIFY_MS, DEFAULT_METRICS_URL = "http://127.0.0.1:18888/metrics", DEFAULT_CONTAINER = "switchroom-hindsight", METRICS_MAX_BYTES, METRICS_TIMEOUT_MS = 1e4, RECALL_OWN_BANK_TIMEOUT_WARN = 0.05, RECALL_OWN_BANK_TIMEOUT_PAGE = 0.15, RECALL_ZERO_MEMORY_WARN = 0.25, RECALL_ZERO_MEMORY_PAGE = 0.4, RECALL_POOL_MEDIAN_WARN = 8, RECALL_POOL_MEDIAN_PAGE = 3, RECALL_SCORE_P50_WARN = 0.02, RECALL_SCORE_P50_PAGE = 0.01, RECALL_WALL_MS, CONSOLIDATION_AGE_WARN_S, CONSOLIDATION_AGE_PAGE_S, CONSOLIDATION_FAILURE_STREAK_WARN = 3, CONSOLIDATION_FAILURE_STREAK_PAGE = 10, CONSOLIDATION_STREAK_RECENCY_S, PENDING_CONSOLIDATION_FLOOR = 500, PENDING_CONSOLIDATION_GROWTH_FRACTION = 0.5, PENDING_CONSOLIDATION_GROWTH_WARN_ABS = 500, PENDING_CONSOLIDATION_GROWTH_PAGE_ABS = 5000, VECTOR_INDEX_SAMPLE_ROWS = 3, RECALL_MIN_SAMPLES = 30, LLM_FAILURE_RATE_WARN = 0.02, LLM_FAILURE_RATE_PAGE = 0.1, LLM_MIN_SAMPLES = 20;
45998
46030
  var init_thresholds = __esm(() => {
46031
+ init_hindsight_recall_tunables();
45999
46032
  MAX_SAMPLE_AGE_MS = 3 * 60 * 60000;
46000
46033
  QUEUE_FLOOR = inParts(QUEUE_FLOOR_MEMORIES);
46001
46034
  QUEUE_GROWTH_MIN_ABS = inParts(QUEUE_GROWTH_MIN_ABS_MEMORIES);
46002
46035
  RENOTIFY_MS = 6 * 60 * 60 * 1000;
46003
46036
  METRICS_MAX_BYTES = 16 * 1024 * 1024;
46037
+ RECALL_WALL_MS = resolveHindsightRecallTunables(undefined).parallelDeadlineSeconds * 1000;
46004
46038
  CONSOLIDATION_AGE_WARN_S = 2 * 60 * 60;
46005
46039
  CONSOLIDATION_AGE_PAGE_S = 12 * 60 * 60;
46006
46040
  CONSOLIDATION_STREAK_RECENCY_S = 2 * 60 * 60;
@@ -51687,6 +51721,9 @@ import { spawnSync as spawnSync12 } from "node:child_process";
51687
51721
  function fixFor(c, target) {
51688
51722
  return remediationFor(classifyComponent(c), target);
51689
51723
  }
51724
+ function hostCliBehindStatus(c) {
51725
+ return c.kind === "cli" ? "fail" : "warn";
51726
+ }
51690
51727
  function runComponentVersionChecks(config, opts = {}) {
51691
51728
  const exec = opts.exec ?? defaultExec2;
51692
51729
  const components = collectComponents(opts.cliVersion ?? SWITCHROOM_VERSION, exec);
@@ -51710,10 +51747,11 @@ function runComponentVersionChecks(config, opts = {}) {
51710
51747
  });
51711
51748
  }
51712
51749
  for (const c of report.behind) {
51750
+ const status = hostCliBehindStatus(c);
51713
51751
  results.push({
51714
51752
  name: `component behind: ${c.name}`,
51715
- status: "warn",
51716
- 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})`,
51717
51755
  fix: fixFor(c, report.target)
51718
51756
  });
51719
51757
  }
@@ -68978,9 +69016,9 @@ __export(exports_server, {
68978
69016
  dispatchTool: () => dispatchTool,
68979
69017
  TOOLS: () => TOOLS
68980
69018
  });
68981
- import { spawnSync as spawnSync22 } from "node:child_process";
69019
+ import { spawnSync as spawnSync23 } from "node:child_process";
68982
69020
  function execCli(args, stdin) {
68983
- const r = spawnSync22(CLI_BIN, args, {
69021
+ const r = spawnSync23(CLI_BIN, args, {
68984
69022
  encoding: "utf-8",
68985
69023
  env: process.env,
68986
69024
  timeout: 15000,
@@ -69489,7 +69527,7 @@ __export(exports_server2, {
69489
69527
  TOOLS: () => TOOLS2
69490
69528
  });
69491
69529
  import { randomBytes as randomBytes16 } from "node:crypto";
69492
- import { existsSync as existsSync105 } from "node:fs";
69530
+ import { existsSync as existsSync106 } from "node:fs";
69493
69531
  function selfSocketPath() {
69494
69532
  return `/run/switchroom/hostd/${SELF_AGENT}/sock`;
69495
69533
  }
@@ -69516,7 +69554,7 @@ async function dispatchTool2(name, args) {
69516
69554
  return errorText2("hostd MCP: SWITCHROOM_AGENT_NAME env var is not set \u2014 cannot " + "determine which per-agent socket to talk to.");
69517
69555
  }
69518
69556
  const sockPath = selfSocketPath();
69519
- if (!existsSync105(sockPath)) {
69557
+ if (!existsSync106(sockPath)) {
69520
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.`);
69521
69559
  }
69522
69560
  let req;
@@ -69767,13 +69805,13 @@ function resolveAuditLogPath() {
69767
69805
  if (process.env.HOSTD_AUDIT_LOG_PATH)
69768
69806
  return process.env.HOSTD_AUDIT_LOG_PATH;
69769
69807
  const bindMounted = "/host-home/.switchroom/host-control-audit.log";
69770
- if (existsSync105(bindMounted))
69808
+ if (existsSync106(bindMounted))
69771
69809
  return bindMounted;
69772
69810
  return defaultAuditLogPath2();
69773
69811
  }
69774
69812
  function getLastUpdateApplyStatus() {
69775
69813
  const path10 = resolveAuditLogPath();
69776
- if (!existsSync105(path10)) {
69814
+ if (!existsSync106(path10)) {
69777
69815
  return errorText2(`get_status: audit log not found at ${path10}. No update_apply has run yet?`);
69778
69816
  }
69779
69817
  let raw;
@@ -70492,11 +70530,11 @@ var init_test_agents = __esm(() => {
70492
70530
  });
70493
70531
 
70494
70532
  // src/litellm/header-passthrough-guard.ts
70495
- import { existsSync as existsSync108, readdirSync as readdirSync41 } from "node:fs";
70533
+ import { existsSync as existsSync109, readdirSync as readdirSync41 } from "node:fs";
70496
70534
  function discoverLiveLitellmConfigPath(opts) {
70497
70535
  const servicesDir = opts?.servicesDir ?? COOLIFY_SERVICES_DIR;
70498
70536
  const readdir2 = opts?.readdirFn ?? ((p) => readdirSync41(p));
70499
- const exists = opts?.existsFn ?? existsSync108;
70537
+ const exists = opts?.existsFn ?? existsSync109;
70500
70538
  let entries;
70501
70539
  try {
70502
70540
  entries = readdir2(servicesDir);
@@ -70586,7 +70624,7 @@ var init_header_passthrough_guard = __esm(() => {
70586
70624
  });
70587
70625
 
70588
70626
  // src/fleet-health/litellm-config-sensor.ts
70589
- import { readFileSync as readFileSync97, existsSync as existsSync109 } from "node:fs";
70627
+ import { readFileSync as readFileSync98, existsSync as existsSync110 } from "node:fs";
70590
70628
  function resolveLitellmConfigPath(explicit, discoverFn = () => discoverLiveLitellmConfigPath()) {
70591
70629
  if (explicit)
70592
70630
  return explicit;
@@ -70597,8 +70635,8 @@ function resolveLitellmConfigPath(explicit, discoverFn = () => discoverLiveLitel
70597
70635
  }
70598
70636
  function scanLitellmConfig(opts = {}) {
70599
70637
  const path10 = resolveLitellmConfigPath(opts.path, opts.discoverFn);
70600
- const exists = opts.existsFn ?? existsSync109;
70601
- 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"));
70602
70640
  const log = opts.log ?? (() => {});
70603
70641
  const nowIso = opts.nowIso ?? new Date().toISOString();
70604
70642
  if (path10 === null) {
@@ -70673,20 +70711,20 @@ __export(exports_scan, {
70673
70711
  ledgerPathForBase: () => ledgerPathForBase
70674
70712
  });
70675
70713
  import {
70676
- readFileSync as readFileSync98,
70714
+ readFileSync as readFileSync99,
70677
70715
  readdirSync as readdirSync42,
70678
- existsSync as existsSync110,
70679
- mkdirSync as mkdirSync63,
70680
- writeFileSync as writeFileSync46
70716
+ existsSync as existsSync111,
70717
+ mkdirSync as mkdirSync64,
70718
+ writeFileSync as writeFileSync47
70681
70719
  } from "node:fs";
70682
- import { resolve as resolve61, dirname as dirname42 } from "node:path";
70720
+ import { resolve as resolve61, dirname as dirname43 } from "node:path";
70683
70721
  import { homedir as homedir61 } from "node:os";
70684
70722
  function resolveSwitchroomBase(home2 = process.env.SWITCHROOM_HOME ?? process.env.HOME ?? homedir61()) {
70685
70723
  return resolve61(home2, ".switchroom");
70686
70724
  }
70687
70725
  function listAgents(base) {
70688
70726
  const dir = resolve61(base, "agents");
70689
- if (!existsSync110(dir))
70727
+ if (!existsSync111(dir))
70690
70728
  return [];
70691
70729
  try {
70692
70730
  return readdirSync42(dir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name).sort();
@@ -70715,16 +70753,16 @@ function runScan(opts = {}) {
70715
70753
  let gwText = "";
70716
70754
  let sawArtifact = false;
70717
70755
  try {
70718
- if (existsSync110(turnsPath)) {
70719
- turnsText = readFileSync98(turnsPath, "utf-8");
70756
+ if (existsSync111(turnsPath)) {
70757
+ turnsText = readFileSync99(turnsPath, "utf-8");
70720
70758
  sawArtifact = true;
70721
70759
  }
70722
70760
  } catch (e) {
70723
70761
  log(`fleet-health: WARN skipping ${agent} turns.jsonl unreadable: ${String(e)}`);
70724
70762
  }
70725
70763
  try {
70726
- if (existsSync110(gwPath)) {
70727
- gwText = readFileSync98(gwPath, "utf-8");
70764
+ if (existsSync111(gwPath)) {
70765
+ gwText = readFileSync99(gwPath, "utf-8");
70728
70766
  sawArtifact = true;
70729
70767
  }
70730
70768
  } catch (e) {
@@ -70766,20 +70804,20 @@ function runScan(opts = {}) {
70766
70804
  function readLedgerIfPresent(base) {
70767
70805
  const path10 = ledgerPathForBase(base);
70768
70806
  try {
70769
- if (!existsSync110(path10))
70807
+ if (!existsSync111(path10))
70770
70808
  return null;
70771
- return JSON.parse(readFileSync98(path10, "utf-8"));
70809
+ return JSON.parse(readFileSync99(path10, "utf-8"));
70772
70810
  } catch {
70773
70811
  return null;
70774
70812
  }
70775
70813
  }
70776
70814
  function ledgerPathForBase(base) {
70777
- return fleetHealthLedgerPath(dirname42(base));
70815
+ return fleetHealthLedgerPath(dirname43(base));
70778
70816
  }
70779
70817
  function writeLedger(base, ledger) {
70780
70818
  const path10 = ledgerPathForBase(base);
70781
- mkdirSync63(dirname42(path10), { recursive: true });
70782
- writeFileSync46(path10, JSON.stringify(ledger, null, 2) + `
70819
+ mkdirSync64(dirname43(path10), { recursive: true });
70820
+ writeFileSync47(path10, JSON.stringify(ledger, null, 2) + `
70783
70821
  `, "utf-8");
70784
70822
  return path10;
70785
70823
  }
@@ -92106,9 +92144,9 @@ init_source();
92106
92144
  init_loader();
92107
92145
  init_lifecycle();
92108
92146
  init_compose_env();
92109
- import { existsSync as existsSync80, mkdirSync as mkdirSync45, readFileSync as readFileSync74, realpathSync as realpathSync6, statSync as statSync45, chownSync as chownSync8 } from "node:fs";
92110
- import { spawnSync as spawnSync16 } from "node:child_process";
92111
- 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";
92112
92150
  import { homedir as homedir44 } from "node:os";
92113
92151
 
92114
92152
  // src/cli/release-yaml.ts
@@ -92637,10 +92675,151 @@ function defaultSelfUpdateIO() {
92637
92675
  // src/cli/update.ts
92638
92676
  init_self_invoke();
92639
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
92640
92819
  function defaultPersistPin(configPath) {
92641
92820
  return (pin) => {
92642
92821
  const path7 = configPath ?? findConfigFile();
92643
- const before = readFileSync74(path7, "utf8");
92822
+ const before = readFileSync75(path7, "utf8");
92644
92823
  const after = setReleasePinInConfig(before, pin);
92645
92824
  if (after === before)
92646
92825
  return;
@@ -92656,16 +92835,16 @@ function defaultPersistPin(configPath) {
92656
92835
  }
92657
92836
  var DEFAULT_COMPOSE_PATH2 = join84(homedir44(), ".switchroom", "compose", "docker-compose.yml");
92658
92837
  function runningFromSwitchroomCheckout(scriptPath) {
92659
- let dir = dirname33(scriptPath);
92838
+ let dir = dirname34(scriptPath);
92660
92839
  for (let i = 0;i < 12; i++) {
92661
- if (existsSync80(join84(dir, ".git"))) {
92840
+ if (existsSync81(join84(dir, ".git"))) {
92662
92841
  try {
92663
- const pkg = JSON.parse(readFileSync74(join84(dir, "package.json"), "utf-8"));
92842
+ const pkg = JSON.parse(readFileSync75(join84(dir, "package.json"), "utf-8"));
92664
92843
  if (pkg.name === "switchroom")
92665
92844
  return true;
92666
92845
  } catch {}
92667
92846
  }
92668
- const parent = dirname33(dir);
92847
+ const parent = dirname34(dir);
92669
92848
  if (parent === dir)
92670
92849
  break;
92671
92850
  dir = parent;
@@ -92726,7 +92905,7 @@ function planUpdate(opts) {
92726
92905
  bundleDir: import.meta.dirname,
92727
92906
  execPath: process.execPath,
92728
92907
  scriptPath,
92729
- inContainer: process.env.SWITCHROOM_HOSTD_CONTEXT === "1" || existsSync80("/.dockerenv")
92908
+ inContainer: process.env.SWITCHROOM_HOSTD_CONTEXT === "1" || existsSync81("/.dockerenv")
92730
92909
  });
92731
92910
  if (detection.kind !== "static-binary") {
92732
92911
  say(source_default.gray(` host CLI not self-updated: ${detection.reason}
@@ -92799,7 +92978,7 @@ function planUpdate(opts) {
92799
92978
  steps.push({
92800
92979
  name: "pull-images",
92801
92980
  description: "Pull broker / kernel / agent images from GHCR",
92802
- 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,
92803
92982
  run: () => {
92804
92983
  const r = runner("docker", [
92805
92984
  "compose",
@@ -92844,6 +93023,69 @@ function planUpdate(opts) {
92844
93023
  throw new Error("switchroom apply failed");
92845
93024
  }
92846
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
+ });
92847
93089
  let hostControlEnabled;
92848
93090
  if (typeof opts.hostControlEnabled === "boolean") {
92849
93091
  hostControlEnabled = opts.hostControlEnabled;
@@ -92920,13 +93162,13 @@ function planUpdate(opts) {
92920
93162
  }
92921
93163
  const source = resolve45(import.meta.dirname, "../../skills");
92922
93164
  const dest = join84(homedir44(), ".switchroom", "skills", "_bundled");
92923
- if (!existsSync80(source)) {
93165
+ if (!existsSync81(source)) {
92924
93166
  process.stderr.write(`switchroom update: sync-bundled-skills \u2014 CLI bundle has no adjacent skills/ at ${source}; skipping.
92925
93167
  `);
92926
93168
  return;
92927
93169
  }
92928
93170
  try {
92929
- mkdirSync45(dirname33(dest), { recursive: true });
93171
+ mkdirSync46(dirname34(dest), { recursive: true });
92930
93172
  const r = syncBundledSkills({
92931
93173
  source,
92932
93174
  dest,
@@ -92952,10 +93194,10 @@ function planUpdate(opts) {
92952
93194
  if (opts.syncBundledSkillsFn)
92953
93195
  return;
92954
93196
  const dest = join84(homedir44(), ".switchroom", "skills", "_bundled");
92955
- if (!existsSync80(dest)) {
93197
+ if (!existsSync81(dest)) {
92956
93198
  return;
92957
93199
  }
92958
- 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)));
92959
93201
  if (missing.length > 0) {
92960
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.`);
92961
93203
  }
@@ -92990,7 +93232,7 @@ function planUpdate(opts) {
92990
93232
  description: "docker compose up -d --remove-orphans (recreates services with new images / compose)",
92991
93233
  run: () => {
92992
93234
  try {
92993
- const composeText = readFileSync74(composePath, "utf8");
93235
+ const composeText = readFileSync75(composePath, "utf8");
92994
93236
  const pf = validateBindSources(composeText);
92995
93237
  if (!pf.ok)
92996
93238
  throw new Error(formatPreflightError(pf));
@@ -93024,7 +93266,7 @@ function planUpdate(opts) {
93024
93266
  return steps;
93025
93267
  }
93026
93268
  function defaultRunner2(cmd, args) {
93027
- const r = spawnSync16(cmd, args, { stdio: "inherit" });
93269
+ const r = spawnSync17(cmd, args, { stdio: "inherit" });
93028
93270
  return { status: r.status ?? 1 };
93029
93271
  }
93030
93272
  function writeMarkerInPreferredLocation(agent, reason, runner) {
@@ -93067,12 +93309,12 @@ function defaultStatusProbe(composePath) {
93067
93309
  try {
93068
93310
  cliBuiltAt = new Date(statSync45(scriptPath).mtimeMs).toISOString();
93069
93311
  } catch {}
93070
- let dir = dirname33(scriptPath);
93312
+ let dir = dirname34(scriptPath);
93071
93313
  for (let i = 0;i < 8; i++) {
93072
93314
  const pkgPath = join84(dir, "package.json");
93073
- if (existsSync80(pkgPath)) {
93315
+ if (existsSync81(pkgPath)) {
93074
93316
  try {
93075
- const pkg = JSON.parse(readFileSync74(pkgPath, "utf-8"));
93317
+ const pkg = JSON.parse(readFileSync75(pkgPath, "utf-8"));
93076
93318
  if (typeof pkg.version === "string")
93077
93319
  cliVersion = pkg.version;
93078
93320
  } catch (err) {
@@ -93080,7 +93322,7 @@ function defaultStatusProbe(composePath) {
93080
93322
  }
93081
93323
  break;
93082
93324
  }
93083
- const parent = dirname33(dir);
93325
+ const parent = dirname34(dir);
93084
93326
  if (parent === dir)
93085
93327
  break;
93086
93328
  dir = parent;
@@ -93093,13 +93335,13 @@ function defaultStatusProbe(composePath) {
93093
93335
  warnings.push("could not resolve CLI version (no package.json found above the resolved script path)");
93094
93336
  }
93095
93337
  const services = [];
93096
- if (!existsSync80(composePath)) {
93338
+ if (!existsSync81(composePath)) {
93097
93339
  warnings.push(`compose file not found at ${composePath}; service status unknown`);
93098
93340
  return { cliVersion, cliBuiltAt, services, warnings };
93099
93341
  }
93100
93342
  let serviceList = [];
93101
93343
  try {
93102
- 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 });
93103
93345
  if (r.status !== 0) {
93104
93346
  warnings.push(`docker compose config --services failed: ${r.stderr?.trim() ?? r.error?.message ?? "unknown"}`);
93105
93347
  return { cliVersion, cliBuiltAt, services, warnings };
@@ -93116,7 +93358,7 @@ function defaultStatusProbe(composePath) {
93116
93358
  let containerCreatedAt = null;
93117
93359
  let status = "<unknown>";
93118
93360
  try {
93119
- 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 });
93120
93362
  if (r.status === 0) {
93121
93363
  const [img, created, st] = r.stdout.trim().split("|");
93122
93364
  image = img ?? null;
@@ -93132,7 +93374,7 @@ function defaultStatusProbe(composePath) {
93132
93374
  let imagePulledAt = null;
93133
93375
  if (image) {
93134
93376
  try {
93135
- 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 });
93136
93378
  if (r.status === 0) {
93137
93379
  const [id, created, lastTag] = r.stdout.trim().split("|");
93138
93380
  imageDigestShort = id?.replace(/^sha256:/, "").slice(0, 12) ?? null;
@@ -93207,7 +93449,7 @@ function buildReexecArgs(opts) {
93207
93449
  return args;
93208
93450
  }
93209
93451
  function defaultReexec(binaryPath, args) {
93210
- const r = spawnSync16(binaryPath, args, {
93452
+ const r = spawnSync17(binaryPath, args, {
93211
93453
  stdio: "inherit",
93212
93454
  env: { ...process.env, [SELF_UPDATE_ENV_SENTINEL]: "1" }
93213
93455
  });
@@ -93216,7 +93458,7 @@ function defaultReexec(binaryPath, args) {
93216
93458
  function renderDriftPreamble(opts) {
93217
93459
  try {
93218
93460
  const exec = opts.componentExec ?? ((cmd, args) => {
93219
- const r = spawnSync16(cmd, args, { encoding: "utf-8", timeout: 1e4 });
93461
+ const r = spawnSync17(cmd, args, { encoding: "utf-8", timeout: 1e4 });
93220
93462
  return { status: r.status ?? 1, stdout: r.stdout ?? "" };
93221
93463
  });
93222
93464
  let pin;
@@ -93340,23 +93582,23 @@ function registerUpdateCommand(program3) {
93340
93582
 
93341
93583
  // src/cli/rollout.ts
93342
93584
  init_helpers();
93343
- import { spawnSync as spawnSync18 } from "node:child_process";
93344
- 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";
93345
93587
  import { homedir as homedir46 } from "node:os";
93346
93588
 
93347
93589
  // src/cli/rollout-pin-journal.ts
93348
93590
  import {
93349
- existsSync as existsSync81,
93350
- readFileSync as readFileSync75,
93351
- writeFileSync as writeFileSync31,
93352
- renameSync as renameSync20,
93591
+ existsSync as existsSync82,
93592
+ readFileSync as readFileSync76,
93593
+ writeFileSync as writeFileSync32,
93594
+ renameSync as renameSync21,
93353
93595
  unlinkSync as unlinkSync15,
93354
93596
  statSync as statSync46,
93355
- mkdirSync as mkdirSync46
93597
+ mkdirSync as mkdirSync47
93356
93598
  } from "node:fs";
93357
93599
  import { homedir as homedir45 } from "node:os";
93358
93600
  import { createHash as createHash17 } from "node:crypto";
93359
- 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";
93360
93602
  init_flock();
93361
93603
  var PIN_JOURNAL_MAX_AGE_MS = 15 * 60 * 1000;
93362
93604
  var STATE_DIR_NAME = ".switchroom";
@@ -93365,7 +93607,7 @@ function pinJournalDir(configPath) {
93365
93607
  if (override && override.trim().length > 0)
93366
93608
  return override.trim();
93367
93609
  if (configPath) {
93368
- const dir = dirname34(resolve46(configPath));
93610
+ const dir = dirname35(resolve46(configPath));
93369
93611
  if (basename9(dir) === STATE_DIR_NAME)
93370
93612
  return dir;
93371
93613
  }
@@ -93408,9 +93650,9 @@ function readPinJournal(configPath, warn = (m) => process.stderr.write(m)) {
93408
93650
  const p = pinJournalPath(configPath);
93409
93651
  let raw;
93410
93652
  try {
93411
- raw = readFileSync75(p, "utf8");
93653
+ raw = readFileSync76(p, "utf8");
93412
93654
  } catch (e) {
93413
- if (existsSync81(p)) {
93655
+ if (existsSync82(p)) {
93414
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.
93415
93657
  `);
93416
93658
  }
@@ -93461,7 +93703,7 @@ function beginPinPersist(configPath, pin, opts = {}) {
93461
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.
93462
93704
  `);
93463
93705
  }
93464
- const priorPin = getReleasePinFromConfig(readFileSync75(configPath, "utf8"));
93706
+ const priorPin = getReleasePinFromConfig(readFileSync76(configPath, "utf8"));
93465
93707
  const journal = {
93466
93708
  v: 1,
93467
93709
  configPath,
@@ -93470,10 +93712,10 @@ function beginPinPersist(configPath, pin, opts = {}) {
93470
93712
  pid: process.pid,
93471
93713
  at: new Date().toISOString()
93472
93714
  };
93473
- mkdirSync46(dirname34(p), { recursive: true });
93715
+ mkdirSync47(dirname35(p), { recursive: true });
93474
93716
  const tmp = `${p}.${process.pid}.tmp`;
93475
- writeFileSync31(tmp, JSON.stringify(journal), { encoding: "utf8", mode: 384 });
93476
- renameSync20(tmp, p);
93717
+ writeFileSync32(tmp, JSON.stringify(journal), { encoding: "utf8", mode: 384 });
93718
+ renameSync21(tmp, p);
93477
93719
  return journal;
93478
93720
  }
93479
93721
  function commitPinPersist(configPath) {
@@ -93482,7 +93724,7 @@ function commitPinPersist(configPath) {
93482
93724
  unlinkSync15(p);
93483
93725
  return null;
93484
93726
  } catch (e) {
93485
- if (!existsSync81(p))
93727
+ if (!existsSync82(p))
93486
93728
  return null;
93487
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\`.`;
93488
93730
  }
@@ -93504,7 +93746,7 @@ function rollbackPinPersist(configPath, opts = {}) {
93504
93746
  }
93505
93747
  }
93506
93748
  try {
93507
- const current = readFileSync75(configPath, "utf8");
93749
+ const current = readFileSync76(configPath, "utf8");
93508
93750
  const next = journal.priorPin ? setReleasePinInConfig(current, journal.priorPin) : deleteReleasePinInConfig(current);
93509
93751
  let mode = 384;
93510
93752
  try {
@@ -93513,7 +93755,7 @@ function rollbackPinPersist(configPath, opts = {}) {
93513
93755
  if (opts.writeConfig) {
93514
93756
  opts.writeConfig(configPath, next, mode);
93515
93757
  } else {
93516
- writeFileSync31(configPath, next, { encoding: "utf8", mode });
93758
+ writeFileSync32(configPath, next, { encoding: "utf8", mode });
93517
93759
  }
93518
93760
  } catch (e) {
93519
93761
  return {
@@ -93561,10 +93803,10 @@ init_audit_reader();
93561
93803
  init_hindsight();
93562
93804
 
93563
93805
  // src/cli/deploy-version-guard.ts
93564
- import { spawnSync as spawnSync17 } from "node:child_process";
93806
+ import { spawnSync as spawnSync18 } from "node:child_process";
93565
93807
  var DOCKER_INSPECT_TIMEOUT_MS = 60 * 1000;
93566
93808
  var defaultRunner3 = (args) => {
93567
- const r = spawnSync17("docker", args, {
93809
+ const r = spawnSync18("docker", args, {
93568
93810
  encoding: "utf8",
93569
93811
  timeout: DOCKER_INSPECT_TIMEOUT_MS,
93570
93812
  killSignal: "SIGKILL"
@@ -93988,7 +94230,7 @@ function isSpawnTimeout(r, killSignal) {
93988
94230
  var ROLLOUT_KILL_SIGNAL = "SIGKILL";
93989
94231
  function createRolloutDeps(params) {
93990
94232
  const { configPath, scriptPath, hostdCtx } = params;
93991
- const spawn6 = params.spawn ?? spawnSync18;
94233
+ const spawn6 = params.spawn ?? spawnSync19;
93992
94234
  const warn = params.warn ?? ((line) => process.stderr.write(line));
93993
94235
  const self = resolveSelfInvocation({
93994
94236
  execPath: params.execPath ?? process.execPath,
@@ -94073,7 +94315,7 @@ function createRolloutDeps(params) {
94073
94315
  return { status: r.ok ? 0 : 1, stdout: r.stdout };
94074
94316
  }),
94075
94317
  persistPin: (pin) => {
94076
- const before = readFileSync76(configPath, "utf8");
94318
+ const before = readFileSync77(configPath, "utf8");
94077
94319
  const after = setReleasePinInConfig(before, pin);
94078
94320
  if (after === before)
94079
94321
  return false;
@@ -94261,8 +94503,8 @@ init_helpers();
94261
94503
  init_lifecycle();
94262
94504
  init_resolve_version();
94263
94505
  import { execSync as execSync3 } from "node:child_process";
94264
- import { existsSync as existsSync82, readFileSync as readFileSync77 } from "node:fs";
94265
- 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";
94266
94508
  function getClaudeCodeVersion() {
94267
94509
  try {
94268
94510
  const out = execSync3("claude --version 2>/dev/null", {
@@ -94313,15 +94555,15 @@ function locateSwitchroomInstallDir() {
94313
94555
  let dir = import.meta.dirname;
94314
94556
  for (let i = 0;i < 10 && dir && dir !== "/"; i++) {
94315
94557
  const pkgPath = join86(dir, "package.json");
94316
- if (existsSync82(pkgPath)) {
94558
+ if (existsSync83(pkgPath)) {
94317
94559
  try {
94318
- const pkg = JSON.parse(readFileSync77(pkgPath, "utf-8"));
94319
- 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"))) {
94320
94562
  return dir;
94321
94563
  }
94322
94564
  } catch {}
94323
94565
  }
94324
- dir = dirname35(dir);
94566
+ dir = dirname36(dir);
94325
94567
  }
94326
94568
  return null;
94327
94569
  }
@@ -94495,7 +94737,7 @@ init_merge();
94495
94737
 
94496
94738
  // src/agents/session-retention.ts
94497
94739
  import {
94498
- existsSync as existsSync83,
94740
+ existsSync as existsSync84,
94499
94741
  readdirSync as readdirSync28,
94500
94742
  statSync as statSync48,
94501
94743
  unlinkSync as unlinkSync16
@@ -94506,7 +94748,7 @@ var DEFAULT_SESSION_RETENTION_MAX_AGE_DAYS = 30;
94506
94748
  var MIN_KEEP = 2;
94507
94749
  function collectSessionJsonl(claudeConfigDir) {
94508
94750
  const projects = join87(claudeConfigDir, "projects");
94509
- if (!existsSync83(projects))
94751
+ if (!existsSync84(projects))
94510
94752
  return [];
94511
94753
  const found = [];
94512
94754
  const walk2 = (dir) => {
@@ -94642,15 +94884,15 @@ function registerHandoffCommand(program3) {
94642
94884
  // src/issues/store.ts
94643
94885
  import {
94644
94886
  closeSync as closeSync16,
94645
- existsSync as existsSync84,
94646
- mkdirSync as mkdirSync47,
94887
+ existsSync as existsSync85,
94888
+ mkdirSync as mkdirSync48,
94647
94889
  openSync as openSync16,
94648
94890
  readdirSync as readdirSync29,
94649
- readFileSync as readFileSync78,
94650
- renameSync as renameSync21,
94891
+ readFileSync as readFileSync79,
94892
+ renameSync as renameSync22,
94651
94893
  statSync as statSync49,
94652
94894
  unlinkSync as unlinkSync17,
94653
- writeFileSync as writeFileSync32,
94895
+ writeFileSync as writeFileSync33,
94654
94896
  writeSync as writeSync9
94655
94897
  } from "node:fs";
94656
94898
  import { join as join88 } from "node:path";
@@ -94681,11 +94923,11 @@ var ISSUES_FILE = "issues.jsonl";
94681
94923
  var ISSUES_LOCK = "issues.lock";
94682
94924
  function readAll(stateDir) {
94683
94925
  const path7 = join88(stateDir, ISSUES_FILE);
94684
- if (!existsSync84(path7))
94926
+ if (!existsSync85(path7))
94685
94927
  return [];
94686
94928
  let raw;
94687
94929
  try {
94688
- raw = readFileSync78(path7, "utf-8");
94930
+ raw = readFileSync79(path7, "utf-8");
94689
94931
  } catch {
94690
94932
  return [];
94691
94933
  }
@@ -94758,7 +95000,7 @@ function record(stateDir, input, nowFn = Date.now) {
94758
95000
  });
94759
95001
  }
94760
95002
  function resolve49(stateDir, fingerprint, nowFn = Date.now) {
94761
- if (!existsSync84(join88(stateDir, ISSUES_FILE)))
95003
+ if (!existsSync85(join88(stateDir, ISSUES_FILE)))
94762
95004
  return 0;
94763
95005
  return withLock(stateDir, () => {
94764
95006
  const all = readAll(stateDir);
@@ -94776,7 +95018,7 @@ function resolve49(stateDir, fingerprint, nowFn = Date.now) {
94776
95018
  });
94777
95019
  }
94778
95020
  function resolveAllBySource(stateDir, source, nowFn = Date.now) {
94779
- if (!existsSync84(join88(stateDir, ISSUES_FILE)))
95021
+ if (!existsSync85(join88(stateDir, ISSUES_FILE)))
94780
95022
  return 0;
94781
95023
  return withLock(stateDir, () => {
94782
95024
  const all = readAll(stateDir);
@@ -94794,7 +95036,7 @@ function resolveAllBySource(stateDir, source, nowFn = Date.now) {
94794
95036
  });
94795
95037
  }
94796
95038
  function prune(stateDir, opts = {}) {
94797
- if (!existsSync84(join88(stateDir, ISSUES_FILE)))
95039
+ if (!existsSync85(join88(stateDir, ISSUES_FILE)))
94798
95040
  return 0;
94799
95041
  return withLock(stateDir, () => {
94800
95042
  const all = readAll(stateDir);
@@ -94824,7 +95066,7 @@ function prune(stateDir, opts = {}) {
94824
95066
  });
94825
95067
  }
94826
95068
  function ensureDir(stateDir) {
94827
- mkdirSync47(stateDir, { recursive: true });
95069
+ mkdirSync48(stateDir, { recursive: true });
94828
95070
  }
94829
95071
  function writeAll(stateDir, events) {
94830
95072
  const path7 = join88(stateDir, ISSUES_FILE);
@@ -94833,8 +95075,8 @@ function writeAll(stateDir, events) {
94833
95075
  const body = events.length === 0 ? "" : events.map((e) => JSON.stringify(e)).join(`
94834
95076
  `) + `
94835
95077
  `;
94836
- writeFileSync32(tmp, body, "utf-8");
94837
- renameSync21(tmp, path7);
95078
+ writeFileSync33(tmp, body, "utf-8");
95079
+ renameSync22(tmp, path7);
94838
95080
  }
94839
95081
  var ORPHAN_TMP_TTL_MS = 60000;
94840
95082
  var TMP_PREFIX = `${ISSUES_FILE}.tmp-`;
@@ -94896,7 +95138,7 @@ function withLock(stateDir, fn) {
94896
95138
  function tryStealStaleLock(lockPath) {
94897
95139
  let pidStr;
94898
95140
  try {
94899
- pidStr = readFileSync78(lockPath, "utf-8").trim();
95141
+ pidStr = readFileSync79(lockPath, "utf-8").trim();
94900
95142
  } catch {
94901
95143
  return true;
94902
95144
  }
@@ -95144,20 +95386,20 @@ function relTime(deltaMs) {
95144
95386
 
95145
95387
  // src/cli/deps.ts
95146
95388
  init_source();
95147
- import { existsSync as existsSync87 } from "node:fs";
95389
+ import { existsSync as existsSync88 } from "node:fs";
95148
95390
  import { homedir as homedir49 } from "node:os";
95149
95391
  import { join as join91, resolve as resolve50 } from "node:path";
95150
95392
 
95151
95393
  // src/deps/python.ts
95152
95394
  import { createHash as createHash18 } from "node:crypto";
95153
95395
  import {
95154
- existsSync as existsSync85,
95155
- mkdirSync as mkdirSync48,
95156
- readFileSync as readFileSync79,
95396
+ existsSync as existsSync86,
95397
+ mkdirSync as mkdirSync49,
95398
+ readFileSync as readFileSync80,
95157
95399
  rmSync as rmSync15,
95158
- writeFileSync as writeFileSync33
95400
+ writeFileSync as writeFileSync34
95159
95401
  } from "node:fs";
95160
- import { dirname as dirname36, join as join89 } from "node:path";
95402
+ import { dirname as dirname37, join as join89 } from "node:path";
95161
95403
  import { homedir as homedir47 } from "node:os";
95162
95404
  import { execFileSync as execFileSync24 } from "node:child_process";
95163
95405
 
@@ -95173,13 +95415,13 @@ function defaultPythonCacheRoot() {
95173
95415
  return join89(homedir47(), ".switchroom", "deps", "python");
95174
95416
  }
95175
95417
  function hashFile(path7) {
95176
- return createHash18("sha256").update(readFileSync79(path7)).digest("hex");
95418
+ return createHash18("sha256").update(readFileSync80(path7)).digest("hex");
95177
95419
  }
95178
95420
  function ensurePythonEnv(opts) {
95179
95421
  const { skillName, requirementsPath, force = false } = opts;
95180
95422
  const cacheRoot = opts.cacheRoot ?? defaultPythonCacheRoot();
95181
95423
  const hostPython = opts.pythonBin ?? "python3";
95182
- if (!existsSync85(requirementsPath)) {
95424
+ if (!existsSync86(requirementsPath)) {
95183
95425
  throw new PythonEnvError(`requirements file not found: ${requirementsPath}`);
95184
95426
  }
95185
95427
  const venvDir = join89(cacheRoot, skillName);
@@ -95188,8 +95430,8 @@ function ensurePythonEnv(opts) {
95188
95430
  const pythonBin = join89(binDir, "python");
95189
95431
  const pipBin = join89(binDir, "pip");
95190
95432
  const targetHash = hashFile(requirementsPath);
95191
- if (!force && existsSync85(stampPath) && existsSync85(pythonBin)) {
95192
- const existingHash = readFileSync79(stampPath, "utf8").trim();
95433
+ if (!force && existsSync86(stampPath) && existsSync86(pythonBin)) {
95434
+ const existingHash = readFileSync80(stampPath, "utf8").trim();
95193
95435
  if (existingHash === targetHash) {
95194
95436
  return {
95195
95437
  skillName,
@@ -95201,10 +95443,10 @@ function ensurePythonEnv(opts) {
95201
95443
  };
95202
95444
  }
95203
95445
  }
95204
- if (existsSync85(venvDir)) {
95446
+ if (existsSync86(venvDir)) {
95205
95447
  rmSync15(venvDir, { recursive: true, force: true });
95206
95448
  }
95207
- mkdirSync48(dirname36(venvDir), { recursive: true });
95449
+ mkdirSync49(dirname37(venvDir), { recursive: true });
95208
95450
  try {
95209
95451
  execFileSync24(hostPython, ["-m", "venv", venvDir], { stdio: "pipe" });
95210
95452
  } catch (err) {
@@ -95223,7 +95465,7 @@ function ensurePythonEnv(opts) {
95223
95465
  const e = err;
95224
95466
  throw new PythonEnvError(`Failed to install requirements for skill "${skillName}": ${e.message}`, e.stderr?.toString());
95225
95467
  }
95226
- writeFileSync33(stampPath, targetHash + `
95468
+ writeFileSync34(stampPath, targetHash + `
95227
95469
  `);
95228
95470
  return {
95229
95471
  skillName,
@@ -95239,13 +95481,13 @@ function ensurePythonEnv(opts) {
95239
95481
  import { createHash as createHash19 } from "node:crypto";
95240
95482
  import {
95241
95483
  copyFileSync as copyFileSync12,
95242
- existsSync as existsSync86,
95243
- mkdirSync as mkdirSync49,
95244
- readFileSync as readFileSync80,
95484
+ existsSync as existsSync87,
95485
+ mkdirSync as mkdirSync50,
95486
+ readFileSync as readFileSync81,
95245
95487
  rmSync as rmSync16,
95246
- writeFileSync as writeFileSync34
95488
+ writeFileSync as writeFileSync35
95247
95489
  } from "node:fs";
95248
- import { dirname as dirname37, join as join90 } from "node:path";
95490
+ import { dirname as dirname38, join as join90 } from "node:path";
95249
95491
  import { homedir as homedir48 } from "node:os";
95250
95492
  import { execFileSync as execFileSync25 } from "node:child_process";
95251
95493
 
@@ -95272,20 +95514,20 @@ function defaultNodeCacheRoot() {
95272
95514
  return join90(homedir48(), ".switchroom", "deps", "node");
95273
95515
  }
95274
95516
  function hashDepInputs(packageJsonPath) {
95275
- const sourceDir = dirname37(packageJsonPath);
95517
+ const sourceDir = dirname38(packageJsonPath);
95276
95518
  const hasher = createHash19("sha256");
95277
95519
  hasher.update(`package.json
95278
95520
  `);
95279
- hasher.update(readFileSync80(packageJsonPath));
95521
+ hasher.update(readFileSync81(packageJsonPath));
95280
95522
  for (const lockName of ALL_LOCKFILES) {
95281
95523
  const lockPath = join90(sourceDir, lockName);
95282
- if (existsSync86(lockPath)) {
95524
+ if (existsSync87(lockPath)) {
95283
95525
  hasher.update(`
95284
95526
  `);
95285
95527
  hasher.update(lockName);
95286
95528
  hasher.update(`
95287
95529
  `);
95288
- hasher.update(readFileSync80(lockPath));
95530
+ hasher.update(readFileSync81(lockPath));
95289
95531
  }
95290
95532
  }
95291
95533
  return hasher.digest("hex");
@@ -95294,17 +95536,17 @@ function ensureNodeEnv(opts) {
95294
95536
  const { skillName, packageJsonPath, force = false } = opts;
95295
95537
  const cacheRoot = opts.cacheRoot ?? defaultNodeCacheRoot();
95296
95538
  const installer = opts.installer ?? "bun";
95297
- if (!existsSync86(packageJsonPath)) {
95539
+ if (!existsSync87(packageJsonPath)) {
95298
95540
  throw new NodeEnvError(`package.json not found: ${packageJsonPath}`);
95299
95541
  }
95300
- const sourceDir = dirname37(packageJsonPath);
95542
+ const sourceDir = dirname38(packageJsonPath);
95301
95543
  const envDir = join90(cacheRoot, skillName);
95302
95544
  const stampPath = join90(envDir, ".package.sha256");
95303
95545
  const nodeModulesDir = join90(envDir, "node_modules");
95304
95546
  const binDir = join90(nodeModulesDir, ".bin");
95305
95547
  const targetHash = hashDepInputs(packageJsonPath);
95306
- if (!force && existsSync86(stampPath) && existsSync86(nodeModulesDir)) {
95307
- const existingHash = readFileSync80(stampPath, "utf8").trim();
95548
+ if (!force && existsSync87(stampPath) && existsSync87(nodeModulesDir)) {
95549
+ const existingHash = readFileSync81(stampPath, "utf8").trim();
95308
95550
  if (existingHash === targetHash) {
95309
95551
  return {
95310
95552
  skillName,
@@ -95315,15 +95557,15 @@ function ensureNodeEnv(opts) {
95315
95557
  };
95316
95558
  }
95317
95559
  }
95318
- if (existsSync86(envDir)) {
95560
+ if (existsSync87(envDir)) {
95319
95561
  rmSync16(envDir, { recursive: true, force: true });
95320
95562
  }
95321
- mkdirSync49(envDir, { recursive: true });
95563
+ mkdirSync50(envDir, { recursive: true });
95322
95564
  copyFileSync12(packageJsonPath, join90(envDir, "package.json"));
95323
95565
  let copiedLockfile = false;
95324
95566
  for (const lockName of LOCKFILES_FOR[installer]) {
95325
95567
  const lockPath = join90(sourceDir, lockName);
95326
- if (existsSync86(lockPath)) {
95568
+ if (existsSync87(lockPath)) {
95327
95569
  copyFileSync12(lockPath, join90(envDir, lockName));
95328
95570
  copiedLockfile = true;
95329
95571
  }
@@ -95340,7 +95582,7 @@ function ensureNodeEnv(opts) {
95340
95582
  const e = err;
95341
95583
  throw new NodeEnvError(`Failed to install node deps for skill "${skillName}" with ${installer}: ${e.message}`, e.stderr?.toString());
95342
95584
  }
95343
- writeFileSync34(stampPath, targetHash + `
95585
+ writeFileSync35(stampPath, targetHash + `
95344
95586
  `);
95345
95587
  return {
95346
95588
  skillName,
@@ -95359,22 +95601,22 @@ function registerDepsCommand(program3) {
95359
95601
  const deps = program3.command("deps").description("Manage cached per-skill dependency environments");
95360
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) => {
95361
95603
  const skillsRoot = builtinSkillsRoot();
95362
- if (!existsSync87(skillsRoot)) {
95604
+ if (!existsSync88(skillsRoot)) {
95363
95605
  console.error(source_default.red(`Bundled skills pool dir not found at ${skillsRoot} \u2014 run \`switchroom update\` to install it.`));
95364
95606
  process.exit(1);
95365
95607
  }
95366
95608
  const skillDir = join91(skillsRoot, skill);
95367
- if (!existsSync87(skillDir)) {
95609
+ if (!existsSync88(skillDir)) {
95368
95610
  console.error(source_default.red(`Unknown skill: ${skill} (no dir at ${skillDir})`));
95369
95611
  process.exit(1);
95370
95612
  }
95371
95613
  const requirementsPath = join91(skillDir, "requirements.txt");
95372
95614
  const packageJsonPath = join91(skillDir, "package.json");
95373
- const wantPython = opts.python ?? (!opts.python && !opts.node && existsSync87(requirementsPath));
95374
- 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));
95375
95617
  let did = 0;
95376
95618
  if (wantPython) {
95377
- if (!existsSync87(requirementsPath)) {
95619
+ if (!existsSync88(requirementsPath)) {
95378
95620
  console.error(source_default.red(`Skill "${skill}" has no requirements.txt at ${requirementsPath}`));
95379
95621
  process.exit(1);
95380
95622
  }
@@ -95398,7 +95640,7 @@ function registerDepsCommand(program3) {
95398
95640
  }
95399
95641
  }
95400
95642
  if (wantNode) {
95401
- if (!existsSync87(packageJsonPath)) {
95643
+ if (!existsSync88(packageJsonPath)) {
95402
95644
  console.error(source_default.red(`Skill "${skill}" has no package.json at ${packageJsonPath}`));
95403
95645
  process.exit(1);
95404
95646
  }
@@ -95431,9 +95673,9 @@ function registerDepsCommand(program3) {
95431
95673
  // src/cli/workspace.ts
95432
95674
  init_helpers();
95433
95675
  init_loader();
95434
- import { existsSync as existsSync88 } from "node:fs";
95676
+ import { existsSync as existsSync89 } from "node:fs";
95435
95677
  import { resolve as resolve51, sep as sep4 } from "node:path";
95436
- import { spawnSync as spawnSync19 } from "node:child_process";
95678
+ import { spawnSync as spawnSync20 } from "node:child_process";
95437
95679
 
95438
95680
  // src/agents/workspace.ts
95439
95681
  import { readFile as readFile2, stat } from "node:fs/promises";
@@ -96146,7 +96388,7 @@ function registerWorkspaceCommand(program3) {
96146
96388
  process.exit(1);
96147
96389
  }
96148
96390
  const editor = process.env["EDITOR"] ?? process.env["VISUAL"] ?? "vi";
96149
- const child = spawnSync19(editor, [target], { stdio: "inherit" });
96391
+ const child = spawnSync20(editor, [target], { stdio: "inherit" });
96150
96392
  if (child.status !== 0 && child.status !== null) {
96151
96393
  process.exit(child.status);
96152
96394
  }
@@ -96208,12 +96450,12 @@ function registerWorkspaceCommand(program3) {
96208
96450
  if (!dir)
96209
96451
  return;
96210
96452
  const gitDir = resolve51(dir, ".git");
96211
- if (!existsSync88(gitDir)) {
96453
+ if (!existsSync89(gitDir)) {
96212
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.
96213
96455
  `);
96214
96456
  return;
96215
96457
  }
96216
- const statusResult = spawnSync19("git", ["status", "--short"], {
96458
+ const statusResult = spawnSync20("git", ["status", "--short"], {
96217
96459
  cwd: dir,
96218
96460
  encoding: "utf-8"
96219
96461
  });
@@ -96228,7 +96470,7 @@ function registerWorkspaceCommand(program3) {
96228
96470
  return;
96229
96471
  }
96230
96472
  const message = opts.message || `checkpoint: ${new Date().toISOString()}`;
96231
- const addResult = spawnSync19("git", ["add", "-A"], {
96473
+ const addResult = spawnSync20("git", ["add", "-A"], {
96232
96474
  cwd: dir,
96233
96475
  encoding: "utf-8"
96234
96476
  });
@@ -96237,7 +96479,7 @@ function registerWorkspaceCommand(program3) {
96237
96479
  `);
96238
96480
  process.exit(1);
96239
96481
  }
96240
- const commitResult = spawnSync19("git", ["commit", "-m", message], {
96482
+ const commitResult = spawnSync20("git", ["commit", "-m", message], {
96241
96483
  cwd: dir,
96242
96484
  encoding: "utf-8"
96243
96485
  });
@@ -96246,7 +96488,7 @@ function registerWorkspaceCommand(program3) {
96246
96488
  `);
96247
96489
  process.exit(1);
96248
96490
  }
96249
- const shaResult = spawnSync19("git", ["rev-parse", "--short", "HEAD"], {
96491
+ const shaResult = spawnSync20("git", ["rev-parse", "--short", "HEAD"], {
96250
96492
  cwd: dir,
96251
96493
  encoding: "utf-8"
96252
96494
  });
@@ -96262,12 +96504,12 @@ function registerWorkspaceCommand(program3) {
96262
96504
  if (!dir)
96263
96505
  return;
96264
96506
  const gitDir = resolve51(dir, ".git");
96265
- if (!existsSync88(gitDir)) {
96507
+ if (!existsSync89(gitDir)) {
96266
96508
  process.stdout.write(`Workspace is not a git repository.
96267
96509
  `);
96268
96510
  return;
96269
96511
  }
96270
- const child = spawnSync19("git", ["status", "--short"], {
96512
+ const child = spawnSync20("git", ["status", "--short"], {
96271
96513
  cwd: dir,
96272
96514
  stdio: "inherit"
96273
96515
  });
@@ -96287,7 +96529,7 @@ function resolveAgentWorkspaceDirOrExit(program3, agentName) {
96287
96529
  const agentsDir = resolveAgentsDir(config);
96288
96530
  const agentDir = resolve51(agentsDir, agentName);
96289
96531
  const dir = resolveAgentWorkspaceDir(agentDir);
96290
- if (!existsSync88(dir)) {
96532
+ if (!existsSync89(dir)) {
96291
96533
  process.stderr.write(`workspace: ${dir} does not exist yet. Run \`switchroom setup\` or \`switchroom agent scaffold ${agentName}\` to seed it.
96292
96534
  `);
96293
96535
  return;
@@ -96323,7 +96565,7 @@ function safeParseInt(value, fallback) {
96323
96565
  init_helpers();
96324
96566
  init_loader();
96325
96567
  init_merge();
96326
- 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";
96327
96569
  import { join as join92, resolve as resolve52 } from "node:path";
96328
96570
  init_scaffold();
96329
96571
  init_profiles();
@@ -96341,7 +96583,7 @@ function resolveSoulTargetOrExit(program3, agentName) {
96341
96583
  const agentsDir = resolveAgentsDir(config);
96342
96584
  const agentDir = resolve52(agentsDir, agentName);
96343
96585
  const workspaceDir = resolveAgentWorkspaceDir(agentDir);
96344
- if (!existsSync89(workspaceDir)) {
96586
+ if (!existsSync90(workspaceDir)) {
96345
96587
  console.error(`soul: ${workspaceDir} does not exist yet. Run \`switchroom setup\` ` + `or \`switchroom agent scaffold ${agentName}\` to seed it.`);
96346
96588
  process.exit(1);
96347
96589
  }
@@ -96367,11 +96609,11 @@ function registerSoulCommand(program3) {
96367
96609
  const t = resolveSoulTargetOrExit(program3, agentName);
96368
96610
  if (!t)
96369
96611
  return;
96370
- if (!existsSync89(t.soulPath)) {
96612
+ if (!existsSync90(t.soulPath)) {
96371
96613
  console.error(`soul: ${t.soulPath} does not exist yet \u2014 run ` + `\`switchroom soul reset ${agentName}\` to seed it.`);
96372
96614
  process.exit(1);
96373
96615
  }
96374
- process.stdout.write(readFileSync81(t.soulPath, "utf-8"));
96616
+ process.stdout.write(readFileSync82(t.soulPath, "utf-8"));
96375
96617
  }));
96376
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) => {
96377
96619
  const t = resolveSoulTargetOrExit(program3, agentName);
@@ -96382,7 +96624,7 @@ function registerSoulCommand(program3) {
96382
96624
  console.error(`soul: profile "${t.profileName}" ships no SOUL.md.hbs \u2014 ` + `nothing to re-seed from.`);
96383
96625
  process.exit(1);
96384
96626
  }
96385
- const exists = existsSync89(t.soulPath);
96627
+ const exists = existsSync90(t.soulPath);
96386
96628
  if (exists && !opts.yes) {
96387
96629
  if (!isInteractive()) {
96388
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).`);
@@ -96397,12 +96639,12 @@ function registerSoulCommand(program3) {
96397
96639
  let backupPath;
96398
96640
  if (exists) {
96399
96641
  backupPath = `${t.soulPath}.bak`;
96400
- if (existsSync89(backupPath)) {
96642
+ if (existsSync90(backupPath)) {
96401
96643
  backupPath = `${t.soulPath}.bak.${Date.now()}`;
96402
96644
  }
96403
96645
  copyFileSync13(t.soulPath, backupPath);
96404
96646
  }
96405
- writeFileSync35(t.soulPath, content, "utf-8");
96647
+ writeFileSync36(t.soulPath, content, "utf-8");
96406
96648
  if (backupPath) {
96407
96649
  console.log(`soul: re-seeded ${agentName}'s SOUL.md from profile ` + `"${t.profileName}".
96408
96650
  ` + ` Previous version saved to ${backupPath}`);
@@ -96416,7 +96658,7 @@ function registerSoulCommand(program3) {
96416
96658
  // src/cli/debug.ts
96417
96659
  init_helpers();
96418
96660
  init_loader();
96419
- 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";
96420
96662
  import { resolve as resolve53, join as join93 } from "node:path";
96421
96663
  import { createHash as createHash20 } from "node:crypto";
96422
96664
  init_merge();
@@ -96429,10 +96671,10 @@ function estimateTokens(bytes) {
96429
96671
  }
96430
96672
  function readMcpServerNames(agentDir) {
96431
96673
  const mcpPath = join93(agentDir, ".mcp.json");
96432
- if (!existsSync90(mcpPath))
96674
+ if (!existsSync91(mcpPath))
96433
96675
  return [];
96434
96676
  try {
96435
- const parsed = JSON.parse(readFileSync82(mcpPath, "utf-8"));
96677
+ const parsed = JSON.parse(readFileSync83(mcpPath, "utf-8"));
96436
96678
  return Object.keys(parsed.mcpServers ?? {});
96437
96679
  } catch {
96438
96680
  return null;
@@ -96443,7 +96685,7 @@ function sha256(content) {
96443
96685
  }
96444
96686
  function findLatestTranscriptJsonl(claudeConfigDir) {
96445
96687
  const projectsDir = join93(claudeConfigDir, "projects");
96446
- if (!existsSync90(projectsDir))
96688
+ if (!existsSync91(projectsDir))
96447
96689
  return;
96448
96690
  try {
96449
96691
  const entries = readdirSync30(projectsDir, { withFileTypes: true });
@@ -96453,7 +96695,7 @@ function findLatestTranscriptJsonl(claudeConfigDir) {
96453
96695
  continue;
96454
96696
  const projectPath = join93(projectsDir, entry.name);
96455
96697
  const transcriptPath = join93(projectPath, "transcript.jsonl");
96456
- if (!existsSync90(transcriptPath))
96698
+ if (!existsSync91(transcriptPath))
96457
96699
  continue;
96458
96700
  const stat3 = statSync50(transcriptPath);
96459
96701
  if (!latest || stat3.mtimeMs > latest.mtime) {
@@ -96467,7 +96709,7 @@ function findLatestTranscriptJsonl(claudeConfigDir) {
96467
96709
  }
96468
96710
  function extractLatestUserMessage(transcriptPath) {
96469
96711
  try {
96470
- const content = readFileSync82(transcriptPath, "utf-8");
96712
+ const content = readFileSync83(transcriptPath, "utf-8");
96471
96713
  const lines = content.trim().split(`
96472
96714
  `).filter(Boolean);
96473
96715
  for (let i = lines.length - 1;i >= 0; i--) {
@@ -96516,7 +96758,7 @@ function registerDebugCommand(program3) {
96516
96758
  }
96517
96759
  const agentsDir = resolveAgentsDir(config);
96518
96760
  const agentDir = resolve53(agentsDir, agentName);
96519
- if (!existsSync90(agentDir)) {
96761
+ if (!existsSync91(agentDir)) {
96520
96762
  console.error(`Agent directory not found: ${agentDir}`);
96521
96763
  process.exit(1);
96522
96764
  }
@@ -96571,7 +96813,7 @@ function registerDebugCommand(program3) {
96571
96813
  }
96572
96814
  console.log(`=== Append System Prompt (per-session) ===
96573
96815
  `);
96574
- const handoffContent = existsSync90(handoffPath) ? readFileSync82(handoffPath, "utf-8") : "";
96816
+ const handoffContent = existsSync91(handoffPath) ? readFileSync83(handoffPath, "utf-8") : "";
96575
96817
  if (handoffContent.trim().length > 0) {
96576
96818
  console.log(`-- Handoff Briefing (${formatBytes(handoffContent.length)}) --`);
96577
96819
  console.log(handoffContent);
@@ -96582,7 +96824,7 @@ function registerDebugCommand(program3) {
96582
96824
  }
96583
96825
  console.log(`=== CLAUDE.md (auto-loaded by Claude Code) ===
96584
96826
  `);
96585
- const claudeMdContent = existsSync90(claudeMdPath) ? readFileSync82(claudeMdPath, "utf-8") : "";
96827
+ const claudeMdContent = existsSync91(claudeMdPath) ? readFileSync83(claudeMdPath, "utf-8") : "";
96586
96828
  if (claudeMdContent.trim().length > 0) {
96587
96829
  console.log(`(${formatBytes(claudeMdContent.length)})`);
96588
96830
  console.log(claudeMdContent);
@@ -96593,7 +96835,7 @@ function registerDebugCommand(program3) {
96593
96835
  }
96594
96836
  console.log(`=== Persona (SOUL.md) ===
96595
96837
  `);
96596
- 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") : "";
96597
96839
  if (soulMdContent.trim().length > 0) {
96598
96840
  console.log(`(${formatBytes(soulMdContent.length)})`);
96599
96841
  console.log(soulMdContent);
@@ -96657,8 +96899,8 @@ function registerDebugCommand(program3) {
96657
96899
  const fleetDir = join93(agentsDir, "..", "fleet");
96658
96900
  const fleetInvPath = join93(fleetDir, "switchroom-invariants.md");
96659
96901
  const fleetClaudePath = join93(fleetDir, "CLAUDE.md");
96660
- const fleetInvBytes = existsSync90(fleetInvPath) ? readFileSync82(fleetInvPath, "utf-8").length : 0;
96661
- 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;
96662
96904
  const fleetBytes = fleetInvBytes + fleetClaudeBytes;
96663
96905
  const totalBytes = stableBytes + perSessionBytes + claudeMdBytes + fleetBytes + perTurnBytes + userBytes;
96664
96906
  console.log(`Stable prefix: ${formatBytes(stableBytes).padEnd(20)} (cache-hot; includes SOUL.md ${soulMdBytes.toLocaleString()}B)`);
@@ -96691,20 +96933,20 @@ init_source();
96691
96933
 
96692
96934
  // src/worktree/claim.ts
96693
96935
  import { execFileSync as execFileSync26 } from "node:child_process";
96694
- 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";
96695
96937
  import { join as join95, resolve as resolve55 } from "node:path";
96696
96938
  import { homedir as homedir51 } from "node:os";
96697
96939
  import { randomBytes as randomBytes14 } from "node:crypto";
96698
96940
 
96699
96941
  // src/worktree/registry.ts
96700
96942
  import {
96701
- mkdirSync as mkdirSync50,
96702
- writeFileSync as writeFileSync36,
96703
- readFileSync as readFileSync83,
96943
+ mkdirSync as mkdirSync51,
96944
+ writeFileSync as writeFileSync37,
96945
+ readFileSync as readFileSync84,
96704
96946
  readdirSync as readdirSync31,
96705
96947
  unlinkSync as unlinkSync18,
96706
- existsSync as existsSync91,
96707
- renameSync as renameSync22
96948
+ existsSync as existsSync92,
96949
+ renameSync as renameSync23
96708
96950
  } from "node:fs";
96709
96951
  import { join as join94, resolve as resolve54 } from "node:path";
96710
96952
  import { homedir as homedir50 } from "node:os";
@@ -96715,20 +96957,20 @@ function recordPath(id) {
96715
96957
  return join94(registryDir(), `${id}.json`);
96716
96958
  }
96717
96959
  function ensureDir2() {
96718
- mkdirSync50(registryDir(), { recursive: true });
96960
+ mkdirSync51(registryDir(), { recursive: true });
96719
96961
  }
96720
96962
  function writeRecord(record2) {
96721
96963
  ensureDir2();
96722
96964
  const target = recordPath(record2.id);
96723
96965
  const tmp = `${target}.tmp${process.pid}`;
96724
- writeFileSync36(tmp, JSON.stringify(record2, null, 2) + `
96966
+ writeFileSync37(tmp, JSON.stringify(record2, null, 2) + `
96725
96967
  `, { mode: 384 });
96726
- renameSync22(tmp, target);
96968
+ renameSync23(tmp, target);
96727
96969
  }
96728
96970
  function readRecord(id) {
96729
96971
  const path10 = recordPath(id);
96730
96972
  try {
96731
- const raw = readFileSync83(path10, "utf8");
96973
+ const raw = readFileSync84(path10, "utf8");
96732
96974
  return JSON.parse(raw);
96733
96975
  } catch {
96734
96976
  return null;
@@ -96761,7 +97003,7 @@ function countByRepo(repoPath) {
96761
97003
  // src/worktree/claim.ts
96762
97004
  function acquireRepoLock(repoPath) {
96763
97005
  const lockDir = registryDir();
96764
- mkdirSync51(lockDir, { recursive: true });
97006
+ mkdirSync52(lockDir, { recursive: true });
96765
97007
  const lockName = repoPath.replace(/[^A-Za-z0-9]/g, "_");
96766
97008
  const lockPath = join95(lockDir, `.lock-${lockName}`);
96767
97009
  const deadline = Date.now() + 5000;
@@ -96817,7 +97059,7 @@ function expandHome(p) {
96817
97059
  }
96818
97060
  async function claimWorktree(input, codeRepos) {
96819
97061
  const repoPath = resolveRepoPath(input.repo, codeRepos);
96820
- if (!existsSync92(repoPath)) {
97062
+ if (!existsSync93(repoPath)) {
96821
97063
  throw new Error(`Repository path does not exist: ${repoPath}`);
96822
97064
  }
96823
97065
  let concurrencyCap = DEFAULT_CONCURRENCY;
@@ -96839,7 +97081,7 @@ async function claimWorktree(input, codeRepos) {
96839
97081
  const taskSuffix = input.taskName ? sanitizeTaskName(input.taskName) : "task";
96840
97082
  branch = `task/${taskSuffix}-${id}`;
96841
97083
  const baseDir = worktreesBaseDir();
96842
- mkdirSync51(baseDir, { recursive: true });
97084
+ mkdirSync52(baseDir, { recursive: true });
96843
97085
  worktreePath = join95(baseDir, `${id}-${taskSuffix}`);
96844
97086
  const ambientOwner = process.env.SWITCHROOM_AGENT_NAME;
96845
97087
  const ownerAgent = input.ownerAgent ?? (ambientOwner != null && ambientOwner !== "" ? ambientOwner : undefined);
@@ -96873,7 +97115,7 @@ async function claimWorktree(input, codeRepos) {
96873
97115
 
96874
97116
  // src/worktree/release.ts
96875
97117
  import { execFileSync as execFileSync27 } from "node:child_process";
96876
- import { existsSync as existsSync93 } from "node:fs";
97118
+ import { existsSync as existsSync94 } from "node:fs";
96877
97119
  function releaseWorktree(input) {
96878
97120
  const { id } = input;
96879
97121
  const record2 = readRecord(id);
@@ -96881,7 +97123,7 @@ function releaseWorktree(input) {
96881
97123
  return { released: true };
96882
97124
  }
96883
97125
  let gitSuccess = true;
96884
- if (existsSync93(record2.path)) {
97126
+ if (existsSync94(record2.path)) {
96885
97127
  try {
96886
97128
  execFileSync27("git", ["worktree", "remove", "--force", record2.path], {
96887
97129
  cwd: record2.repo,
@@ -96920,7 +97162,7 @@ function listWorktrees() {
96920
97162
 
96921
97163
  // src/worktree/reaper.ts
96922
97164
  import { execFileSync as execFileSync28 } from "node:child_process";
96923
- import { existsSync as existsSync94 } from "node:fs";
97165
+ import { existsSync as existsSync95 } from "node:fs";
96924
97166
  var STALE_THRESHOLD_MS = 10 * 60 * 1000;
96925
97167
  function reapSkipReasonText(action) {
96926
97168
  switch (action) {
@@ -96981,7 +97223,7 @@ function planReaper(nowMs, deps = {}) {
96981
97223
  const plan = [];
96982
97224
  for (const record2 of listRecords()) {
96983
97225
  const heartbeatAge = now - new Date(record2.heartbeatAt).getTime();
96984
- const worktreeExists = existsSync94(record2.path);
97226
+ const worktreeExists = existsSync95(record2.path);
96985
97227
  if (!worktreeExists) {
96986
97228
  plan.push({
96987
97229
  record: record2,
@@ -97062,12 +97304,12 @@ function runReaper(nowMs, deps = {}) {
97062
97304
  // src/worktree/gc.ts
97063
97305
  import { execFileSync as execFileSync29 } from "node:child_process";
97064
97306
  import {
97065
- existsSync as existsSync95,
97066
- readFileSync as readFileSync84,
97307
+ existsSync as existsSync96,
97308
+ readFileSync as readFileSync85,
97067
97309
  readdirSync as readdirSync32,
97068
97310
  statSync as statSync51,
97069
- renameSync as renameSync23,
97070
- mkdirSync as mkdirSync52,
97311
+ renameSync as renameSync24,
97312
+ mkdirSync as mkdirSync53,
97071
97313
  rmSync as rmSync17
97072
97314
  } from "node:fs";
97073
97315
  import { homedir as homedir52 } from "node:os";
@@ -97189,9 +97431,9 @@ function trashRoot() {
97189
97431
  return resolve56(process.env.SWITCHROOM_WORKTREE_TRASH ?? join96(homedir52(), ".switchroom", "worktree-gc-trash"));
97190
97432
  }
97191
97433
  function planGc(roots, deps = {}) {
97192
- const exists = deps.existsSync ?? existsSync95;
97434
+ const exists = deps.existsSync ?? existsSync96;
97193
97435
  const readDir = deps.readDir ?? ((p) => readdirSync32(p));
97194
- const readFile4 = deps.readFile ?? ((p) => readFileSync84(p, "utf8"));
97436
+ const readFile4 = deps.readFile ?? ((p) => readFileSync85(p, "utf8"));
97195
97437
  const stat3 = deps.stat ?? ((p) => statSync51(p));
97196
97438
  const exec = deps.exec ?? defaultExec3;
97197
97439
  const prSignal = deps.prSignal ?? ((repo, branch) => defaultPrSignal(repo, branch, exec));
@@ -97319,10 +97561,10 @@ function planGc(roots, deps = {}) {
97319
97561
  }
97320
97562
  function applyGc(plan, deps = {}) {
97321
97563
  const exec = deps.exec ?? defaultExec3;
97322
- const mkdirp = deps.mkdirp ?? ((p) => void mkdirSync52(p, { recursive: true }));
97564
+ const mkdirp = deps.mkdirp ?? ((p) => void mkdirSync53(p, { recursive: true }));
97323
97565
  const move = deps.move ?? ((src, dest) => {
97324
97566
  try {
97325
- renameSync23(src, dest);
97567
+ renameSync24(src, dest);
97326
97568
  } catch {
97327
97569
  exec("mv", [src, dest]);
97328
97570
  }
@@ -97368,7 +97610,7 @@ function selectPurgeTargets(entries, olderThanDays) {
97368
97610
  return entries.filter((e) => e.ageDays >= olderThanDays).map((e) => e.path);
97369
97611
  }
97370
97612
  function listTrashEntries(nowMs, deps = {}) {
97371
- const exists = deps.existsSync ?? existsSync95;
97613
+ const exists = deps.existsSync ?? existsSync96;
97372
97614
  const readDir = deps.readDir ?? ((p) => readdirSync32(p));
97373
97615
  const root = trashRoot();
97374
97616
  if (!exists(root))
@@ -97630,10 +97872,10 @@ init_drive();
97630
97872
  init_scaffold_integration();
97631
97873
  import {
97632
97874
  chmodSync as chmodSync16,
97633
- mkdirSync as mkdirSync53,
97875
+ mkdirSync as mkdirSync54,
97634
97876
  readdirSync as readdirSync33,
97635
97877
  rmSync as rmSync18,
97636
- writeFileSync as writeFileSync37
97878
+ writeFileSync as writeFileSync38
97637
97879
  } from "node:fs";
97638
97880
  import { join as join97 } from "node:path";
97639
97881
  function encodeCredentialsFilename(email) {
@@ -97828,14 +98070,14 @@ function resolveCredentialsDir(env2) {
97828
98070
  return join97(stateBase, "google-workspace-mcp", "credentials");
97829
98071
  }
97830
98072
  function writeSeedFile(dir, email, seed) {
97831
- mkdirSync53(dir, { recursive: true, mode: 448 });
98073
+ mkdirSync54(dir, { recursive: true, mode: 448 });
97832
98074
  chmodSync16(dir, 448);
97833
98075
  for (const name of readdirSync33(dir)) {
97834
98076
  rmSync18(join97(dir, name), { force: true, recursive: true });
97835
98077
  }
97836
98078
  const filename = encodeCredentialsFilename(email);
97837
98079
  const filePath = join97(dir, filename);
97838
- writeFileSync37(filePath, JSON.stringify(seed), { mode: 384 });
98080
+ writeFileSync38(filePath, JSON.stringify(seed), { mode: 384 });
97839
98081
  chmodSync16(filePath, 384);
97840
98082
  return filePath;
97841
98083
  }
@@ -97993,8 +98235,8 @@ function registerDriveMcpLauncherCommand(program3) {
97993
98235
  // src/cli/m365-mcp-launcher.ts
97994
98236
  init_scaffold_integration();
97995
98237
  import { spawn as spawn6 } from "node:child_process";
97996
- import { writeFileSync as writeFileSync38, mkdirSync as mkdirSync54 } from "node:fs";
97997
- 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";
97998
98240
  var SOFTERIA_TOKEN_ENV = "MS365_MCP_OAUTH_TOKEN";
97999
98241
  var DEFAULT_REFRESH_LEAD_MS = 5 * 60 * 1000;
98000
98242
  var MAX_REFRESH_INTERVAL_MS = 60 * 60 * 1000;
@@ -98030,8 +98272,8 @@ function computeRefreshDelayMs(expiresAt, now, leadMs = DEFAULT_REFRESH_LEAD_MS)
98030
98272
  function writeRefreshHeartbeat(agentName, data, account) {
98031
98273
  const path10 = heartbeatPath(agentName, account);
98032
98274
  try {
98033
- mkdirSync54(dirname38(path10), { recursive: true });
98034
- 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 });
98035
98277
  } catch {}
98036
98278
  }
98037
98279
  function heartbeatPath(agentName, account) {
@@ -98271,8 +98513,8 @@ function registerM365McpLauncherCommand(program3) {
98271
98513
  // src/cli/notion-mcp-launcher.ts
98272
98514
  init_scaffold_integration();
98273
98515
  import { spawn as spawn7 } from "node:child_process";
98274
- import { existsSync as existsSync96, mkdirSync as mkdirSync55, writeFileSync as writeFileSync39 } from "node:fs";
98275
- 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";
98276
98518
  var HEARTBEAT_WRITE_INTERVAL_MS = 30 * 1000;
98277
98519
  var DEFAULT_HEARTBEAT_PATH = "/state/agent/notion-launcher.heartbeat.json";
98278
98520
  var DEFAULT_VAULT_KEY = "notion/integration-token";
@@ -98282,10 +98524,10 @@ function buildNotionMcpArgs(opts) {
98282
98524
  }
98283
98525
  function defaultWriteHeartbeat(path10, contents) {
98284
98526
  try {
98285
- const dir = dirname39(path10);
98286
- if (!existsSync96(dir))
98287
- mkdirSync55(dir, { recursive: true });
98288
- writeFileSync39(path10, contents);
98527
+ const dir = dirname40(path10);
98528
+ if (!existsSync97(dir))
98529
+ mkdirSync56(dir, { recursive: true });
98530
+ writeFileSync40(path10, contents);
98289
98531
  } catch {}
98290
98532
  }
98291
98533
  async function runNotionMcpLauncher(opts, runtime) {
@@ -98394,7 +98636,7 @@ function registerNotionMcpLauncherCommand(program3) {
98394
98636
  }
98395
98637
 
98396
98638
  // src/cli/hindsight-mcp-shim.ts
98397
- 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";
98398
98640
  import { tmpdir as tmpdir5 } from "node:os";
98399
98641
  import { join as join99 } from "node:path";
98400
98642
  import { createInterface as createInterface6 } from "node:readline";
@@ -98846,18 +99088,18 @@ class HindsightShim {
98846
99088
  }
98847
99089
  writeCache(result) {
98848
99090
  try {
98849
- mkdirSync56(this.opts.cacheDir, { recursive: true });
99091
+ mkdirSync57(this.opts.cacheDir, { recursive: true });
98850
99092
  const tmp = join99(this.opts.cacheDir, `.${TOOLS_CACHE_FILENAME}.${process.pid}.tmp`);
98851
- writeFileSync40(tmp, JSON.stringify(result, null, 2) + `
99093
+ writeFileSync41(tmp, JSON.stringify(result, null, 2) + `
98852
99094
  `);
98853
- renameSync24(tmp, this.cachePath);
99095
+ renameSync25(tmp, this.cachePath);
98854
99096
  } catch (err) {
98855
99097
  this.log(`[hindsight-shim] cache write failed: ${String(err)}`);
98856
99098
  }
98857
99099
  }
98858
99100
  readCache() {
98859
99101
  try {
98860
- const parsed = JSON.parse(readFileSync85(this.cachePath, "utf-8"));
99102
+ const parsed = JSON.parse(readFileSync86(this.cachePath, "utf-8"));
98861
99103
  if (Array.isArray(parsed.tools))
98862
99104
  return parsed;
98863
99105
  return null;
@@ -99090,7 +99332,7 @@ function registerHindsightMcpShimCommand(program3) {
99090
99332
 
99091
99333
  // src/cli/deliver-file.ts
99092
99334
  init_client2();
99093
- import { readFileSync as readFileSync86, statSync as statSync52 } from "node:fs";
99335
+ import { readFileSync as readFileSync87, statSync as statSync52 } from "node:fs";
99094
99336
  import { basename as basename13 } from "node:path";
99095
99337
 
99096
99338
  // src/delivery/onedrive.ts
@@ -99430,7 +99672,7 @@ async function defaultResolveProvider() {
99430
99672
  async function runDeliverFile(localPath, deps = {}) {
99431
99673
  const agentName = safeAgentName(deps.agentName ?? process.env.SWITCHROOM_AGENT_NAME);
99432
99674
  const sizeOf = deps.fileSize ?? ((p) => statSync52(p).size);
99433
- const read = deps.readFile ?? ((p) => new Uint8Array(readFileSync86(p)));
99675
+ const read = deps.readFile ?? ((p) => new Uint8Array(readFileSync87(p)));
99434
99676
  const resolveProvider = deps.resolveProvider ?? defaultResolveProvider;
99435
99677
  let size;
99436
99678
  try {
@@ -99751,7 +99993,7 @@ function runRedactStdin() {
99751
99993
  }
99752
99994
 
99753
99995
  // src/cli/status-ask.ts
99754
- 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";
99755
99997
  import { join as join100 } from "node:path";
99756
99998
  import { homedir as homedir53 } from "node:os";
99757
99999
 
@@ -100027,7 +100269,7 @@ function runReport(opts) {
100027
100269
  for (const src of sources) {
100028
100270
  let content;
100029
100271
  try {
100030
- content = readFileSync87(src.path, "utf-8");
100272
+ content = readFileSync88(src.path, "utf-8");
100031
100273
  } catch (err) {
100032
100274
  process.stderr.write(`status-ask report: cannot read ${src.path}: ${err instanceof Error ? err.message : String(err)}
100033
100275
  `);
@@ -100074,7 +100316,7 @@ function runReport(opts) {
100074
100316
  function resolveSources(explicitPath) {
100075
100317
  if (explicitPath != null && explicitPath.trim() !== "") {
100076
100318
  const trimmed = explicitPath.trim();
100077
- if (!existsSync97(trimmed)) {
100319
+ if (!existsSync98(trimmed)) {
100078
100320
  process.stderr.write(`status-ask report: ${trimmed}: file not found
100079
100321
  `);
100080
100322
  process.exit(1);
@@ -100090,7 +100332,7 @@ function resolveSources(explicitPath) {
100090
100332
  } catch {
100091
100333
  agentsDir = join100(homedir53(), ".switchroom", "agents");
100092
100334
  }
100093
- if (!existsSync97(agentsDir))
100335
+ if (!existsSync98(agentsDir))
100094
100336
  return [];
100095
100337
  const sources = [];
100096
100338
  let entries;
@@ -100101,7 +100343,7 @@ function resolveSources(explicitPath) {
100101
100343
  }
100102
100344
  for (const name of entries) {
100103
100345
  const path10 = join100(agentsDir, name, "runtime-metrics.jsonl");
100104
- if (existsSync97(path10)) {
100346
+ if (existsSync98(path10)) {
100105
100347
  sources.push({ path: path10, agent: name });
100106
100348
  }
100107
100349
  }
@@ -100131,13 +100373,13 @@ var import_yaml21 = __toESM(require_dist(), 1);
100131
100373
  init_paths();
100132
100374
  import {
100133
100375
  closeSync as closeSync18,
100134
- existsSync as existsSync98,
100376
+ existsSync as existsSync99,
100135
100377
  fsyncSync as fsyncSync8,
100136
- mkdirSync as mkdirSync57,
100378
+ mkdirSync as mkdirSync58,
100137
100379
  openSync as openSync18,
100138
100380
  readdirSync as readdirSync35,
100139
- readFileSync as readFileSync88,
100140
- renameSync as renameSync25,
100381
+ readFileSync as readFileSync89,
100382
+ renameSync as renameSync26,
100141
100383
  statSync as statSync53,
100142
100384
  unlinkSync as unlinkSync20,
100143
100385
  writeSync as writeSync10
@@ -100161,15 +100403,15 @@ function overlayPathsFor(agent, opts = {}) {
100161
100403
  };
100162
100404
  }
100163
100405
  function ensureDirs(paths) {
100164
- mkdirSync57(paths.scheduleDir, { recursive: true });
100165
- mkdirSync57(paths.scheduleStagingDir, { recursive: true });
100406
+ mkdirSync58(paths.scheduleDir, { recursive: true });
100407
+ mkdirSync58(paths.scheduleStagingDir, { recursive: true });
100166
100408
  }
100167
100409
  function ensureSkillsDirs(paths) {
100168
- mkdirSync57(paths.skillsDir, { recursive: true });
100169
- mkdirSync57(paths.skillsStagingDir, { recursive: true });
100410
+ mkdirSync58(paths.skillsDir, { recursive: true });
100411
+ mkdirSync58(paths.skillsStagingDir, { recursive: true });
100170
100412
  }
100171
100413
  function withAgentLock(paths, fn) {
100172
- mkdirSync57(paths.agentRoot, { recursive: true });
100414
+ mkdirSync58(paths.agentRoot, { recursive: true });
100173
100415
  const start = Date.now();
100174
100416
  const TIMEOUT_MS = 5000;
100175
100417
  let fd = null;
@@ -100219,7 +100461,7 @@ function writeOverlayEntry(agent, slug, yamlText, opts = {}) {
100219
100461
  } finally {
100220
100462
  closeSync18(fd);
100221
100463
  }
100222
- renameSync25(stagingPath, finalPath);
100464
+ renameSync26(stagingPath, finalPath);
100223
100465
  return finalPath;
100224
100466
  });
100225
100467
  }
@@ -100236,7 +100478,7 @@ function writeSkillsOverlayEntry(agent, slug, yamlText, opts = {}) {
100236
100478
  } finally {
100237
100479
  closeSync18(fd);
100238
100480
  }
100239
- renameSync25(stagingPath, finalPath);
100481
+ renameSync26(stagingPath, finalPath);
100240
100482
  return finalPath;
100241
100483
  });
100242
100484
  }
@@ -100244,7 +100486,7 @@ function deleteSkillsOverlayEntry(agent, slug, opts = {}) {
100244
100486
  const paths = overlayPathsFor(agent, opts);
100245
100487
  return withAgentLock(paths, () => {
100246
100488
  const finalPath = join101(paths.skillsDir, `${slug}.yaml`);
100247
- if (!existsSync98(finalPath))
100489
+ if (!existsSync99(finalPath))
100248
100490
  return false;
100249
100491
  unlinkSync20(finalPath);
100250
100492
  return true;
@@ -100252,7 +100494,7 @@ function deleteSkillsOverlayEntry(agent, slug, opts = {}) {
100252
100494
  }
100253
100495
  function listSkillsOverlayEntries(agent, opts = {}) {
100254
100496
  const paths = overlayPathsFor(agent, opts);
100255
- if (!existsSync98(paths.skillsDir))
100497
+ if (!existsSync99(paths.skillsDir))
100256
100498
  return [];
100257
100499
  const out = [];
100258
100500
  for (const name of readdirSync35(paths.skillsDir)) {
@@ -100260,7 +100502,7 @@ function listSkillsOverlayEntries(agent, opts = {}) {
100260
100502
  continue;
100261
100503
  const full = join101(paths.skillsDir, name);
100262
100504
  try {
100263
- const raw = readFileSync88(full, "utf-8");
100505
+ const raw = readFileSync89(full, "utf-8");
100264
100506
  const slug = name.replace(/\.ya?ml$/i, "");
100265
100507
  out.push({ slug, path: full, raw });
100266
100508
  } catch {}
@@ -100271,7 +100513,7 @@ function deleteOverlayEntry(agent, slug, opts = {}) {
100271
100513
  const paths = overlayPathsFor(agent, opts);
100272
100514
  return withAgentLock(paths, () => {
100273
100515
  const finalPath = join101(paths.scheduleDir, `${slug}.yaml`);
100274
- if (!existsSync98(finalPath))
100516
+ if (!existsSync99(finalPath))
100275
100517
  return false;
100276
100518
  unlinkSync20(finalPath);
100277
100519
  return true;
@@ -100279,7 +100521,7 @@ function deleteOverlayEntry(agent, slug, opts = {}) {
100279
100521
  }
100280
100522
  function listOverlayEntries(agent, opts = {}) {
100281
100523
  const paths = overlayPathsFor(agent, opts);
100282
- if (!existsSync98(paths.scheduleDir))
100524
+ if (!existsSync99(paths.scheduleDir))
100283
100525
  return [];
100284
100526
  const out = [];
100285
100527
  for (const name of readdirSync35(paths.scheduleDir)) {
@@ -100287,7 +100529,7 @@ function listOverlayEntries(agent, opts = {}) {
100287
100529
  continue;
100288
100530
  const full = join101(paths.scheduleDir, name);
100289
100531
  try {
100290
- const raw = readFileSync88(full, "utf-8");
100532
+ const raw = readFileSync89(full, "utf-8");
100291
100533
  const slug = name.replace(/\.ya?ml$/i, "");
100292
100534
  out.push({ slug, path: full, raw });
100293
100535
  } catch {}
@@ -100507,15 +100749,15 @@ function reconcileAgentCronOnly(agent) {
100507
100749
  // src/cli/agent-config-pending.ts
100508
100750
  import {
100509
100751
  closeSync as closeSync19,
100510
- existsSync as existsSync99,
100752
+ existsSync as existsSync100,
100511
100753
  fsyncSync as fsyncSync9,
100512
- mkdirSync as mkdirSync58,
100754
+ mkdirSync as mkdirSync59,
100513
100755
  openSync as openSync19,
100514
100756
  readdirSync as readdirSync36,
100515
- readFileSync as readFileSync89,
100516
- renameSync as renameSync26,
100757
+ readFileSync as readFileSync90,
100758
+ renameSync as renameSync27,
100517
100759
  unlinkSync as unlinkSync21,
100518
- writeFileSync as writeFileSync41,
100760
+ writeFileSync as writeFileSync42,
100519
100761
  writeSync as writeSync11
100520
100762
  } from "node:fs";
100521
100763
  import { join as join102 } from "node:path";
@@ -100527,7 +100769,7 @@ function pendingDir(agent, opts = {}) {
100527
100769
  }
100528
100770
  function ensurePendingDir(agent, opts = {}) {
100529
100771
  const dir = pendingDir(agent, opts);
100530
- mkdirSync58(dir, { recursive: true });
100772
+ mkdirSync59(dir, { recursive: true });
100531
100773
  return dir;
100532
100774
  }
100533
100775
  function newStageId() {
@@ -100556,15 +100798,15 @@ function stagePendingScheduleEntry(opts) {
100556
100798
  } finally {
100557
100799
  closeSync19(fd);
100558
100800
  }
100559
- renameSync26(yamlTmp, yamlPath);
100801
+ renameSync27(yamlTmp, yamlPath);
100560
100802
  }
100561
- writeFileSync41(metaPath, JSON.stringify(meta, null, 2) + `
100803
+ writeFileSync42(metaPath, JSON.stringify(meta, null, 2) + `
100562
100804
  `, { mode: 384 });
100563
100805
  return { stageId, yamlPath, metaPath };
100564
100806
  }
100565
100807
  function listPendingScheduleEntries(agent, opts = {}) {
100566
100808
  const dir = pendingDir(agent, opts);
100567
- if (!existsSync99(dir))
100809
+ if (!existsSync100(dir))
100568
100810
  return [];
100569
100811
  const out = [];
100570
100812
  for (const name of readdirSync36(dir).sort()) {
@@ -100573,10 +100815,10 @@ function listPendingScheduleEntries(agent, opts = {}) {
100573
100815
  const stageId = name.slice(0, -".meta.json".length);
100574
100816
  const metaPath = join102(dir, name);
100575
100817
  const yamlPath = join102(dir, `${stageId}.yaml`);
100576
- if (!existsSync99(yamlPath))
100818
+ if (!existsSync100(yamlPath))
100577
100819
  continue;
100578
100820
  try {
100579
- const meta = JSON.parse(readFileSync89(metaPath, "utf-8"));
100821
+ const meta = JSON.parse(readFileSync90(metaPath, "utf-8"));
100580
100822
  if (meta?.v !== 1 || typeof meta.stage_id !== "string")
100581
100823
  continue;
100582
100824
  out.push({ stageId: meta.stage_id, agent: meta.agent, yamlPath, metaPath, meta });
@@ -100592,10 +100834,10 @@ function commitPendingScheduleEntry(opts) {
100592
100834
  const slug = match.meta.entry.name ?? match.stageId;
100593
100835
  const paths = overlayPathsFor(opts.agent, { root: opts.root });
100594
100836
  const finalPath = join102(paths.scheduleDir, `${slug}.yaml`);
100595
- if (existsSync99(finalPath)) {
100837
+ if (existsSync100(finalPath)) {
100596
100838
  return { committed: false, reason: "slug_collision" };
100597
100839
  }
100598
- renameSync26(match.yamlPath, finalPath);
100840
+ renameSync27(match.yamlPath, finalPath);
100599
100841
  unlinkSync21(match.metaPath);
100600
100842
  return { committed: true, path: finalPath, slug };
100601
100843
  }
@@ -100614,7 +100856,7 @@ function denyPendingScheduleEntry(opts) {
100614
100856
  }
100615
100857
 
100616
100858
  // src/cli/agent-config-write.ts
100617
- import { existsSync as existsSync100, readFileSync as readFileSync90 } from "node:fs";
100859
+ import { existsSync as existsSync101, readFileSync as readFileSync91 } from "node:fs";
100618
100860
  import { execFileSync as execFileSync30 } from "node:child_process";
100619
100861
 
100620
100862
  // src/scheduler/schedule-report.ts
@@ -101004,8 +101246,8 @@ function scheduleRemove(opts) {
101004
101246
  }
101005
101247
  let priorContent = null;
101006
101248
  try {
101007
- if (existsSync100(match.path))
101008
- priorContent = readFileSync90(match.path, "utf-8");
101249
+ if (existsSync101(match.path))
101250
+ priorContent = readFileSync91(match.path, "utf-8");
101009
101251
  } catch {}
101010
101252
  deleteOverlayEntry(agent, match.slug, { root: opts.root });
101011
101253
  const reconcileFn = opts.reconcile === undefined ? opts.root ? null : reconcileAgentCronOnly : opts.reconcile;
@@ -101208,7 +101450,7 @@ function registerAgentConfigWriteCommands(program3) {
101208
101450
  }
101209
101451
  let blob;
101210
101452
  if (opts.jsonl) {
101211
- blob = existsSync100(opts.jsonl) ? readFileSync90(opts.jsonl, "utf-8") : "";
101453
+ blob = existsSync101(opts.jsonl) ? readFileSync91(opts.jsonl, "utf-8") : "";
101212
101454
  } else {
101213
101455
  try {
101214
101456
  blob = execFileSync30("docker", ["exec", `switchroom-${agent}`, "cat", "/state/agent/scheduler.jsonl"], {
@@ -101240,7 +101482,7 @@ function registerAgentConfigWriteCommands(program3) {
101240
101482
 
101241
101483
  // src/cli/agent-config-skill-write.ts
101242
101484
  var import_yaml22 = __toESM(require_dist(), 1);
101243
- import { existsSync as existsSync101 } from "node:fs";
101485
+ import { existsSync as existsSync102 } from "node:fs";
101244
101486
  init_reconcile_default_skills();
101245
101487
  init_agent_config();
101246
101488
  var import_yaml23 = __toESM(require_dist(), 1);
@@ -101320,7 +101562,7 @@ function skillInstall(opts) {
101320
101562
  }
101321
101563
  const poolDir = opts.bundledSkillsPoolDir ?? getBundledSkillsPoolDir();
101322
101564
  const skillPath = join103(poolDir, skillName);
101323
- if (!existsSync101(skillPath)) {
101565
+ if (!existsSync102(skillPath)) {
101324
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.`);
101325
101567
  }
101326
101568
  const yamlText = import_yaml22.stringify({ skills: [skillName] });
@@ -101484,22 +101726,22 @@ function registerAgentConfigSkillWriteCommands(program3) {
101484
101726
  // src/cli/skill.ts
101485
101727
  import {
101486
101728
  closeSync as closeSync20,
101487
- existsSync as existsSync102,
101729
+ existsSync as existsSync103,
101488
101730
  lstatSync as lstatSync12,
101489
- mkdirSync as mkdirSync59,
101731
+ mkdirSync as mkdirSync60,
101490
101732
  mkdtempSync as mkdtempSync5,
101491
101733
  openSync as openSync20,
101492
- readFileSync as readFileSync91,
101734
+ readFileSync as readFileSync92,
101493
101735
  readdirSync as readdirSync37,
101494
101736
  realpathSync as realpathSync7,
101495
- renameSync as renameSync27,
101737
+ renameSync as renameSync28,
101496
101738
  rmSync as rmSync19,
101497
101739
  statSync as statSync54,
101498
- writeFileSync as writeFileSync42
101740
+ writeFileSync as writeFileSync43
101499
101741
  } from "node:fs";
101500
101742
  import { tmpdir as tmpdir6, homedir as homedir54 } from "node:os";
101501
- import { dirname as dirname40, join as join104, relative as relative4, resolve as resolve58 } from "node:path";
101502
- 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";
101503
101745
 
101504
101746
  // src/cli/skill-common.ts
101505
101747
  var import_yaml24 = __toESM(require_dist(), 1);
@@ -101782,7 +102024,7 @@ function loadFromDir(dir) {
101782
102024
  continue;
101783
102025
  }
101784
102026
  if (ent.isFile()) {
101785
- const buf = readFileSync91(full);
102027
+ const buf = readFileSync92(full);
101786
102028
  files[rel.replace(/\\/g, "/")] = buf.toString("utf-8");
101787
102029
  }
101788
102030
  }
@@ -101793,7 +102035,7 @@ function loadFromDir(dir) {
101793
102035
  function loadFromTarball(tarPath) {
101794
102036
  const isGz = tarPath.endsWith(".gz") || tarPath.endsWith(".tgz");
101795
102037
  const listFlags = isGz ? ["-tzf"] : ["-tf"];
101796
- const list2 = spawnSync20("tar", [...listFlags, tarPath], {
102038
+ const list2 = spawnSync21("tar", [...listFlags, tarPath], {
101797
102039
  encoding: "utf-8",
101798
102040
  stdio: ["ignore", "pipe", "pipe"]
101799
102041
  });
@@ -101810,7 +102052,7 @@ function loadFromTarball(tarPath) {
101810
102052
  const staging = mkdtempSync5(join104(tmpdir6(), "skill-apply-extract-"));
101811
102053
  try {
101812
102054
  const flags = isGz ? ["-xzf"] : ["-xf"];
101813
- const r = spawnSync20("tar", [
102055
+ const r = spawnSync21("tar", [
101814
102056
  ...flags,
101815
102057
  tarPath,
101816
102058
  "-C",
@@ -101831,7 +102073,7 @@ function loadFromTarball(tarPath) {
101831
102073
  }
101832
102074
  }
101833
102075
  function loadSingleFile(filePath) {
101834
- const content = readFileSync91(filePath, "utf-8");
102076
+ const content = readFileSync92(filePath, "utf-8");
101835
102077
  return { "SKILL.md": content };
101836
102078
  }
101837
102079
  function loadFromStdin() {
@@ -101885,7 +102127,7 @@ function validatePayload(name, files) {
101885
102127
  if (errors2.length === 0) {
101886
102128
  for (const [path10, content] of Object.entries(files)) {
101887
102129
  if (SH_SCRIPT_RE2.test(path10)) {
101888
- const r = spawnSync20("bash", ["-n"], {
102130
+ const r = spawnSync21("bash", ["-n"], {
101889
102131
  input: content,
101890
102132
  encoding: "utf-8"
101891
102133
  });
@@ -101896,8 +102138,8 @@ function validatePayload(name, files) {
101896
102138
  const tmp = mkdtempSync5(join104(tmpdir6(), "skill-apply-py-"));
101897
102139
  const tmpPy = join104(tmp, "check.py");
101898
102140
  try {
101899
- writeFileSync42(tmpPy, content);
101900
- const r = spawnSync20("python3", ["-m", "py_compile", tmpPy], {
102141
+ writeFileSync43(tmpPy, content);
102142
+ const r = spawnSync21("python3", ["-m", "py_compile", tmpPy], {
101901
102143
  encoding: "utf-8"
101902
102144
  });
101903
102145
  if (r.status !== 0) {
@@ -101914,7 +102156,7 @@ function validatePayload(name, files) {
101914
102156
  function diffSummary(currentDir, files) {
101915
102157
  const lines = [];
101916
102158
  const currentFiles = {};
101917
- if (existsSync102(currentDir)) {
102159
+ if (existsSync103(currentDir)) {
101918
102160
  const walk2 = (sub) => {
101919
102161
  for (const ent of readdirSync37(sub, { withFileTypes: true })) {
101920
102162
  const full = join104(sub, ent.name);
@@ -101922,7 +102164,7 @@ function diffSummary(currentDir, files) {
101922
102164
  if (ent.isDirectory()) {
101923
102165
  walk2(full);
101924
102166
  } else if (ent.isFile()) {
101925
- currentFiles[rel.replace(/\\/g, "/")] = readFileSync91(full, "utf-8");
102167
+ currentFiles[rel.replace(/\\/g, "/")] = readFileSync92(full, "utf-8");
101926
102168
  }
101927
102169
  }
101928
102170
  };
@@ -101950,8 +102192,8 @@ function diffSummary(currentDir, files) {
101950
102192
  `);
101951
102193
  }
101952
102194
  function writePayload(poolDir, name, files) {
101953
- if (!existsSync102(poolDir)) {
101954
- mkdirSync59(poolDir, { recursive: true, mode: 493 });
102195
+ if (!existsSync103(poolDir)) {
102196
+ mkdirSync60(poolDir, { recursive: true, mode: 493 });
101955
102197
  }
101956
102198
  const target = join104(poolDir, name);
101957
102199
  let targetIsSymlink = false;
@@ -101969,10 +102211,10 @@ function writePayload(poolDir, name, files) {
101969
102211
  try {
101970
102212
  for (const [path10, content] of Object.entries(files)) {
101971
102213
  const full = join104(staging, path10);
101972
- mkdirSync59(dirname40(full), { recursive: true, mode: 493 });
102214
+ mkdirSync60(dirname41(full), { recursive: true, mode: 493 });
101973
102215
  const fd = openSync20(full, "wx");
101974
102216
  try {
101975
- writeFileSync42(fd, content);
102217
+ writeFileSync43(fd, content);
101976
102218
  } finally {
101977
102219
  closeSync20(fd);
101978
102220
  }
@@ -101988,9 +102230,9 @@ function writePayload(poolDir, name, files) {
101988
102230
  } catch {}
101989
102231
  if (targetExists) {
101990
102232
  oldRename = `${target}.skill-apply-old-${Date.now()}`;
101991
- renameSync27(target, oldRename);
102233
+ renameSync28(target, oldRename);
101992
102234
  }
101993
- renameSync27(staging, target);
102235
+ renameSync28(staging, target);
101994
102236
  if (oldRename) {
101995
102237
  rmSync19(oldRename, { recursive: true, force: true });
101996
102238
  oldRename = null;
@@ -101999,12 +102241,12 @@ function writePayload(poolDir, name, files) {
101999
102241
  try {
102000
102242
  rmSync19(staging, { recursive: true, force: true });
102001
102243
  } catch {}
102002
- if (oldRename && existsSync102(oldRename)) {
102244
+ if (oldRename && existsSync103(oldRename)) {
102003
102245
  try {
102004
- if (existsSync102(target)) {
102246
+ if (existsSync103(target)) {
102005
102247
  rmSync19(target, { recursive: true, force: true });
102006
102248
  }
102007
- renameSync27(oldRename, target);
102249
+ renameSync28(oldRename, target);
102008
102250
  } catch {}
102009
102251
  }
102010
102252
  throw err2;
@@ -102022,7 +102264,7 @@ function registerSkillCommand(program3) {
102022
102264
  files = loadFromStdin();
102023
102265
  } else {
102024
102266
  const fromPath = resolve58(opts.from);
102025
- if (!existsSync102(fromPath)) {
102267
+ if (!existsSync103(fromPath)) {
102026
102268
  fail4(`--from path does not exist: ${opts.from}`);
102027
102269
  }
102028
102270
  const st = statSync54(fromPath);
@@ -102060,7 +102302,7 @@ function registerSkillCommand(program3) {
102060
102302
  \u2713 Wrote ${name} to ${currentDir}`));
102061
102303
  const self = selfInvokeArgv(["apply", "--non-interactive"]);
102062
102304
  console.log(source_default.gray(`Running \`switchroom apply --non-interactive\`...`));
102063
- const r = spawnSync20(self.command, self.argv, { stdio: "inherit" });
102305
+ const r = spawnSync21(self.command, self.argv, { stdio: "inherit" });
102064
102306
  if (r.status !== 0) {
102065
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.)`));
102066
102308
  }
@@ -102078,22 +102320,22 @@ function sumBytes(files) {
102078
102320
  init_esm();
102079
102321
  import {
102080
102322
  closeSync as closeSync21,
102081
- existsSync as existsSync103,
102323
+ existsSync as existsSync104,
102082
102324
  lstatSync as lstatSync13,
102083
- mkdirSync as mkdirSync60,
102325
+ mkdirSync as mkdirSync61,
102084
102326
  mkdtempSync as mkdtempSync6,
102085
102327
  openSync as openSync21,
102086
- readFileSync as readFileSync92,
102328
+ readFileSync as readFileSync93,
102087
102329
  readdirSync as readdirSync38,
102088
- renameSync as renameSync28,
102330
+ renameSync as renameSync29,
102089
102331
  rmSync as rmSync20,
102090
102332
  statSync as statSync55,
102091
102333
  utimesSync,
102092
- writeFileSync as writeFileSync43
102334
+ writeFileSync as writeFileSync44
102093
102335
  } from "node:fs";
102094
- 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";
102095
102337
  import { homedir as homedir55, tmpdir as tmpdir7 } from "node:os";
102096
- import { spawnSync as spawnSync21 } from "node:child_process";
102338
+ import { spawnSync as spawnSync22 } from "node:child_process";
102097
102339
  init_helpers();
102098
102340
  init_agent_config();
102099
102341
  init_source();
@@ -102104,14 +102346,14 @@ var PERSONAL_SKILLS_SUBPATH = "personal-skills";
102104
102346
  function resolveConfigSkillsDir(agent) {
102105
102347
  const override = process.env.SWITCHROOM_CONFIG_DIR;
102106
102348
  const candidate = override ? resolve59(override) : join105(homedir55(), ".switchroom-config");
102107
- if (!existsSync103(candidate))
102349
+ if (!existsSync104(candidate))
102108
102350
  return null;
102109
102351
  return join105(candidate, "agents", agent, PERSONAL_SKILLS_SUBPATH);
102110
102352
  }
102111
102353
  var MIRROR_PRIOR_TTL_MS = 24 * 60 * 60 * 1000;
102112
102354
  function sweepMirrorPriors(configSkillsRoot) {
102113
102355
  try {
102114
- if (!existsSync103(configSkillsRoot))
102356
+ if (!existsSync104(configSkillsRoot))
102115
102357
  return;
102116
102358
  const now = Date.now();
102117
102359
  for (const ent of readdirSync38(configSkillsRoot)) {
@@ -102147,17 +102389,17 @@ function mirrorToConfigRepo(agent, name, liveSkillDir) {
102147
102389
  }
102148
102390
  if (liveSkillDir === null) {
102149
102391
  sweepMirrorPriors(configSkillsRoot);
102150
- if (existsSync103(dest)) {
102392
+ if (existsSync104(dest)) {
102151
102393
  const trash = join105(configSkillsRoot, `.${name}-trash-${Date.now()}`);
102152
- renameSync28(dest, trash);
102394
+ renameSync29(dest, trash);
102153
102395
  }
102154
102396
  return;
102155
102397
  }
102156
- mkdirSync60(configSkillsRoot, { recursive: true, mode: 493 });
102398
+ mkdirSync61(configSkillsRoot, { recursive: true, mode: 493 });
102157
102399
  sweepMirrorPriors(configSkillsRoot);
102158
102400
  const staging = mkdtempSync6(join105(configSkillsRoot, `.${name}-staging-`));
102159
102401
  const walk2 = (src, dst) => {
102160
- mkdirSync60(dst, { recursive: true, mode: 493 });
102402
+ mkdirSync61(dst, { recursive: true, mode: 493 });
102161
102403
  for (const ent of readdirSync38(src, { withFileTypes: true })) {
102162
102404
  const s = join105(src, ent.name);
102163
102405
  const d = join105(dst, ent.name);
@@ -102166,16 +102408,16 @@ function mirrorToConfigRepo(agent, name, liveSkillDir) {
102166
102408
  if (ent.isDirectory())
102167
102409
  walk2(s, d);
102168
102410
  else if (ent.isFile()) {
102169
- writeFileSync43(d, readFileSync92(s));
102411
+ writeFileSync44(d, readFileSync93(s));
102170
102412
  }
102171
102413
  }
102172
102414
  };
102173
102415
  walk2(liveSkillDir, staging);
102174
- if (existsSync103(dest)) {
102416
+ if (existsSync104(dest)) {
102175
102417
  const prior = join105(configSkillsRoot, `.${name}-prior-${Date.now()}`);
102176
- renameSync28(dest, prior);
102418
+ renameSync29(dest, prior);
102177
102419
  }
102178
- renameSync28(staging, dest);
102420
+ renameSync29(staging, dest);
102179
102421
  } catch (err2) {
102180
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.
102181
102423
  `));
@@ -102212,7 +102454,7 @@ function trashDir(agentsRoot, agent) {
102212
102454
  }
102213
102455
  function countPersonalSkills(agentsRoot, agent) {
102214
102456
  const skillsDir = join105(agentsRoot, agent, ".claude", "skills");
102215
- if (!existsSync103(skillsDir))
102457
+ if (!existsSync104(skillsDir))
102216
102458
  return 0;
102217
102459
  let n = 0;
102218
102460
  for (const ent of readdirSync38(skillsDir, { withFileTypes: true })) {
@@ -102259,7 +102501,7 @@ function loadFromDir2(dir) {
102259
102501
  }
102260
102502
  if (ent.isFile()) {
102261
102503
  const rel = relative5(abs, full).replace(/\\/g, "/");
102262
- files[rel] = readFileSync92(full, "utf-8");
102504
+ files[rel] = readFileSync93(full, "utf-8");
102263
102505
  }
102264
102506
  }
102265
102507
  };
@@ -102297,7 +102539,7 @@ function behavioralValidate(files) {
102297
102539
  const errors2 = [];
102298
102540
  for (const [path10, content] of Object.entries(files)) {
102299
102541
  if (SH_SCRIPT_RE.test(path10)) {
102300
- const r = spawnSync21("bash", ["-n"], { input: content, encoding: "utf-8" });
102542
+ const r = spawnSync22("bash", ["-n"], { input: content, encoding: "utf-8" });
102301
102543
  if (r.status !== 0) {
102302
102544
  errors2.push(`${path10} fails \`bash -n\`: ${(r.stderr ?? "").trim()}`);
102303
102545
  }
@@ -102305,8 +102547,8 @@ function behavioralValidate(files) {
102305
102547
  const tmp = mkdtempSync6(join105(tmpdir7(), "skill-personal-py-"));
102306
102548
  const tmpPy = join105(tmp, "check.py");
102307
102549
  try {
102308
- writeFileSync43(tmpPy, content);
102309
- const r = spawnSync21("python3", ["-m", "py_compile", tmpPy], {
102550
+ writeFileSync44(tmpPy, content);
102551
+ const r = spawnSync22("python3", ["-m", "py_compile", tmpPy], {
102310
102552
  encoding: "utf-8"
102311
102553
  });
102312
102554
  if (r.status !== 0) {
@@ -102321,7 +102563,7 @@ function behavioralValidate(files) {
102321
102563
  }
102322
102564
  function sweepTrash(agentsRoot, agent) {
102323
102565
  const trash = trashDir(agentsRoot, agent);
102324
- if (!existsSync103(trash))
102566
+ if (!existsSync104(trash))
102325
102567
  return;
102326
102568
  const now = Date.now();
102327
102569
  for (const ent of readdirSync38(trash, { withFileTypes: true })) {
@@ -102347,16 +102589,16 @@ function writePersonalSkill(targetDir, files) {
102347
102589
  if (targetIsSymlink) {
102348
102590
  fail5(`refusing to overwrite symlink at ${targetDir}; investigate manually`);
102349
102591
  }
102350
- mkdirSync60(dirname41(targetDir), { recursive: true, mode: 493 });
102351
- 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-`));
102352
102594
  let oldRename = null;
102353
102595
  try {
102354
102596
  for (const [path10, content] of Object.entries(files)) {
102355
102597
  const full = join105(staging, path10);
102356
- mkdirSync60(dirname41(full), { recursive: true, mode: 493 });
102598
+ mkdirSync61(dirname42(full), { recursive: true, mode: 493 });
102357
102599
  const fd = openSync21(full, "wx");
102358
102600
  try {
102359
- writeFileSync43(fd, content);
102601
+ writeFileSync44(fd, content);
102360
102602
  } finally {
102361
102603
  closeSync21(fd);
102362
102604
  }
@@ -102372,9 +102614,9 @@ function writePersonalSkill(targetDir, files) {
102372
102614
  } catch {}
102373
102615
  if (targetExists) {
102374
102616
  oldRename = `${targetDir}.personal-old-${Date.now()}`;
102375
- renameSync28(targetDir, oldRename);
102617
+ renameSync29(targetDir, oldRename);
102376
102618
  }
102377
- renameSync28(staging, targetDir);
102619
+ renameSync29(staging, targetDir);
102378
102620
  if (oldRename) {
102379
102621
  rmSync20(oldRename, { recursive: true, force: true });
102380
102622
  oldRename = null;
@@ -102383,12 +102625,12 @@ function writePersonalSkill(targetDir, files) {
102383
102625
  try {
102384
102626
  rmSync20(staging, { recursive: true, force: true });
102385
102627
  } catch {}
102386
- if (oldRename && existsSync103(oldRename)) {
102628
+ if (oldRename && existsSync104(oldRename)) {
102387
102629
  try {
102388
- if (existsSync103(targetDir)) {
102630
+ if (existsSync104(targetDir)) {
102389
102631
  rmSync20(targetDir, { recursive: true, force: true });
102390
102632
  }
102391
- renameSync28(oldRename, targetDir);
102633
+ renameSync29(oldRename, targetDir);
102392
102634
  } catch {}
102393
102635
  }
102394
102636
  throw err2;
@@ -102451,7 +102693,7 @@ function loadFiles(opts) {
102451
102693
  return loadFromStdin2();
102452
102694
  }
102453
102695
  const p = resolve59(opts.from);
102454
- if (!existsSync103(p)) {
102696
+ if (!existsSync104(p)) {
102455
102697
  fail5(`--from path does not exist: ${opts.from}`);
102456
102698
  }
102457
102699
  const st = statSync55(p);
@@ -102459,7 +102701,7 @@ function loadFiles(opts) {
102459
102701
  return loadFromDir2(p);
102460
102702
  }
102461
102703
  if (p.endsWith(".md")) {
102462
- return { "SKILL.md": readFileSync92(p, "utf-8") };
102704
+ return { "SKILL.md": readFileSync93(p, "utf-8") };
102463
102705
  }
102464
102706
  fail5(`--from must be a directory or a .md file. Got: ${opts.from}`);
102465
102707
  }
@@ -102513,7 +102755,7 @@ function resolveCloneSource(source, opts) {
102513
102755
  const slug = m[2];
102514
102756
  const root = tier === "bundled" ? opts.bundledRoot ?? defaultBundledRoot() : opts.sharedRoot ?? defaultSharedRoot();
102515
102757
  const dir = join105(root, slug);
102516
- if (!existsSync103(dir)) {
102758
+ if (!existsSync104(dir)) {
102517
102759
  fail5(`clone source ${JSON.stringify(source)} not found at ${dir}; ` + `check \`switchroom skill search --tier ${tier}\``, 1);
102518
102760
  }
102519
102761
  const st = lstatSync13(dir);
@@ -102548,7 +102790,7 @@ function readSourceFiles(dir) {
102548
102790
  fail5(`clone source has oversized file ${rel} (${st.size} bytes > ${CLONE_MAX_FILE_BYTES}); ` + `refuse to read`, 3);
102549
102791
  }
102550
102792
  } catch {}
102551
- files[rel] = readFileSync92(full, "utf-8");
102793
+ files[rel] = readFileSync93(full, "utf-8");
102552
102794
  }
102553
102795
  }
102554
102796
  };
@@ -102637,10 +102879,10 @@ function removePersonalAction(name, opts) {
102637
102879
  throw err2;
102638
102880
  }
102639
102881
  const trashRoot2 = trashDir(agentsRoot, agent);
102640
- mkdirSync60(trashRoot2, { recursive: true, mode: 493 });
102882
+ mkdirSync61(trashRoot2, { recursive: true, mode: 493 });
102641
102883
  const ts = Date.now();
102642
102884
  const trashTarget = join105(trashRoot2, `${name}-${ts}`);
102643
- renameSync28(target, trashTarget);
102885
+ renameSync29(target, trashTarget);
102644
102886
  const now = new Date(ts);
102645
102887
  utimesSync(trashTarget, now, now);
102646
102888
  mirrorToConfigRepo(agent, name, null);
@@ -102660,7 +102902,7 @@ function listPersonalAction(opts) {
102660
102902
  sweepTrash(agentsRoot, agent);
102661
102903
  const skillsDir = join105(agentsRoot, agent, ".claude", "skills");
102662
102904
  const personal = [];
102663
- if (existsSync103(skillsDir)) {
102905
+ if (existsSync104(skillsDir)) {
102664
102906
  for (const ent of readdirSync38(skillsDir, { withFileTypes: true })) {
102665
102907
  if (!ent.isDirectory())
102666
102908
  continue;
@@ -102718,7 +102960,7 @@ function registerSkillPersonalCommands(program3) {
102718
102960
  import { createConnection as createConnection4 } from "node:net";
102719
102961
  import { homedir as homedir56 } from "node:os";
102720
102962
  import { join as join106 } from "node:path";
102721
- import { readFileSync as readFileSync93 } from "node:fs";
102963
+ import { readFileSync as readFileSync94 } from "node:fs";
102722
102964
  var IPC_CONNECT_TIMEOUT_MS = 5000;
102723
102965
  function gatewaySocketPath() {
102724
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"));
@@ -102756,7 +102998,7 @@ function registerSelfImproveProposeSkillCommand(program3) {
102756
102998
  fail6("agent name required (--agent or $SWITCHROOM_AGENT_NAME)");
102757
102999
  let draft;
102758
103000
  try {
102759
- draft = JSON.parse(readFileSync93(opts.draft, "utf-8"));
103001
+ draft = JSON.parse(readFileSync94(opts.draft, "utf-8"));
102760
103002
  } catch (e) {
102761
103003
  fail6(`failed to read/parse --draft: ${e.message}`);
102762
103004
  }
@@ -102793,7 +103035,7 @@ function registerSelfImproveProposeSkillCommand(program3) {
102793
103035
  init_esm();
102794
103036
  init_helpers();
102795
103037
  var import_yaml25 = __toESM(require_dist(), 1);
102796
- 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";
102797
103039
  import { homedir as homedir57 } from "node:os";
102798
103040
  import { join as join107, resolve as resolve60 } from "node:path";
102799
103041
  var PERSONAL_PREFIX2 = "personal-";
@@ -102810,11 +103052,11 @@ function defaultBundledRoot2() {
102810
103052
  }
102811
103053
  function readSkillFrontmatter(skillDir) {
102812
103054
  const mdPath = join107(skillDir, "SKILL.md");
102813
- if (!existsSync104(mdPath))
103055
+ if (!existsSync105(mdPath))
102814
103056
  return null;
102815
103057
  let content;
102816
103058
  try {
102817
- content = readFileSync94(mdPath, "utf-8");
103059
+ content = readFileSync95(mdPath, "utf-8");
102818
103060
  } catch {
102819
103061
  return null;
102820
103062
  }
@@ -102854,7 +103096,7 @@ function listPersonalSkills(agent, agentsRoot = defaultAgentsRoot()) {
102854
103096
  if (!AGENT_NAME_RE3.test(agent))
102855
103097
  return [];
102856
103098
  const skillsDir = join107(agentsRoot, agent, ".claude/skills");
102857
- if (!existsSync104(skillsDir))
103099
+ if (!existsSync105(skillsDir))
102858
103100
  return [];
102859
103101
  const out = [];
102860
103102
  let entries;
@@ -102892,7 +103134,7 @@ function listPersonalSkills(agent, agentsRoot = defaultAgentsRoot()) {
102892
103134
  return out;
102893
103135
  }
102894
103136
  function listSharedSkills(sharedRoot = defaultSharedRoot2()) {
102895
- if (!existsSync104(sharedRoot))
103137
+ if (!existsSync105(sharedRoot))
102896
103138
  return [];
102897
103139
  const out = [];
102898
103140
  let entries;
@@ -102930,7 +103172,7 @@ function listSharedSkills(sharedRoot = defaultSharedRoot2()) {
102930
103172
  return out;
102931
103173
  }
102932
103174
  function listBundledSkills(bundledRoot = defaultBundledRoot2()) {
102933
- if (!existsSync104(bundledRoot))
103175
+ if (!existsSync105(bundledRoot))
102934
103176
  return [];
102935
103177
  const out = [];
102936
103178
  let entries;
@@ -103088,10 +103330,10 @@ init_source();
103088
103330
  init_helpers();
103089
103331
  init_operator_uid();
103090
103332
  import {
103091
- existsSync as existsSync106,
103092
- mkdirSync as mkdirSync61,
103333
+ existsSync as existsSync107,
103334
+ mkdirSync as mkdirSync62,
103093
103335
  readdirSync as readdirSync40,
103094
- writeFileSync as writeFileSync44,
103336
+ writeFileSync as writeFileSync45,
103095
103337
  statSync as statSync57,
103096
103338
  lstatSync as lstatSync14,
103097
103339
  realpathSync as realpathSync8,
@@ -103099,13 +103341,13 @@ import {
103099
103341
  } from "node:fs";
103100
103342
  import { homedir as homedir58 } from "node:os";
103101
103343
  import { join as join108 } from "node:path";
103102
- import { spawnSync as spawnSync24 } from "node:child_process";
103344
+ import { spawnSync as spawnSync25 } from "node:child_process";
103103
103345
 
103104
103346
  // src/cli/singleton-stale-cleanup.ts
103105
- import { spawnSync as spawnSync23 } from "node:child_process";
103347
+ import { spawnSync as spawnSync24 } from "node:child_process";
103106
103348
  function makeDockerRunner() {
103107
103349
  return (args) => {
103108
- const r = spawnSync23("docker", args, { encoding: "utf8" });
103350
+ const r = spawnSync24("docker", args, { encoding: "utf8" });
103109
103351
  return {
103110
103352
  ok: r.status === 0,
103111
103353
  stdout: r.stdout ?? "",
@@ -103464,7 +103706,7 @@ function resolveHostdSkillsTarget(hostHome) {
103464
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.`);
103465
103707
  return;
103466
103708
  }
103467
- if (!existsSync106(target)) {
103709
+ if (!existsSync107(target)) {
103468
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.`);
103469
103711
  return;
103470
103712
  }
@@ -103478,7 +103720,7 @@ function hostdComposePath() {
103478
103720
  }
103479
103721
  function backupExistingCompose() {
103480
103722
  const p = hostdComposePath();
103481
- if (!existsSync106(p))
103723
+ if (!existsSync107(p))
103482
103724
  return null;
103483
103725
  const ts = new Date().toISOString().replace(/[:.]/g, "-");
103484
103726
  const bak = `${p}.bak-${ts}`;
@@ -103486,7 +103728,7 @@ function backupExistingCompose() {
103486
103728
  return bak;
103487
103729
  }
103488
103730
  function runDocker(args) {
103489
- const r = spawnSync24("docker", args, { encoding: "utf8" });
103731
+ const r = spawnSync25("docker", args, { encoding: "utf8" });
103490
103732
  return {
103491
103733
  ok: r.status === 0,
103492
103734
  stdout: r.stdout ?? "",
@@ -103511,7 +103753,7 @@ async function doInstall(opts, program3) {
103511
103753
  }
103512
103754
  const dir = hostdDir();
103513
103755
  const composePath = hostdComposePath();
103514
- mkdirSync61(dir, { recursive: true });
103756
+ mkdirSync62(dir, { recursive: true });
103515
103757
  const imageTag = resolveHostdImageTag(opts.tag, cfg.release);
103516
103758
  const guard = checkDowngrade({
103517
103759
  container: "switchroom-hostd",
@@ -103544,7 +103786,7 @@ async function doInstall(opts, program3) {
103544
103786
  const bak = backupExistingCompose();
103545
103787
  if (bak)
103546
103788
  console.log(source_default.dim(` Backed up existing compose to ${bak}`));
103547
- writeFileSync44(composePath, yaml, "utf8");
103789
+ writeFileSync45(composePath, yaml, "utf8");
103548
103790
  console.log(source_default.green(` \u2713 Wrote ${composePath}`));
103549
103791
  const adminAgents = Object.entries(cfg.agents ?? {}).filter(([, a]) => a?.admin === true).map(([name]) => name);
103550
103792
  console.log(source_default.dim(` agents served (one socket each): ${allAgents.length === 0 ? "(none)" : allAgents.join(", ")}`));
@@ -103576,7 +103818,7 @@ function doStatus() {
103576
103818
  const composeYml = hostdComposePath();
103577
103819
  console.log(source_default.bold("switchroom-hostd"));
103578
103820
  console.log("");
103579
- if (!existsSync106(composeYml)) {
103821
+ if (!existsSync107(composeYml)) {
103580
103822
  console.log(source_default.yellow(" compose: not installed"));
103581
103823
  console.log(source_default.dim(" run `switchroom hostd install` to set up."));
103582
103824
  return;
@@ -103597,14 +103839,14 @@ function doStatus() {
103597
103839
  } else {
103598
103840
  console.log(source_default.green(` container: ${ps.stdout.trim()}`));
103599
103841
  }
103600
- if (existsSync106(dir)) {
103842
+ if (existsSync107(dir)) {
103601
103843
  const entries = [];
103602
103844
  try {
103603
103845
  for (const name of readdirSync40(dir)) {
103604
103846
  if (name === "docker-compose.yml" || name.startsWith("docker-compose.yml."))
103605
103847
  continue;
103606
103848
  const sockPath = join108(dir, name, "sock");
103607
- if (existsSync106(sockPath)) {
103849
+ if (existsSync107(sockPath)) {
103608
103850
  const st = statSync57(sockPath);
103609
103851
  if ((st.mode & 61440) === 49152) {
103610
103852
  entries.push(`${name} \u2192 ${sockPath}`);
@@ -103623,7 +103865,7 @@ function doStatus() {
103623
103865
  }
103624
103866
  function doUninstall() {
103625
103867
  const composeYml = hostdComposePath();
103626
- if (!existsSync106(composeYml)) {
103868
+ if (!existsSync107(composeYml)) {
103627
103869
  console.log(source_default.yellow(" No hostd install detected (no compose file at this path)."));
103628
103870
  return;
103629
103871
  }
@@ -103647,7 +103889,7 @@ function registerHostdCommand(program3) {
103647
103889
  hostd.command("uninstall").description("Stop the hostd container. Leaves the compose file in place for re-install.").action(() => doUninstall());
103648
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) => {
103649
103891
  const logPath = opts.path ?? defaultAuditLogPath2();
103650
- if (!existsSync106(logPath)) {
103892
+ if (!existsSync107(logPath)) {
103651
103893
  console.error(source_default.yellow(`Audit log not found at ${logPath}.`) + source_default.gray(`
103652
103894
  The log is created when hostd handles its first privileged-verb request.`));
103653
103895
  return;
@@ -103696,10 +103938,10 @@ init_source();
103696
103938
  init_helpers();
103697
103939
  init_operator_uid();
103698
103940
  init_compose();
103699
- 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";
103700
103942
  import { homedir as homedir59 } from "node:os";
103701
103943
  import { join as join109 } from "node:path";
103702
- import { spawnSync as spawnSync25 } from "node:child_process";
103944
+ import { spawnSync as spawnSync26 } from "node:child_process";
103703
103945
  function resolveWebImageTag(explicitTag, release) {
103704
103946
  if (explicitTag)
103705
103947
  return explicitTag;
@@ -103807,7 +104049,7 @@ function webdComposePath() {
103807
104049
  }
103808
104050
  function backupExistingCompose2() {
103809
104051
  const p = webdComposePath();
103810
- if (!existsSync107(p))
104052
+ if (!existsSync108(p))
103811
104053
  return null;
103812
104054
  const ts = new Date().toISOString().replace(/[:.]/g, "-");
103813
104055
  const bak = `${p}.bak-${ts}`;
@@ -103815,7 +104057,7 @@ function backupExistingCompose2() {
103815
104057
  return bak;
103816
104058
  }
103817
104059
  function runDocker2(args) {
103818
- const r = spawnSync25("docker", args, { encoding: "utf8" });
104060
+ const r = spawnSync26("docker", args, { encoding: "utf8" });
103819
104061
  return {
103820
104062
  ok: r.status === 0,
103821
104063
  stdout: r.stdout ?? "",
@@ -103838,7 +104080,7 @@ async function doInstall2(opts, program3) {
103838
104080
  }
103839
104081
  const dir = webdDir();
103840
104082
  const composePath = webdComposePath();
103841
- mkdirSync62(dir, { recursive: true });
104083
+ mkdirSync63(dir, { recursive: true });
103842
104084
  const cfg = getConfig(program3);
103843
104085
  const imageTag = resolveWebImageTag(opts.tag, cfg.release);
103844
104086
  const port = cfg.web_service?.port ?? 8080;
@@ -103873,7 +104115,7 @@ async function doInstall2(opts, program3) {
103873
104115
  const bak = backupExistingCompose2();
103874
104116
  if (bak)
103875
104117
  console.log(source_default.dim(` Backed up existing compose to ${bak}`));
103876
- writeFileSync45(composePath, yaml, "utf8");
104118
+ writeFileSync46(composePath, yaml, "utf8");
103877
104119
  try {
103878
104120
  if (typeof process.geteuid === "function" && process.geteuid() === 0) {
103879
104121
  chownSync10(dir, operatorUid, operatorUid);
@@ -103915,7 +104157,7 @@ function doStatus2() {
103915
104157
  const composeYml = webdComposePath();
103916
104158
  console.log(source_default.bold("switchroom-web"));
103917
104159
  console.log("");
103918
- if (!existsSync107(composeYml)) {
104160
+ if (!existsSync108(composeYml)) {
103919
104161
  console.log(source_default.yellow(" compose: not installed"));
103920
104162
  console.log(source_default.dim(" run `switchroom webd install` to set up."));
103921
104163
  return;
@@ -103939,7 +104181,7 @@ function doStatus2() {
103939
104181
  }
103940
104182
  function doUninstall2() {
103941
104183
  const composeYml = webdComposePath();
103942
- if (!existsSync107(composeYml)) {
104184
+ if (!existsSync108(composeYml)) {
103943
104185
  console.log(source_default.yellow(" No web-service install detected (no compose file at this path)."));
103944
104186
  return;
103945
104187
  }
@@ -104214,13 +104456,13 @@ init_helpers();
104214
104456
  init_scan();
104215
104457
 
104216
104458
  // src/fleet-health/gh-sync.ts
104217
- import { spawnSync as spawnSync26 } from "node:child_process";
104459
+ import { spawnSync as spawnSync27 } from "node:child_process";
104218
104460
  var LABEL = "fleet-health";
104219
104461
  function defaultGhDeps(log) {
104220
104462
  return {
104221
104463
  log,
104222
104464
  run: (args) => {
104223
- const r = spawnSync26("gh", args, { encoding: "utf-8" });
104465
+ const r = spawnSync27("gh", args, { encoding: "utf-8" });
104224
104466
  return {
104225
104467
  ok: r.status === 0,
104226
104468
  stdout: (r.stdout ?? "").trim(),
@@ -104425,7 +104667,7 @@ function printDeepDiveBrief(targets) {
104425
104667
 
104426
104668
  // src/cli/hindsight-watch.ts
104427
104669
  init_source();
104428
- import { existsSync as existsSync112, readdirSync as readdirSync45 } from "node:fs";
104670
+ import { existsSync as existsSync113, readdirSync as readdirSync45 } from "node:fs";
104429
104671
  import { homedir as homedir63 } from "node:os";
104430
104672
  import { join as join112, resolve as resolve63 } from "node:path";
104431
104673
 
@@ -104495,8 +104737,8 @@ function postOperatorNoticeViaGateways(candidates, text, log, connectTimeoutMs =
104495
104737
  init_install_cron();
104496
104738
 
104497
104739
  // src/hindsight-watch/probe.ts
104498
- import { spawnSync as spawnSync27 } from "node:child_process";
104499
- 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";
104500
104742
  import { homedir as homedir62 } from "node:os";
104501
104743
  import { resolve as resolve62 } from "node:path";
104502
104744
 
@@ -104624,7 +104866,7 @@ function readLlmSignals(series) {
104624
104866
  }
104625
104867
 
104626
104868
  // src/hindsight-watch/recall-log.ts
104627
- 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";
104628
104870
  import { join as join111 } from "node:path";
104629
104871
  var RECALL_WINDOW_ROWS = 200;
104630
104872
  var RECALL_MAX_TAIL_BYTES = 1024 * 1024;
@@ -104633,7 +104875,7 @@ function recallLogPath2(agentDir) {
104633
104875
  return join111(agentDir, ".claude", "plugins", "data", "hindsight-memory-inline", "state", "recall_log.jsonl");
104634
104876
  }
104635
104877
  function readRecallLogTail2(path10, windowRows = RECALL_WINDOW_ROWS) {
104636
- if (!existsSync111(path10))
104878
+ if (!existsSync112(path10))
104637
104879
  return [];
104638
104880
  let text;
104639
104881
  let truncatedHead = false;
@@ -104845,7 +105087,7 @@ async function probeMetrics(url = DEFAULT_METRICS_URL, fetchImpl = fetch) {
104845
105087
  }
104846
105088
  }
104847
105089
  var defaultRunner4 = (cmd, args) => {
104848
- const r = spawnSync27(cmd, args, { stdio: "pipe", timeout: 1e4, encoding: "utf8" });
105090
+ const r = spawnSync28(cmd, args, { stdio: "pipe", timeout: 1e4, encoding: "utf8" });
104849
105091
  if (r.error)
104850
105092
  return { status: null, stdout: "", stderr: r.error.message };
104851
105093
  return { status: r.status, stdout: r.stdout ?? "", stderr: r.stderr ?? "" };
@@ -104873,7 +105115,7 @@ function readDropCount(hindsightDir) {
104873
105115
  try {
104874
105116
  if (statSync59(path10).size > DROPS_LEDGER_MAX_BYTES)
104875
105117
  return 0;
104876
- parsed = JSON.parse(readFileSync99(path10, "utf8"));
105118
+ parsed = JSON.parse(readFileSync100(path10, "utf8"));
104877
105119
  } catch {
104878
105120
  return 0;
104879
105121
  }
@@ -105312,7 +105554,7 @@ function latencySuffix(r) {
105312
105554
  return "";
105313
105555
  const n = typeof r.elapsedConsidered === "number" ? r.elapsedConsidered : 0;
105314
105556
  return `
105315
- recall wall time p95 ${Math.round(p95)}ms over ${n} fire(s) (not thresholded \u2014 the 8000ms per-bank budget leaves no healthy band below it)`;
105557
+ recall wall time p95 ${Math.round(p95)}ms over ${n} fire(s) (not thresholded \u2014 the ${RECALL_WALL_MS}ms recall deadline leaves no healthy band below it)`;
105316
105558
  }
105317
105559
  function evaluateRecallOwnBankTimeout(ring) {
105318
105560
  const signal = "recall-own-bank-timeout";
@@ -105911,14 +106153,25 @@ function runInstallCron(cronUser) {
105911
106153
  `);
105912
106154
  return 0;
105913
106155
  }
105914
- async function notifyOperator(agentsDir, text, log) {
106156
+ var PREFERRED_RELAY_AGENT = "overlord";
106157
+ function orderRelayCandidates(candidates, preferred = PREFERRED_RELAY_AGENT) {
106158
+ const first = candidates.filter((c) => c.agent === preferred);
106159
+ const rest = candidates.filter((c) => c.agent !== preferred);
106160
+ return [...first, ...rest];
106161
+ }
106162
+ function collectRelayCandidates(agentsDir) {
105915
106163
  const candidates = [];
106164
+ for (const name of readdirSync45(agentsDir).sort()) {
106165
+ const sock = resolve63(agentsDir, name, "telegram", "gateway.sock");
106166
+ if (existsSync113(sock))
106167
+ candidates.push({ agent: name, sock });
106168
+ }
106169
+ return orderRelayCandidates(candidates);
106170
+ }
106171
+ async function notifyOperator(agentsDir, text, log) {
106172
+ let candidates = [];
105916
106173
  try {
105917
- for (const name of readdirSync45(agentsDir).sort()) {
105918
- const sock = resolve63(agentsDir, name, "telegram", "gateway.sock");
105919
- if (existsSync112(sock))
105920
- candidates.push({ agent: name, sock });
105921
- }
106174
+ candidates = collectRelayCandidates(agentsDir);
105922
106175
  } catch (e) {
105923
106176
  log(`hindsight-watch: agents dir unreadable (${e.message})`);
105924
106177
  }
@@ -105932,13 +106185,13 @@ async function notifyOperator(agentsDir, text, log) {
105932
106185
 
105933
106186
  // src/cli/openrouter-watch.ts
105934
106187
  init_source();
105935
- import { existsSync as existsSync114, readdirSync as readdirSync46 } from "node:fs";
106188
+ import { existsSync as existsSync115, readdirSync as readdirSync46 } from "node:fs";
105936
106189
  import { homedir as homedir65 } from "node:os";
105937
106190
  import { join as join113, resolve as resolve65 } from "node:path";
105938
106191
 
105939
106192
  // src/openrouter/install-cron.ts
105940
- import { existsSync as existsSync113, mkdirSync as mkdirSync64, readFileSync as readFileSync100, renameSync as renameSync29, writeFileSync as writeFileSync47 } from "node:fs";
105941
- 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";
105942
106195
  var CRON_PATH2 = "/etc/cron.d/openrouter-watch";
105943
106196
  var CRON_SCHEDULE2 = "17 * * * *";
105944
106197
  var CRON_LOG_PATH2 = "/var/log/openrouter-watch.log";
@@ -105955,30 +106208,30 @@ function renderCron2(opts) {
105955
106208
  function installCron2(opts) {
105956
106209
  const path10 = opts.path ?? CRON_PATH2;
105957
106210
  const content = renderCron2(opts);
105958
- if (existsSync113(path10)) {
106211
+ if (existsSync114(path10)) {
105959
106212
  try {
105960
- if (readFileSync100(path10, "utf8") === content) {
106213
+ if (readFileSync101(path10, "utf8") === content) {
105961
106214
  return { status: "unchanged", path: path10, content };
105962
106215
  }
105963
106216
  } catch {}
105964
106217
  }
105965
- mkdirSync64(dirname43(path10), { recursive: true });
106218
+ mkdirSync65(dirname44(path10), { recursive: true });
105966
106219
  const tmp = `${path10}.${process.pid}.tmp`;
105967
- writeFileSync47(tmp, content, { mode: 420 });
105968
- renameSync29(tmp, path10);
106220
+ writeFileSync48(tmp, content, { mode: 420 });
106221
+ renameSync30(tmp, path10);
105969
106222
  return { status: "installed", path: path10, content };
105970
106223
  }
105971
106224
  // src/openrouter/state.ts
105972
- 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";
105973
106226
  import { homedir as homedir64 } from "node:os";
105974
- import { dirname as dirname44, resolve as resolve64 } from "node:path";
106227
+ import { dirname as dirname45, resolve as resolve64 } from "node:path";
105975
106228
  function defaultStatePath3(home2 = process.env.SWITCHROOM_HOME ?? process.env.HOME ?? homedir64()) {
105976
106229
  return resolve64(home2, ".switchroom", "openrouter-watch", "state.json");
105977
106230
  }
105978
106231
  function loadState2(path10) {
105979
106232
  let parsed;
105980
106233
  try {
105981
- parsed = JSON.parse(readFileSync101(path10, "utf8"));
106234
+ parsed = JSON.parse(readFileSync102(path10, "utf8"));
105982
106235
  } catch {
105983
106236
  return {};
105984
106237
  }
@@ -105998,12 +106251,12 @@ function loadState2(path10) {
105998
106251
  return out;
105999
106252
  }
106000
106253
  function saveState2(path10, state) {
106001
- mkdirSync65(dirname44(path10), { recursive: true, mode: 448 });
106254
+ mkdirSync66(dirname45(path10), { recursive: true, mode: 448 });
106002
106255
  const tmp = `${path10}.${process.pid}.tmp`;
106003
106256
  const payload = { v: 1, ...state };
106004
- writeFileSync48(tmp, JSON.stringify(payload, null, 2) + `
106257
+ writeFileSync49(tmp, JSON.stringify(payload, null, 2) + `
106005
106258
  `, { mode: 384 });
106006
- renameSync30(tmp, path10);
106259
+ renameSync31(tmp, path10);
106007
106260
  }
106008
106261
 
106009
106262
  // src/openrouter/watch.ts
@@ -106188,7 +106441,7 @@ async function notifyOperator2(agentsDir, text, log) {
106188
106441
  try {
106189
106442
  for (const name of readdirSync46(agentsDir).sort()) {
106190
106443
  const sock = resolve65(agentsDir, name, "telegram", "gateway.sock");
106191
- if (existsSync114(sock))
106444
+ if (existsSync115(sock))
106192
106445
  candidates.push({ agent: name, sock });
106193
106446
  }
106194
106447
  } catch (e) {