switchroom 0.21.0 → 0.21.3

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.21.0", COMMIT_SHA = "d8bd2d30";
2123
+ var VERSION = "0.21.3", COMMIT_SHA = "8a74c2f6";
2124
2124
 
2125
2125
  // src/cli/resolve-version.ts
2126
2126
  import { existsSync, readFileSync } from "node:fs";
@@ -63459,10 +63459,13 @@ function serializeStamp(stamp) {
63459
63459
  `;
63460
63460
  }
63461
63461
  function refreshHostCliStamp(input, io = {}) {
63462
+ const stamp = buildHostCliStamp(input, io);
63463
+ if (!stamp)
63464
+ return { status: "skipped", reason: "running in a container" };
63465
+ return writeHostCliStamp(stamp, io);
63466
+ }
63467
+ function writeHostCliStamp(stamp, io = {}) {
63462
63468
  try {
63463
- const stamp = buildHostCliStamp(input, io);
63464
- if (!stamp)
63465
- return { status: "skipped", reason: "running in a container" };
63466
63469
  const dir = resolveStampDir(io);
63467
63470
  if (!dir)
63468
63471
  return { status: "skipped", reason: "no switchroom home found" };
@@ -84740,10 +84743,10 @@ var init_test_agents = __esm(() => {
84740
84743
  });
84741
84744
 
84742
84745
  // src/litellm/header-passthrough-guard.ts
84743
- import { existsSync as existsSync124, readdirSync as readdirSync47 } from "node:fs";
84746
+ import { existsSync as existsSync124, readdirSync as readdirSync48 } from "node:fs";
84744
84747
  function discoverLiveLitellmConfigPath(opts) {
84745
84748
  const servicesDir = opts?.servicesDir ?? COOLIFY_SERVICES_DIR;
84746
- const readdir2 = opts?.readdirFn ?? ((p) => readdirSync47(p));
84749
+ const readdir2 = opts?.readdirFn ?? ((p) => readdirSync48(p));
84747
84750
  const exists = opts?.existsFn ?? existsSync124;
84748
84751
  let entries;
84749
84752
  try {
@@ -84964,7 +84967,7 @@ var init_passthrough_mount_guard = __esm(() => {
84964
84967
  // src/fleet-health/litellm-config-sensor.ts
84965
84968
  import { execFileSync as execFileSync35 } from "node:child_process";
84966
84969
  import { readFileSync as readFileSync111, existsSync as existsSync125 } from "node:fs";
84967
- import { dirname as dirname51, join as join126 } from "node:path";
84970
+ import { dirname as dirname52, join as join127 } from "node:path";
84968
84971
  function resolveLiveLitellmPythonVersion() {
84969
84972
  try {
84970
84973
  const ps = execFileSync35("docker", ["ps", "--format", "{{.Names}}\t{{.Image}}"], {
@@ -85048,7 +85051,7 @@ function scanLitellmConfig(opts = {}) {
85048
85051
  ts: nowIso
85049
85052
  });
85050
85053
  }
85051
- const composePath = join126(dirname51(path10), LIVE_COMPOSE_BASENAME);
85054
+ const composePath = join127(dirname52(path10), LIVE_COMPOSE_BASENAME);
85052
85055
  let composeText = null;
85053
85056
  if (exists(composePath)) {
85054
85057
  try {
@@ -85152,12 +85155,12 @@ __export(exports_scan, {
85152
85155
  });
85153
85156
  import {
85154
85157
  readFileSync as readFileSync112,
85155
- readdirSync as readdirSync48,
85158
+ readdirSync as readdirSync49,
85156
85159
  existsSync as existsSync126,
85157
85160
  mkdirSync as mkdirSync71,
85158
85161
  writeFileSync as writeFileSync53
85159
85162
  } from "node:fs";
85160
- import { resolve as resolve64, dirname as dirname52 } from "node:path";
85163
+ import { resolve as resolve64, dirname as dirname53 } from "node:path";
85161
85164
  import { homedir as homedir68 } from "node:os";
85162
85165
  function resolveSwitchroomBase(home2 = process.env.SWITCHROOM_HOME ?? process.env.HOME ?? homedir68()) {
85163
85166
  return resolve64(home2, ".switchroom");
@@ -85167,7 +85170,7 @@ function listAgents(base) {
85167
85170
  if (!existsSync126(dir))
85168
85171
  return [];
85169
85172
  try {
85170
- return readdirSync48(dir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name).sort();
85173
+ return readdirSync49(dir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name).sort();
85171
85174
  } catch {
85172
85175
  return [];
85173
85176
  }
@@ -85254,11 +85257,11 @@ function readLedgerIfPresent(base) {
85254
85257
  }
85255
85258
  }
85256
85259
  function ledgerPathForBase(base) {
85257
- return fleetHealthLedgerPath(dirname52(base));
85260
+ return fleetHealthLedgerPath(dirname53(base));
85258
85261
  }
85259
85262
  function writeLedger(base, ledger) {
85260
85263
  const path10 = ledgerPathForBase(base);
85261
- mkdirSync71(dirname52(path10), { recursive: true });
85264
+ mkdirSync71(dirname53(path10), { recursive: true });
85262
85265
  writeFileSync53(path10, JSON.stringify(ledger, null, 2) + `
85263
85266
  `, "utf-8");
85264
85267
  return path10;
@@ -116419,7 +116422,7 @@ function registerUpdateCommand(program3) {
116419
116422
  // src/cli/rollout.ts
116420
116423
  init_helpers();
116421
116424
  import { spawnSync as spawnSync22 } from "node:child_process";
116422
- import { readFileSync as readFileSync85, chownSync as chownSync12, statSync as statSync53 } from "node:fs";
116425
+ import { readFileSync as readFileSync85, chownSync as chownSync12, statSync as statSync54 } from "node:fs";
116423
116426
  import { homedir as homedir51 } from "node:os";
116424
116427
 
116425
116428
  // src/cli/rollout-pin-journal.ts
@@ -116633,6 +116636,353 @@ function recoverPinJournal(configPath, opts = {}) {
116633
116636
  // src/cli/rollout.ts
116634
116637
  init_operator_uid();
116635
116638
  init_host_cli_stamp();
116639
+
116640
+ // src/cli/host-cli-upgrade.ts
116641
+ init_self_update();
116642
+ import { lchownSync, lstatSync as lstatSync14, readdirSync as readdirSync32, statSync as statSync53 } from "node:fs";
116643
+ import { basename as basename10, dirname as dirname42, join as join96 } from "node:path";
116644
+ init_shipped_assets();
116645
+ var HOST_CLI_UPGRADE_SENTINEL = "SWITCHROOM_HOST_CLI_UPGRADE:";
116646
+ function encodeHostCliUpgradeResult(r) {
116647
+ return `${HOST_CLI_UPGRADE_SENTINEL}${JSON.stringify(r)}`;
116648
+ }
116649
+ function parseHostCliUpgradeResult(logs) {
116650
+ const lines = logs.split(`
116651
+ `);
116652
+ for (let i2 = lines.length - 1;i2 >= 0; i2--) {
116653
+ const line = lines[i2]?.trim() ?? "";
116654
+ if (!line.startsWith(HOST_CLI_UPGRADE_SENTINEL))
116655
+ continue;
116656
+ try {
116657
+ const o = JSON.parse(line.slice(HOST_CLI_UPGRADE_SENTINEL.length));
116658
+ if (typeof o !== "object" || o === null)
116659
+ return null;
116660
+ if (typeof o.ok !== "boolean")
116661
+ return null;
116662
+ return {
116663
+ ok: o.ok,
116664
+ ...typeof o.version === "string" ? { version: o.version } : {},
116665
+ ...typeof o.binaryPath === "string" ? { binaryPath: o.binaryPath } : {},
116666
+ ...typeof o.error === "string" ? { error: o.error } : {}
116667
+ };
116668
+ } catch {
116669
+ return null;
116670
+ }
116671
+ }
116672
+ return null;
116673
+ }
116674
+ var SEMVER_TAG_RE2 = /^v\d+\.\d+\.\d+$/;
116675
+ function defaultIo() {
116676
+ return {
116677
+ isFile: (p) => {
116678
+ try {
116679
+ return statSync53(p).isFile();
116680
+ } catch {
116681
+ return false;
116682
+ }
116683
+ },
116684
+ kind: (p) => {
116685
+ try {
116686
+ const st = lstatSync14(p);
116687
+ if (st.isSymbolicLink())
116688
+ return "symlink";
116689
+ if (st.isDirectory())
116690
+ return "dir";
116691
+ if (st.isFile())
116692
+ return "file";
116693
+ return "other";
116694
+ } catch {
116695
+ return;
116696
+ }
116697
+ },
116698
+ owner: (p) => {
116699
+ try {
116700
+ const st = lstatSync14(p);
116701
+ return { uid: st.uid, gid: st.gid };
116702
+ } catch {
116703
+ return;
116704
+ }
116705
+ },
116706
+ chown: (p, uid, gid) => lchownSync(p, uid, gid),
116707
+ list: (d) => {
116708
+ try {
116709
+ return readdirSync32(d);
116710
+ } catch {
116711
+ return [];
116712
+ }
116713
+ },
116714
+ selfUpdate: defaultSelfUpdateIO(),
116715
+ platform: process.platform,
116716
+ arch: process.arch,
116717
+ getuid: () => process.getuid?.()
116718
+ };
116719
+ }
116720
+ function handBackOwnership(paths, owner, io) {
116721
+ const failures = [];
116722
+ const seen = new Set;
116723
+ const stack = [...paths];
116724
+ while (stack.length > 0) {
116725
+ const p = stack.pop();
116726
+ if (p === undefined || seen.has(p))
116727
+ continue;
116728
+ seen.add(p);
116729
+ const kind = io.kind(p);
116730
+ if (kind === undefined)
116731
+ continue;
116732
+ try {
116733
+ io.chown(p, owner.uid, owner.gid);
116734
+ } catch (err) {
116735
+ failures.push(`${p}: ${err.message}`);
116736
+ }
116737
+ if (kind !== "dir")
116738
+ continue;
116739
+ for (const child of io.list(p))
116740
+ stack.push(join96(p, child));
116741
+ }
116742
+ return failures;
116743
+ }
116744
+ async function runHostCliUpgrade(opts, io = defaultIo(), log = () => {}) {
116745
+ const { binary, pin, from } = opts;
116746
+ if (!SEMVER_TAG_RE2.test(pin)) {
116747
+ return { ok: false, error: `--pin must be a vX.Y.Z release tag, got "${pin}"` };
116748
+ }
116749
+ if (!binary.startsWith("/")) {
116750
+ return { ok: false, error: `--binary must be an absolute path, got "${binary}"` };
116751
+ }
116752
+ if (basename10(binary) !== "switchroom") {
116753
+ return {
116754
+ ok: false,
116755
+ error: `--binary must name a file called \`switchroom\`, got ` + `"${basename10(binary)}" \u2014 refusing to overwrite an unrelated file.`
116756
+ };
116757
+ }
116758
+ if (!io.isFile(binary)) {
116759
+ return {
116760
+ ok: false,
116761
+ error: `${binary} is not an existing regular file \u2014 the host bindir is either ` + `not mounted or the recorded host CLI path is stale.`
116762
+ };
116763
+ }
116764
+ const asset = releaseAssetName(io.platform, io.arch);
116765
+ if (!asset) {
116766
+ return {
116767
+ ok: false,
116768
+ error: `no published binary for ${io.platform}/${io.arch}`
116769
+ };
116770
+ }
116771
+ const priorOwner = io.owner(binary);
116772
+ const handBack = () => {
116773
+ try {
116774
+ if (!priorOwner || priorOwner.uid === io.getuid())
116775
+ return;
116776
+ const installRoot = payloadInstallRoot(binary);
116777
+ const failures = handBackOwnership([
116778
+ binary,
116779
+ join96(dirname42(binary), ".switchroom-versions"),
116780
+ dirname42(installRoot),
116781
+ installRoot,
116782
+ payloadVersionDir(installRoot, pin)
116783
+ ], priorOwner, io);
116784
+ if (failures.length > 0) {
116785
+ log(`warning: could not hand ownership back to uid ${priorOwner.uid}: ` + `${failures.join("; ")}
116786
+ `);
116787
+ }
116788
+ } catch (err) {
116789
+ log(`warning: ownership handoff failed: ${err.message}
116790
+ `);
116791
+ }
116792
+ };
116793
+ try {
116794
+ let result;
116795
+ try {
116796
+ result = await performSelfUpdate({
116797
+ plan: {
116798
+ action: "update",
116799
+ from: `v${from.replace(/^v/, "")}`,
116800
+ to: pin,
116801
+ binaryPath: binary
116802
+ },
116803
+ assetName: asset,
116804
+ io: io.selfUpdate,
116805
+ log
116806
+ });
116807
+ } catch (err) {
116808
+ return { ok: false, error: err.message };
116809
+ }
116810
+ const proven = io.selfUpdate.probeBinaryVersion(binary);
116811
+ if (!proven || `v${proven.replace(/^v/, "")}` !== pin) {
116812
+ return {
116813
+ ok: false,
116814
+ error: `swapped ${binary} but it reports ${proven ?? "<nothing>"}, not ${pin} \u2014 ` + `the install did not land. ${result.message}`
116815
+ };
116816
+ }
116817
+ return { ok: true, version: pin, binaryPath: binary };
116818
+ } finally {
116819
+ handBack();
116820
+ }
116821
+ }
116822
+ function registerHostCliUpgradeCommand(program3) {
116823
+ program3.command("host-cli-upgrade").description("INTERNAL (#4585): replace a bind-mounted HOST switchroom binary with a " + "published release, checksum-verified. Spawned by rollout inside a " + "short-lived helper container; not for interactive use.").requiredOption("--binary <path>", "Path of the host binary to replace").requiredOption("--pin <version>", "Target release tag, vX.Y.Z").requiredOption("--from <version>", "Version currently installed").action(async (opts) => {
116824
+ const result = await runHostCliUpgrade(opts, defaultIo(), (s) => process.stderr.write(s.endsWith(`
116825
+ `) ? s : `${s}
116826
+ `));
116827
+ process.stdout.write(`${encodeHostCliUpgradeResult(result)}
116828
+ `);
116829
+ if (!result.ok) {
116830
+ process.stderr.write(`host-cli-upgrade failed: ${result.error}
116831
+ `);
116832
+ process.exitCode = 1;
116833
+ }
116834
+ });
116835
+ }
116836
+
116837
+ // src/cli/host-cli-heal.ts
116838
+ var HEAL_PREFIX_MOUNT = "/hostcli";
116839
+ var HEAL_HELPER_CONTAINER = "switchroom-hostcli-heal";
116840
+ var HOSTD_CONTAINER_NAME = "switchroom-hostd";
116841
+ var HOST_CLI_HEAL_TIMEOUT_MS = (() => {
116842
+ const raw = process.env.SWITCHROOM_HOST_CLI_HEAL_TIMEOUT_MS;
116843
+ const n = raw ? Number(raw) : NaN;
116844
+ return Number.isFinite(n) && n > 0 ? n : 10 * 60 * 1000;
116845
+ })();
116846
+ function planHostCliHeal(opts) {
116847
+ const { stamp, target, hostdCtx } = opts;
116848
+ if (!hostdCtx) {
116849
+ return {
116850
+ action: "skip",
116851
+ reason: "not running in hostd context \u2014 on the host shell the operator can run " + "the install command directly"
116852
+ };
116853
+ }
116854
+ if (!stamp)
116855
+ return { action: "skip", reason: "no host-cli.json stamp to act on" };
116856
+ if (!/^v\d+\.\d+\.\d+$/.test(target)) {
116857
+ return { action: "skip", reason: `target "${target}" is not a vX.Y.Z release tag` };
116858
+ }
116859
+ if (stamp.installKind !== "static-binary") {
116860
+ return {
116861
+ action: "skip",
116862
+ reason: `the host CLI is a ${stamp.installKind} install \u2014 only a static-binary ` + `install can be replaced by swapping one file, so an operator must run ` + `the upgrade host-side`
116863
+ };
116864
+ }
116865
+ const path7 = stamp.path;
116866
+ if (!path7.startsWith("/") || path7.includes("/..")) {
116867
+ return { action: "skip", reason: `recorded host CLI path "${path7}" is not a plain absolute path` };
116868
+ }
116869
+ const installDir = path7.slice(0, path7.lastIndexOf("/"));
116870
+ const name = path7.slice(path7.lastIndexOf("/") + 1);
116871
+ if (name !== "switchroom") {
116872
+ return { action: "skip", reason: `recorded host CLI path "${path7}" is not named \`switchroom\`` };
116873
+ }
116874
+ const prefixHostPath = installDir.slice(0, installDir.lastIndexOf("/"));
116875
+ const dirName = installDir.slice(installDir.lastIndexOf("/") + 1);
116876
+ if (prefixHostPath.length === 0 || dirName.length === 0) {
116877
+ return {
116878
+ action: "skip",
116879
+ reason: `recorded host CLI path "${path7}" has no install prefix to bind \u2014 ` + `refusing to mount the host root`
116880
+ };
116881
+ }
116882
+ return {
116883
+ action: "heal",
116884
+ prefixHostPath,
116885
+ containerBinaryPath: `${HEAL_PREFIX_MOUNT}/${dirName}/switchroom`,
116886
+ from: stamp.version,
116887
+ target
116888
+ };
116889
+ }
116890
+ function healHelperArgs(opts) {
116891
+ const { plan, helperImage } = opts;
116892
+ return [
116893
+ "run",
116894
+ "-d",
116895
+ "--name",
116896
+ opts.containerName ?? HEAL_HELPER_CONTAINER,
116897
+ "--label",
116898
+ "switchroom.hostcli-heal=true",
116899
+ "-v",
116900
+ `${plan.prefixHostPath}:${HEAL_PREFIX_MOUNT}:rw`,
116901
+ helperImage,
116902
+ "switchroom",
116903
+ "host-cli-upgrade",
116904
+ "--binary",
116905
+ plan.containerBinaryPath,
116906
+ "--pin",
116907
+ plan.target,
116908
+ "--from",
116909
+ plan.from
116910
+ ];
116911
+ }
116912
+ function resolveHelperImage(docker) {
116913
+ const r = docker(["inspect", "--format", "{{.Config.Image}}", HOSTD_CONTAINER_NAME]);
116914
+ if (!r.ok)
116915
+ return null;
116916
+ const ref = r.stdout.trim().split(`
116917
+ `)[0]?.trim() ?? "";
116918
+ return ref.length > 0 ? ref : null;
116919
+ }
116920
+ function runHostCliHeal(opts) {
116921
+ const { plan, docker } = opts;
116922
+ const name = opts.containerName ?? HEAL_HELPER_CONTAINER;
116923
+ const log = opts.log ?? (() => {});
116924
+ const image = resolveHelperImage(docker);
116925
+ if (!image) {
116926
+ return {
116927
+ ok: false,
116928
+ message: `could not resolve the image of the running \`${HOSTD_CONTAINER_NAME}\` ` + `container, so there is no image to run the upgrade helper from`
116929
+ };
116930
+ }
116931
+ docker(["rm", "-f", name]);
116932
+ log(`\u21bb host CLI ${plan.from} \u2192 ${plan.target}: running the upgrade helper ` + `(${image}, binding ${plan.prefixHostPath})
116933
+ `);
116934
+ const started = docker(healHelperArgs({ plan, helperImage: image, containerName: name }));
116935
+ if (!started.ok) {
116936
+ return {
116937
+ ok: false,
116938
+ message: `could not start the upgrade helper: ${oneLine(started.stderr) || "docker run failed"}`
116939
+ };
116940
+ }
116941
+ try {
116942
+ return waitForHelper(docker, name, plan);
116943
+ } catch (err) {
116944
+ return { ok: false, message: `the upgrade helper could not be waited on: ${err.message}` };
116945
+ } finally {
116946
+ try {
116947
+ docker(["rm", "-f", name]);
116948
+ } catch {}
116949
+ }
116950
+ }
116951
+ function waitForHelper(docker, name, plan) {
116952
+ const waited = docker(["wait", name]);
116953
+ const logs = docker(["logs", name]);
116954
+ const blob = `${logs.stdout}
116955
+ ${logs.stderr}`;
116956
+ const parsed = parseHostCliUpgradeResult(blob);
116957
+ if (!waited.ok) {
116958
+ return {
116959
+ ok: false,
116960
+ message: `waiting on the upgrade helper failed (${oneLine(waited.stderr) || "docker wait failed"})` + (parsed?.error ? `; helper reported: ${parsed.error}` : "")
116961
+ };
116962
+ }
116963
+ const code = waited.stdout.trim().split(`
116964
+ `).pop()?.trim() ?? "";
116965
+ if (code !== "0" || !parsed || !parsed.ok) {
116966
+ return {
116967
+ ok: false,
116968
+ message: `the upgrade helper exited ${code || "?"}: ` + (parsed?.error ?? (oneLine(blob) || "no diagnostic on stdout/stderr"))
116969
+ };
116970
+ }
116971
+ if (!parsed.version) {
116972
+ return { ok: false, message: "the upgrade helper reported success without a version" };
116973
+ }
116974
+ return {
116975
+ ok: true,
116976
+ version: parsed.version,
116977
+ message: `host CLI upgraded ${plan.from} \u2192 ${parsed.version} at ${plan.containerBinaryPath.replace(HEAL_PREFIX_MOUNT, plan.prefixHostPath)}`
116978
+ };
116979
+ }
116980
+ function oneLine(s) {
116981
+ const flat = s.replace(/\s+/g, " ").trim();
116982
+ return flat.length > 400 ? `${flat.slice(0, 397)}...` : flat;
116983
+ }
116984
+
116985
+ // src/cli/rollout.ts
116636
116986
  init_self_invoke();
116637
116987
  init_atomic();
116638
116988
 
@@ -117281,7 +117631,7 @@ function createRolloutDeps(params) {
117281
117631
  if (after === before)
117282
117632
  return false;
117283
117633
  beginPinPersist(configPath, pin);
117284
- writeConfigPreservingOwnership(configPath, after, statSync53(configPath).mode & 511);
117634
+ writeConfigPreservingOwnership(configPath, after, statSync54(configPath).mode & 511);
117285
117635
  return true;
117286
117636
  },
117287
117637
  commitPin: () => {
@@ -117309,8 +117659,21 @@ function createRolloutDeps(params) {
117309
117659
  } : {}
117310
117660
  };
117311
117661
  }
117312
- function registerRolloutCommand(program3) {
117662
+ function registerRolloutCommand(program3, testHooks) {
117313
117663
  const hostdCtx = isHostdContext2();
117664
+ const hostCliHealDocker = testHooks?.hostCliHealDocker;
117665
+ const defaultHostCliHealDocker = (args) => {
117666
+ try {
117667
+ const r = spawnSync22("docker", args, {
117668
+ encoding: "utf8",
117669
+ timeout: HOST_CLI_HEAL_TIMEOUT_MS,
117670
+ killSignal: ROLLOUT_KILL_SIGNAL
117671
+ });
117672
+ return { ok: r.status === 0, stdout: r.stdout ?? "", stderr: r.stderr ?? "" };
117673
+ } catch (err) {
117674
+ return { ok: false, stdout: "", stderr: err.message };
117675
+ }
117676
+ };
117314
117677
  program3.command("rollout").description("Deploy a pinned version to the fleet, safely (staggered restart + " + "per-agent version assert + web/hostd refresh)." + (hostdCtx ? "" : " Run with sudo.")).option("--pin <version>", "Version to roll (e.g. v0.15.18). Defaults to release.pin from config.").option("--agents <list>", "Comma-separated subset of agents to roll (default: all configured).").option("--skip-web", "Skip the web refresh (host-shell path: also the hostd + hindsight " + "refresh). On the hostd/agent path only the web refresh is skipped \u2014 " + "hindsight is still recreated and hostd stays deferred regardless.").option("--allow-downgrade", "Permit rolling to an older semver tag (operator-approved rollback path). " + "When set, the downgrade guard is relaxed so --pin may be older than the " + "current release.pin. All other safety rails apply unchanged.").option("--allow-stale-host-cli", "Roll the fleet even though the HOST operator CLI is observably behind " + "the target. Escape hatch for the host-CLI-first gate: the host CLI is " + "then left drifted and every later host-shell command runs old code. " + "HOST-SHELL ONLY: deliberately not exposed as an `mcp__hostd__rollout` " + "parameter, so an agent cannot roll past the gate on its own \u2014 " + "overriding requires the same host shell needed to actually fix it.").option("--dry-run", "Print the plan and exit without changing anything.").action(async (opts) => {
117315
117678
  if (!opts.dryRun) {
117316
117679
  const note = recoverPinJournal(getConfigPath(program3));
@@ -117360,29 +117723,6 @@ function registerRolloutCommand(program3) {
117360
117723
  process.exitCode = 2;
117361
117724
  return;
117362
117725
  }
117363
- const hostCliStamp = readHostCliStamp();
117364
- if (!opts.allowStaleHostCli && shouldRefuseStaleHostCli(hostCliStamp, target)) {
117365
- const observed = hostCliStamp?.version ?? "unknown";
117366
- const refusal = `rollout refused: the HOST operator CLI is v${observed}, OLDER than ` + `the target ${target}. The host CLI must be upgraded FIRST \u2014 it is ` + `what runs \`switchroom apply\`, \`vault\`, \`doctor\` and the next ` + `roll host-side, and leaving it behind is how it silently drifted ` + `five releases. Run this on the host, then re-run the roll: ` + `${hostCliInstallCommand(hostCliStamp, target)}. ` + `(Observed from ${HOST_CLI_STAMP_FILENAME}, refreshed by every ` + `host-context switchroom command \u2014 if you already upgraded, run any ` + `switchroom command on the host to refresh it, or pass ` + `--allow-stale-host-cli to roll anyway.) Nothing was changed.`;
117367
- process.stderr.write(refusal + `
117368
- `);
117369
- if (hostdCtx) {
117370
- process.stdout.write(encodeRolloutResultLine({
117371
- ok: false,
117372
- rolled: [],
117373
- failedStep: PREFLIGHT_HOST_CLI_STALE_STEP,
117374
- got: observed,
117375
- warnings: [refusal]
117376
- }) + `
117377
- `);
117378
- }
117379
- process.exitCode = 2;
117380
- return;
117381
- }
117382
- if (opts.allowStaleHostCli && shouldRefuseStaleHostCli(hostCliStamp, target)) {
117383
- process.stderr.write(`\u26a0\ufe0f --allow-stale-host-cli: rolling past a HOST operator CLI on ` + `v${hostCliStamp?.version} (target ${target}). Fix it host-side ` + `with: ${hostCliInstallCommand(hostCliStamp, target)}
117384
- `);
117385
- }
117386
117726
  if (shouldRefuseDowngrade(hostdCtx, resolvedPin, config.release?.pin, opts.allowDowngrade)) {
117387
117727
  const current = config.release?.pin;
117388
117728
  process.stderr.write(`rollout (hostd path) refuses a DOWNGRADE: ${resolvedPin} is older ` + `than the current pin ${current}. Pass --allow-downgrade to ` + `authorize an operator-approved rollback to a known-good earlier ` + `tag. Nothing was changed.
@@ -117410,6 +117750,63 @@ function registerRolloutCommand(program3) {
117410
117750
  process.exitCode = 2;
117411
117751
  return;
117412
117752
  }
117753
+ let hostCliStamp = readHostCliStamp();
117754
+ let healNote;
117755
+ let healDeferredByDryRun = false;
117756
+ if (!opts.allowStaleHostCli && shouldRefuseStaleHostCli(hostCliStamp, target)) {
117757
+ const plan = planHostCliHeal({ stamp: hostCliStamp, target, hostdCtx });
117758
+ if (plan.action === "skip") {
117759
+ healNote = `host CLI self-heal not attempted: ${plan.reason}.`;
117760
+ } else if (opts.dryRun) {
117761
+ healDeferredByDryRun = true;
117762
+ healNote = `would upgrade the HOST CLI ${plan.from} \u2192 ${plan.target} first, in a ` + `short-lived helper container binding ${plan.prefixHostPath}`;
117763
+ process.stdout.write(`\u21bb dry-run: ${healNote}
117764
+ `);
117765
+ } else {
117766
+ const outcome = runHostCliHeal({
117767
+ plan,
117768
+ docker: hostCliHealDocker ?? defaultHostCliHealDocker,
117769
+ log: (line) => process.stderr.write(line)
117770
+ });
117771
+ if (outcome.ok && outcome.version) {
117772
+ const updated = {
117773
+ ...hostCliStamp,
117774
+ version: outcome.version.replace(/^v/, "")
117775
+ };
117776
+ const w = writeHostCliStamp(updated, testHooks?.hostCliStampIo ?? {});
117777
+ hostCliStamp = updated;
117778
+ healNote = `${outcome.message}` + (w.status === "skipped" ? ` (proceeding on the PROVEN version; ${HOST_CLI_STAMP_FILENAME} ` + `could not be refreshed: ${w.reason} \u2014 the next roll will ` + `re-observe the old version and heal again)` : "");
117779
+ process.stderr.write(`\u2705 ${healNote}
117780
+ `);
117781
+ } else {
117782
+ healNote = `host CLI self-heal FAILED: ${outcome.message}.`;
117783
+ process.stderr.write(`\u26a0\ufe0f ${healNote}
117784
+ `);
117785
+ }
117786
+ }
117787
+ }
117788
+ if (!opts.allowStaleHostCli && !healDeferredByDryRun && shouldRefuseStaleHostCli(hostCliStamp, target)) {
117789
+ const observed = hostCliStamp?.version ?? "unknown";
117790
+ const refusal = `rollout refused: the HOST operator CLI is v${observed}, OLDER than ` + `the target ${target}. The host CLI must be upgraded FIRST \u2014 it is ` + `what runs \`switchroom apply\`, \`vault\`, \`doctor\` and the next ` + `roll host-side, and leaving it behind is how it silently drifted ` + `five releases. ` + (healNote ? `${healNote} ` : "") + `An operator must run this on the host, then re-run the roll: ` + `${hostCliInstallCommand(hostCliStamp, target)}. ` + `(Observed from ${HOST_CLI_STAMP_FILENAME}, refreshed by every ` + `host-context switchroom command \u2014 if you already upgraded, run any ` + `switchroom command on the host to refresh it, or pass ` + `--allow-stale-host-cli to roll anyway.) Nothing was changed.`;
117791
+ process.stderr.write(refusal + `
117792
+ `);
117793
+ if (hostdCtx) {
117794
+ process.stdout.write(encodeRolloutResultLine({
117795
+ ok: false,
117796
+ rolled: [],
117797
+ failedStep: PREFLIGHT_HOST_CLI_STALE_STEP,
117798
+ got: observed,
117799
+ warnings: [refusal]
117800
+ }) + `
117801
+ `);
117802
+ }
117803
+ process.exitCode = 2;
117804
+ return;
117805
+ }
117806
+ if (opts.allowStaleHostCli && shouldRefuseStaleHostCli(hostCliStamp, target)) {
117807
+ process.stderr.write(`\u26a0\ufe0f --allow-stale-host-cli: rolling past a HOST operator CLI on ` + `v${hostCliStamp?.version} (target ${target}). Fix it host-side ` + `with: ${hostCliInstallCommand(hostCliStamp, target)}
117808
+ `);
117809
+ }
117413
117810
  const steps = planRollout(requested, {
117414
117811
  skipWeb: opts.skipWeb,
117415
117812
  pinToPersist: resolvedPin ?? undefined,
@@ -117429,7 +117826,7 @@ function registerRolloutCommand(program3) {
117429
117826
  hindsightApiUrl = rawUrl ? rawUrl.replace(/\/mcp\/?$/, "").replace(/\/$/, "") : HINDSIGHT_DEFAULT_API_BASE_URL;
117430
117827
  resolveBankId = (agent) => config.agents?.[agent]?.memory?.collection ?? agent;
117431
117828
  }
117432
- const deps = createRolloutDeps({
117829
+ const deps = testHooks?.rolloutDeps ?? createRolloutDeps({
117433
117830
  configPath,
117434
117831
  scriptPath,
117435
117832
  hostdCtx,
@@ -117519,7 +117916,7 @@ init_lifecycle();
117519
117916
  init_resolve_version();
117520
117917
  import { execSync as execSync3 } from "node:child_process";
117521
117918
  import { existsSync as existsSync93, readFileSync as readFileSync86 } from "node:fs";
117522
- import { dirname as dirname42, join as join96 } from "node:path";
117919
+ import { dirname as dirname43, join as join97 } from "node:path";
117523
117920
  function getClaudeCodeVersion() {
117524
117921
  try {
117525
117922
  const out = execSync3("claude --version 2>/dev/null", {
@@ -117569,16 +117966,16 @@ function formatUptime3(timestamp) {
117569
117966
  function locateSwitchroomInstallDir() {
117570
117967
  let dir = import.meta.dirname;
117571
117968
  for (let i2 = 0;i2 < 10 && dir && dir !== "/"; i2++) {
117572
- const pkgPath = join96(dir, "package.json");
117969
+ const pkgPath = join97(dir, "package.json");
117573
117970
  if (existsSync93(pkgPath)) {
117574
117971
  try {
117575
117972
  const pkg = JSON.parse(readFileSync86(pkgPath, "utf-8"));
117576
- if (pkg.name === "switchroom" && existsSync93(join96(dir, ".git"))) {
117973
+ if (pkg.name === "switchroom" && existsSync93(join97(dir, ".git"))) {
117577
117974
  return dir;
117578
117975
  }
117579
117976
  } catch {}
117580
117977
  }
117581
- dir = dirname42(dir);
117978
+ dir = dirname43(dir);
117582
117979
  }
117583
117980
  return null;
117584
117981
  }
@@ -117755,31 +118152,31 @@ init_merge();
117755
118152
  // src/agents/session-retention.ts
117756
118153
  import {
117757
118154
  existsSync as existsSync94,
117758
- readdirSync as readdirSync32,
117759
- statSync as statSync54,
118155
+ readdirSync as readdirSync33,
118156
+ statSync as statSync55,
117760
118157
  unlinkSync as unlinkSync18
117761
118158
  } from "node:fs";
117762
- import { join as join97 } from "node:path";
118159
+ import { join as join98 } from "node:path";
117763
118160
  var DEFAULT_SESSION_RETENTION_MAX_COUNT = 20;
117764
118161
  var DEFAULT_SESSION_RETENTION_MAX_AGE_DAYS = 30;
117765
118162
  var MIN_KEEP = 2;
117766
118163
  function collectSessionJsonl(claudeConfigDir) {
117767
- const projects = join97(claudeConfigDir, "projects");
118164
+ const projects = join98(claudeConfigDir, "projects");
117768
118165
  if (!existsSync94(projects))
117769
118166
  return [];
117770
118167
  const found = [];
117771
118168
  const walk2 = (dir) => {
117772
118169
  let entries;
117773
118170
  try {
117774
- entries = readdirSync32(dir);
118171
+ entries = readdirSync33(dir);
117775
118172
  } catch {
117776
118173
  return;
117777
118174
  }
117778
118175
  for (const name of entries) {
117779
- const full = join97(dir, name);
118176
+ const full = join98(dir, name);
117780
118177
  let st;
117781
118178
  try {
117782
- st = statSync54(full);
118179
+ st = statSync55(full);
117783
118180
  } catch {
117784
118181
  continue;
117785
118182
  }
@@ -117900,15 +118297,15 @@ import {
117900
118297
  existsSync as existsSync95,
117901
118298
  mkdirSync as mkdirSync53,
117902
118299
  openSync as openSync17,
117903
- readdirSync as readdirSync33,
118300
+ readdirSync as readdirSync34,
117904
118301
  readFileSync as readFileSync87,
117905
118302
  renameSync as renameSync25,
117906
- statSync as statSync55,
118303
+ statSync as statSync56,
117907
118304
  unlinkSync as unlinkSync19,
117908
118305
  writeFileSync as writeFileSync38,
117909
118306
  writeSync as writeSync9
117910
118307
  } from "node:fs";
117911
- import { join as join98 } from "node:path";
118308
+ import { join as join99 } from "node:path";
117912
118309
  import { randomBytes as randomBytes15 } from "node:crypto";
117913
118310
  import { execSync as execSync4 } from "node:child_process";
117914
118311
 
@@ -117935,7 +118332,7 @@ function computeFingerprint(source, code) {
117935
118332
  var ISSUES_FILE = "issues.jsonl";
117936
118333
  var ISSUES_LOCK = "issues.lock";
117937
118334
  function readAll(stateDir) {
117938
- const path7 = join98(stateDir, ISSUES_FILE);
118335
+ const path7 = join99(stateDir, ISSUES_FILE);
117939
118336
  if (!existsSync95(path7))
117940
118337
  return [];
117941
118338
  let raw;
@@ -118013,7 +118410,7 @@ function record(stateDir, input, nowFn = Date.now) {
118013
118410
  });
118014
118411
  }
118015
118412
  function resolve51(stateDir, fingerprint, nowFn = Date.now) {
118016
- if (!existsSync95(join98(stateDir, ISSUES_FILE)))
118413
+ if (!existsSync95(join99(stateDir, ISSUES_FILE)))
118017
118414
  return 0;
118018
118415
  return withLock(stateDir, () => {
118019
118416
  const all = readAll(stateDir);
@@ -118031,7 +118428,7 @@ function resolve51(stateDir, fingerprint, nowFn = Date.now) {
118031
118428
  });
118032
118429
  }
118033
118430
  function resolveAllBySource(stateDir, source, nowFn = Date.now) {
118034
- if (!existsSync95(join98(stateDir, ISSUES_FILE)))
118431
+ if (!existsSync95(join99(stateDir, ISSUES_FILE)))
118035
118432
  return 0;
118036
118433
  return withLock(stateDir, () => {
118037
118434
  const all = readAll(stateDir);
@@ -118049,7 +118446,7 @@ function resolveAllBySource(stateDir, source, nowFn = Date.now) {
118049
118446
  });
118050
118447
  }
118051
118448
  function prune(stateDir, opts = {}) {
118052
- if (!existsSync95(join98(stateDir, ISSUES_FILE)))
118449
+ if (!existsSync95(join99(stateDir, ISSUES_FILE)))
118053
118450
  return 0;
118054
118451
  return withLock(stateDir, () => {
118055
118452
  const all = readAll(stateDir);
@@ -118082,7 +118479,7 @@ function ensureDir(stateDir) {
118082
118479
  mkdirSync53(stateDir, { recursive: true });
118083
118480
  }
118084
118481
  function writeAll(stateDir, events) {
118085
- const path7 = join98(stateDir, ISSUES_FILE);
118482
+ const path7 = join99(stateDir, ISSUES_FILE);
118086
118483
  sweepOrphanTmpFiles(stateDir);
118087
118484
  const tmp = `${path7}.tmp-${process.pid}-${randomBytes15(4).toString("hex")}`;
118088
118485
  const body = events.length === 0 ? "" : events.map((e) => JSON.stringify(e)).join(`
@@ -118096,7 +118493,7 @@ var TMP_PREFIX = `${ISSUES_FILE}.tmp-`;
118096
118493
  function sweepOrphanTmpFiles(stateDir) {
118097
118494
  let entries;
118098
118495
  try {
118099
- entries = readdirSync33(stateDir);
118496
+ entries = readdirSync34(stateDir);
118100
118497
  } catch {
118101
118498
  return;
118102
118499
  }
@@ -118104,9 +118501,9 @@ function sweepOrphanTmpFiles(stateDir) {
118104
118501
  for (const entry of entries) {
118105
118502
  if (!entry.startsWith(TMP_PREFIX))
118106
118503
  continue;
118107
- const tmpPath = join98(stateDir, entry);
118504
+ const tmpPath = join99(stateDir, entry);
118108
118505
  try {
118109
- const stat = statSync55(tmpPath);
118506
+ const stat = statSync56(tmpPath);
118110
118507
  if (stat.mtimeMs < cutoff) {
118111
118508
  unlinkSync19(tmpPath);
118112
118509
  }
@@ -118116,7 +118513,7 @@ function sweepOrphanTmpFiles(stateDir) {
118116
118513
  var LOCK_RETRY_MS = 25;
118117
118514
  var LOCK_TIMEOUT_MS = 1e4;
118118
118515
  function withLock(stateDir, fn) {
118119
- const lockPath = join98(stateDir, ISSUES_LOCK);
118516
+ const lockPath = join99(stateDir, ISSUES_LOCK);
118120
118517
  const startedAt = Date.now();
118121
118518
  let fd = null;
118122
118519
  while (fd === null) {
@@ -118401,7 +118798,7 @@ function relTime(deltaMs) {
118401
118798
  init_source();
118402
118799
  import { existsSync as existsSync98 } from "node:fs";
118403
118800
  import { homedir as homedir54 } from "node:os";
118404
- import { join as join101, resolve as resolve52 } from "node:path";
118801
+ import { join as join102, resolve as resolve52 } from "node:path";
118405
118802
 
118406
118803
  // src/deps/python.ts
118407
118804
  import { createHash as createHash18 } from "node:crypto";
@@ -118412,7 +118809,7 @@ import {
118412
118809
  rmSync as rmSync16,
118413
118810
  writeFileSync as writeFileSync39
118414
118811
  } from "node:fs";
118415
- import { dirname as dirname43, join as join99 } from "node:path";
118812
+ import { dirname as dirname44, join as join100 } from "node:path";
118416
118813
  import { homedir as homedir52 } from "node:os";
118417
118814
  import { execFileSync as execFileSync28 } from "node:child_process";
118418
118815
 
@@ -118425,7 +118822,7 @@ class PythonEnvError extends Error {
118425
118822
  }
118426
118823
  }
118427
118824
  function defaultPythonCacheRoot() {
118428
- return join99(homedir52(), ".switchroom", "deps", "python");
118825
+ return join100(homedir52(), ".switchroom", "deps", "python");
118429
118826
  }
118430
118827
  function hashFile(path7) {
118431
118828
  return createHash18("sha256").update(readFileSync88(path7)).digest("hex");
@@ -118437,11 +118834,11 @@ function ensurePythonEnv(opts) {
118437
118834
  if (!existsSync96(requirementsPath)) {
118438
118835
  throw new PythonEnvError(`requirements file not found: ${requirementsPath}`);
118439
118836
  }
118440
- const venvDir = join99(cacheRoot, skillName);
118441
- const stampPath = join99(venvDir, ".requirements.sha256");
118442
- const binDir = join99(venvDir, "bin");
118443
- const pythonBin = join99(binDir, "python");
118444
- const pipBin = join99(binDir, "pip");
118837
+ const venvDir = join100(cacheRoot, skillName);
118838
+ const stampPath = join100(venvDir, ".requirements.sha256");
118839
+ const binDir = join100(venvDir, "bin");
118840
+ const pythonBin = join100(binDir, "python");
118841
+ const pipBin = join100(binDir, "pip");
118445
118842
  const targetHash = hashFile(requirementsPath);
118446
118843
  if (!force && existsSync96(stampPath) && existsSync96(pythonBin)) {
118447
118844
  const existingHash = readFileSync88(stampPath, "utf8").trim();
@@ -118459,7 +118856,7 @@ function ensurePythonEnv(opts) {
118459
118856
  if (existsSync96(venvDir)) {
118460
118857
  rmSync16(venvDir, { recursive: true, force: true });
118461
118858
  }
118462
- mkdirSync54(dirname43(venvDir), { recursive: true });
118859
+ mkdirSync54(dirname44(venvDir), { recursive: true });
118463
118860
  try {
118464
118861
  execFileSync28(hostPython, ["-m", "venv", venvDir], { stdio: "pipe" });
118465
118862
  } catch (err) {
@@ -118500,7 +118897,7 @@ import {
118500
118897
  rmSync as rmSync17,
118501
118898
  writeFileSync as writeFileSync40
118502
118899
  } from "node:fs";
118503
- import { dirname as dirname44, join as join100 } from "node:path";
118900
+ import { dirname as dirname45, join as join101 } from "node:path";
118504
118901
  import { homedir as homedir53 } from "node:os";
118505
118902
  import { execFileSync as execFileSync29 } from "node:child_process";
118506
118903
 
@@ -118524,16 +118921,16 @@ var LOCKFILES_FOR = {
118524
118921
  npm: ["package-lock.json"]
118525
118922
  };
118526
118923
  function defaultNodeCacheRoot() {
118527
- return join100(homedir53(), ".switchroom", "deps", "node");
118924
+ return join101(homedir53(), ".switchroom", "deps", "node");
118528
118925
  }
118529
118926
  function hashDepInputs(packageJsonPath) {
118530
- const sourceDir = dirname44(packageJsonPath);
118927
+ const sourceDir = dirname45(packageJsonPath);
118531
118928
  const hasher = createHash19("sha256");
118532
118929
  hasher.update(`package.json
118533
118930
  `);
118534
118931
  hasher.update(readFileSync89(packageJsonPath));
118535
118932
  for (const lockName of ALL_LOCKFILES) {
118536
- const lockPath = join100(sourceDir, lockName);
118933
+ const lockPath = join101(sourceDir, lockName);
118537
118934
  if (existsSync97(lockPath)) {
118538
118935
  hasher.update(`
118539
118936
  `);
@@ -118552,11 +118949,11 @@ function ensureNodeEnv(opts) {
118552
118949
  if (!existsSync97(packageJsonPath)) {
118553
118950
  throw new NodeEnvError(`package.json not found: ${packageJsonPath}`);
118554
118951
  }
118555
- const sourceDir = dirname44(packageJsonPath);
118556
- const envDir = join100(cacheRoot, skillName);
118557
- const stampPath = join100(envDir, ".package.sha256");
118558
- const nodeModulesDir = join100(envDir, "node_modules");
118559
- const binDir = join100(nodeModulesDir, ".bin");
118952
+ const sourceDir = dirname45(packageJsonPath);
118953
+ const envDir = join101(cacheRoot, skillName);
118954
+ const stampPath = join101(envDir, ".package.sha256");
118955
+ const nodeModulesDir = join101(envDir, "node_modules");
118956
+ const binDir = join101(nodeModulesDir, ".bin");
118560
118957
  const targetHash = hashDepInputs(packageJsonPath);
118561
118958
  if (!force && existsSync97(stampPath) && existsSync97(nodeModulesDir)) {
118562
118959
  const existingHash = readFileSync89(stampPath, "utf8").trim();
@@ -118574,12 +118971,12 @@ function ensureNodeEnv(opts) {
118574
118971
  rmSync17(envDir, { recursive: true, force: true });
118575
118972
  }
118576
118973
  mkdirSync55(envDir, { recursive: true });
118577
- copyFileSync13(packageJsonPath, join100(envDir, "package.json"));
118974
+ copyFileSync13(packageJsonPath, join101(envDir, "package.json"));
118578
118975
  let copiedLockfile = false;
118579
118976
  for (const lockName of LOCKFILES_FOR[installer]) {
118580
- const lockPath = join100(sourceDir, lockName);
118977
+ const lockPath = join101(sourceDir, lockName);
118581
118978
  if (existsSync97(lockPath)) {
118582
- copyFileSync13(lockPath, join100(envDir, lockName));
118979
+ copyFileSync13(lockPath, join101(envDir, lockName));
118583
118980
  copiedLockfile = true;
118584
118981
  }
118585
118982
  }
@@ -118618,13 +119015,13 @@ function registerDepsCommand(program3) {
118618
119015
  console.error(source_default.red(`Bundled skills pool dir not found at ${skillsRoot} \u2014 run \`switchroom update\` to install it.`));
118619
119016
  process.exit(1);
118620
119017
  }
118621
- const skillDir = join101(skillsRoot, skill);
119018
+ const skillDir = join102(skillsRoot, skill);
118622
119019
  if (!existsSync98(skillDir)) {
118623
119020
  console.error(source_default.red(`Unknown skill: ${skill} (no dir at ${skillDir})`));
118624
119021
  process.exit(1);
118625
119022
  }
118626
- const requirementsPath = join101(skillDir, "requirements.txt");
118627
- const packageJsonPath = join101(skillDir, "package.json");
119023
+ const requirementsPath = join102(skillDir, "requirements.txt");
119024
+ const packageJsonPath = join102(skillDir, "package.json");
118628
119025
  const wantPython = opts.python ?? (!opts.python && !opts.node && existsSync98(requirementsPath));
118629
119026
  const wantNode = opts.node ?? (!opts.python && !opts.node && existsSync98(packageJsonPath));
118630
119027
  let did = 0;
@@ -119579,7 +119976,7 @@ init_helpers();
119579
119976
  init_loader();
119580
119977
  init_merge();
119581
119978
  import { copyFileSync as copyFileSync14, existsSync as existsSync100, readFileSync as readFileSync90, writeFileSync as writeFileSync41 } from "node:fs";
119582
- import { join as join102, resolve as resolve54 } from "node:path";
119979
+ import { join as join103, resolve as resolve54 } from "node:path";
119583
119980
  init_scaffold();
119584
119981
  init_profiles();
119585
119982
  init_schema();
@@ -119605,7 +120002,7 @@ function resolveSoulTargetOrExit(program3, agentName) {
119605
120002
  profileName,
119606
120003
  profilePath,
119607
120004
  workspaceDir,
119608
- soulPath: join102(workspaceDir, "SOUL.md"),
120005
+ soulPath: join103(workspaceDir, "SOUL.md"),
119609
120006
  soul: merged.soul
119610
120007
  };
119611
120008
  }
@@ -119671,8 +120068,8 @@ function registerSoulCommand(program3) {
119671
120068
  // src/cli/debug.ts
119672
120069
  init_helpers();
119673
120070
  init_loader();
119674
- import { existsSync as existsSync101, readFileSync as readFileSync91, readdirSync as readdirSync34, statSync as statSync56 } from "node:fs";
119675
- import { resolve as resolve55, join as join103 } from "node:path";
120071
+ import { existsSync as existsSync101, readFileSync as readFileSync91, readdirSync as readdirSync35, statSync as statSync57 } from "node:fs";
120072
+ import { resolve as resolve55, join as join104 } from "node:path";
119676
120073
  import { createHash as createHash20 } from "node:crypto";
119677
120074
  init_merge();
119678
120075
  init_hindsight2();
@@ -119683,7 +120080,7 @@ function estimateTokens(bytes) {
119683
120080
  return Math.round(bytes / 3.7);
119684
120081
  }
119685
120082
  function readMcpServerNames(agentDir) {
119686
- const mcpPath = join103(agentDir, ".mcp.json");
120083
+ const mcpPath = join104(agentDir, ".mcp.json");
119687
120084
  if (!existsSync101(mcpPath))
119688
120085
  return [];
119689
120086
  try {
@@ -119697,20 +120094,20 @@ function sha2562(content) {
119697
120094
  return createHash20("sha256").update(content).digest("hex").slice(0, 16);
119698
120095
  }
119699
120096
  function findLatestTranscriptJsonl(claudeConfigDir) {
119700
- const projectsDir = join103(claudeConfigDir, "projects");
120097
+ const projectsDir = join104(claudeConfigDir, "projects");
119701
120098
  if (!existsSync101(projectsDir))
119702
120099
  return;
119703
120100
  try {
119704
- const entries = readdirSync34(projectsDir, { withFileTypes: true });
120101
+ const entries = readdirSync35(projectsDir, { withFileTypes: true });
119705
120102
  let latest;
119706
120103
  for (const entry of entries) {
119707
120104
  if (!entry.isDirectory())
119708
120105
  continue;
119709
- const projectPath = join103(projectsDir, entry.name);
119710
- const transcriptPath = join103(projectPath, "transcript.jsonl");
120106
+ const projectPath = join104(projectsDir, entry.name);
120107
+ const transcriptPath = join104(projectPath, "transcript.jsonl");
119711
120108
  if (!existsSync101(transcriptPath))
119712
120109
  continue;
119713
- const stat3 = statSync56(transcriptPath);
120110
+ const stat3 = statSync57(transcriptPath);
119714
120111
  if (!latest || stat3.mtimeMs > latest.mtime) {
119715
120112
  latest = { path: transcriptPath, mtime: stat3.mtimeMs };
119716
120113
  }
@@ -119776,11 +120173,11 @@ function registerDebugCommand(program3) {
119776
120173
  process.exit(1);
119777
120174
  }
119778
120175
  const workspaceDir = resolveAgentWorkspaceDir(agentDir);
119779
- const claudeConfigDir = join103(agentDir, ".claude");
119780
- const claudeMdPath = join103(agentDir, "CLAUDE.md");
119781
- const soulMdPath = join103(agentDir, "SOUL.md");
119782
- const workspaceSoulMdPath = join103(workspaceDir, "SOUL.md");
119783
- const handoffPath = join103(agentDir, ".handoff.md");
120176
+ const claudeConfigDir = join104(agentDir, ".claude");
120177
+ const claudeMdPath = join104(agentDir, "CLAUDE.md");
120178
+ const soulMdPath = join104(agentDir, "SOUL.md");
120179
+ const workspaceSoulMdPath = join104(workspaceDir, "SOUL.md");
120180
+ const handoffPath = join104(agentDir, ".handoff.md");
119784
120181
  const lastN = parseInt(opts.last, 10);
119785
120182
  if (isNaN(lastN) || lastN < 1) {
119786
120183
  console.error("--last must be a positive integer");
@@ -119909,9 +120306,9 @@ function registerDebugCommand(program3) {
119909
120306
  const soulMdBytes = soulMdContent.length;
119910
120307
  const perTurnBytes = dynamicResult.concatenated.length;
119911
120308
  const userBytes = userMessage?.text.length ?? 0;
119912
- const fleetDir = join103(agentsDir, "..", "fleet");
119913
- const fleetInvPath = join103(fleetDir, "switchroom-invariants.md");
119914
- const fleetClaudePath = join103(fleetDir, "CLAUDE.md");
120309
+ const fleetDir = join104(agentsDir, "..", "fleet");
120310
+ const fleetInvPath = join104(fleetDir, "switchroom-invariants.md");
120311
+ const fleetClaudePath = join104(fleetDir, "CLAUDE.md");
119915
120312
  const fleetInvBytes = existsSync101(fleetInvPath) ? readFileSync91(fleetInvPath, "utf-8").length : 0;
119916
120313
  const fleetClaudeBytes = existsSync101(fleetClaudePath) ? readFileSync91(fleetClaudePath, "utf-8").length : 0;
119917
120314
  const fleetBytes = fleetInvBytes + fleetClaudeBytes;
@@ -119947,7 +120344,7 @@ init_source();
119947
120344
  // src/worktree/claim.ts
119948
120345
  import { execFileSync as execFileSync30 } from "node:child_process";
119949
120346
  import { closeSync as closeSync18, mkdirSync as mkdirSync57, openSync as openSync18, existsSync as existsSync103, unlinkSync as unlinkSync21 } from "node:fs";
119950
- import { join as join105, resolve as resolve57 } from "node:path";
120347
+ import { join as join106, resolve as resolve57 } from "node:path";
119951
120348
  import { homedir as homedir56 } from "node:os";
119952
120349
  import { randomBytes as randomBytes16 } from "node:crypto";
119953
120350
 
@@ -119956,18 +120353,18 @@ import {
119956
120353
  mkdirSync as mkdirSync56,
119957
120354
  writeFileSync as writeFileSync42,
119958
120355
  readFileSync as readFileSync92,
119959
- readdirSync as readdirSync35,
120356
+ readdirSync as readdirSync36,
119960
120357
  unlinkSync as unlinkSync20,
119961
120358
  existsSync as existsSync102,
119962
120359
  renameSync as renameSync26
119963
120360
  } from "node:fs";
119964
- import { join as join104, resolve as resolve56 } from "node:path";
120361
+ import { join as join105, resolve as resolve56 } from "node:path";
119965
120362
  import { homedir as homedir55 } from "node:os";
119966
120363
  function registryDir() {
119967
- return resolve56(process.env.SWITCHROOM_WORKTREE_DIR ?? join104(homedir55(), ".switchroom", "worktrees"));
120364
+ return resolve56(process.env.SWITCHROOM_WORKTREE_DIR ?? join105(homedir55(), ".switchroom", "worktrees"));
119968
120365
  }
119969
120366
  function recordPath(id) {
119970
- return join104(registryDir(), `${id}.json`);
120367
+ return join105(registryDir(), `${id}.json`);
119971
120368
  }
119972
120369
  function ensureDir2() {
119973
120370
  mkdirSync56(registryDir(), { recursive: true });
@@ -119999,7 +120396,7 @@ function listRecords() {
119999
120396
  ensureDir2();
120000
120397
  const dir = registryDir();
120001
120398
  const records = [];
120002
- for (const entry of readdirSync35(dir)) {
120399
+ for (const entry of readdirSync36(dir)) {
120003
120400
  if (!entry.endsWith(".json"))
120004
120401
  continue;
120005
120402
  const id = entry.slice(0, -5);
@@ -120018,7 +120415,7 @@ function acquireRepoLock(repoPath) {
120018
120415
  const lockDir = registryDir();
120019
120416
  mkdirSync57(lockDir, { recursive: true });
120020
120417
  const lockName = repoPath.replace(/[^A-Za-z0-9]/g, "_");
120021
- const lockPath = join105(lockDir, `.lock-${lockName}`);
120418
+ const lockPath = join106(lockDir, `.lock-${lockName}`);
120022
120419
  const deadline = Date.now() + 5000;
120023
120420
  let fd = null;
120024
120421
  while (fd === null) {
@@ -120045,7 +120442,7 @@ function acquireRepoLock(repoPath) {
120045
120442
  }
120046
120443
  var DEFAULT_CONCURRENCY = 5;
120047
120444
  function worktreesBaseDir() {
120048
- return resolve57(process.env.SWITCHROOM_WORKTREE_BASE ?? join105(homedir56(), ".switchroom", "worktree-checkouts"));
120445
+ return resolve57(process.env.SWITCHROOM_WORKTREE_BASE ?? join106(homedir56(), ".switchroom", "worktree-checkouts"));
120049
120446
  }
120050
120447
  function shortId() {
120051
120448
  return randomBytes16(4).toString("hex");
@@ -120067,7 +120464,7 @@ function resolveRepoPath(repo, codeRepos) {
120067
120464
  }
120068
120465
  function expandHome(p) {
120069
120466
  if (p.startsWith("~/"))
120070
- return join105(homedir56(), p.slice(2));
120467
+ return join106(homedir56(), p.slice(2));
120071
120468
  return p;
120072
120469
  }
120073
120470
  async function claimWorktree(input, codeRepos) {
@@ -120095,7 +120492,7 @@ async function claimWorktree(input, codeRepos) {
120095
120492
  branch = `task/${taskSuffix}-${id}`;
120096
120493
  const baseDir = worktreesBaseDir();
120097
120494
  mkdirSync57(baseDir, { recursive: true });
120098
- worktreePath = join105(baseDir, `${id}-${taskSuffix}`);
120495
+ worktreePath = join106(baseDir, `${id}-${taskSuffix}`);
120099
120496
  const ambientOwner = process.env.SWITCHROOM_AGENT_NAME;
120100
120497
  const ownerAgent = input.ownerAgent ?? (ambientOwner != null && ambientOwner !== "" ? ambientOwner : undefined);
120101
120498
  const now2 = new Date().toISOString();
@@ -120319,14 +120716,14 @@ import { execFileSync as execFileSync33 } from "node:child_process";
120319
120716
  import {
120320
120717
  existsSync as existsSync106,
120321
120718
  readFileSync as readFileSync93,
120322
- readdirSync as readdirSync36,
120323
- statSync as statSync57,
120719
+ readdirSync as readdirSync37,
120720
+ statSync as statSync58,
120324
120721
  renameSync as renameSync27,
120325
120722
  mkdirSync as mkdirSync58,
120326
120723
  rmSync as rmSync18
120327
120724
  } from "node:fs";
120328
120725
  import { homedir as homedir57 } from "node:os";
120329
- import { join as join106, resolve as resolve58 } from "node:path";
120726
+ import { join as join107, resolve as resolve58 } from "node:path";
120330
120727
  function parseGitdirPointer(dotGitFileContents) {
120331
120728
  const m = /^gitdir:\s*(.+?)\s*$/m.exec(dotGitFileContents);
120332
120729
  return m ? m[1] : null;
@@ -120485,7 +120882,7 @@ function defaultNewestTrackedMtimeMs(dir, exec) {
120485
120882
  let newest = 0;
120486
120883
  for (const f of files) {
120487
120884
  try {
120488
- const m = statSync57(join106(dir, f)).mtimeMs;
120885
+ const m = statSync58(join107(dir, f)).mtimeMs;
120489
120886
  if (m > newest)
120490
120887
  newest = m;
120491
120888
  } catch {}
@@ -120493,17 +120890,17 @@ function defaultNewestTrackedMtimeMs(dir, exec) {
120493
120890
  return newest || Date.now();
120494
120891
  }
120495
120892
  function trashRoot() {
120496
- return resolve58(process.env.SWITCHROOM_WORKTREE_TRASH ?? join106(homedir57(), ".switchroom", "worktree-gc-trash"));
120893
+ return resolve58(process.env.SWITCHROOM_WORKTREE_TRASH ?? join107(homedir57(), ".switchroom", "worktree-gc-trash"));
120497
120894
  }
120498
120895
  function planGc(roots, deps = {}, taskTreeRoots = []) {
120499
120896
  const exists = deps.existsSync ?? existsSync106;
120500
- const readDir = deps.readDir ?? ((p) => readdirSync36(p));
120897
+ const readDir = deps.readDir ?? ((p) => readdirSync37(p));
120501
120898
  const readFile4 = deps.readFile ?? ((p) => readFileSync93(p, "utf8"));
120502
- const stat3 = deps.stat ?? ((p) => statSync57(p));
120899
+ const stat3 = deps.stat ?? ((p) => statSync58(p));
120503
120900
  const exec = deps.exec ?? defaultExec3;
120504
120901
  const prSignal = deps.prSignal ?? ((repo, branch) => defaultPrSignal(repo, branch, exec));
120505
120902
  const stamp = deps.dateStamp ?? "undated";
120506
- const trash = join106(trashRoot(), stamp);
120903
+ const trash = join107(trashRoot(), stamp);
120507
120904
  const probeInUse = deps.probeInUse ?? probePathInUse;
120508
120905
  const newestMtime = deps.newestTrackedMtimeMs ?? ((dir) => defaultNewestTrackedMtimeMs(dir, exec));
120509
120906
  const idleDays = deps.idleDays ?? 14;
@@ -120544,10 +120941,10 @@ function planGc(roots, deps = {}, taskTreeRoots = []) {
120544
120941
  continue;
120545
120942
  }
120546
120943
  for (const name of entries) {
120547
- const dir = join106(root, name);
120944
+ const dir = join107(root, name);
120548
120945
  if (isEphemeralPath(dir))
120549
120946
  continue;
120550
- const dotGit = join106(dir, ".git");
120947
+ const dotGit = join107(dir, ".git");
120551
120948
  if (!exists(dotGit))
120552
120949
  continue;
120553
120950
  let st;
@@ -120576,7 +120973,7 @@ function planGc(roots, deps = {}, taskTreeRoots = []) {
120576
120973
  ownerRepos.add(repoRoot);
120577
120974
  if (exists(ptr))
120578
120975
  continue;
120579
- orphans.push({ dir, owner: repoRoot, dest: join106(trash, name) });
120976
+ orphans.push({ dir, owner: repoRoot, dest: join107(trash, name) });
120580
120977
  }
120581
120978
  }
120582
120979
  const registered = [];
@@ -120631,10 +121028,10 @@ function planGc(roots, deps = {}, taskTreeRoots = []) {
120631
121028
  continue;
120632
121029
  }
120633
121030
  for (const name of entries) {
120634
- const dir = join106(root, name);
121031
+ const dir = join107(root, name);
120635
121032
  if (isEphemeralPath(dir))
120636
121033
  continue;
120637
- const dotGit = join106(dir, ".git");
121034
+ const dotGit = join107(dir, ".git");
120638
121035
  if (!exists(dotGit))
120639
121036
  continue;
120640
121037
  let shape;
@@ -120739,7 +121136,7 @@ function planGc(roots, deps = {}, taskTreeRoots = []) {
120739
121136
  verdict,
120740
121137
  prSignal: sig,
120741
121138
  idle,
120742
- dest: join106(trash, name),
121139
+ dest: join107(trash, name),
120743
121140
  willAct
120744
121141
  });
120745
121142
  }
@@ -120816,13 +121213,13 @@ function selectPurgeTargets(entries, olderThanDays) {
120816
121213
  }
120817
121214
  function listTrashEntries(nowMs, deps = {}) {
120818
121215
  const exists = deps.existsSync ?? existsSync106;
120819
- const readDir = deps.readDir ?? ((p) => readdirSync36(p));
121216
+ const readDir = deps.readDir ?? ((p) => readdirSync37(p));
120820
121217
  const root = trashRoot();
120821
121218
  if (!exists(root))
120822
121219
  return [];
120823
121220
  const out = [];
120824
121221
  for (const stamp of readDir(root)) {
120825
- const stampDir = join106(root, stamp);
121222
+ const stampDir = join107(root, stamp);
120826
121223
  let names;
120827
121224
  try {
120828
121225
  names = readDir(stampDir);
@@ -120830,10 +121227,10 @@ function listTrashEntries(nowMs, deps = {}) {
120830
121227
  continue;
120831
121228
  }
120832
121229
  for (const name of names) {
120833
- const p = join106(stampDir, name);
121230
+ const p = join107(stampDir, name);
120834
121231
  let mtimeMs = nowMs;
120835
121232
  try {
120836
- mtimeMs = statSync57(p).mtimeMs;
121233
+ mtimeMs = statSync58(p).mtimeMs;
120837
121234
  } catch {}
120838
121235
  out.push({ path: p, ageDays: (nowMs - mtimeMs) / 86400000 });
120839
121236
  }
@@ -120854,20 +121251,20 @@ function purgeTrash(paths) {
120854
121251
  return { deleted, errors: errors2 };
120855
121252
  }
120856
121253
  function defaultRoots() {
120857
- return [join106(homedir57(), "code")];
121254
+ return [join107(homedir57(), "code")];
120858
121255
  }
120859
121256
  function defaultTaskTreeRoots() {
120860
- const agentsDir = join106(homedir57(), ".switchroom", "agents");
121257
+ const agentsDir = join107(homedir57(), ".switchroom", "agents");
120861
121258
  let names;
120862
121259
  try {
120863
- names = readdirSync36(agentsDir);
121260
+ names = readdirSync37(agentsDir);
120864
121261
  } catch {
120865
121262
  return [];
120866
121263
  }
120867
121264
  const roots = [];
120868
121265
  for (const name of names.sort()) {
120869
121266
  for (const sub of ["home/work", "home/workspace"]) {
120870
- const r = join106(agentsDir, name, sub);
121267
+ const r = join107(agentsDir, name, sub);
120871
121268
  if (existsSync106(r))
120872
121269
  roots.push(r);
120873
121270
  }
@@ -121128,11 +121525,11 @@ init_scaffold_integration();
121128
121525
  import {
121129
121526
  chmodSync as chmodSync17,
121130
121527
  mkdirSync as mkdirSync59,
121131
- readdirSync as readdirSync37,
121528
+ readdirSync as readdirSync38,
121132
121529
  rmSync as rmSync19,
121133
121530
  writeFileSync as writeFileSync43
121134
121531
  } from "node:fs";
121135
- import { join as join107 } from "node:path";
121532
+ import { join as join108 } from "node:path";
121136
121533
  function encodeCredentialsFilename(email) {
121137
121534
  const SAFE = new Set([
121138
121535
  ..."ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
@@ -121396,16 +121793,16 @@ function resolveCredentialsDir(env2) {
121396
121793
  if (explicit && explicit.length > 0)
121397
121794
  return explicit;
121398
121795
  const stateBase = env2.SWITCHROOM_CONTAINER === "1" ? "/state/agent" : env2.HOME ?? ".";
121399
- return join107(stateBase, "google-workspace-mcp", "credentials");
121796
+ return join108(stateBase, "google-workspace-mcp", "credentials");
121400
121797
  }
121401
121798
  function writeSeedFile(dir, email, seed) {
121402
121799
  mkdirSync59(dir, { recursive: true, mode: 448 });
121403
121800
  chmodSync17(dir, 448);
121404
- for (const name of readdirSync37(dir)) {
121405
- rmSync19(join107(dir, name), { force: true, recursive: true });
121801
+ for (const name of readdirSync38(dir)) {
121802
+ rmSync19(join108(dir, name), { force: true, recursive: true });
121406
121803
  }
121407
121804
  const filename = encodeCredentialsFilename(email);
121408
- const filePath = join107(dir, filename);
121805
+ const filePath = join108(dir, filename);
121409
121806
  writeFileSync43(filePath, JSON.stringify(seed), { mode: 384 });
121410
121807
  chmodSync17(filePath, 384);
121411
121808
  return filePath;
@@ -121602,7 +121999,7 @@ function registerDriveMcpLauncherCommand(program3) {
121602
121999
  init_scaffold_integration();
121603
122000
  import { spawn as spawn6 } from "node:child_process";
121604
122001
  import { writeFileSync as writeFileSync44, mkdirSync as mkdirSync60 } from "node:fs";
121605
- import { dirname as dirname45, join as join108 } from "node:path";
122002
+ import { dirname as dirname46, join as join109 } from "node:path";
121606
122003
  var SOFTERIA_TOKEN_ENV = "MS365_MCP_OAUTH_TOKEN";
121607
122004
  var DEFAULT_REFRESH_LEAD_MS = 5 * 60 * 1000;
121608
122005
  var MAX_REFRESH_INTERVAL_MS = 60 * 60 * 1000;
@@ -121638,7 +122035,7 @@ function computeRefreshDelayMs(expiresAt, now2, leadMs = DEFAULT_REFRESH_LEAD_MS
121638
122035
  function writeRefreshHeartbeat(agentName, data, account) {
121639
122036
  const path10 = heartbeatPath(agentName, account);
121640
122037
  try {
121641
- mkdirSync60(dirname45(path10), { recursive: true });
122038
+ mkdirSync60(dirname46(path10), { recursive: true });
121642
122039
  writeFileSync44(path10, JSON.stringify(data, null, 2), { mode: 420 });
121643
122040
  } catch {}
121644
122041
  }
@@ -121647,7 +122044,7 @@ function heartbeatPath(agentName, account) {
121647
122044
  const override = process.env.SWITCHROOM_M365_HEARTBEAT_DIR;
121648
122045
  if (override) {
121649
122046
  const base = slug ? `m365-launcher-${agentName}-${slug}` : `m365-launcher-${agentName}`;
121650
- return join108(override, `${base}.heartbeat.json`);
122047
+ return join109(override, `${base}.heartbeat.json`);
121651
122048
  }
121652
122049
  return slug ? `/state/agent/m365-launcher-${slug}.heartbeat.json` : "/state/agent/m365-launcher.heartbeat.json";
121653
122050
  }
@@ -121880,7 +122277,7 @@ function registerM365McpLauncherCommand(program3) {
121880
122277
  init_scaffold_integration();
121881
122278
  import { spawn as spawn7 } from "node:child_process";
121882
122279
  import { existsSync as existsSync107, mkdirSync as mkdirSync61, writeFileSync as writeFileSync45 } from "node:fs";
121883
- import { dirname as dirname46 } from "node:path";
122280
+ import { dirname as dirname47 } from "node:path";
121884
122281
  var HEARTBEAT_WRITE_INTERVAL_MS = 30 * 1000;
121885
122282
  var DEFAULT_HEARTBEAT_PATH = "/state/agent/notion-launcher.heartbeat.json";
121886
122283
  var DEFAULT_VAULT_KEY = "notion/integration-token";
@@ -121890,7 +122287,7 @@ function buildNotionMcpArgs(opts) {
121890
122287
  }
121891
122288
  function defaultWriteHeartbeat(path10, contents) {
121892
122289
  try {
121893
- const dir = dirname46(path10);
122290
+ const dir = dirname47(path10);
121894
122291
  if (!existsSync107(dir))
121895
122292
  mkdirSync61(dir, { recursive: true });
121896
122293
  writeFileSync45(path10, contents);
@@ -122005,7 +122402,7 @@ function registerNotionMcpLauncherCommand(program3) {
122005
122402
  init_hindsight_directive_admin();
122006
122403
  import { mkdirSync as mkdirSync62, readFileSync as readFileSync94, renameSync as renameSync28, writeFileSync as writeFileSync46 } from "node:fs";
122007
122404
  import { tmpdir as tmpdir5 } from "node:os";
122008
- import { join as join109 } from "node:path";
122405
+ import { join as join110 } from "node:path";
122009
122406
  import { createInterface as createInterface7 } from "node:readline";
122010
122407
 
122011
122408
  // src/memory/hindsight-knowledge-admin.ts
@@ -122593,12 +122990,12 @@ class HindsightShim {
122593
122990
  `));
122594
122991
  }
122595
122992
  get cachePath() {
122596
- return join109(this.opts.cacheDir, TOOLS_CACHE_FILENAME);
122993
+ return join110(this.opts.cacheDir, TOOLS_CACHE_FILENAME);
122597
122994
  }
122598
122995
  writeCache(result) {
122599
122996
  try {
122600
122997
  mkdirSync62(this.opts.cacheDir, { recursive: true });
122601
- const tmp = join109(this.opts.cacheDir, `.${TOOLS_CACHE_FILENAME}.${process.pid}.tmp`);
122998
+ const tmp = join110(this.opts.cacheDir, `.${TOOLS_CACHE_FILENAME}.${process.pid}.tmp`);
122602
122999
  writeFileSync46(tmp, JSON.stringify(result, null, 2) + `
122603
123000
  `);
122604
123001
  renameSync28(tmp, this.cachePath);
@@ -122882,7 +123279,7 @@ function resolveShimOptionsFromEnv(env2) {
122882
123279
  return {
122883
123280
  url: env2.HINDSIGHT_MCP_URL || HINDSIGHT_DEFAULT_MCP_URL,
122884
123281
  bankId: env2.HINDSIGHT_BANK_ID || "",
122885
- cacheDir: env2.HINDSIGHT_SHIM_CACHE_DIR || join109(home2, ".hindsight-shim")
123282
+ cacheDir: env2.HINDSIGHT_SHIM_CACHE_DIR || join110(home2, ".hindsight-shim")
122886
123283
  };
122887
123284
  }
122888
123285
  function registerHindsightMcpShimCommand(program3) {
@@ -122895,11 +123292,11 @@ function registerHindsightMcpShimCommand(program3) {
122895
123292
 
122896
123293
  // src/cli/deliver-file.ts
122897
123294
  init_client2();
122898
- import { readFileSync as readFileSync95, statSync as statSync58 } from "node:fs";
122899
- import { basename as basename13 } from "node:path";
123295
+ import { readFileSync as readFileSync95, statSync as statSync59 } from "node:fs";
123296
+ import { basename as basename14 } from "node:path";
122900
123297
 
122901
123298
  // src/delivery/onedrive.ts
122902
- import { basename as basename11 } from "node:path";
123299
+ import { basename as basename12 } from "node:path";
122903
123300
  var GRAPH = "https://graph.microsoft.com/v1.0";
122904
123301
  var ONEDRIVE_INLINE_MAX_BYTES = 4 * 1024 * 1024;
122905
123302
  function authHeaders2(token) {
@@ -123022,14 +123419,14 @@ async function createShareLink(deps, item, scopes = ["anonymous", "organization"
123022
123419
  async function deliverToOneDrive(args) {
123023
123420
  const deps = { accessToken: args.accessToken, fetchImpl: args.fetchImpl };
123024
123421
  const folder = await ensureSwitchroomFolder(deps, args.agentName);
123025
- const filename = basename11(args.localPath);
123422
+ const filename = basename12(args.localPath);
123026
123423
  const item = await uploadFile(deps, folder.id, filename, args.bytes);
123027
123424
  const link = await createShareLink(deps, item, args.linkScopes);
123028
123425
  return { itemId: item.id, link, folderPath: `Switchroom/${args.agentName}` };
123029
123426
  }
123030
123427
 
123031
123428
  // src/delivery/gdrive.ts
123032
- import { basename as basename12 } from "node:path";
123429
+ import { basename as basename13 } from "node:path";
123033
123430
  var DRIVE = "https://www.googleapis.com/drive/v3";
123034
123431
  var UPLOAD = "https://www.googleapis.com/upload/drive/v3";
123035
123432
  var FOLDER_MIME = "application/vnd.google-apps.folder";
@@ -123177,7 +123574,7 @@ async function createShareLink2(deps, file, scopes = ["anyone"]) {
123177
123574
  async function deliverToGoogleDrive(args) {
123178
123575
  const deps = { accessToken: args.accessToken, fetchImpl: args.fetchImpl };
123179
123576
  const folder = await ensureSwitchroomFolder2(deps, args.agentName);
123180
- const filename = basename12(args.localPath);
123577
+ const filename = basename13(args.localPath);
123181
123578
  const file = await uploadFile2(deps, folder.id, filename, args.bytes);
123182
123579
  const link = await createShareLink2(deps, file, args.linkScopes);
123183
123580
  return { itemId: file.id, link, folderPath: `Switchroom/${args.agentName}` };
@@ -123234,7 +123631,7 @@ async function defaultResolveProvider() {
123234
123631
  }
123235
123632
  async function runDeliverFile(localPath, deps = {}) {
123236
123633
  const agentName = safeAgentName(deps.agentName ?? process.env.SWITCHROOM_AGENT_NAME);
123237
- const sizeOf = deps.fileSize ?? ((p) => statSync58(p).size);
123634
+ const sizeOf = deps.fileSize ?? ((p) => statSync59(p).size);
123238
123635
  const read = deps.readFile ?? ((p) => new Uint8Array(readFileSync95(p)));
123239
123636
  const resolveProvider = deps.resolveProvider ?? defaultResolveProvider;
123240
123637
  let size;
@@ -123256,7 +123653,7 @@ async function runDeliverFile(localPath, deps = {}) {
123256
123653
  try {
123257
123654
  const bytes = read(localPath);
123258
123655
  const out = await provider.deliver({ agentName, localPath, bytes });
123259
- return { ok: true, provider: provider.name, link: out.link, folderPath: out.folderPath, filename: basename13(localPath) };
123656
+ return { ok: true, provider: provider.name, link: out.link, folderPath: out.folderPath, filename: basename14(localPath) };
123260
123657
  } catch (err) {
123261
123658
  return { ok: false, provider: provider.name, error: `upload failed: ${err.message}` };
123262
123659
  }
@@ -123556,8 +123953,8 @@ function runRedactStdin() {
123556
123953
  }
123557
123954
 
123558
123955
  // src/cli/status-ask.ts
123559
- import { readFileSync as readFileSync96, existsSync as existsSync108, readdirSync as readdirSync38 } from "node:fs";
123560
- import { join as join110 } from "node:path";
123956
+ import { readFileSync as readFileSync96, existsSync as existsSync108, readdirSync as readdirSync39 } from "node:fs";
123957
+ import { join as join111 } from "node:path";
123561
123958
  import { homedir as homedir58 } from "node:os";
123562
123959
 
123563
123960
  // src/status-ask/report.ts
@@ -123893,19 +124290,19 @@ function resolveSources(explicitPath) {
123893
124290
  const config = loadConfig();
123894
124291
  agentsDir = resolveAgentsDir(config);
123895
124292
  } catch {
123896
- agentsDir = join110(homedir58(), ".switchroom", "agents");
124293
+ agentsDir = join111(homedir58(), ".switchroom", "agents");
123897
124294
  }
123898
124295
  if (!existsSync108(agentsDir))
123899
124296
  return [];
123900
124297
  const sources = [];
123901
124298
  let entries;
123902
124299
  try {
123903
- entries = readdirSync38(agentsDir);
124300
+ entries = readdirSync39(agentsDir);
123904
124301
  } catch {
123905
124302
  return [];
123906
124303
  }
123907
124304
  for (const name of entries) {
123908
- const path10 = join110(agentsDir, name, "runtime-metrics.jsonl");
124305
+ const path10 = join111(agentsDir, name, "runtime-metrics.jsonl");
123909
124306
  if (existsSync108(path10)) {
123910
124307
  sources.push({ path: path10, agent: name });
123911
124308
  }
@@ -123941,28 +124338,28 @@ import {
123941
124338
  fsyncSync as fsyncSync8,
123942
124339
  mkdirSync as mkdirSync63,
123943
124340
  openSync as openSync19,
123944
- readdirSync as readdirSync39,
124341
+ readdirSync as readdirSync40,
123945
124342
  readFileSync as readFileSync97,
123946
124343
  renameSync as renameSync29,
123947
- statSync as statSync59,
124344
+ statSync as statSync60,
123948
124345
  unlinkSync as unlinkSync22,
123949
124346
  writeSync as writeSync10
123950
124347
  } from "node:fs";
123951
- import { join as join111, resolve as resolve59 } from "node:path";
124348
+ import { join as join112, resolve as resolve59 } from "node:path";
123952
124349
  var STAGING_SUBDIR = ".staging";
123953
124350
  function overlayPathsFor(agent, opts = {}) {
123954
124351
  const base = opts.root ? resolve59(opts.root, agent) : resolve59(resolveDualPath(`~/.switchroom/agents/${agent}`));
123955
- const scheduleDir = join111(base, "schedule.d");
123956
- const scheduleStagingDir = join111(scheduleDir, STAGING_SUBDIR);
123957
- const skillsDir = join111(base, "skills.d");
123958
- const skillsStagingDir = join111(skillsDir, STAGING_SUBDIR);
124352
+ const scheduleDir = join112(base, "schedule.d");
124353
+ const scheduleStagingDir = join112(scheduleDir, STAGING_SUBDIR);
124354
+ const skillsDir = join112(base, "skills.d");
124355
+ const skillsStagingDir = join112(skillsDir, STAGING_SUBDIR);
123959
124356
  return {
123960
124357
  agentRoot: base,
123961
124358
  scheduleDir,
123962
124359
  scheduleStagingDir,
123963
124360
  skillsDir,
123964
124361
  skillsStagingDir,
123965
- lockPath: join111(base, ".lock"),
124362
+ lockPath: join112(base, ".lock"),
123966
124363
  stagingDir: scheduleStagingDir
123967
124364
  };
123968
124365
  }
@@ -123988,7 +124385,7 @@ function withAgentLock(paths, fn) {
123988
124385
  if (e.code !== "EEXIST")
123989
124386
  throw err;
123990
124387
  try {
123991
- const age = Date.now() - statSync59(paths.lockPath).mtimeMs;
124388
+ const age = Date.now() - statSync60(paths.lockPath).mtimeMs;
123992
124389
  if (age > 30000) {
123993
124390
  unlinkSync22(paths.lockPath);
123994
124391
  continue;
@@ -124021,7 +124418,7 @@ function alignStagedOwnerToDir(stagingPath, targetDir) {
124021
124418
  const euid = overlayWriterRuntime.geteuid();
124022
124419
  if (euid === undefined)
124023
124420
  return;
124024
- const dirStat = statSync59(targetDir);
124421
+ const dirStat = statSync60(targetDir);
124025
124422
  if (dirStat.uid === euid)
124026
124423
  return;
124027
124424
  overlayWriterRuntime.chown(stagingPath, dirStat.uid, dirStat.gid);
@@ -124031,8 +124428,8 @@ function writeOverlayEntry(agent, slug, yamlText, opts = {}) {
124031
124428
  const paths = overlayPathsFor(agent, opts);
124032
124429
  return withAgentLock(paths, () => {
124033
124430
  ensureDirs(paths);
124034
- const stagingPath = join111(paths.scheduleStagingDir, `${slug}.yaml`);
124035
- const finalPath = join111(paths.scheduleDir, `${slug}.yaml`);
124431
+ const stagingPath = join112(paths.scheduleStagingDir, `${slug}.yaml`);
124432
+ const finalPath = join112(paths.scheduleDir, `${slug}.yaml`);
124036
124433
  const fd = openSync19(stagingPath, "w", 384);
124037
124434
  try {
124038
124435
  writeSync10(fd, yamlText);
@@ -124049,8 +124446,8 @@ function writeSkillsOverlayEntry(agent, slug, yamlText, opts = {}) {
124049
124446
  const paths = overlayPathsFor(agent, opts);
124050
124447
  return withAgentLock(paths, () => {
124051
124448
  ensureSkillsDirs(paths);
124052
- const stagingPath = join111(paths.skillsStagingDir, `${slug}.yaml`);
124053
- const finalPath = join111(paths.skillsDir, `${slug}.yaml`);
124449
+ const stagingPath = join112(paths.skillsStagingDir, `${slug}.yaml`);
124450
+ const finalPath = join112(paths.skillsDir, `${slug}.yaml`);
124054
124451
  const fd = openSync19(stagingPath, "w", 384);
124055
124452
  try {
124056
124453
  writeSync10(fd, yamlText);
@@ -124066,7 +124463,7 @@ function writeSkillsOverlayEntry(agent, slug, yamlText, opts = {}) {
124066
124463
  function deleteSkillsOverlayEntry(agent, slug, opts = {}) {
124067
124464
  const paths = overlayPathsFor(agent, opts);
124068
124465
  return withAgentLock(paths, () => {
124069
- const finalPath = join111(paths.skillsDir, `${slug}.yaml`);
124466
+ const finalPath = join112(paths.skillsDir, `${slug}.yaml`);
124070
124467
  if (!existsSync109(finalPath))
124071
124468
  return false;
124072
124469
  unlinkSync22(finalPath);
@@ -124078,10 +124475,10 @@ function listSkillsOverlayEntries(agent, opts = {}) {
124078
124475
  if (!existsSync109(paths.skillsDir))
124079
124476
  return [];
124080
124477
  const out = [];
124081
- for (const name of readdirSync39(paths.skillsDir)) {
124478
+ for (const name of readdirSync40(paths.skillsDir)) {
124082
124479
  if (!/\.ya?ml$/i.test(name))
124083
124480
  continue;
124084
- const full = join111(paths.skillsDir, name);
124481
+ const full = join112(paths.skillsDir, name);
124085
124482
  try {
124086
124483
  const raw = readFileSync97(full, "utf-8");
124087
124484
  const slug = name.replace(/\.ya?ml$/i, "");
@@ -124093,7 +124490,7 @@ function listSkillsOverlayEntries(agent, opts = {}) {
124093
124490
  function deleteOverlayEntry(agent, slug, opts = {}) {
124094
124491
  const paths = overlayPathsFor(agent, opts);
124095
124492
  return withAgentLock(paths, () => {
124096
- const finalPath = join111(paths.scheduleDir, `${slug}.yaml`);
124493
+ const finalPath = join112(paths.scheduleDir, `${slug}.yaml`);
124097
124494
  if (!existsSync109(finalPath))
124098
124495
  return false;
124099
124496
  unlinkSync22(finalPath);
@@ -124105,10 +124502,10 @@ function listOverlayEntries(agent, opts = {}) {
124105
124502
  if (!existsSync109(paths.scheduleDir))
124106
124503
  return [];
124107
124504
  const out = [];
124108
- for (const name of readdirSync39(paths.scheduleDir)) {
124505
+ for (const name of readdirSync40(paths.scheduleDir)) {
124109
124506
  if (!/\.ya?ml$/i.test(name))
124110
124507
  continue;
124111
- const full = join111(paths.scheduleDir, name);
124508
+ const full = join112(paths.scheduleDir, name);
124112
124509
  try {
124113
124510
  const raw = readFileSync97(full, "utf-8");
124114
124511
  const slug = name.replace(/\.ya?ml$/i, "");
@@ -124334,19 +124731,19 @@ import {
124334
124731
  fsyncSync as fsyncSync9,
124335
124732
  mkdirSync as mkdirSync64,
124336
124733
  openSync as openSync20,
124337
- readdirSync as readdirSync40,
124734
+ readdirSync as readdirSync41,
124338
124735
  readFileSync as readFileSync98,
124339
124736
  renameSync as renameSync30,
124340
124737
  unlinkSync as unlinkSync23,
124341
124738
  writeFileSync as writeFileSync47,
124342
124739
  writeSync as writeSync11
124343
124740
  } from "node:fs";
124344
- import { join as join112 } from "node:path";
124741
+ import { join as join113 } from "node:path";
124345
124742
  import { randomBytes as randomBytes17 } from "node:crypto";
124346
124743
  var STAGE_ID_PREFIX = "cap_";
124347
124744
  function pendingDir(agent, opts = {}) {
124348
124745
  const paths = overlayPathsFor(agent, opts);
124349
- return join112(paths.scheduleDir, ".pending");
124746
+ return join113(paths.scheduleDir, ".pending");
124350
124747
  }
124351
124748
  function ensurePendingDir(agent, opts = {}) {
124352
124749
  const dir = pendingDir(agent, opts);
@@ -124359,8 +124756,8 @@ function newStageId() {
124359
124756
  function stagePendingScheduleEntry(opts) {
124360
124757
  const dir = ensurePendingDir(opts.agent, { root: opts.root });
124361
124758
  const stageId = opts.stageId ?? newStageId();
124362
- const yamlPath = join112(dir, `${stageId}.yaml`);
124363
- const metaPath = join112(dir, `${stageId}.meta.json`);
124759
+ const yamlPath = join113(dir, `${stageId}.yaml`);
124760
+ const metaPath = join113(dir, `${stageId}.meta.json`);
124364
124761
  const meta = {
124365
124762
  v: 1,
124366
124763
  stage_id: stageId,
@@ -124390,12 +124787,12 @@ function listPendingScheduleEntries(agent, opts = {}) {
124390
124787
  if (!existsSync110(dir))
124391
124788
  return [];
124392
124789
  const out = [];
124393
- for (const name of readdirSync40(dir).sort()) {
124790
+ for (const name of readdirSync41(dir).sort()) {
124394
124791
  if (!name.endsWith(".meta.json"))
124395
124792
  continue;
124396
124793
  const stageId = name.slice(0, -".meta.json".length);
124397
- const metaPath = join112(dir, name);
124398
- const yamlPath = join112(dir, `${stageId}.yaml`);
124794
+ const metaPath = join113(dir, name);
124795
+ const yamlPath = join113(dir, `${stageId}.yaml`);
124399
124796
  if (!existsSync110(yamlPath))
124400
124797
  continue;
124401
124798
  try {
@@ -124414,7 +124811,7 @@ function commitPendingScheduleEntry(opts) {
124414
124811
  return { committed: false, reason: "not_found" };
124415
124812
  const slug = match.meta.entry.name ?? match.stageId;
124416
124813
  const paths = overlayPathsFor(opts.agent, { root: opts.root });
124417
- const finalPath = join112(paths.scheduleDir, `${slug}.yaml`);
124814
+ const finalPath = join113(paths.scheduleDir, `${slug}.yaml`);
124418
124815
  if (existsSync110(finalPath)) {
124419
124816
  return { committed: false, reason: "slug_collision" };
124420
124817
  }
@@ -125067,7 +125464,7 @@ import { existsSync as existsSync112 } from "node:fs";
125067
125464
  init_reconcile_default_skills();
125068
125465
  init_agent_config();
125069
125466
  var import_yaml25 = __toESM(require_dist(), 1);
125070
- import { join as join113 } from "node:path";
125467
+ import { join as join114 } from "node:path";
125071
125468
  var MAX_SKILLS_PER_AGENT2 = 20;
125072
125469
  var V1_ALLOWED_SOURCE_PREFIX = "bundled:";
125073
125470
  function exitCodeFor2(code) {
@@ -125142,7 +125539,7 @@ function skillInstall(opts) {
125142
125539
  return err("E_SKILL_QUOTA_EXCEEDED", `agent ${agent} already has ${used} overlay-installed skills (cap ${MAX_SKILLS_PER_AGENT2})`);
125143
125540
  }
125144
125541
  const poolDir = opts.bundledSkillsPoolDir ?? getBundledSkillsPoolDir();
125145
- const skillPath = join113(poolDir, skillName);
125542
+ const skillPath = join114(poolDir, skillName);
125146
125543
  if (!existsSync112(skillPath)) {
125147
125544
  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.`);
125148
125545
  }
@@ -125314,20 +125711,20 @@ import {
125314
125711
  chmodSync as chmodSync18,
125315
125712
  closeSync as closeSync21,
125316
125713
  existsSync as existsSync113,
125317
- lstatSync as lstatSync14,
125714
+ lstatSync as lstatSync15,
125318
125715
  mkdirSync as mkdirSync65,
125319
125716
  mkdtempSync as mkdtempSync5,
125320
125717
  openSync as openSync21,
125321
125718
  readFileSync as readFileSync100,
125322
- readdirSync as readdirSync41,
125719
+ readdirSync as readdirSync42,
125323
125720
  realpathSync as realpathSync9,
125324
125721
  renameSync as renameSync31,
125325
125722
  rmSync as rmSync20,
125326
- statSync as statSync60,
125723
+ statSync as statSync61,
125327
125724
  writeFileSync as writeFileSync48
125328
125725
  } from "node:fs";
125329
125726
  import { tmpdir as tmpdir6, homedir as homedir59 } from "node:os";
125330
- import { dirname as dirname47, join as join114, relative as relative6, resolve as resolve60 } from "node:path";
125727
+ import { dirname as dirname48, join as join115, relative as relative6, resolve as resolve60 } from "node:path";
125331
125728
  import { spawnSync as spawnSync24 } from "node:child_process";
125332
125729
  var SKILL_NAME_RE = /^[a-z0-9][a-z0-9_-]{0,62}$/;
125333
125730
  var SH_SCRIPT_RE2 = /^scripts\/[A-Za-z0-9_.-]+\.sh$/;
@@ -125341,7 +125738,7 @@ function scanForClaudeP2(content) {
125341
125738
  function resolveSkillsPoolDir2(override) {
125342
125739
  const raw = override ?? "~/.switchroom/skills";
125343
125740
  if (raw.startsWith("~/")) {
125344
- return join114(homedir59(), raw.slice(2));
125741
+ return join115(homedir59(), raw.slice(2));
125345
125742
  }
125346
125743
  if (raw === "~")
125347
125744
  return homedir59();
@@ -125373,14 +125770,14 @@ function isTarballPath(p) {
125373
125770
  }
125374
125771
  function loadFromDir(dir) {
125375
125772
  const abs = realpathSync9(dir);
125376
- if (!statSync60(abs).isDirectory()) {
125773
+ if (!statSync61(abs).isDirectory()) {
125377
125774
  fail4(`--from path is not a directory: ${dir}`);
125378
125775
  }
125379
125776
  const files = {};
125380
125777
  const walk2 = (sub) => {
125381
- const entries = readdirSync41(sub, { withFileTypes: true });
125778
+ const entries = readdirSync42(sub, { withFileTypes: true });
125382
125779
  for (const ent of entries) {
125383
- const full = join114(sub, ent.name);
125780
+ const full = join115(sub, ent.name);
125384
125781
  const rel = relative6(abs, full);
125385
125782
  if (ent.isSymbolicLink()) {
125386
125783
  fail4(`refusing to read symlink inside --from dir: ${rel}`);
@@ -125415,7 +125812,7 @@ function loadFromTarball(tarPath) {
125415
125812
  fail4(`tarball contains disallowed path: ${JSON.stringify(entry)} \u2014 ` + `refusing to extract before any file is written`);
125416
125813
  }
125417
125814
  }
125418
- const staging = mkdtempSync5(join114(tmpdir6(), "skill-apply-extract-"));
125815
+ const staging = mkdtempSync5(join115(tmpdir6(), "skill-apply-extract-"));
125419
125816
  try {
125420
125817
  const flags = isGz ? ["-xzf"] : ["-xf"];
125421
125818
  const r = spawnSync24("tar", [
@@ -125501,8 +125898,8 @@ function validatePayload(name, files) {
125501
125898
  errors2.push(`${path10} fails \`bash -n\` syntax check: ${(r.stderr ?? "").trim()}`);
125502
125899
  }
125503
125900
  } else if (PY_SCRIPT_RE2.test(path10)) {
125504
- const tmp = mkdtempSync5(join114(tmpdir6(), "skill-apply-py-"));
125505
- const tmpPy = join114(tmp, "check.py");
125901
+ const tmp = mkdtempSync5(join115(tmpdir6(), "skill-apply-py-"));
125902
+ const tmpPy = join115(tmp, "check.py");
125506
125903
  try {
125507
125904
  writeFileSync48(tmpPy, content);
125508
125905
  const r = spawnSync24("python3", ["-m", "py_compile", tmpPy], {
@@ -125524,8 +125921,8 @@ function diffSummary(currentDir, files) {
125524
125921
  const currentFiles = {};
125525
125922
  if (existsSync113(currentDir)) {
125526
125923
  const walk2 = (sub) => {
125527
- for (const ent of readdirSync41(sub, { withFileTypes: true })) {
125528
- const full = join114(sub, ent.name);
125924
+ for (const ent of readdirSync42(sub, { withFileTypes: true })) {
125925
+ const full = join115(sub, ent.name);
125529
125926
  const rel = relative6(currentDir, full);
125530
125927
  if (ent.isDirectory()) {
125531
125928
  walk2(full);
@@ -125561,10 +125958,10 @@ function writePayload(poolDir, name, files) {
125561
125958
  if (!existsSync113(poolDir)) {
125562
125959
  mkdirSync65(poolDir, { recursive: true, mode: 493 });
125563
125960
  }
125564
- const target = join114(poolDir, name);
125961
+ const target = join115(poolDir, name);
125565
125962
  let targetIsSymlink = false;
125566
125963
  try {
125567
- const st = lstatSync14(target);
125964
+ const st = lstatSync15(target);
125568
125965
  if (st.isSymbolicLink()) {
125569
125966
  targetIsSymlink = true;
125570
125967
  }
@@ -125572,13 +125969,13 @@ function writePayload(poolDir, name, files) {
125572
125969
  if (targetIsSymlink) {
125573
125970
  fail4(`refusing to overwrite symlink at ${target}; investigate manually`);
125574
125971
  }
125575
- const staging = mkdtempSync5(join114(poolDir, `.skill-apply-stage-${name}-`));
125972
+ const staging = mkdtempSync5(join115(poolDir, `.skill-apply-stage-${name}-`));
125576
125973
  chmodSync18(staging, 493);
125577
125974
  let oldRename = null;
125578
125975
  try {
125579
125976
  for (const [path10, content] of Object.entries(files)) {
125580
- const full = join114(staging, path10);
125581
- mkdirSync65(dirname47(full), { recursive: true, mode: 493 });
125977
+ const full = join115(staging, path10);
125978
+ mkdirSync65(dirname48(full), { recursive: true, mode: 493 });
125582
125979
  const fd = openSync21(full, "wx");
125583
125980
  try {
125584
125981
  writeFileSync48(fd, content);
@@ -125592,7 +125989,7 @@ function writePayload(poolDir, name, files) {
125592
125989
  }
125593
125990
  let targetExists = false;
125594
125991
  try {
125595
- lstatSync14(target);
125992
+ lstatSync15(target);
125596
125993
  targetExists = true;
125597
125994
  } catch {}
125598
125995
  if (targetExists) {
@@ -125634,7 +126031,7 @@ function registerSkillCommand(program3) {
125634
126031
  if (!existsSync113(fromPath)) {
125635
126032
  fail4(`--from path does not exist: ${opts.from}`);
125636
126033
  }
125637
- const st = statSync60(fromPath);
126034
+ const st = statSync61(fromPath);
125638
126035
  if (st.isDirectory()) {
125639
126036
  files = loadFromDir(fromPath);
125640
126037
  } else if (isTarballPath(fromPath)) {
@@ -125655,7 +126052,7 @@ function registerSkillCommand(program3) {
125655
126052
  }
125656
126053
  const config = loadConfig();
125657
126054
  const poolDir = resolveSkillsPoolDir2(config.switchroom?.skills_dir);
125658
- const currentDir = join114(poolDir, name);
126055
+ const currentDir = join115(poolDir, name);
125659
126056
  console.log(source_default.bold(`Skill: ${name}`) + source_default.gray(` (${Object.keys(files).length} files, ${sumBytes(files)} bytes)`));
125660
126057
  console.log(source_default.bold("Diff vs current pool content:"));
125661
126058
  console.log(diffSummary(currentDir, files));
@@ -125693,19 +126090,19 @@ import {
125693
126090
  chmodSync as chmodSync19,
125694
126091
  closeSync as closeSync22,
125695
126092
  existsSync as existsSync114,
125696
- lstatSync as lstatSync15,
126093
+ lstatSync as lstatSync16,
125697
126094
  mkdirSync as mkdirSync66,
125698
126095
  mkdtempSync as mkdtempSync6,
125699
126096
  openSync as openSync22,
125700
126097
  readFileSync as readFileSync101,
125701
- readdirSync as readdirSync42,
126098
+ readdirSync as readdirSync43,
125702
126099
  renameSync as renameSync32,
125703
126100
  rmSync as rmSync21,
125704
- statSync as statSync61,
126101
+ statSync as statSync62,
125705
126102
  utimesSync,
125706
126103
  writeFileSync as writeFileSync49
125707
126104
  } from "node:fs";
125708
- import { dirname as dirname48, join as join115, relative as relative7, resolve as resolve61 } from "node:path";
126105
+ import { dirname as dirname49, join as join116, relative as relative7, resolve as resolve61 } from "node:path";
125709
126106
  import { homedir as homedir60, tmpdir as tmpdir7 } from "node:os";
125710
126107
  import { spawnSync as spawnSync25 } from "node:child_process";
125711
126108
  var PERSONAL_PREFIX = "personal-";
@@ -125714,10 +126111,10 @@ var TRASH_TTL_MS = 24 * 60 * 60 * 1000;
125714
126111
  var PERSONAL_SKILLS_SUBPATH2 = "personal-skills";
125715
126112
  function resolveConfigSkillsDir(agent) {
125716
126113
  const override = process.env.SWITCHROOM_CONFIG_DIR;
125717
- const candidate = override ? resolve61(override) : join115(homedir60(), ".switchroom-config");
126114
+ const candidate = override ? resolve61(override) : join116(homedir60(), ".switchroom-config");
125718
126115
  if (!existsSync114(candidate))
125719
126116
  return null;
125720
- return join115(candidate, "agents", agent, PERSONAL_SKILLS_SUBPATH2);
126117
+ return join116(candidate, "agents", agent, PERSONAL_SKILLS_SUBPATH2);
125721
126118
  }
125722
126119
  var MIRROR_PRIOR_TTL_MS = 24 * 60 * 60 * 1000;
125723
126120
  function sweepMirrorPriors(configSkillsRoot) {
@@ -125725,7 +126122,7 @@ function sweepMirrorPriors(configSkillsRoot) {
125725
126122
  if (!existsSync114(configSkillsRoot))
125726
126123
  return;
125727
126124
  const now2 = Date.now();
125728
- for (const ent of readdirSync42(configSkillsRoot)) {
126125
+ for (const ent of readdirSync43(configSkillsRoot)) {
125729
126126
  const m = /^\.(?:.+)-(?:prior|trash)-(\d+)$/.exec(ent);
125730
126127
  if (!m)
125731
126128
  continue;
@@ -125735,7 +126132,7 @@ function sweepMirrorPriors(configSkillsRoot) {
125735
126132
  if (now2 - ts < MIRROR_PRIOR_TTL_MS)
125736
126133
  continue;
125737
126134
  try {
125738
- rmSync21(join115(configSkillsRoot, ent), { recursive: true, force: true });
126135
+ rmSync21(join116(configSkillsRoot, ent), { recursive: true, force: true });
125739
126136
  } catch {}
125740
126137
  }
125741
126138
  } catch {}
@@ -125744,11 +126141,11 @@ function mirrorToConfigRepo(agent, name, liveSkillDir) {
125744
126141
  const configSkillsRoot = resolveConfigSkillsDir(agent);
125745
126142
  if (!configSkillsRoot)
125746
126143
  return;
125747
- const dest = join115(configSkillsRoot, name);
126144
+ const dest = join116(configSkillsRoot, name);
125748
126145
  try {
125749
126146
  if (liveSkillDir !== null) {
125750
126147
  try {
125751
- const st = lstatSync15(liveSkillDir);
126148
+ const st = lstatSync16(liveSkillDir);
125752
126149
  if (st.isSymbolicLink()) {
125753
126150
  process.stderr.write(source_default.yellow(`warning: refusing to mirror ${liveSkillDir} \u2014 source is a symlink
125754
126151
  `));
@@ -125759,19 +126156,19 @@ function mirrorToConfigRepo(agent, name, liveSkillDir) {
125759
126156
  if (liveSkillDir === null) {
125760
126157
  sweepMirrorPriors(configSkillsRoot);
125761
126158
  if (existsSync114(dest)) {
125762
- const trash = join115(configSkillsRoot, `.${name}-trash-${Date.now()}`);
126159
+ const trash = join116(configSkillsRoot, `.${name}-trash-${Date.now()}`);
125763
126160
  renameSync32(dest, trash);
125764
126161
  }
125765
126162
  return;
125766
126163
  }
125767
126164
  mkdirSync66(configSkillsRoot, { recursive: true, mode: 493 });
125768
126165
  sweepMirrorPriors(configSkillsRoot);
125769
- const staging = mkdtempSync6(join115(configSkillsRoot, `.${name}-staging-`));
126166
+ const staging = mkdtempSync6(join116(configSkillsRoot, `.${name}-staging-`));
125770
126167
  const walk2 = (src, dst) => {
125771
126168
  mkdirSync66(dst, { recursive: true, mode: 493 });
125772
- for (const ent of readdirSync42(src, { withFileTypes: true })) {
125773
- const s = join115(src, ent.name);
125774
- const d = join115(dst, ent.name);
126169
+ for (const ent of readdirSync43(src, { withFileTypes: true })) {
126170
+ const s = join116(src, ent.name);
126171
+ const d = join116(dst, ent.name);
125775
126172
  if (ent.isSymbolicLink())
125776
126173
  continue;
125777
126174
  if (ent.isDirectory())
@@ -125784,7 +126181,7 @@ function mirrorToConfigRepo(agent, name, liveSkillDir) {
125784
126181
  walk2(liveSkillDir, staging);
125785
126182
  chmodSync19(staging, 493);
125786
126183
  if (existsSync114(dest)) {
125787
- const prior = join115(configSkillsRoot, `.${name}-prior-${Date.now()}`);
126184
+ const prior = join116(configSkillsRoot, `.${name}-prior-${Date.now()}`);
125788
126185
  renameSync32(dest, prior);
125789
126186
  }
125790
126187
  renameSync32(staging, dest);
@@ -125814,20 +126211,20 @@ function resolveAgent(opts) {
125814
126211
  function resolveAgentsRoot(opts) {
125815
126212
  if (opts.root)
125816
126213
  return resolve61(opts.root);
125817
- return join115(homedir60(), ".switchroom", "agents");
126214
+ return join116(homedir60(), ".switchroom", "agents");
125818
126215
  }
125819
126216
  function personalSkillDir(agentsRoot, agent, name) {
125820
- return join115(agentsRoot, agent, ".claude", "skills", PERSONAL_PREFIX + name);
126217
+ return join116(agentsRoot, agent, ".claude", "skills", PERSONAL_PREFIX + name);
125821
126218
  }
125822
126219
  function trashDir(agentsRoot, agent) {
125823
- return join115(agentsRoot, agent, ".claude", TRASH_DIRNAME);
126220
+ return join116(agentsRoot, agent, ".claude", TRASH_DIRNAME);
125824
126221
  }
125825
126222
  function countPersonalSkills(agentsRoot, agent) {
125826
- const skillsDir = join115(agentsRoot, agent, ".claude", "skills");
126223
+ const skillsDir = join116(agentsRoot, agent, ".claude", "skills");
125827
126224
  if (!existsSync114(skillsDir))
125828
126225
  return 0;
125829
126226
  let n = 0;
125830
- for (const ent of readdirSync42(skillsDir, { withFileTypes: true })) {
126227
+ for (const ent of readdirSync43(skillsDir, { withFileTypes: true })) {
125831
126228
  if (ent.isDirectory() && ent.name.startsWith(PERSONAL_PREFIX))
125832
126229
  n += 1;
125833
126230
  }
@@ -125855,13 +126252,13 @@ function readStdinSync2() {
125855
126252
  }
125856
126253
  function loadFromDir2(dir) {
125857
126254
  const abs = resolve61(dir);
125858
- if (!statSync61(abs).isDirectory()) {
126255
+ if (!statSync62(abs).isDirectory()) {
125859
126256
  fail5(`--from path is not a directory: ${dir}`);
125860
126257
  }
125861
126258
  const files = {};
125862
126259
  const walk2 = (sub) => {
125863
- for (const ent of readdirSync42(sub, { withFileTypes: true })) {
125864
- const full = join115(sub, ent.name);
126260
+ for (const ent of readdirSync43(sub, { withFileTypes: true })) {
126261
+ const full = join116(sub, ent.name);
125865
126262
  if (ent.isSymbolicLink()) {
125866
126263
  fail5(`refusing to read symlink in --from dir: ${relative7(abs, full)}`);
125867
126264
  }
@@ -125914,8 +126311,8 @@ function behavioralValidate(files) {
125914
126311
  errors2.push(`${path10} fails \`bash -n\`: ${(r.stderr ?? "").trim()}`);
125915
126312
  }
125916
126313
  } else if (PY_SCRIPT_RE.test(path10)) {
125917
- const tmp = mkdtempSync6(join115(tmpdir7(), "skill-personal-py-"));
125918
- const tmpPy = join115(tmp, "check.py");
126314
+ const tmp = mkdtempSync6(join116(tmpdir7(), "skill-personal-py-"));
126315
+ const tmpPy = join116(tmp, "check.py");
125919
126316
  try {
125920
126317
  writeFileSync49(tmpPy, content);
125921
126318
  const r = spawnSync25("python3", ["-m", "py_compile", tmpPy], {
@@ -125936,12 +126333,12 @@ function sweepTrash(agentsRoot, agent) {
125936
126333
  if (!existsSync114(trash))
125937
126334
  return;
125938
126335
  const now2 = Date.now();
125939
- for (const ent of readdirSync42(trash, { withFileTypes: true })) {
126336
+ for (const ent of readdirSync43(trash, { withFileTypes: true })) {
125940
126337
  if (!ent.isDirectory())
125941
126338
  continue;
125942
- const entPath = join115(trash, ent.name);
126339
+ const entPath = join116(trash, ent.name);
125943
126340
  try {
125944
- const st = statSync61(entPath);
126341
+ const st = statSync62(entPath);
125945
126342
  if (now2 - st.mtimeMs > TRASH_TTL_MS) {
125946
126343
  rmSync21(entPath, { recursive: true, force: true });
125947
126344
  }
@@ -125951,7 +126348,7 @@ function sweepTrash(agentsRoot, agent) {
125951
126348
  function writePersonalSkill(targetDir, files) {
125952
126349
  let targetIsSymlink = false;
125953
126350
  try {
125954
- const st = lstatSync15(targetDir);
126351
+ const st = lstatSync16(targetDir);
125955
126352
  if (st.isSymbolicLink()) {
125956
126353
  targetIsSymlink = true;
125957
126354
  }
@@ -125959,14 +126356,14 @@ function writePersonalSkill(targetDir, files) {
125959
126356
  if (targetIsSymlink) {
125960
126357
  fail5(`refusing to overwrite symlink at ${targetDir}; investigate manually`);
125961
126358
  }
125962
- mkdirSync66(dirname48(targetDir), { recursive: true, mode: 493 });
125963
- const staging = mkdtempSync6(join115(dirname48(targetDir), `.skill-personal-stage-`));
126359
+ mkdirSync66(dirname49(targetDir), { recursive: true, mode: 493 });
126360
+ const staging = mkdtempSync6(join116(dirname49(targetDir), `.skill-personal-stage-`));
125964
126361
  chmodSync19(staging, 493);
125965
126362
  let oldRename = null;
125966
126363
  try {
125967
126364
  for (const [path10, content] of Object.entries(files)) {
125968
- const full = join115(staging, path10);
125969
- mkdirSync66(dirname48(full), { recursive: true, mode: 493 });
126365
+ const full = join116(staging, path10);
126366
+ mkdirSync66(dirname49(full), { recursive: true, mode: 493 });
125970
126367
  const fd = openSync22(full, "wx");
125971
126368
  try {
125972
126369
  writeFileSync49(fd, content);
@@ -125980,7 +126377,7 @@ function writePersonalSkill(targetDir, files) {
125980
126377
  }
125981
126378
  let targetExists = false;
125982
126379
  try {
125983
- lstatSync15(targetDir);
126380
+ lstatSync16(targetDir);
125984
126381
  targetExists = true;
125985
126382
  } catch {}
125986
126383
  if (targetExists) {
@@ -126015,7 +126412,7 @@ function loadValidateWrite(agentsRoot, agent, name, files, ensureNew) {
126015
126412
  const target = personalSkillDir(agentsRoot, agent, name);
126016
126413
  const exists = (() => {
126017
126414
  try {
126018
- lstatSync15(target);
126415
+ lstatSync16(target);
126019
126416
  return true;
126020
126417
  } catch {
126021
126418
  return false;
@@ -126067,7 +126464,7 @@ function loadFiles(opts) {
126067
126464
  if (!existsSync114(p)) {
126068
126465
  fail5(`--from path does not exist: ${opts.from}`);
126069
126466
  }
126070
- const st = statSync61(p);
126467
+ const st = statSync62(p);
126071
126468
  if (st.isDirectory()) {
126072
126469
  return loadFromDir2(p);
126073
126470
  }
@@ -126112,10 +126509,10 @@ function editPersonalAction(name, opts) {
126112
126509
  }
126113
126510
  var CLONE_SOURCE_RE = /^(shared|bundled):([a-z0-9][a-z0-9_-]{0,62})$/;
126114
126511
  function defaultSharedRoot() {
126115
- return join115(homedir60(), ".switchroom", "skills");
126512
+ return join116(homedir60(), ".switchroom", "skills");
126116
126513
  }
126117
126514
  function defaultBundledRoot() {
126118
- return join115(homedir60(), ".switchroom", "skills", "_bundled");
126515
+ return join116(homedir60(), ".switchroom", "skills", "_bundled");
126119
126516
  }
126120
126517
  function resolveCloneSource(source, opts) {
126121
126518
  const m = CLONE_SOURCE_RE.exec(source);
@@ -126125,11 +126522,11 @@ function resolveCloneSource(source, opts) {
126125
126522
  const tier = m[1];
126126
126523
  const slug = m[2];
126127
126524
  const root = tier === "bundled" ? opts.bundledRoot ?? defaultBundledRoot() : opts.sharedRoot ?? defaultSharedRoot();
126128
- const dir = join115(root, slug);
126525
+ const dir = join116(root, slug);
126129
126526
  if (!existsSync114(dir)) {
126130
126527
  fail5(`clone source ${JSON.stringify(source)} not found at ${dir}; ` + `check \`switchroom skill search --tier ${tier}\``, 1);
126131
126528
  }
126132
- const st = lstatSync15(dir);
126529
+ const st = lstatSync16(dir);
126133
126530
  if (st.isSymbolicLink()) {
126134
126531
  fail5(`clone source ${JSON.stringify(source)} is a symlink at ${dir}; ` + `point clone at the canonical pool path instead`);
126135
126532
  }
@@ -126140,8 +126537,8 @@ function readSourceFiles(dir) {
126140
126537
  const files = {};
126141
126538
  const skipped = [];
126142
126539
  const walk2 = (sub) => {
126143
- for (const ent of readdirSync42(sub, { withFileTypes: true })) {
126144
- const full = join115(sub, ent.name);
126540
+ for (const ent of readdirSync43(sub, { withFileTypes: true })) {
126541
+ const full = join116(sub, ent.name);
126145
126542
  if (ent.isSymbolicLink()) {
126146
126543
  continue;
126147
126544
  }
@@ -126156,7 +126553,7 @@ function readSourceFiles(dir) {
126156
126553
  continue;
126157
126554
  }
126158
126555
  try {
126159
- const st = lstatSync15(full);
126556
+ const st = lstatSync16(full);
126160
126557
  if (st.size > CLONE_MAX_FILE_BYTES) {
126161
126558
  fail5(`clone source has oversized file ${rel} (${st.size} bytes > ${CLONE_MAX_FILE_BYTES}); ` + `refuse to read`, 3);
126162
126559
  }
@@ -126238,7 +126635,7 @@ function removePersonalAction(name, opts) {
126238
126635
  }
126239
126636
  const target = personalSkillDir(agentsRoot, agent, name);
126240
126637
  try {
126241
- const st = lstatSync15(target);
126638
+ const st = lstatSync16(target);
126242
126639
  if (st.isSymbolicLink()) {
126243
126640
  fail5(`refusing to remove symlink at ${target}; investigate manually`);
126244
126641
  }
@@ -126252,7 +126649,7 @@ function removePersonalAction(name, opts) {
126252
126649
  const trashRoot2 = trashDir(agentsRoot, agent);
126253
126650
  mkdirSync66(trashRoot2, { recursive: true, mode: 493 });
126254
126651
  const ts = Date.now();
126255
- const trashTarget = join115(trashRoot2, `${name}-${ts}`);
126652
+ const trashTarget = join116(trashRoot2, `${name}-${ts}`);
126256
126653
  renameSync32(target, trashTarget);
126257
126654
  const now2 = new Date(ts);
126258
126655
  utimesSync(trashTarget, now2, now2);
@@ -126271,27 +126668,27 @@ function listPersonalAction(opts) {
126271
126668
  const agent = resolveAgent(opts);
126272
126669
  const agentsRoot = resolveAgentsRoot(opts);
126273
126670
  sweepTrash(agentsRoot, agent);
126274
- const skillsDir = join115(agentsRoot, agent, ".claude", "skills");
126671
+ const skillsDir = join116(agentsRoot, agent, ".claude", "skills");
126275
126672
  const personal = [];
126276
126673
  if (existsSync114(skillsDir)) {
126277
- for (const ent of readdirSync42(skillsDir, { withFileTypes: true })) {
126674
+ for (const ent of readdirSync43(skillsDir, { withFileTypes: true })) {
126278
126675
  if (!ent.isDirectory())
126279
126676
  continue;
126280
126677
  if (!ent.name.startsWith(PERSONAL_PREFIX))
126281
126678
  continue;
126282
126679
  const skillName = ent.name.slice(PERSONAL_PREFIX.length);
126283
- const skillPath = join115(skillsDir, ent.name);
126680
+ const skillPath = join116(skillsDir, ent.name);
126284
126681
  let fileCount = 0;
126285
126682
  let totalBytes = 0;
126286
126683
  const walk2 = (sub) => {
126287
- for (const e of readdirSync42(sub, { withFileTypes: true })) {
126684
+ for (const e of readdirSync43(sub, { withFileTypes: true })) {
126288
126685
  if (e.isFile()) {
126289
126686
  fileCount += 1;
126290
126687
  try {
126291
- totalBytes += statSync61(join115(sub, e.name)).size;
126688
+ totalBytes += statSync62(join116(sub, e.name)).size;
126292
126689
  } catch {}
126293
126690
  } else if (e.isDirectory()) {
126294
- walk2(join115(sub, e.name));
126691
+ walk2(join116(sub, e.name));
126295
126692
  }
126296
126693
  }
126297
126694
  };
@@ -126330,7 +126727,7 @@ function registerSkillPersonalCommands(program3) {
126330
126727
  // src/cli/self-improve-propose-skill.ts
126331
126728
  import { createConnection as createConnection4 } from "node:net";
126332
126729
  import { homedir as homedir61 } from "node:os";
126333
- import { join as join116 } from "node:path";
126730
+ import { join as join117 } from "node:path";
126334
126731
  import { readFileSync as readFileSync102 } from "node:fs";
126335
126732
 
126336
126733
  // src/self-improve/skill-proposals.ts
@@ -126378,7 +126775,7 @@ var STOPWORDS = new Set([
126378
126775
  // src/cli/self-improve-propose-skill.ts
126379
126776
  var IPC_CONNECT_TIMEOUT_MS = 5000;
126380
126777
  function gatewaySocketPath() {
126381
- return process.env.SWITCHROOM_GATEWAY_SOCKET ?? (process.env.TELEGRAM_STATE_DIR ? join116(process.env.TELEGRAM_STATE_DIR, "gateway.sock") : join116(homedir61(), ".claude", "channels", "telegram", "gateway.sock"));
126778
+ return process.env.SWITCHROOM_GATEWAY_SOCKET ?? (process.env.TELEGRAM_STATE_DIR ? join117(process.env.TELEGRAM_STATE_DIR, "gateway.sock") : join117(homedir61(), ".claude", "channels", "telegram", "gateway.sock"));
126382
126779
  }
126383
126780
  function fail6(msg, code = 1) {
126384
126781
  console.error(msg);
@@ -126458,11 +126855,11 @@ function registerSelfImproveProposeSkillCommand(program3) {
126458
126855
  // src/cli/self-improve-eval-case.ts
126459
126856
  import { createConnection as createConnection5 } from "node:net";
126460
126857
  import { homedir as homedir62 } from "node:os";
126461
- import { join as join120, resolve as resolve62, sep as sep7 } from "node:path";
126858
+ import { join as join121, resolve as resolve62, sep as sep7 } from "node:path";
126462
126859
  import { existsSync as existsSync119, readFileSync as readFileSync107, realpathSync as realpathSync10 } from "node:fs";
126463
126860
 
126464
126861
  // src/self-improve/apply-guard.ts
126465
- import { existsSync as existsSync117, lstatSync as lstatSync16, readFileSync as readFileSync105, statSync as statSync63 } from "node:fs";
126862
+ import { existsSync as existsSync117, lstatSync as lstatSync17, readFileSync as readFileSync105, statSync as statSync64 } from "node:fs";
126466
126863
 
126467
126864
  // src/self-improve/config.ts
126468
126865
  function intEnv(name, def) {
@@ -126483,11 +126880,11 @@ function resolveSelfImproveConfig() {
126483
126880
  }
126484
126881
 
126485
126882
  // src/self-improve/eval-gate.ts
126486
- import { existsSync as existsSync115, readFileSync as readFileSync103, readdirSync as readdirSync43, statSync as statSync62 } from "node:fs";
126487
- import { join as join117 } from "node:path";
126883
+ import { existsSync as existsSync115, readFileSync as readFileSync103, readdirSync as readdirSync44, statSync as statSync63 } from "node:fs";
126884
+ import { join as join118 } from "node:path";
126488
126885
  import { spawnSync as spawnSync26 } from "node:child_process";
126489
126886
  function evalsJsonPath(skillDir) {
126490
- return join117(skillDir, "evals", "evals.json");
126887
+ return join118(skillDir, "evals", "evals.json");
126491
126888
  }
126492
126889
  function skillHasEvals(skillDir) {
126493
126890
  const p = evalsJsonPath(skillDir);
@@ -126501,7 +126898,7 @@ function skillHasEvals(skillDir) {
126501
126898
  }
126502
126899
  }
126503
126900
  function aggregateBenchmark(benchmarkDir, repoRoot, pythonBin = process.env.SWITCHROOM_PYTHON ?? "python3") {
126504
- const script = join117(repoRoot, "skills", "skill-creator", "scripts", "aggregate_benchmark.py");
126901
+ const script = join118(repoRoot, "skills", "skill-creator", "scripts", "aggregate_benchmark.py");
126505
126902
  if (!existsSync115(script)) {
126506
126903
  return { ok: false, error: `aggregate_benchmark.py not found at ${script}` };
126507
126904
  }
@@ -126515,25 +126912,25 @@ function aggregateBenchmark(benchmarkDir, repoRoot, pythonBin = process.env.SWIT
126515
126912
  error: `aggregate_benchmark exited ${r.status}: ${(r.stderr ?? "").trim()}`
126516
126913
  };
126517
126914
  }
126518
- return { ok: true, benchmarkJson: join117(benchmarkDir, "benchmark.json") };
126915
+ return { ok: true, benchmarkJson: join118(benchmarkDir, "benchmark.json") };
126519
126916
  }
126520
126917
  function isBenchmarkDir(dir) {
126521
126918
  try {
126522
- if (!statSync62(dir).isDirectory())
126919
+ if (!statSync63(dir).isDirectory())
126523
126920
  return false;
126524
126921
  } catch {
126525
126922
  return false;
126526
126923
  }
126527
126924
  const hasEvalDirs = (d) => {
126528
126925
  try {
126529
- return readdirSync43(d, { withFileTypes: true }).some((e) => e.isDirectory() && e.name.startsWith("eval-"));
126926
+ return readdirSync44(d, { withFileTypes: true }).some((e) => e.isDirectory() && e.name.startsWith("eval-"));
126530
126927
  } catch {
126531
126928
  return false;
126532
126929
  }
126533
126930
  };
126534
126931
  if (hasEvalDirs(dir))
126535
126932
  return true;
126536
- const runs = join117(dir, "runs");
126933
+ const runs = join118(dir, "runs");
126537
126934
  return existsSync115(runs) && hasEvalDirs(runs);
126538
126935
  }
126539
126936
  function resolveBenchmarkDir(baseDir, explicit) {
@@ -126544,13 +126941,13 @@ function resolveBenchmarkDir(baseDir, explicit) {
126544
126941
  return baseDir;
126545
126942
  let entries;
126546
126943
  try {
126547
- entries = readdirSync43(baseDir, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => join117(baseDir, e.name)).filter(isBenchmarkDir);
126944
+ entries = readdirSync44(baseDir, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => join118(baseDir, e.name)).filter(isBenchmarkDir);
126548
126945
  } catch {
126549
126946
  return null;
126550
126947
  }
126551
126948
  if (entries.length === 0)
126552
126949
  return null;
126553
- entries.sort((a, b) => statSync62(b).mtimeMs - statSync62(a).mtimeMs);
126950
+ entries.sort((a, b) => statSync63(b).mtimeMs - statSync63(a).mtimeMs);
126554
126951
  return entries[0];
126555
126952
  }
126556
126953
  var CANDIDATE_CONFIGS = ["with_skill", "candidate", "new_skill", "after"];
@@ -126617,12 +127014,12 @@ import {
126617
127014
  mkdirSync as mkdirSync67,
126618
127015
  openSync as openSync23,
126619
127016
  readFileSync as readFileSync104,
126620
- readdirSync as readdirSync44,
127017
+ readdirSync as readdirSync45,
126621
127018
  renameSync as renameSync33,
126622
127019
  writeFileSync as writeFileSync50,
126623
127020
  writeSync as writeSync12
126624
127021
  } from "node:fs";
126625
- import { dirname as dirname49, join as join118 } from "node:path";
127022
+ import { dirname as dirname50, join as join119 } from "node:path";
126626
127023
  import { createHash as createHash21 } from "node:crypto";
126627
127024
 
126628
127025
  // src/self-improve/pii-scan.ts
@@ -126773,7 +127170,7 @@ function readEvalsDoc(skillDir) {
126773
127170
  }
126774
127171
  }
126775
127172
  function writeAtomic(path10, content) {
126776
- mkdirSync67(dirname49(path10), { recursive: true });
127173
+ mkdirSync67(dirname50(path10), { recursive: true });
126777
127174
  const tmp = `${path10}.tmp-${process.pid}-${Date.now()}`;
126778
127175
  writeFileSync50(tmp, content, { encoding: "utf-8", mode: 420 });
126779
127176
  renameSync33(tmp, path10);
@@ -126812,7 +127209,7 @@ function appendEvalCase(skillDir, slug, input) {
126812
127209
  }
126813
127210
  var HELD_OUT_FILE = "self-improve-held-out-evals.jsonl";
126814
127211
  function heldOutPath(stateDir) {
126815
- return join118(stateDir, HELD_OUT_FILE);
127212
+ return join119(stateDir, HELD_OUT_FILE);
126816
127213
  }
126817
127214
  function heldOutHasFingerprint(stateDir, slug, fp) {
126818
127215
  const path10 = heldOutPath(stateDir);
@@ -126861,10 +127258,10 @@ function appendHeldOutCase(stateDir, slug, ec, opts = {}) {
126861
127258
  var EVAL_MANIFEST_FILE = "self-improve-eval-manifest.json";
126862
127259
  var EVAL_BASELINE_SUBDIR = "self-improve-eval-baselines";
126863
127260
  function manifestPath(stateDir) {
126864
- return join118(stateDir, EVAL_MANIFEST_FILE);
127261
+ return join119(stateDir, EVAL_MANIFEST_FILE);
126865
127262
  }
126866
127263
  function baselineEvalsPath(stateDir, slug) {
126867
- return join118(stateDir, EVAL_BASELINE_SUBDIR, slug, "evals.json");
127264
+ return join119(stateDir, EVAL_BASELINE_SUBDIR, slug, "evals.json");
126868
127265
  }
126869
127266
  function evalsSha256(skillDir) {
126870
127267
  const p = evalsJsonPath(skillDir);
@@ -126900,7 +127297,7 @@ function recordEvalBaseline(stateDir, slug, skillDir, opts = {}) {
126900
127297
  m[slug] = { sha256: sha, updated_at: new Date(now2()).toISOString(), skill_dir: skillDir };
126901
127298
  writeManifest(stateDir, m);
126902
127299
  const snap = baselineEvalsPath(stateDir, slug);
126903
- mkdirSync67(dirname49(snap), { recursive: true });
127300
+ mkdirSync67(dirname50(snap), { recursive: true });
126904
127301
  copyFileSync15(evalsJsonPath(skillDir), snap);
126905
127302
  }
126906
127303
 
@@ -126908,7 +127305,7 @@ function recordEvalBaseline(stateDir, slug, skillDir, opts = {}) {
126908
127305
  var BENCHMARK_SUBDIR = "self-improve-benchmarks";
126909
127306
  function ownsSkill(skillDir) {
126910
127307
  try {
126911
- const st = lstatSync16(skillDir);
127308
+ const st = lstatSync17(skillDir);
126912
127309
  if (st.isSymbolicLink())
126913
127310
  return false;
126914
127311
  return st.isDirectory();
@@ -126926,10 +127323,10 @@ import {
126926
127323
  readFileSync as readFileSync106,
126927
127324
  writeSync as writeSync13
126928
127325
  } from "node:fs";
126929
- import { join as join119 } from "node:path";
127326
+ import { join as join120 } from "node:path";
126930
127327
  var EVAL_CASE_PROPOSALS_FILE = "eval-case-proposals.jsonl";
126931
127328
  function proposalsPath(stateDir) {
126932
- return join119(stateDir, EVAL_CASE_PROPOSALS_FILE);
127329
+ return join120(stateDir, EVAL_CASE_PROPOSALS_FILE);
126933
127330
  }
126934
127331
  function isRecord2(v) {
126935
127332
  return !!v && typeof v === "object" && typeof v.id === "string" && typeof v.skill_slug === "string" && !!v.case && typeof v.case === "object";
@@ -126964,16 +127361,16 @@ function getEvalCaseProposal(stateDir, id) {
126964
127361
  // src/cli/self-improve-eval-case.ts
126965
127362
  var IPC_CONNECT_TIMEOUT_MS2 = 5000;
126966
127363
  function stateDir() {
126967
- return process.env.TELEGRAM_STATE_DIR ?? join120(homedir62(), ".claude", "channels", "telegram");
127364
+ return process.env.TELEGRAM_STATE_DIR ?? join121(homedir62(), ".claude", "channels", "telegram");
126968
127365
  }
126969
127366
  function gatewaySocketPath2() {
126970
- return process.env.SWITCHROOM_GATEWAY_SOCKET ?? join120(stateDir(), "gateway.sock");
127367
+ return process.env.SWITCHROOM_GATEWAY_SOCKET ?? join121(stateDir(), "gateway.sock");
126971
127368
  }
126972
127369
  function skillsRoot() {
126973
- return join120(homedir62(), ".claude", "skills");
127370
+ return join121(homedir62(), ".claude", "skills");
126974
127371
  }
126975
127372
  function skillDirFor(slug) {
126976
- return join120(skillsRoot(), slug);
127373
+ return join121(skillsRoot(), slug);
126977
127374
  }
126978
127375
  function authorizeApplyTarget(persistedDir, slug) {
126979
127376
  const dir = skillDirFor(slug);
@@ -127171,20 +127568,20 @@ function registerSelfImproveEvalCaseCommands(program3) {
127171
127568
 
127172
127569
  // src/cli/self-improve-bench.ts
127173
127570
  import { homedir as homedir63 } from "node:os";
127174
- import { dirname as dirname50, join as join121 } from "node:path";
127571
+ import { dirname as dirname51, join as join122 } from "node:path";
127175
127572
  init_shipped_assets();
127176
127573
  function fail8(msg, code = 1) {
127177
127574
  console.error(msg);
127178
127575
  process.exit(code);
127179
127576
  }
127180
127577
  function stateDir2() {
127181
- return process.env.TELEGRAM_STATE_DIR ?? join121(homedir63(), ".claude", "channels", "telegram");
127578
+ return process.env.TELEGRAM_STATE_DIR ?? join122(homedir63(), ".claude", "channels", "telegram");
127182
127579
  }
127183
127580
  function skillDirFor2(slug) {
127184
- return join121(homedir63(), ".claude", "skills", slug);
127581
+ return join122(homedir63(), ".claude", "skills", slug);
127185
127582
  }
127186
127583
  function benchmarkBaseDir(slug) {
127187
- return join121(stateDir2(), BENCHMARK_SUBDIR, slug);
127584
+ return join122(stateDir2(), BENCHMARK_SUBDIR, slug);
127188
127585
  }
127189
127586
  function resolveAggregatorRepoRoot() {
127190
127587
  const res = resolveShippedAsset(SKILLS_ASSET, {
@@ -127196,7 +127593,7 @@ function resolveAggregatorRepoRoot() {
127196
127593
  `);
127197
127594
  return null;
127198
127595
  }
127199
- return dirname50(res.path);
127596
+ return dirname51(res.path);
127200
127597
  }
127201
127598
  function registerSelfImproveBenchCommand(program3) {
127202
127599
  const parent = program3.commands.find((c) => c.name() === "self-improve") ?? program3.command("self-improve").description("Agent self-improvement ops");
@@ -127246,9 +127643,9 @@ function registerSelfImproveBenchCommand(program3) {
127246
127643
  init_esm();
127247
127644
  init_helpers();
127248
127645
  var import_yaml26 = __toESM(require_dist(), 1);
127249
- import { existsSync as existsSync120, readdirSync as readdirSync45, readFileSync as readFileSync108, statSync as statSync64 } from "node:fs";
127646
+ import { existsSync as existsSync120, readdirSync as readdirSync46, readFileSync as readFileSync108, statSync as statSync65 } from "node:fs";
127250
127647
  import { homedir as homedir64 } from "node:os";
127251
- import { join as join122, resolve as resolve63 } from "node:path";
127648
+ import { join as join123, resolve as resolve63 } from "node:path";
127252
127649
  var PERSONAL_PREFIX2 = "personal-";
127253
127650
  var BUNDLED_SUBDIR = "_bundled";
127254
127651
  var AGENT_NAME_RE3 = /^[a-z][a-z0-9_-]{0,62}$/;
@@ -127262,7 +127659,7 @@ function defaultBundledRoot2() {
127262
127659
  return resolve63(homedir64(), ".switchroom/skills/_bundled");
127263
127660
  }
127264
127661
  function readSkillFrontmatter(skillDir) {
127265
- const mdPath = join122(skillDir, "SKILL.md");
127662
+ const mdPath = join123(skillDir, "SKILL.md");
127266
127663
  if (!existsSync120(mdPath))
127267
127664
  return null;
127268
127665
  let content;
@@ -127295,9 +127692,9 @@ function readSkillFrontmatter(skillDir) {
127295
127692
  return { fm: parsed };
127296
127693
  }
127297
127694
  function statSkillMd(skillDir) {
127298
- const mdPath = join122(skillDir, "SKILL.md");
127695
+ const mdPath = join123(skillDir, "SKILL.md");
127299
127696
  try {
127300
- const st = statSync64(mdPath);
127697
+ const st = statSync65(mdPath);
127301
127698
  return { size: st.size, mtime: st.mtime.toISOString() };
127302
127699
  } catch {
127303
127700
  return null;
@@ -127306,22 +127703,22 @@ function statSkillMd(skillDir) {
127306
127703
  function listPersonalSkills(agent, agentsRoot = defaultAgentsRoot()) {
127307
127704
  if (!AGENT_NAME_RE3.test(agent))
127308
127705
  return [];
127309
- const skillsDir = join122(agentsRoot, agent, ".claude/skills");
127706
+ const skillsDir = join123(agentsRoot, agent, ".claude/skills");
127310
127707
  if (!existsSync120(skillsDir))
127311
127708
  return [];
127312
127709
  const out = [];
127313
127710
  let entries;
127314
127711
  try {
127315
- entries = readdirSync45(skillsDir);
127712
+ entries = readdirSync46(skillsDir);
127316
127713
  } catch {
127317
127714
  return [];
127318
127715
  }
127319
127716
  for (const ent of entries) {
127320
127717
  if (!ent.startsWith(PERSONAL_PREFIX2))
127321
127718
  continue;
127322
- const dirPath = join122(skillsDir, ent);
127719
+ const dirPath = join123(skillsDir, ent);
127323
127720
  try {
127324
- if (!statSync64(dirPath).isDirectory())
127721
+ if (!statSync65(dirPath).isDirectory())
127325
127722
  continue;
127326
127723
  } catch {
127327
127724
  continue;
@@ -127350,7 +127747,7 @@ function listSharedSkills(sharedRoot = defaultSharedRoot2()) {
127350
127747
  const out = [];
127351
127748
  let entries;
127352
127749
  try {
127353
- entries = readdirSync45(sharedRoot);
127750
+ entries = readdirSync46(sharedRoot);
127354
127751
  } catch {
127355
127752
  return [];
127356
127753
  }
@@ -127359,9 +127756,9 @@ function listSharedSkills(sharedRoot = defaultSharedRoot2()) {
127359
127756
  continue;
127360
127757
  if (ent.startsWith("."))
127361
127758
  continue;
127362
- const dirPath = join122(sharedRoot, ent);
127759
+ const dirPath = join123(sharedRoot, ent);
127363
127760
  try {
127364
- if (!statSync64(dirPath).isDirectory())
127761
+ if (!statSync65(dirPath).isDirectory())
127365
127762
  continue;
127366
127763
  } catch {
127367
127764
  continue;
@@ -127388,16 +127785,16 @@ function listBundledSkills(bundledRoot = defaultBundledRoot2()) {
127388
127785
  const out = [];
127389
127786
  let entries;
127390
127787
  try {
127391
- entries = readdirSync45(bundledRoot);
127788
+ entries = readdirSync46(bundledRoot);
127392
127789
  } catch {
127393
127790
  return [];
127394
127791
  }
127395
127792
  for (const ent of entries) {
127396
127793
  if (ent.startsWith("."))
127397
127794
  continue;
127398
- const dirPath = join122(bundledRoot, ent);
127795
+ const dirPath = join123(bundledRoot, ent);
127399
127796
  try {
127400
- if (!statSync64(dirPath).isDirectory())
127797
+ if (!statSync65(dirPath).isDirectory())
127401
127798
  continue;
127402
127799
  } catch {
127403
127800
  continue;
@@ -127544,15 +127941,15 @@ init_operator_uid();
127544
127941
  import {
127545
127942
  existsSync as existsSync122,
127546
127943
  mkdirSync as mkdirSync69,
127547
- readdirSync as readdirSync46,
127944
+ readdirSync as readdirSync47,
127548
127945
  writeFileSync as writeFileSync51,
127549
- statSync as statSync65,
127550
- lstatSync as lstatSync17,
127946
+ statSync as statSync66,
127947
+ lstatSync as lstatSync18,
127551
127948
  realpathSync as realpathSync11,
127552
127949
  copyFileSync as copyFileSync16
127553
127950
  } from "node:fs";
127554
127951
  import { homedir as homedir65 } from "node:os";
127555
- import { join as join123 } from "node:path";
127952
+ import { join as join124 } from "node:path";
127556
127953
  import { spawnSync as spawnSync29 } from "node:child_process";
127557
127954
 
127558
127955
  // src/cli/singleton-stale-cleanup.ts
@@ -127908,10 +128305,10 @@ function resolveHostdHostHome(env2 = process.env, home2 = homedir65()) {
127908
128305
  return resolved;
127909
128306
  }
127910
128307
  function resolveHostdSkillsTarget(hostHome) {
127911
- const skillsPath = join123(hostHome, ".switchroom", "skills");
128308
+ const skillsPath = join124(hostHome, ".switchroom", "skills");
127912
128309
  let st;
127913
128310
  try {
127914
- st = lstatSync17(skillsPath);
128311
+ st = lstatSync18(skillsPath);
127915
128312
  } catch {
127916
128313
  return;
127917
128314
  }
@@ -127932,10 +128329,10 @@ function resolveHostdSkillsTarget(hostHome) {
127932
128329
  return target;
127933
128330
  }
127934
128331
  function hostdDir() {
127935
- return join123(homedir65(), ".switchroom", "hostd");
128332
+ return join124(homedir65(), ".switchroom", "hostd");
127936
128333
  }
127937
128334
  function hostdComposePath() {
127938
- return join123(hostdDir(), "docker-compose.yml");
128335
+ return join124(hostdDir(), "docker-compose.yml");
127939
128336
  }
127940
128337
  function backupExistingCompose() {
127941
128338
  const p = hostdComposePath();
@@ -128062,12 +128459,12 @@ function doStatus() {
128062
128459
  if (existsSync122(dir)) {
128063
128460
  const entries = [];
128064
128461
  try {
128065
- for (const name of readdirSync46(dir)) {
128462
+ for (const name of readdirSync47(dir)) {
128066
128463
  if (name === "docker-compose.yml" || name.startsWith("docker-compose.yml."))
128067
128464
  continue;
128068
- const sockPath = join123(dir, name, "sock");
128465
+ const sockPath = join124(dir, name, "sock");
128069
128466
  if (existsSync122(sockPath)) {
128070
- const st = statSync65(sockPath);
128467
+ const st = statSync66(sockPath);
128071
128468
  if ((st.mode & 61440) === 49152) {
128072
128469
  entries.push(`${name} \u2192 ${sockPath}`);
128073
128470
  }
@@ -128160,7 +128557,7 @@ init_operator_uid();
128160
128557
  init_compose();
128161
128558
  import { chownSync as chownSync14, existsSync as existsSync123, mkdirSync as mkdirSync70, writeFileSync as writeFileSync52, copyFileSync as copyFileSync17 } from "node:fs";
128162
128559
  import { homedir as homedir66 } from "node:os";
128163
- import { join as join124 } from "node:path";
128560
+ import { join as join125 } from "node:path";
128164
128561
  import { spawnSync as spawnSync30 } from "node:child_process";
128165
128562
  function resolveWebImageTag(explicitTag, release) {
128166
128563
  if (explicitTag)
@@ -128262,10 +128659,10 @@ services:
128262
128659
  `;
128263
128660
  }
128264
128661
  function webdDir() {
128265
- return join124(homedir66(), ".switchroom", "web");
128662
+ return join125(homedir66(), ".switchroom", "web");
128266
128663
  }
128267
128664
  function webdComposePath() {
128268
- return join124(webdDir(), "docker-compose.yml");
128665
+ return join125(webdDir(), "docker-compose.yml");
128269
128666
  }
128270
128667
  function backupExistingCompose2() {
128271
128668
  const p = webdComposePath();
@@ -128431,9 +128828,9 @@ function registerWebdCommand(program3) {
128431
128828
  // src/cli/host-repair.ts
128432
128829
  init_source();
128433
128830
  import { homedir as homedir67 } from "node:os";
128434
- import { join as join125 } from "node:path";
128831
+ import { join as join126 } from "node:path";
128435
128832
  var ARTIFACT_ALLOWLIST = {
128436
- dockerComposePluginDir: (home2) => join125(home2, ".docker", "cli-plugins", "docker-compose"),
128833
+ dockerComposePluginDir: (home2) => join126(home2, ".docker", "cli-plugins", "docker-compose"),
128437
128834
  stateSentinel: "/state"
128438
128835
  };
128439
128836
  function isStateBogusAutoDir(probe2) {
@@ -128587,18 +128984,18 @@ function applyMountRepairs(items, deps) {
128587
128984
  function registerHostCommand(program3) {
128588
128985
  const host = program3.command("host").description("Host-level maintenance operations for switchroom");
128589
128986
  host.command("repair-mounts").description("Detect and remove known auto-dir artifacts left by a container-context deploy " + "(2026-06-23 outage class). Default: dry-run. Pass --yes to apply.").option("--yes", "Actually perform the removals (default is dry-run)").action(async (opts) => {
128590
- const { rmdirSync: rmdirSync2, rmSync: rmSync22, lstatSync: lstatSync18, readdirSync: readdirSync47 } = await import("node:fs");
128987
+ const { rmdirSync: rmdirSync2, rmSync: rmSync22, lstatSync: lstatSync19, readdirSync: readdirSync48 } = await import("node:fs");
128591
128988
  const probe2 = {
128592
128989
  lstat(path10) {
128593
128990
  try {
128594
- return lstatSync18(path10);
128991
+ return lstatSync19(path10);
128595
128992
  } catch {
128596
128993
  return null;
128597
128994
  }
128598
128995
  },
128599
128996
  readdir(path10) {
128600
128997
  try {
128601
- return readdirSync47(path10);
128998
+ return readdirSync48(path10);
128602
128999
  } catch {
128603
129000
  return null;
128604
129001
  }
@@ -128887,9 +129284,9 @@ function printDeepDiveBrief(targets) {
128887
129284
 
128888
129285
  // src/cli/hindsight-watch.ts
128889
129286
  init_source();
128890
- import { existsSync as existsSync128, readdirSync as readdirSync51 } from "node:fs";
129287
+ import { existsSync as existsSync128, readdirSync as readdirSync52 } from "node:fs";
128891
129288
  import { homedir as homedir70 } from "node:os";
128892
- import { join as join128, resolve as resolve66 } from "node:path";
129289
+ import { join as join129, resolve as resolve66 } from "node:path";
128893
129290
 
128894
129291
  // src/host-control/config-degraded.ts
128895
129292
  import { connect as connect3 } from "node:net";
@@ -128958,7 +129355,7 @@ init_install_cron();
128958
129355
 
128959
129356
  // src/hindsight-watch/probe.ts
128960
129357
  import { spawnSync as spawnSync32 } from "node:child_process";
128961
- import { readFileSync as readFileSync113, readdirSync as readdirSync50, statSync as statSync67 } from "node:fs";
129358
+ import { readFileSync as readFileSync113, readdirSync as readdirSync51, statSync as statSync68 } from "node:fs";
128962
129359
  import { homedir as homedir69 } from "node:os";
128963
129360
  import { resolve as resolve65 } from "node:path";
128964
129361
 
@@ -129086,13 +129483,13 @@ function readLlmSignals(series) {
129086
129483
  }
129087
129484
 
129088
129485
  // src/hindsight-watch/recall-log.ts
129089
- import { closeSync as closeSync25, existsSync as existsSync127, openSync as openSync25, readdirSync as readdirSync49, readSync as readSync6, statSync as statSync66 } from "node:fs";
129090
- import { join as join127 } from "node:path";
129486
+ import { closeSync as closeSync25, existsSync as existsSync127, openSync as openSync25, readdirSync as readdirSync50, readSync as readSync6, statSync as statSync67 } from "node:fs";
129487
+ import { join as join128 } from "node:path";
129091
129488
  var RECALL_WINDOW_ROWS = 200;
129092
129489
  var RECALL_MAX_TAIL_BYTES = 1024 * 1024;
129093
129490
  var RECALL_MAX_ROW_AGE_MS = 24 * 60 * 60 * 1000;
129094
129491
  function recallLogPath2(agentDir) {
129095
- return join127(agentDir, ".claude", "plugins", "data", "hindsight-memory-inline", "state", "recall_log.jsonl");
129492
+ return join128(agentDir, ".claude", "plugins", "data", "hindsight-memory-inline", "state", "recall_log.jsonl");
129096
129493
  }
129097
129494
  function readRecallLogTail2(path10, windowRows = RECALL_WINDOW_ROWS) {
129098
129495
  if (!existsSync127(path10))
@@ -129101,7 +129498,7 @@ function readRecallLogTail2(path10, windowRows = RECALL_WINDOW_ROWS) {
129101
129498
  let truncatedHead = false;
129102
129499
  let fd;
129103
129500
  try {
129104
- const size = statSync66(path10).size;
129501
+ const size = statSync67(path10).size;
129105
129502
  const start = Math.max(0, size - RECALL_MAX_TAIL_BYTES);
129106
129503
  truncatedHead = start > 0;
129107
129504
  const length = size - start;
@@ -129236,11 +129633,11 @@ function summarizeRecallRows2(rows) {
129236
129633
  return out;
129237
129634
  }
129238
129635
  function probeRecallLogs(agentsDir, now2, windowRows = RECALL_WINDOW_ROWS, maxAgeMs = RECALL_MAX_ROW_AGE_MS) {
129239
- const names = readdirSync49(agentsDir);
129636
+ const names = readdirSync50(agentsDir);
129240
129637
  const all = [];
129241
129638
  let agents = 0;
129242
129639
  for (const name of names) {
129243
- const rows = withinWindow(readRecallLogTail2(recallLogPath2(join127(agentsDir, name)), windowRows), now2, maxAgeMs);
129640
+ const rows = withinWindow(readRecallLogTail2(recallLogPath2(join128(agentsDir, name)), windowRows), now2, maxAgeMs);
129244
129641
  if (rows.length > 0)
129245
129642
  agents++;
129246
129643
  all.push(...rows);
@@ -129333,7 +129730,7 @@ function readDropCount(hindsightDir) {
129333
129730
  const path10 = resolve65(hindsightDir, "pending-drops.json");
129334
129731
  let parsed;
129335
129732
  try {
129336
- if (statSync67(path10).size > DROPS_LEDGER_MAX_BYTES)
129733
+ if (statSync68(path10).size > DROPS_LEDGER_MAX_BYTES)
129337
129734
  return 0;
129338
129735
  parsed = JSON.parse(readFileSync113(path10, "utf8"));
129339
129736
  } catch {
@@ -129350,7 +129747,7 @@ function resolveAgentsDir2(explicit) {
129350
129747
  function probeSpool(agentsDir = resolveAgentsDir2()) {
129351
129748
  let names;
129352
129749
  try {
129353
- names = readdirSync50(agentsDir);
129750
+ names = readdirSync51(agentsDir);
129354
129751
  } catch (e) {
129355
129752
  throw new ProbeError(`reading ${agentsDir}: ${e.message}`, "spool");
129356
129753
  }
@@ -129364,7 +129761,7 @@ function probeSpool(agentsDir = resolveAgentsDir2()) {
129364
129761
  const hindsightDir = resolve65(agentsDir, name, "home", ".hindsight");
129365
129762
  let entries = null;
129366
129763
  try {
129367
- entries = readdirSync50(resolve65(hindsightDir, "pending-retains"));
129764
+ entries = readdirSync51(resolve65(hindsightDir, "pending-retains"));
129368
129765
  } catch {}
129369
129766
  if (entries !== null) {
129370
129767
  agents++;
@@ -129376,19 +129773,19 @@ function probeSpool(agentsDir = resolveAgentsDir2()) {
129376
129773
  }
129377
129774
  }
129378
129775
  try {
129379
- for (const f of readdirSync50(resolve65(hindsightDir, "pending-evicted"))) {
129776
+ for (const f of readdirSync51(resolve65(hindsightDir, "pending-evicted"))) {
129380
129777
  if (f.endsWith(".json"))
129381
129778
  evicted++;
129382
129779
  }
129383
129780
  } catch {}
129384
129781
  try {
129385
- for (const f of readdirSync50(resolve65(hindsightDir, "pending-dead"))) {
129782
+ for (const f of readdirSync51(resolve65(hindsightDir, "pending-dead"))) {
129386
129783
  if (f.endsWith(".dead"))
129387
129784
  dead++;
129388
129785
  }
129389
129786
  } catch {}
129390
129787
  try {
129391
- for (const f of readdirSync50(resolve65(hindsightDir, "pending-duplicate"))) {
129788
+ for (const f of readdirSync51(resolve65(hindsightDir, "pending-duplicate"))) {
129392
129789
  if (f.endsWith(".json"))
129393
129790
  duplicates++;
129394
129791
  }
@@ -130298,7 +130695,7 @@ function registerHindsightWatchCommand(program3) {
130298
130695
  process.exitCode = runInstallCron(opts.cronUser);
130299
130696
  return;
130300
130697
  }
130301
- const agentsDir = opts.agentsDir ?? process.env.SWITCHROOM_AGENTS_DIR ?? join128(process.env.SWITCHROOM_HOME ?? process.env.HOME ?? homedir70(), ".switchroom", "agents");
130698
+ const agentsDir = opts.agentsDir ?? process.env.SWITCHROOM_AGENTS_DIR ?? join129(process.env.SWITCHROOM_HOME ?? process.env.HOME ?? homedir70(), ".switchroom", "agents");
130302
130699
  const statePath = opts.state ?? defaultStatePath2();
130303
130700
  const log = (m) => {
130304
130701
  process.stderr.write(`${m}
@@ -130412,7 +130809,7 @@ function orderRelayCandidates(candidates, preferred = PREFERRED_RELAY_AGENT) {
130412
130809
  }
130413
130810
  function collectRelayCandidates(agentsDir) {
130414
130811
  const candidates = [];
130415
- for (const name of readdirSync51(agentsDir).sort()) {
130812
+ for (const name of readdirSync52(agentsDir).sort()) {
130416
130813
  const sock = resolve66(agentsDir, name, "telegram", "gateway.sock");
130417
130814
  if (existsSync128(sock))
130418
130815
  candidates.push({ agent: name, sock });
@@ -130437,7 +130834,7 @@ async function notifyOperator(agentsDir, text, log) {
130437
130834
  // src/cli/hindsight-bench.ts
130438
130835
  init_source();
130439
130836
  import { mkdirSync as mkdirSync72, readFileSync as readFileSync114, writeFileSync as writeFileSync54 } from "node:fs";
130440
- import { dirname as dirname53, resolve as resolve67 } from "node:path";
130837
+ import { dirname as dirname54, resolve as resolve67 } from "node:path";
130441
130838
 
130442
130839
  // src/hindsight-bench/anonymise.ts
130443
130840
  function pseudonym(n, width) {
@@ -131565,7 +131962,7 @@ function readResult(path10) {
131565
131962
  }
131566
131963
  function writeOut(path10, body) {
131567
131964
  const abs = resolve67(path10);
131568
- mkdirSync72(dirname53(abs), { recursive: true });
131965
+ mkdirSync72(dirname54(abs), { recursive: true });
131569
131966
  writeFileSync54(abs, body);
131570
131967
  process.stderr.write(`${source_default.green("\u2713")} wrote ${abs}
131571
131968
  `);
@@ -131770,13 +132167,13 @@ async function runMeasureMode(opts) {
131770
132167
 
131771
132168
  // src/cli/openrouter-watch.ts
131772
132169
  init_source();
131773
- import { existsSync as existsSync130, readdirSync as readdirSync52 } from "node:fs";
132170
+ import { existsSync as existsSync130, readdirSync as readdirSync53 } from "node:fs";
131774
132171
  import { homedir as homedir72 } from "node:os";
131775
- import { join as join129, resolve as resolve69 } from "node:path";
132172
+ import { join as join130, resolve as resolve69 } from "node:path";
131776
132173
 
131777
132174
  // src/openrouter/install-cron.ts
131778
132175
  import { existsSync as existsSync129, mkdirSync as mkdirSync73, readFileSync as readFileSync115, renameSync as renameSync34, writeFileSync as writeFileSync55 } from "node:fs";
131779
- import { dirname as dirname54 } from "node:path";
132176
+ import { dirname as dirname55 } from "node:path";
131780
132177
  var CRON_PATH3 = "/etc/cron.d/openrouter-watch";
131781
132178
  var CRON_SCHEDULE2 = "17 * * * *";
131782
132179
  var CRON_LOG_PATH3 = "/var/log/openrouter-watch.log";
@@ -131800,7 +132197,7 @@ function installCron3(opts) {
131800
132197
  }
131801
132198
  } catch {}
131802
132199
  }
131803
- mkdirSync73(dirname54(path10), { recursive: true });
132200
+ mkdirSync73(dirname55(path10), { recursive: true });
131804
132201
  const tmp = `${path10}.${process.pid}.tmp`;
131805
132202
  writeFileSync55(tmp, content, { mode: 420 });
131806
132203
  renameSync34(tmp, path10);
@@ -131809,7 +132206,7 @@ function installCron3(opts) {
131809
132206
  // src/openrouter/state.ts
131810
132207
  import { mkdirSync as mkdirSync74, readFileSync as readFileSync116, renameSync as renameSync35, writeFileSync as writeFileSync56 } from "node:fs";
131811
132208
  import { homedir as homedir71 } from "node:os";
131812
- import { dirname as dirname55, resolve as resolve68 } from "node:path";
132209
+ import { dirname as dirname56, resolve as resolve68 } from "node:path";
131813
132210
  function defaultStatePath3(home2 = process.env.SWITCHROOM_HOME ?? process.env.HOME ?? homedir71()) {
131814
132211
  return resolve68(home2, ".switchroom", "openrouter-watch", "state.json");
131815
132212
  }
@@ -131836,7 +132233,7 @@ function loadState2(path10) {
131836
132233
  return out;
131837
132234
  }
131838
132235
  function saveState2(path10, state) {
131839
- mkdirSync74(dirname55(path10), { recursive: true, mode: 448 });
132236
+ mkdirSync74(dirname56(path10), { recursive: true, mode: 448 });
131840
132237
  const tmp = `${path10}.${process.pid}.tmp`;
131841
132238
  const payload = { v: 1, ...state };
131842
132239
  writeFileSync56(tmp, JSON.stringify(payload, null, 2) + `
@@ -131927,7 +132324,7 @@ function registerOpenRouterWatchCommand(program3) {
131927
132324
  process.exitCode = runInstallCron2(opts.cronUser);
131928
132325
  return;
131929
132326
  }
131930
- const agentsDir = opts.agentsDir ?? process.env.SWITCHROOM_AGENTS_DIR ?? join129(process.env.SWITCHROOM_HOME ?? process.env.HOME ?? homedir72(), ".switchroom", "agents");
132327
+ const agentsDir = opts.agentsDir ?? process.env.SWITCHROOM_AGENTS_DIR ?? join130(process.env.SWITCHROOM_HOME ?? process.env.HOME ?? homedir72(), ".switchroom", "agents");
131931
132328
  const statePath = opts.state ?? defaultStatePath3();
131932
132329
  const log = (m) => {
131933
132330
  process.stderr.write(`${m}
@@ -132024,7 +132421,7 @@ function runInstallCron2(cronUser) {
132024
132421
  async function notifyOperator2(agentsDir, text, log) {
132025
132422
  const candidates = [];
132026
132423
  try {
132027
- for (const name of readdirSync52(agentsDir).sort()) {
132424
+ for (const name of readdirSync53(agentsDir).sort()) {
132028
132425
  const sock = resolve69(agentsDir, name, "telegram", "gateway.sock");
132029
132426
  if (existsSync130(sock))
132030
132427
  candidates.push({ agent: name, sock });
@@ -132047,7 +132444,7 @@ init_sync();
132047
132444
  init_install_cron2();
132048
132445
  init_flock();
132049
132446
  import { homedir as homedir73 } from "node:os";
132050
- import { join as join130 } from "node:path";
132447
+ import { join as join131 } from "node:path";
132051
132448
  function switchroomHome() {
132052
132449
  return process.env.SWITCHROOM_HOME ?? process.env.HOME ?? homedir73();
132053
132450
  }
@@ -132059,9 +132456,9 @@ function resolveSyncOptions(configPath, opts) {
132059
132456
  cfg = loaded.config_repo;
132060
132457
  } catch {}
132061
132458
  const home2 = switchroomHome();
132062
- const repoPath = opts.path ? resolvePath(opts.path) : cfg.path ? resolvePath(cfg.path) : join130(home2, ".switchroom-config");
132063
- const livePath = process.env.SWITCHROOM_CONFIG ?? join130(home2, ".switchroom", "switchroom.yaml");
132064
- const agentsDir = process.env.SWITCHROOM_AGENTS_DIR ?? join130(home2, ".switchroom", "agents");
132459
+ const repoPath = opts.path ? resolvePath(opts.path) : cfg.path ? resolvePath(cfg.path) : join131(home2, ".switchroom-config");
132460
+ const livePath = process.env.SWITCHROOM_CONFIG ?? join131(home2, ".switchroom", "switchroom.yaml");
132461
+ const agentsDir = process.env.SWITCHROOM_AGENTS_DIR ?? join131(home2, ".switchroom", "agents");
132065
132462
  const push = opts.push === false ? false : cfg.push ?? true;
132066
132463
  const remote = opts.remote ?? cfg.remote ?? "origin";
132067
132464
  const requirePrivate = opts.requirePrivate ?? cfg.require_private ?? true;
@@ -132245,6 +132642,7 @@ registerDoctorCommand(program3);
132245
132642
  registerUpdateCommand(program3);
132246
132643
  registerRolloutCommand(program3);
132247
132644
  registerRollbackCommand(program3);
132645
+ registerHostCliUpgradeCommand(program3);
132248
132646
  registerRestartCommand(program3);
132249
132647
  registerVersionCommand(program3);
132250
132648
  registerVersionsCommand(program3);