switchroom 0.13.58 → 0.13.60

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.
@@ -29659,19 +29659,123 @@ var init_doctor_drive = __esm(() => {
29659
29659
  init_doctor_secret_access();
29660
29660
  });
29661
29661
 
29662
+ // src/cli/doctor-scaffold-wiring.ts
29663
+ import { join as join45, resolve as resolve30 } from "node:path";
29664
+ function readJson2(d, path4) {
29665
+ if (!d.existsSync(path4))
29666
+ return { kind: "absent" };
29667
+ let raw;
29668
+ try {
29669
+ raw = d.readFileSync(path4);
29670
+ } catch (err) {
29671
+ const code = err?.code;
29672
+ if (code === "EACCES" || code === "EPERM")
29673
+ return { kind: "unreadable" };
29674
+ return { kind: "absent" };
29675
+ }
29676
+ try {
29677
+ return { kind: "ok", data: JSON.parse(raw) };
29678
+ } catch {
29679
+ return { kind: "corrupt" };
29680
+ }
29681
+ }
29682
+ function checkIntegrationScaffoldWiring(args) {
29683
+ const { label, mcpKey, agents, agentsDir, deps } = args;
29684
+ const results = [];
29685
+ if (agents.length === 0)
29686
+ return results;
29687
+ if (agentsDir === undefined) {
29688
+ return [
29689
+ {
29690
+ name: `${label}: scaffold wiring`,
29691
+ status: "warn",
29692
+ detail: "could not resolve the agents directory (no switchroom block) \u2014 skipped scaffold wiring check"
29693
+ }
29694
+ ];
29695
+ }
29696
+ for (const name of agents) {
29697
+ const agentDir = resolve30(agentsDir, name);
29698
+ if (!deps.existsSync(agentDir)) {
29699
+ results.push({
29700
+ name: `${label}: ${name} scaffold`,
29701
+ status: "warn",
29702
+ detail: `${agentDir} not scaffolded yet \u2014 run \`switchroom apply\``
29703
+ });
29704
+ continue;
29705
+ }
29706
+ const mcpPath = join45(agentDir, ".mcp.json");
29707
+ const claudeJsonPath = join45(agentDir, ".claude", ".claude.json");
29708
+ const mcpRead = readJson2(deps, mcpPath);
29709
+ const trustRead = readJson2(deps, claudeJsonPath);
29710
+ if (mcpRead.kind === "unreadable" || trustRead.kind === "unreadable") {
29711
+ results.push({
29712
+ name: `${label}: ${name} scaffold`,
29713
+ status: "skip",
29714
+ detail: "scaffold files are agent-UID-owned (mode 0600) \u2014 unverifiable from the host operator; the agent process reads them fine. Verify in-container if needed: `docker exec switchroom-" + name + " sh -lc 'python3 -m json.tool /state/agent/.mcp.json >/dev/null && echo ok'`"
29715
+ });
29716
+ continue;
29717
+ }
29718
+ let mcpOk = false;
29719
+ let mcpDetail = `no .mcp.json`;
29720
+ if (mcpRead.kind === "ok") {
29721
+ const mcpServers = mcpRead.data?.mcpServers ?? {};
29722
+ const entry = mcpServers[mcpKey];
29723
+ if (!entry) {
29724
+ mcpDetail = `.mcp.json has no ${mcpKey} server`;
29725
+ } else if (!entry.env || Object.keys(entry.env).length === 0) {
29726
+ mcpDetail = `${mcpKey} entry has no env block \u2014 Claude spawns MCP with a sanitized env; the launcher can't reach switchroom.yaml/the broker (bug-8 class)`;
29727
+ } else {
29728
+ mcpOk = true;
29729
+ }
29730
+ } else if (mcpRead.kind === "corrupt") {
29731
+ mcpDetail = ".mcp.json exists but is not valid JSON (corrupt)";
29732
+ }
29733
+ let trustOk = false;
29734
+ let trustDetail = "no .claude/.claude.json";
29735
+ if (trustRead.kind === "ok") {
29736
+ const projects = trustRead.data?.projects ?? {};
29737
+ const proj = projects[resolve30(agentDir)];
29738
+ const enabled = proj?.enabledMcpjsonServers;
29739
+ if (Array.isArray(enabled) && enabled.includes(mcpKey)) {
29740
+ trustOk = true;
29741
+ } else {
29742
+ trustDetail = `${mcpKey} not in projects[].enabledMcpjsonServers \u2014 Claude silently ignores the un-allowlisted server (bug-9 / scaffold-ordering class)`;
29743
+ }
29744
+ } else if (trustRead.kind === "corrupt") {
29745
+ trustDetail = ".claude.json exists but is not valid JSON (corrupt)";
29746
+ }
29747
+ if (mcpOk && trustOk) {
29748
+ results.push({
29749
+ name: `${label}: ${name} scaffold`,
29750
+ status: "ok",
29751
+ detail: `${mcpKey} wired in .mcp.json (with env) and trusted in .claude.json`
29752
+ });
29753
+ } else {
29754
+ results.push({
29755
+ name: `${label}: ${name} scaffold`,
29756
+ status: "fail",
29757
+ detail: !mcpOk ? mcpDetail : trustDetail,
29758
+ fix: "`switchroom agent restart " + name + "` (reconcile regenerates .mcp.json + re-trusts); if it persists, this is a scaffold bug \u2014 report it"
29759
+ });
29760
+ }
29761
+ }
29762
+ return results;
29763
+ }
29764
+ var init_doctor_scaffold_wiring = () => {};
29765
+
29662
29766
  // src/cli/doctor-microsoft.ts
29663
29767
  import {
29664
29768
  existsSync as realExistsSync2,
29665
29769
  readFileSync as realReadFileSync2
29666
29770
  } from "node:fs";
29667
- import { join as join45 } from "node:path";
29771
+ import { join as join46 } from "node:path";
29668
29772
  import { homedir as homedir25 } from "node:os";
29669
29773
  function resolveDeps2(deps) {
29670
29774
  const home2 = deps.homeDir?.() ?? homedir25();
29671
29775
  return {
29672
29776
  existsSync: deps.existsSync ?? realExistsSync2,
29673
29777
  readFileSync: deps.readFileSync ?? realReadFileSync2,
29674
- agentsDir: join45(home2, ".switchroom", "agents"),
29778
+ agentsDir: join46(home2, ".switchroom", "agents"),
29675
29779
  now: deps.now ?? Date.now
29676
29780
  };
29677
29781
  }
@@ -29765,7 +29869,7 @@ function checkOAuthClient2(config, anyAgentEnabled) {
29765
29869
  ];
29766
29870
  }
29767
29871
  function readHeartbeat(d, agentName) {
29768
- const path4 = join45(d.agentsDir, agentName, "m365-launcher.heartbeat.json");
29872
+ const path4 = join46(d.agentsDir, agentName, "m365-launcher.heartbeat.json");
29769
29873
  if (!d.existsSync(path4)) {
29770
29874
  return { error: "heartbeat file missing \u2014 launcher has not yet started" };
29771
29875
  }
@@ -29840,9 +29944,21 @@ function runMicrosoftChecks(config, deps = {}) {
29840
29944
  const msAgents = computeMicrosoftEnabledAgents(config);
29841
29945
  results.push(...checkOAuthClient2(config, msAgents.length > 0));
29842
29946
  results.push(...checkLauncherHeartbeat(msAgents, d));
29947
+ results.push(...checkIntegrationScaffoldWiring({
29948
+ label: "microsoft",
29949
+ mcpKey: "ms-365",
29950
+ agents: msAgents,
29951
+ agentsDir: d.agentsDir,
29952
+ deps: {
29953
+ existsSync: d.existsSync,
29954
+ readFileSync: (path4) => d.readFileSync(path4, "utf-8")
29955
+ }
29956
+ }));
29843
29957
  return results;
29844
29958
  }
29845
- var init_doctor_microsoft = () => {};
29959
+ var init_doctor_microsoft = __esm(() => {
29960
+ init_doctor_scaffold_wiring();
29961
+ });
29846
29962
 
29847
29963
  // src/cli/doctor-notion.ts
29848
29964
  import {
@@ -29850,7 +29966,7 @@ import {
29850
29966
  readFileSync as realReadFileSync3,
29851
29967
  statSync as realStatSync
29852
29968
  } from "node:fs";
29853
- import { join as join46 } from "node:path";
29969
+ import { join as join47 } from "node:path";
29854
29970
  import { homedir as homedir26 } from "node:os";
29855
29971
  function resolveDeps3(deps) {
29856
29972
  const home2 = deps.homeDir?.() ?? homedir26();
@@ -29858,7 +29974,7 @@ function resolveDeps3(deps) {
29858
29974
  existsSync: deps.existsSync ?? realExistsSync3,
29859
29975
  readFileSync: deps.readFileSync ?? realReadFileSync3,
29860
29976
  statSync: deps.statSync ?? realStatSync,
29861
- agentsDir: join46(home2, ".switchroom", "agents"),
29977
+ agentsDir: join47(home2, ".switchroom", "agents"),
29862
29978
  now: deps.now ?? Date.now,
29863
29979
  vaultAclReader: deps.vaultAclReader ?? (async () => ({ kind: "unreachable", msg: "no default reader wired" }))
29864
29980
  };
@@ -29983,7 +30099,7 @@ function checkLauncherHeartbeat2(notionAgents, d) {
29983
30099
  return [];
29984
30100
  const results = [];
29985
30101
  for (const name of notionAgents) {
29986
- const heartbeatPath = join46(d.agentsDir, name, "notion-launcher.heartbeat.json");
30102
+ const heartbeatPath = join47(d.agentsDir, name, "notion-launcher.heartbeat.json");
29987
30103
  if (!d.existsSync(heartbeatPath)) {
29988
30104
  results.push({
29989
30105
  name: `notion:launcher-heartbeat:${name}`,
@@ -30033,11 +30149,22 @@ async function runNotionChecks(config, deps = {}) {
30033
30149
  if (notionAgents.length > 0 && config.notion_workspace) {
30034
30150
  results.push(...await checkVaultAclAligned(config, notionAgents, d));
30035
30151
  results.push(...checkLauncherHeartbeat2(notionAgents, d));
30152
+ results.push(...checkIntegrationScaffoldWiring({
30153
+ label: "notion",
30154
+ mcpKey: "notion",
30155
+ agents: notionAgents,
30156
+ agentsDir: d.agentsDir,
30157
+ deps: {
30158
+ existsSync: d.existsSync,
30159
+ readFileSync: (path4) => d.readFileSync(path4, "utf-8")
30160
+ }
30161
+ }));
30036
30162
  }
30037
30163
  return results;
30038
30164
  }
30039
30165
  var HEARTBEAT_STALE_MS;
30040
30166
  var init_doctor_notion = __esm(() => {
30167
+ init_doctor_scaffold_wiring();
30041
30168
  HEARTBEAT_STALE_MS = 60 * 1000;
30042
30169
  });
30043
30170
 
@@ -30048,9 +30175,9 @@ import {
30048
30175
  statSync as realStatSync2
30049
30176
  } from "node:fs";
30050
30177
  import { homedir as homedir27 } from "node:os";
30051
- import { join as join47 } from "node:path";
30178
+ import { join as join48 } from "node:path";
30052
30179
  function runCredentialsMigrationChecks(config, deps = {}) {
30053
- const credDir = deps.credentialsDir ?? join47(homedir27(), ".switchroom", "credentials");
30180
+ const credDir = deps.credentialsDir ?? join48(homedir27(), ".switchroom", "credentials");
30054
30181
  const existsSync49 = deps.existsSync ?? ((p) => realExistsSync4(p));
30055
30182
  const readdirSync19 = deps.readdirSync ?? ((p) => realReaddirSync(p));
30056
30183
  const isDirectory = deps.isDirectory ?? ((p) => {
@@ -30078,7 +30205,7 @@ function runCredentialsMigrationChecks(config, deps = {}) {
30078
30205
  const flat = [];
30079
30206
  const perAgentDirs = [];
30080
30207
  for (const e of entries) {
30081
- const full = join47(credDir, e);
30208
+ const full = join48(credDir, e);
30082
30209
  if (isDirectory(full) && agentNames.has(e)) {
30083
30210
  perAgentDirs.push(e);
30084
30211
  } else {
@@ -30202,13 +30329,13 @@ var init_doctor_inlined_secrets = __esm(() => {
30202
30329
  // src/cli/doctor-audit-integrity.ts
30203
30330
  import { readFileSync as fsReadFileSync2 } from "node:fs";
30204
30331
  import { homedir as homedir28 } from "node:os";
30205
- import { join as join48 } from "node:path";
30332
+ import { join as join49 } from "node:path";
30206
30333
  function rootWrittenLogs(home2) {
30207
30334
  return [
30208
- { label: "vault-broker", path: join48(home2, ".switchroom", "vault-audit.log") },
30335
+ { label: "vault-broker", path: join49(home2, ".switchroom", "vault-audit.log") },
30209
30336
  {
30210
30337
  label: "hostd",
30211
- path: join48(home2, ".switchroom", "host-control-audit.log")
30338
+ path: join49(home2, ".switchroom", "host-control-audit.log")
30212
30339
  }
30213
30340
  ];
30214
30341
  }
@@ -30273,7 +30400,7 @@ var init_doctor_audit_integrity = __esm(() => {
30273
30400
  import { connect as connect2 } from "node:net";
30274
30401
  async function hostdRequest(opts, req) {
30275
30402
  const timeoutMs = opts.timeoutMs ?? 5000;
30276
- return new Promise((resolve30, reject) => {
30403
+ return new Promise((resolve31, reject) => {
30277
30404
  const socket = connect2(opts.socketPath);
30278
30405
  let buf = "";
30279
30406
  let settled = false;
@@ -30319,7 +30446,7 @@ async function hostdRequest(opts, req) {
30319
30446
  settled = true;
30320
30447
  clearTimeout(timer);
30321
30448
  socket.end();
30322
- resolve30(resp);
30449
+ resolve31(resp);
30323
30450
  } catch (err) {
30324
30451
  if (settled)
30325
30452
  return;
@@ -30352,13 +30479,13 @@ var init_client4 = __esm(() => {
30352
30479
  // src/cli/doctor-agent-smoke.ts
30353
30480
  import { existsSync as existsSync49 } from "node:fs";
30354
30481
  import { homedir as homedir29 } from "node:os";
30355
- import { join as join49 } from "node:path";
30482
+ import { join as join50 } from "node:path";
30356
30483
  import { randomUUID as randomUUID4 } from "node:crypto";
30357
30484
  async function runAgentSmokeChecks(config, deps = {}) {
30358
30485
  if (deps.fast)
30359
30486
  return [];
30360
30487
  const home2 = deps.homeDir ?? homedir29();
30361
- const sock = deps.operatorSockPath ?? join49(home2, ".switchroom", "hostd", "operator", "sock");
30488
+ const sock = deps.operatorSockPath ?? join50(home2, ".switchroom", "hostd", "operator", "sock");
30362
30489
  if (!deps.hostdRequestImpl && !existsSync49(sock)) {
30363
30490
  return [
30364
30491
  {
@@ -30439,7 +30566,7 @@ var init_doctor_agent_smoke = __esm(() => {
30439
30566
  import { execFileSync as execFileSync14 } from "node:child_process";
30440
30567
  import { existsSync as existsSync50, statSync as statSync22 } from "node:fs";
30441
30568
  import { homedir as homedir30 } from "node:os";
30442
- import { join as join50 } from "node:path";
30569
+ import { join as join51 } from "node:path";
30443
30570
  function probeBindMountInode(hostPath, brokerContainerPath, opts) {
30444
30571
  const statHost = opts?.statHost ?? defaultStatHost;
30445
30572
  const statBroker = opts?.statBroker ?? defaultStatBroker;
@@ -30585,13 +30712,13 @@ function runVaultBrokerDurabilityChecks(_config, opts) {
30585
30712
  probeBrokerUnlocked(opts?.statusProbe),
30586
30713
  probeAutoUnlockBlob(home2),
30587
30714
  probeMachineIdMount(),
30588
- formatBindMountResult("vault-broker: vault.enc bind mount", join50(home2, ".switchroom", "vault", "vault.enc"), "/state/vault/vault.enc", probe2(join50(home2, ".switchroom", "vault", "vault.enc"), "/state/vault/vault.enc")),
30589
- formatBindMountResult("vault-broker: vault-grants.db bind mount (#1737)", join50(home2, ".switchroom", "vault-grants.db"), "/root/.switchroom/vault-grants.db", probe2(join50(home2, ".switchroom", "vault-grants.db"), "/root/.switchroom/vault-grants.db")),
30590
- formatBindMountResult("vault-broker: vault-audit.log bind mount (#1025)", join50(home2, ".switchroom", "vault-audit.log"), "/root/.switchroom/vault-audit.log", probe2(join50(home2, ".switchroom", "vault-audit.log"), "/root/.switchroom/vault-audit.log"))
30715
+ formatBindMountResult("vault-broker: vault.enc bind mount", join51(home2, ".switchroom", "vault", "vault.enc"), "/state/vault/vault.enc", probe2(join51(home2, ".switchroom", "vault", "vault.enc"), "/state/vault/vault.enc")),
30716
+ formatBindMountResult("vault-broker: vault-grants.db bind mount (#1737)", join51(home2, ".switchroom", "vault-grants.db"), "/root/.switchroom/vault-grants.db", probe2(join51(home2, ".switchroom", "vault-grants.db"), "/root/.switchroom/vault-grants.db")),
30717
+ formatBindMountResult("vault-broker: vault-audit.log bind mount (#1025)", join51(home2, ".switchroom", "vault-audit.log"), "/root/.switchroom/vault-audit.log", probe2(join51(home2, ".switchroom", "vault-audit.log"), "/root/.switchroom/vault-audit.log"))
30591
30718
  ];
30592
30719
  }
30593
30720
  function probeAutoUnlockBlob(home2) {
30594
- const blobPath = join50(home2, ".switchroom", "vault-auto-unlock");
30721
+ const blobPath = join51(home2, ".switchroom", "vault-auto-unlock");
30595
30722
  if (!existsSync50(blobPath)) {
30596
30723
  return {
30597
30724
  name: "vault-broker: auto-unlock blob",
@@ -30702,16 +30829,16 @@ import {
30702
30829
  readdirSync as readdirSync19,
30703
30830
  statSync as statSync23
30704
30831
  } from "node:fs";
30705
- import { dirname as dirname12, join as join51, resolve as resolve30 } from "node:path";
30832
+ import { dirname as dirname12, join as join52, resolve as resolve31 } from "node:path";
30706
30833
  import { createPublicKey, createPrivateKey } from "node:crypto";
30707
30834
  function findInNvm(bin) {
30708
- const nvmRoot = join51(process.env.HOME ?? "", ".nvm", "versions", "node");
30835
+ const nvmRoot = join52(process.env.HOME ?? "", ".nvm", "versions", "node");
30709
30836
  if (!existsSync51(nvmRoot))
30710
30837
  return null;
30711
30838
  try {
30712
30839
  const versions = readdirSync19(nvmRoot).sort().reverse();
30713
30840
  for (const v of versions) {
30714
- const candidate = join51(nvmRoot, v, "bin", bin);
30841
+ const candidate = join52(nvmRoot, v, "bin", bin);
30715
30842
  try {
30716
30843
  const s = statSync23(candidate);
30717
30844
  if (s.isFile() || s.isSymbolicLink()) {
@@ -30876,7 +31003,7 @@ function findChromium(homeDir = process.env.HOME ?? "", envBrowsersPath = proces
30876
31003
  if (envBrowsersPath && envBrowsersPath.length > 0) {
30877
31004
  cacheLocations.push(envBrowsersPath);
30878
31005
  }
30879
- cacheLocations.push(join51(homeDir, ".cache", "ms-playwright"));
31006
+ cacheLocations.push(join52(homeDir, ".cache", "ms-playwright"));
30880
31007
  for (const cacheDir of cacheLocations) {
30881
31008
  if (!existsSync51(cacheDir))
30882
31009
  continue;
@@ -30884,10 +31011,10 @@ function findChromium(homeDir = process.env.HOME ?? "", envBrowsersPath = proces
30884
31011
  const entries = readdirSync19(cacheDir).filter((e) => e.startsWith("chromium"));
30885
31012
  for (const entry of entries) {
30886
31013
  const candidates2 = [
30887
- join51(cacheDir, entry, "chrome-linux64", "chrome"),
30888
- join51(cacheDir, entry, "chrome-linux", "chrome"),
30889
- join51(cacheDir, entry, "chrome-linux64", "headless_shell"),
30890
- join51(cacheDir, entry, "chrome-linux", "headless_shell")
31014
+ join52(cacheDir, entry, "chrome-linux64", "chrome"),
31015
+ join52(cacheDir, entry, "chrome-linux", "chrome"),
31016
+ join52(cacheDir, entry, "chrome-linux64", "headless_shell"),
31017
+ join52(cacheDir, entry, "chrome-linux", "headless_shell")
30891
31018
  ];
30892
31019
  for (const path4 of candidates2) {
30893
31020
  if (existsSync51(path4))
@@ -30997,7 +31124,7 @@ function checkUserDeclaredMcps(name, agentConfig, config, renderedMcpServers) {
30997
31124
  function checkLegacyState() {
30998
31125
  const results = [];
30999
31126
  const h = process.env.HOME ?? "/root";
31000
- const clerkDir = join51(h, LEGACY_STATE_DIR);
31127
+ const clerkDir = join52(h, LEGACY_STATE_DIR);
31001
31128
  const clerkPresent = existsSync51(clerkDir);
31002
31129
  results.push({
31003
31130
  name: "legacy ~/.clerk state",
@@ -31007,7 +31134,7 @@ function checkLegacyState() {
31007
31134
  fix: "Legacy state detected. Run `mv ~/.clerk ~/.switchroom` and rename " + "any top-level `clerk:` key in switchroom.yaml to `switchroom:`. " + "This back-compat shim is REMOVED in v0.13.0 \u2014 no automatic " + "migration exists."
31008
31135
  } : {}
31009
31136
  });
31010
- const legacySock = join51(h, ".switchroom", "vault-broker.sock");
31137
+ const legacySock = join52(h, ".switchroom", "vault-broker.sock");
31011
31138
  let sockStat = null;
31012
31139
  try {
31013
31140
  sockStat = lstatSync5(legacySock);
@@ -31303,7 +31430,7 @@ async function checkHindsight(config) {
31303
31430
  }
31304
31431
  function checkPendingRetainsQueue(dir) {
31305
31432
  const home2 = process.env.HOME ?? "";
31306
- const pendingDir = dir ?? process.env.HINDSIGHT_PENDING_DIR ?? join51(home2, ".hindsight", "pending-retains");
31433
+ const pendingDir = dir ?? process.env.HINDSIGHT_PENDING_DIR ?? join52(home2, ".hindsight", "pending-retains");
31307
31434
  if (!existsSync51(pendingDir)) {
31308
31435
  return {
31309
31436
  name: "pending-retains queue",
@@ -31434,7 +31561,7 @@ async function checkTelegram(config) {
31434
31561
  const plugin = agentConfig.channels?.telegram?.plugin ?? "switchroom";
31435
31562
  if (plugin !== "switchroom")
31436
31563
  continue;
31437
- const envPath = join51(agentsDir, name, "telegram", ".env");
31564
+ const envPath = join52(agentsDir, name, "telegram", ".env");
31438
31565
  const read = tryReadHostFile(envPath);
31439
31566
  if (read.kind === "eacces") {
31440
31567
  results.push({
@@ -31517,7 +31644,7 @@ function checkStartShStale(agentName, startShPath) {
31517
31644
  }
31518
31645
  function checkLeakedHomeSwitchroom(agentName, agentDir) {
31519
31646
  const label = `${agentName}: $HOME/.switchroom symlink (#910)`;
31520
- const path4 = join51(agentDir, "home", ".switchroom");
31647
+ const path4 = join52(agentDir, "home", ".switchroom");
31521
31648
  let stats;
31522
31649
  try {
31523
31650
  stats = lstatSync5(path4);
@@ -31554,7 +31681,7 @@ function checkLeakedHomeSwitchroom(agentName, agentDir) {
31554
31681
  }
31555
31682
  function checkRepoHygiene(repoRoot) {
31556
31683
  const results = [];
31557
- const exportDir = join51(repoRoot, "clerk-export");
31684
+ const exportDir = join52(repoRoot, "clerk-export");
31558
31685
  if (existsSync51(exportDir)) {
31559
31686
  results.push({
31560
31687
  name: "repo hygiene: clerk-export/ on disk (#1072)",
@@ -31563,7 +31690,7 @@ function checkRepoHygiene(repoRoot) {
31563
31690
  fix: `Run scripts/migrate-clerk-export-to-vault.sh to move the bundle ` + `into the vault, then delete the on-disk copy.`
31564
31691
  });
31565
31692
  }
31566
- const knownTarball = join51(repoRoot, "clerk-export-with-secrets.tar.gz");
31693
+ const knownTarball = join52(repoRoot, "clerk-export-with-secrets.tar.gz");
31567
31694
  if (existsSync51(knownTarball)) {
31568
31695
  results.push({
31569
31696
  name: "repo hygiene: clerk-export-with-secrets.tar.gz on disk (#1072)",
@@ -31581,7 +31708,7 @@ function checkRepoHygiene(repoRoot) {
31581
31708
  results.push({
31582
31709
  name: `repo hygiene: ${name} on disk (#1072)`,
31583
31710
  status: "warn",
31584
- detail: `${join51(repoRoot, name)} matches the *-with-secrets*.tar.gz ` + `pattern. Likely contains real credentials.`,
31711
+ detail: `${join52(repoRoot, name)} matches the *-with-secrets*.tar.gz ` + `pattern. Likely contains real credentials.`,
31585
31712
  fix: `Inspect, migrate any secrets into the vault, then delete the ` + `archive.`
31586
31713
  });
31587
31714
  }
@@ -31604,9 +31731,9 @@ function checkRepoHygiene(repoRoot) {
31604
31731
  }
31605
31732
  function isSwitchroomCheckout(dir) {
31606
31733
  try {
31607
- if (!existsSync51(join51(dir, ".git")))
31734
+ if (!existsSync51(join52(dir, ".git")))
31608
31735
  return false;
31609
- const pkgPath = join51(dir, "package.json");
31736
+ const pkgPath = join52(dir, "package.json");
31610
31737
  if (!existsSync51(pkgPath))
31611
31738
  return false;
31612
31739
  const pkg = JSON.parse(readFileSync46(pkgPath, "utf-8"));
@@ -31621,7 +31748,7 @@ function checkAgents(config, configPath) {
31621
31748
  const statuses = getAllAgentStatuses(config);
31622
31749
  const authStatuses = getAllAuthStatuses(config);
31623
31750
  for (const [name, agentConfig] of Object.entries(config.agents)) {
31624
- const agentDir = resolve30(agentsDir, name);
31751
+ const agentDir = resolve31(agentsDir, name);
31625
31752
  if (!existsSync51(agentDir)) {
31626
31753
  results.push({
31627
31754
  name: `${name}: scaffold`,
@@ -31643,7 +31770,7 @@ function checkAgents(config, configPath) {
31643
31770
  fix: `Rotate the bot token (e.g. via \`switchroom vault\`), then run ` + `\`switchroom agent unquarantine ${name}\` and \`switchroom agent restart ${name}\``
31644
31771
  });
31645
31772
  }
31646
- results.push(checkStartShStale(name, join51(agentDir, "start.sh")));
31773
+ results.push(checkStartShStale(name, join52(agentDir, "start.sh")));
31647
31774
  results.push(checkLeakedHomeSwitchroom(name, agentDir));
31648
31775
  const status = statuses[name];
31649
31776
  const active = status?.active ?? "unknown";
@@ -31720,7 +31847,7 @@ function checkAgents(config, configPath) {
31720
31847
  }
31721
31848
  }
31722
31849
  if (agentConfig.channels?.telegram?.plugin === "switchroom") {
31723
- const mcpJsonPath = join51(agentDir, ".mcp.json");
31850
+ const mcpJsonPath = join52(agentDir, ".mcp.json");
31724
31851
  if (!existsSync51(mcpJsonPath)) {
31725
31852
  results.push({
31726
31853
  name: `${name}: .mcp.json`,
@@ -31804,7 +31931,7 @@ function mffAgentName(config) {
31804
31931
  function mffEnvPath(config) {
31805
31932
  const home2 = process.env.HOME ?? "/root";
31806
31933
  const agent = mffAgentName(config);
31807
- return agent ? resolve30(home2, ".switchroom/credentials", agent, "my-family-finance/.env") : resolve30(home2, ".switchroom/credentials/my-family-finance/.env");
31934
+ return agent ? resolve31(home2, ".switchroom/credentials", agent, "my-family-finance/.env") : resolve31(home2, ".switchroom/credentials/my-family-finance/.env");
31808
31935
  }
31809
31936
  function mffEnvState(envPath) {
31810
31937
  if (!existsSync51(envPath))
@@ -32022,7 +32149,7 @@ async function checkMffAuthFlow(envPath = mffEnvPath(), timeoutMs = 8000) {
32022
32149
  };
32023
32150
  }
32024
32151
  const credDir = dirname12(envPath);
32025
- const authScript = join51(credDir, "claude-auth.py");
32152
+ const authScript = join52(credDir, "claude-auth.py");
32026
32153
  if (!existsSync51(authScript)) {
32027
32154
  return {
32028
32155
  name: "mff: auth flow",
@@ -32220,14 +32347,14 @@ async function checkManifestDrift(probers) {
32220
32347
  return results;
32221
32348
  }
32222
32349
  function runDockerSection(config) {
32223
- const composePath = resolve30(process.env.HOME ?? "", ".switchroom", "compose", "docker-compose.yml");
32350
+ const composePath = resolve31(process.env.HOME ?? "", ".switchroom", "compose", "docker-compose.yml");
32224
32351
  const active = isDockerMode({ composePath });
32225
32352
  let composeYaml;
32226
32353
  let dockerfileAgent;
32227
32354
  try {
32228
32355
  composeYaml = readFileSync46(composePath, "utf8");
32229
32356
  } catch {}
32230
- const dockerfilePath = resolve30(process.env.HOME ?? "", ".switchroom", "docker", "Dockerfile.agent");
32357
+ const dockerfilePath = resolve31(process.env.HOME ?? "", ".switchroom", "docker", "Dockerfile.agent");
32231
32358
  try {
32232
32359
  dockerfileAgent = readFileSync46(dockerfilePath, "utf8");
32233
32360
  } catch {}
@@ -40594,7 +40721,7 @@ class Protocol {
40594
40721
  return;
40595
40722
  }
40596
40723
  const pollInterval = task2.pollInterval ?? this._options?.defaultTaskPollInterval ?? 1000;
40597
- await new Promise((resolve47) => setTimeout(resolve47, pollInterval));
40724
+ await new Promise((resolve48) => setTimeout(resolve48, pollInterval));
40598
40725
  options?.signal?.throwIfAborted();
40599
40726
  }
40600
40727
  } catch (error2) {
@@ -40606,7 +40733,7 @@ class Protocol {
40606
40733
  }
40607
40734
  request(request, resultSchema, options) {
40608
40735
  const { relatedRequestId, resumptionToken, onresumptiontoken, task, relatedTask } = options ?? {};
40609
- return new Promise((resolve47, reject) => {
40736
+ return new Promise((resolve48, reject) => {
40610
40737
  const earlyReject = (error2) => {
40611
40738
  reject(error2);
40612
40739
  };
@@ -40684,7 +40811,7 @@ class Protocol {
40684
40811
  if (!parseResult.success) {
40685
40812
  reject(parseResult.error);
40686
40813
  } else {
40687
- resolve47(parseResult.data);
40814
+ resolve48(parseResult.data);
40688
40815
  }
40689
40816
  } catch (error2) {
40690
40817
  reject(error2);
@@ -40875,12 +41002,12 @@ class Protocol {
40875
41002
  interval = task.pollInterval;
40876
41003
  }
40877
41004
  } catch {}
40878
- return new Promise((resolve47, reject) => {
41005
+ return new Promise((resolve48, reject) => {
40879
41006
  if (signal.aborted) {
40880
41007
  reject(new McpError(ErrorCode2.InvalidRequest, "Request cancelled"));
40881
41008
  return;
40882
41009
  }
40883
- const timeoutId = setTimeout(resolve47, interval);
41010
+ const timeoutId = setTimeout(resolve48, interval);
40884
41011
  signal.addEventListener("abort", () => {
40885
41012
  clearTimeout(timeoutId);
40886
41013
  reject(new McpError(ErrorCode2.InvalidRequest, "Request cancelled"));
@@ -43865,7 +43992,7 @@ var require_compile = __commonJS((exports2) => {
43865
43992
  const schOrFunc = root.refs[ref];
43866
43993
  if (schOrFunc)
43867
43994
  return schOrFunc;
43868
- let _sch = resolve47.call(this, root, ref);
43995
+ let _sch = resolve48.call(this, root, ref);
43869
43996
  if (_sch === undefined) {
43870
43997
  const schema = (_a = root.localRefs) === null || _a === undefined ? undefined : _a[ref];
43871
43998
  const { schemaId } = this.opts;
@@ -43892,7 +44019,7 @@ var require_compile = __commonJS((exports2) => {
43892
44019
  function sameSchemaEnv(s1, s2) {
43893
44020
  return s1.schema === s2.schema && s1.root === s2.root && s1.baseId === s2.baseId;
43894
44021
  }
43895
- function resolve47(root, ref) {
44022
+ function resolve48(root, ref) {
43896
44023
  let sch;
43897
44024
  while (typeof (sch = this.refs[ref]) == "string")
43898
44025
  ref = sch;
@@ -44422,7 +44549,7 @@ var require_fast_uri = __commonJS((exports2, module) => {
44422
44549
  }
44423
44550
  return uri;
44424
44551
  }
44425
- function resolve47(baseURI, relativeURI, options) {
44552
+ function resolve48(baseURI, relativeURI, options) {
44426
44553
  const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
44427
44554
  const resolved = resolveComponent(parse6(baseURI, schemelessOptions), parse6(relativeURI, schemelessOptions), schemelessOptions, true);
44428
44555
  schemelessOptions.skipEscape = true;
@@ -44650,7 +44777,7 @@ var require_fast_uri = __commonJS((exports2, module) => {
44650
44777
  var fastUri = {
44651
44778
  SCHEMES,
44652
44779
  normalize,
44653
- resolve: resolve47,
44780
+ resolve: resolve48,
44654
44781
  resolveComponent,
44655
44782
  equal,
44656
44783
  serialize,
@@ -48033,12 +48160,12 @@ class StdioServerTransport {
48033
48160
  this.onclose?.();
48034
48161
  }
48035
48162
  send(message) {
48036
- return new Promise((resolve47) => {
48163
+ return new Promise((resolve48) => {
48037
48164
  const json = serializeMessage(message);
48038
48165
  if (this._stdout.write(json)) {
48039
- resolve47();
48166
+ resolve48();
48040
48167
  } else {
48041
- this._stdout.once("drain", resolve47);
48168
+ this._stdout.once("drain", resolve48);
48042
48169
  }
48043
48170
  });
48044
48171
  }
@@ -48930,8 +49057,8 @@ var {
48930
49057
  } = import__.default;
48931
49058
 
48932
49059
  // src/build-info.ts
48933
- var VERSION = "0.13.58";
48934
- var COMMIT_SHA = "20818078";
49060
+ var VERSION = "0.13.60";
49061
+ var COMMIT_SHA = "9696d125";
48935
49062
 
48936
49063
  // src/cli/agent.ts
48937
49064
  init_source();
@@ -50475,6 +50602,26 @@ function resolveNotionMcpEntry(agentName, agentConfig, switchroomConfig) {
50475
50602
  };
50476
50603
  return entry;
50477
50604
  }
50605
+ var INTEGRATION_MCP_RESOLVERS = [
50606
+ {
50607
+ label: "Google Workspace",
50608
+ emitKey: "gdrive",
50609
+ retractionKey: "gdrive",
50610
+ resolve: resolveGdriveMcpEntry
50611
+ },
50612
+ {
50613
+ label: "Microsoft 365",
50614
+ emitKey: "ms-365",
50615
+ retractionKey: "ms-365",
50616
+ resolve: resolveMs365McpEntry
50617
+ },
50618
+ {
50619
+ label: "Notion",
50620
+ emitKey: "notion",
50621
+ retractionKey: "notion",
50622
+ resolve: resolveNotionMcpEntry
50623
+ }
50624
+ ];
50478
50625
  function scaffoldAgent(name, agentConfigRaw, agentsDir, telegramConfig, switchroomConfig, userIdOverride, switchroomConfigPath) {
50479
50626
  const agentConfig = resolveAgentConfig(switchroomConfig?.defaults, switchroomConfig?.profiles, agentConfigRaw);
50480
50627
  const agentDir = resolve10(agentsDir, name);
@@ -50583,18 +50730,10 @@ function scaffoldAgent(name, agentConfigRaw, agentsDir, telegramConfig, switchro
50583
50730
  settings.mcpServers[entry.key] = entry.value;
50584
50731
  }
50585
50732
  }
50586
- {
50587
- const gdrive = resolveGdriveMcpEntry(name, agentConfig, switchroomConfig);
50588
- if (gdrive && !settings.mcpServers[gdrive.key]) {
50589
- settings.mcpServers[gdrive.key] = gdrive.value;
50590
- }
50591
- const ms365 = resolveMs365McpEntry(name, agentConfig, switchroomConfig);
50592
- if (ms365 && !settings.mcpServers[ms365.key]) {
50593
- settings.mcpServers[ms365.key] = ms365.value;
50594
- }
50595
- const notion = resolveNotionMcpEntry(name, agentConfig, switchroomConfig);
50596
- if (notion && !settings.mcpServers[notion.key]) {
50597
- settings.mcpServers[notion.key] = notion.value;
50733
+ for (const integration of INTEGRATION_MCP_RESOLVERS) {
50734
+ const entry = integration.resolve(name, agentConfig, switchroomConfig);
50735
+ if (entry && !settings.mcpServers[entry.key]) {
50736
+ settings.mcpServers[entry.key] = entry.value;
50598
50737
  }
50599
50738
  }
50600
50739
  installHindsightPlugin(name, agentDir, switchroomConfig);
@@ -50661,17 +50800,11 @@ function scaffoldAgent(name, agentConfigRaw, agentsDir, telegramConfig, switchro
50661
50800
  }
50662
50801
  }
50663
50802
  if (switchroomConfig) {
50664
- const gdrive = resolveGdriveMcpEntry(name, agentConfig, switchroomConfig);
50665
- if (gdrive) {
50666
- mcpServers[gdrive.key] = gdrive.value;
50667
- }
50668
- const ms365 = resolveMs365McpEntry(name, agentConfig, switchroomConfig);
50669
- if (ms365) {
50670
- mcpServers[ms365.key] = ms365.value;
50671
- }
50672
- const notion = resolveNotionMcpEntry(name, agentConfig, switchroomConfig);
50673
- if (notion) {
50674
- mcpServers[notion.key] = notion.value;
50803
+ for (const integration of INTEGRATION_MCP_RESOLVERS) {
50804
+ const entry = integration.resolve(name, agentConfig, switchroomConfig);
50805
+ if (entry) {
50806
+ mcpServers[entry.key] = entry.value;
50807
+ }
50675
50808
  }
50676
50809
  }
50677
50810
  if (agentConfig.mcp_servers) {
@@ -51075,15 +51208,6 @@ function buildSettingsHooksBlock(p) {
51075
51208
  }
51076
51209
  ]
51077
51210
  },
51078
- {
51079
- hooks: [
51080
- {
51081
- type: "command",
51082
- command: wrap("hook:ack-first-pretool", `node "${join8(DOCKER_BUNDLED_HOOKS_PATH, "ack-first-pretool.mjs")}"`),
51083
- timeout: 5
51084
- }
51085
- ]
51086
- },
51087
51211
  {
51088
51212
  matcher: "^(Write|Edit|MultiEdit)$",
51089
51213
  hooks: [
@@ -51478,23 +51602,13 @@ function reconcileAgent(name, agentConfigRaw, agentsDir, telegramConfig, switchr
51478
51602
  }
51479
51603
  }
51480
51604
  {
51481
- const gdrive = resolveGdriveMcpEntry(name, agentConfig, switchroomConfig);
51482
- if (gdrive) {
51483
- mcpServers[gdrive.key] = gdrive.value;
51484
- } else {
51485
- delete mcpServers["gdrive"];
51486
- }
51487
- const ms365 = resolveMs365McpEntry(name, agentConfig, switchroomConfig);
51488
- if (ms365) {
51489
- mcpServers[ms365.key] = ms365.value;
51490
- } else {
51491
- delete mcpServers["ms-365"];
51492
- }
51493
- const notion = resolveNotionMcpEntry(name, agentConfig, switchroomConfig);
51494
- if (notion) {
51495
- mcpServers[notion.key] = notion.value;
51496
- } else {
51497
- delete mcpServers["notion"];
51605
+ for (const integration of INTEGRATION_MCP_RESOLVERS) {
51606
+ const entry = integration.resolve(name, agentConfig, switchroomConfig);
51607
+ if (entry) {
51608
+ mcpServers[entry.key] = entry.value;
51609
+ } else {
51610
+ delete mcpServers[integration.retractionKey];
51611
+ }
51498
51612
  }
51499
51613
  }
51500
51614
  if (agentConfig.mcp_servers) {
@@ -51677,17 +51791,11 @@ ${body}
51677
51791
  }
51678
51792
  }
51679
51793
  {
51680
- const gdrive = resolveGdriveMcpEntry(name, agentConfig, switchroomConfig);
51681
- if (gdrive) {
51682
- mcpServers[gdrive.key] = gdrive.value;
51683
- }
51684
- const ms365 = resolveMs365McpEntry(name, agentConfig, switchroomConfig);
51685
- if (ms365) {
51686
- mcpServers[ms365.key] = ms365.value;
51687
- }
51688
- const notion = resolveNotionMcpEntry(name, agentConfig, switchroomConfig);
51689
- if (notion) {
51690
- mcpServers[notion.key] = notion.value;
51794
+ for (const integration of INTEGRATION_MCP_RESOLVERS) {
51795
+ const entry = integration.resolve(name, agentConfig, switchroomConfig);
51796
+ if (entry) {
51797
+ mcpServers[entry.key] = entry.value;
51798
+ }
51691
51799
  }
51692
51800
  }
51693
51801
  if (agentConfig.mcp_servers) {
@@ -72182,15 +72290,15 @@ init_loader();
72182
72290
  init_lifecycle();
72183
72291
  import { cpSync as cpSync2, existsSync as existsSync52, mkdirSync as mkdirSync28, readFileSync as readFileSync47, realpathSync as realpathSync5, rmSync as rmSync12, statSync as statSync24 } from "node:fs";
72184
72292
  import { spawnSync as spawnSync8 } from "node:child_process";
72185
- import { join as join52, dirname as dirname13, resolve as resolve31 } from "node:path";
72293
+ import { join as join53, dirname as dirname13, resolve as resolve32 } from "node:path";
72186
72294
  import { homedir as homedir31 } from "node:os";
72187
- var DEFAULT_COMPOSE_PATH = join52(homedir31(), ".switchroom", "compose", "docker-compose.yml");
72295
+ var DEFAULT_COMPOSE_PATH = join53(homedir31(), ".switchroom", "compose", "docker-compose.yml");
72188
72296
  function runningFromSwitchroomCheckout(scriptPath) {
72189
72297
  let dir = dirname13(scriptPath);
72190
72298
  for (let i = 0;i < 12; i++) {
72191
- if (existsSync52(join52(dir, ".git"))) {
72299
+ if (existsSync52(join53(dir, ".git"))) {
72192
72300
  try {
72193
- const pkg = JSON.parse(readFileSync47(join52(dir, "package.json"), "utf-8"));
72301
+ const pkg = JSON.parse(readFileSync47(join53(dir, "package.json"), "utf-8"));
72194
72302
  if (pkg.name === "switchroom")
72195
72303
  return true;
72196
72304
  } catch {}
@@ -72320,8 +72428,8 @@ function planUpdate(opts) {
72320
72428
  opts.syncBundledSkillsFn();
72321
72429
  return;
72322
72430
  }
72323
- const source = resolve31(import.meta.dirname, "../../skills");
72324
- const dest = join52(homedir31(), ".switchroom", "skills", "_bundled");
72431
+ const source = resolve32(import.meta.dirname, "../../skills");
72432
+ const dest = join53(homedir31(), ".switchroom", "skills", "_bundled");
72325
72433
  if (!existsSync52(source)) {
72326
72434
  process.stderr.write(`switchroom update: sync-bundled-skills \u2014 CLI bundle has no adjacent skills/ at ${source}; skipping.
72327
72435
  `);
@@ -72435,7 +72543,7 @@ function defaultStatusProbe(composePath) {
72435
72543
  } catch {}
72436
72544
  let dir = dirname13(scriptPath);
72437
72545
  for (let i = 0;i < 8; i++) {
72438
- const pkgPath = join52(dir, "package.json");
72546
+ const pkgPath = join53(dir, "package.json");
72439
72547
  if (existsSync52(pkgPath)) {
72440
72548
  try {
72441
72549
  const pkg = JSON.parse(readFileSync47(pkgPath, "utf-8"));
@@ -72647,7 +72755,7 @@ init_source();
72647
72755
  init_helpers();
72648
72756
  init_loader();
72649
72757
  init_lifecycle();
72650
- import { resolve as resolve32 } from "node:path";
72758
+ import { resolve as resolve33 } from "node:path";
72651
72759
 
72652
72760
  // src/cli/version.ts
72653
72761
  init_source();
@@ -72655,7 +72763,7 @@ init_helpers();
72655
72763
  init_lifecycle();
72656
72764
  import { execSync as execSync4 } from "node:child_process";
72657
72765
  import { existsSync as existsSync53, readFileSync as readFileSync48 } from "node:fs";
72658
- import { dirname as dirname14, join as join53 } from "node:path";
72766
+ import { dirname as dirname14, join as join54 } from "node:path";
72659
72767
  function getClaudeCodeVersion() {
72660
72768
  try {
72661
72769
  const out = execSync4("claude --version 2>/dev/null", {
@@ -72705,11 +72813,11 @@ function formatUptime3(timestamp) {
72705
72813
  function locateSwitchroomInstallDir() {
72706
72814
  let dir = import.meta.dirname;
72707
72815
  for (let i = 0;i < 10 && dir && dir !== "/"; i++) {
72708
- const pkgPath = join53(dir, "package.json");
72816
+ const pkgPath = join54(dir, "package.json");
72709
72817
  if (existsSync53(pkgPath)) {
72710
72818
  try {
72711
72819
  const pkg = JSON.parse(readFileSync48(pkgPath, "utf-8"));
72712
- if (pkg.name === "switchroom" && existsSync53(join53(dir, ".git"))) {
72820
+ if (pkg.name === "switchroom" && existsSync53(join54(dir, ".git"))) {
72713
72821
  return dir;
72714
72822
  }
72715
72823
  } catch {}
@@ -72802,7 +72910,7 @@ function registerRestartCommand(program3) {
72802
72910
  }
72803
72911
  const didRestart = res.restarted || !graceful;
72804
72912
  if (didRestart) {
72805
- const agentDir = resolve32(agentsDir, name);
72913
+ const agentDir = resolve33(agentsDir, name);
72806
72914
  const converged = waitForAuthConverge(name, agentDir);
72807
72915
  if (!converged) {
72808
72916
  console.log(source_default.yellow(` ${name}: agent is up but auth status didn't converge in 30s \u2014 check logs`));
@@ -72883,7 +72991,7 @@ Dependency manifest`));
72883
72991
  // src/cli/handoff.ts
72884
72992
  init_helpers();
72885
72993
  init_loader();
72886
- import { resolve as resolve33 } from "node:path";
72994
+ import { resolve as resolve34 } from "node:path";
72887
72995
  function registerHandoffCommand(program3) {
72888
72996
  program3.command("handoff <agent>", { hidden: true }).description("Build the agent's session handoff sidecars \u2014 a transcript-tail " + "briefing (.handoff.md) and topic line (.handoff-topic). " + "[internal \u2014 used by the Stop hook]").option("--max-turns <n>", "Max turns kept in the handoff transcript tail", String(DEFAULT_MAX_TURNS)).action(withConfigError(async (agentName, opts) => {
72889
72997
  let agentConfig;
@@ -72897,7 +73005,7 @@ function registerHandoffCommand(program3) {
72897
73005
  return;
72898
73006
  }
72899
73007
  const agentsDir = resolveAgentsDir(config);
72900
- agentDir = resolve33(agentsDir, agentName);
73008
+ agentDir = resolve34(agentsDir, agentName);
72901
73009
  } catch (err) {
72902
73010
  if (!(err instanceof ConfigError))
72903
73011
  throw err;
@@ -72912,7 +73020,7 @@ function registerHandoffCommand(program3) {
72912
73020
  `);
72913
73021
  return;
72914
73022
  }
72915
- const claudeConfigDir = resolve33(agentDir, ".claude");
73023
+ const claudeConfigDir = resolve34(agentDir, ".claude");
72916
73024
  const jsonl = findLatestSessionJsonl(claudeConfigDir);
72917
73025
  if (!jsonl) {
72918
73026
  process.stderr.write(`handoff: no session JSONL under ${claudeConfigDir}/projects; skipping
@@ -72946,7 +73054,7 @@ import {
72946
73054
  writeFileSync as writeFileSync26,
72947
73055
  writeSync as writeSync7
72948
73056
  } from "node:fs";
72949
- import { join as join54 } from "node:path";
73057
+ import { join as join55 } from "node:path";
72950
73058
  import { randomBytes as randomBytes12 } from "node:crypto";
72951
73059
  import { execSync as execSync5 } from "node:child_process";
72952
73060
 
@@ -73266,7 +73374,7 @@ function redactedMarker(ruleId) {
73266
73374
  var ISSUES_FILE = "issues.jsonl";
73267
73375
  var ISSUES_LOCK = "issues.lock";
73268
73376
  function readAll(stateDir) {
73269
- const path4 = join54(stateDir, ISSUES_FILE);
73377
+ const path4 = join55(stateDir, ISSUES_FILE);
73270
73378
  if (!existsSync54(path4))
73271
73379
  return [];
73272
73380
  let raw;
@@ -73343,8 +73451,8 @@ function record(stateDir, input, nowFn = Date.now) {
73343
73451
  return result;
73344
73452
  });
73345
73453
  }
73346
- function resolve34(stateDir, fingerprint, nowFn = Date.now) {
73347
- if (!existsSync54(join54(stateDir, ISSUES_FILE)))
73454
+ function resolve35(stateDir, fingerprint, nowFn = Date.now) {
73455
+ if (!existsSync54(join55(stateDir, ISSUES_FILE)))
73348
73456
  return 0;
73349
73457
  return withLock(stateDir, () => {
73350
73458
  const all = readAll(stateDir);
@@ -73362,7 +73470,7 @@ function resolve34(stateDir, fingerprint, nowFn = Date.now) {
73362
73470
  });
73363
73471
  }
73364
73472
  function resolveAllBySource(stateDir, source, nowFn = Date.now) {
73365
- if (!existsSync54(join54(stateDir, ISSUES_FILE)))
73473
+ if (!existsSync54(join55(stateDir, ISSUES_FILE)))
73366
73474
  return 0;
73367
73475
  return withLock(stateDir, () => {
73368
73476
  const all = readAll(stateDir);
@@ -73380,7 +73488,7 @@ function resolveAllBySource(stateDir, source, nowFn = Date.now) {
73380
73488
  });
73381
73489
  }
73382
73490
  function prune(stateDir, opts = {}) {
73383
- if (!existsSync54(join54(stateDir, ISSUES_FILE)))
73491
+ if (!existsSync54(join55(stateDir, ISSUES_FILE)))
73384
73492
  return 0;
73385
73493
  return withLock(stateDir, () => {
73386
73494
  const all = readAll(stateDir);
@@ -73413,7 +73521,7 @@ function ensureDir(stateDir) {
73413
73521
  mkdirSync29(stateDir, { recursive: true });
73414
73522
  }
73415
73523
  function writeAll(stateDir, events) {
73416
- const path4 = join54(stateDir, ISSUES_FILE);
73524
+ const path4 = join55(stateDir, ISSUES_FILE);
73417
73525
  sweepOrphanTmpFiles(stateDir);
73418
73526
  const tmp = `${path4}.tmp-${process.pid}-${randomBytes12(4).toString("hex")}`;
73419
73527
  const body = events.length === 0 ? "" : events.map((e) => JSON.stringify(e)).join(`
@@ -73435,7 +73543,7 @@ function sweepOrphanTmpFiles(stateDir) {
73435
73543
  for (const entry of entries) {
73436
73544
  if (!entry.startsWith(TMP_PREFIX))
73437
73545
  continue;
73438
- const tmpPath = join54(stateDir, entry);
73546
+ const tmpPath = join55(stateDir, entry);
73439
73547
  try {
73440
73548
  const stat = statSync25(tmpPath);
73441
73549
  if (stat.mtimeMs < cutoff) {
@@ -73447,7 +73555,7 @@ function sweepOrphanTmpFiles(stateDir) {
73447
73555
  var LOCK_RETRY_MS = 25;
73448
73556
  var LOCK_TIMEOUT_MS = 1e4;
73449
73557
  function withLock(stateDir, fn) {
73450
- const lockPath = join54(stateDir, ISSUES_LOCK);
73558
+ const lockPath = join55(stateDir, ISSUES_LOCK);
73451
73559
  const startedAt = Date.now();
73452
73560
  let fd = null;
73453
73561
  while (fd === null) {
@@ -73631,11 +73739,11 @@ function registerIssuesCommand(program3) {
73631
73739
  const stateDir = resolveStateDir2(opts);
73632
73740
  let flipped;
73633
73741
  if (opts.source && opts.code) {
73634
- flipped = resolve34(stateDir, computeFingerprint(opts.source, opts.code));
73742
+ flipped = resolve35(stateDir, computeFingerprint(opts.source, opts.code));
73635
73743
  } else if (opts.source && !fingerprint) {
73636
73744
  flipped = resolveAllBySource(stateDir, opts.source);
73637
73745
  } else if (fingerprint) {
73638
- flipped = resolve34(stateDir, fingerprint);
73746
+ flipped = resolve35(stateDir, fingerprint);
73639
73747
  } else {
73640
73748
  process.stderr.write(`issues resolve: need either <fingerprint>, --source, or --source + --code
73641
73749
  `);
@@ -73732,7 +73840,7 @@ function relTime(deltaMs) {
73732
73840
  init_source();
73733
73841
  import { existsSync as existsSync57 } from "node:fs";
73734
73842
  import { homedir as homedir34 } from "node:os";
73735
- import { join as join57, resolve as resolve35 } from "node:path";
73843
+ import { join as join58, resolve as resolve36 } from "node:path";
73736
73844
 
73737
73845
  // src/deps/python.ts
73738
73846
  import { createHash as createHash11 } from "node:crypto";
@@ -73743,7 +73851,7 @@ import {
73743
73851
  rmSync as rmSync13,
73744
73852
  writeFileSync as writeFileSync27
73745
73853
  } from "node:fs";
73746
- import { dirname as dirname15, join as join55 } from "node:path";
73854
+ import { dirname as dirname15, join as join56 } from "node:path";
73747
73855
  import { homedir as homedir32 } from "node:os";
73748
73856
  import { execFileSync as execFileSync15 } from "node:child_process";
73749
73857
 
@@ -73756,7 +73864,7 @@ class PythonEnvError extends Error {
73756
73864
  }
73757
73865
  }
73758
73866
  function defaultPythonCacheRoot() {
73759
- return join55(homedir32(), ".switchroom", "deps", "python");
73867
+ return join56(homedir32(), ".switchroom", "deps", "python");
73760
73868
  }
73761
73869
  function hashFile(path4) {
73762
73870
  return createHash11("sha256").update(readFileSync50(path4)).digest("hex");
@@ -73768,11 +73876,11 @@ function ensurePythonEnv(opts) {
73768
73876
  if (!existsSync55(requirementsPath)) {
73769
73877
  throw new PythonEnvError(`requirements file not found: ${requirementsPath}`);
73770
73878
  }
73771
- const venvDir = join55(cacheRoot, skillName);
73772
- const stampPath = join55(venvDir, ".requirements.sha256");
73773
- const binDir = join55(venvDir, "bin");
73774
- const pythonBin = join55(binDir, "python");
73775
- const pipBin = join55(binDir, "pip");
73879
+ const venvDir = join56(cacheRoot, skillName);
73880
+ const stampPath = join56(venvDir, ".requirements.sha256");
73881
+ const binDir = join56(venvDir, "bin");
73882
+ const pythonBin = join56(binDir, "python");
73883
+ const pipBin = join56(binDir, "pip");
73776
73884
  const targetHash = hashFile(requirementsPath);
73777
73885
  if (!force && existsSync55(stampPath) && existsSync55(pythonBin)) {
73778
73886
  const existingHash = readFileSync50(stampPath, "utf8").trim();
@@ -73831,7 +73939,7 @@ import {
73831
73939
  rmSync as rmSync14,
73832
73940
  writeFileSync as writeFileSync28
73833
73941
  } from "node:fs";
73834
- import { dirname as dirname16, join as join56 } from "node:path";
73942
+ import { dirname as dirname16, join as join57 } from "node:path";
73835
73943
  import { homedir as homedir33 } from "node:os";
73836
73944
  import { execFileSync as execFileSync16 } from "node:child_process";
73837
73945
 
@@ -73855,7 +73963,7 @@ var LOCKFILES_FOR = {
73855
73963
  npm: ["package-lock.json"]
73856
73964
  };
73857
73965
  function defaultNodeCacheRoot() {
73858
- return join56(homedir33(), ".switchroom", "deps", "node");
73966
+ return join57(homedir33(), ".switchroom", "deps", "node");
73859
73967
  }
73860
73968
  function hashDepInputs(packageJsonPath) {
73861
73969
  const sourceDir = dirname16(packageJsonPath);
@@ -73864,7 +73972,7 @@ function hashDepInputs(packageJsonPath) {
73864
73972
  `);
73865
73973
  hasher.update(readFileSync51(packageJsonPath));
73866
73974
  for (const lockName of ALL_LOCKFILES) {
73867
- const lockPath = join56(sourceDir, lockName);
73975
+ const lockPath = join57(sourceDir, lockName);
73868
73976
  if (existsSync56(lockPath)) {
73869
73977
  hasher.update(`
73870
73978
  `);
@@ -73884,10 +73992,10 @@ function ensureNodeEnv(opts) {
73884
73992
  throw new NodeEnvError(`package.json not found: ${packageJsonPath}`);
73885
73993
  }
73886
73994
  const sourceDir = dirname16(packageJsonPath);
73887
- const envDir = join56(cacheRoot, skillName);
73888
- const stampPath = join56(envDir, ".package.sha256");
73889
- const nodeModulesDir = join56(envDir, "node_modules");
73890
- const binDir = join56(nodeModulesDir, ".bin");
73995
+ const envDir = join57(cacheRoot, skillName);
73996
+ const stampPath = join57(envDir, ".package.sha256");
73997
+ const nodeModulesDir = join57(envDir, "node_modules");
73998
+ const binDir = join57(nodeModulesDir, ".bin");
73891
73999
  const targetHash = hashDepInputs(packageJsonPath);
73892
74000
  if (!force && existsSync56(stampPath) && existsSync56(nodeModulesDir)) {
73893
74001
  const existingHash = readFileSync51(stampPath, "utf8").trim();
@@ -73905,12 +74013,12 @@ function ensureNodeEnv(opts) {
73905
74013
  rmSync14(envDir, { recursive: true, force: true });
73906
74014
  }
73907
74015
  mkdirSync31(envDir, { recursive: true });
73908
- copyFileSync9(packageJsonPath, join56(envDir, "package.json"));
74016
+ copyFileSync9(packageJsonPath, join57(envDir, "package.json"));
73909
74017
  let copiedLockfile = false;
73910
74018
  for (const lockName of LOCKFILES_FOR[installer]) {
73911
- const lockPath = join56(sourceDir, lockName);
74019
+ const lockPath = join57(sourceDir, lockName);
73912
74020
  if (existsSync56(lockPath)) {
73913
- copyFileSync9(lockPath, join56(envDir, lockName));
74021
+ copyFileSync9(lockPath, join57(envDir, lockName));
73914
74022
  copiedLockfile = true;
73915
74023
  }
73916
74024
  }
@@ -73939,7 +74047,7 @@ function ensureNodeEnv(opts) {
73939
74047
 
73940
74048
  // src/cli/deps.ts
73941
74049
  function builtinSkillsRoot() {
73942
- return resolve35(homedir34(), ".switchroom/skills/_bundled");
74050
+ return resolve36(homedir34(), ".switchroom/skills/_bundled");
73943
74051
  }
73944
74052
  function registerDepsCommand(program3) {
73945
74053
  const deps = program3.command("deps").description("Manage cached per-skill dependency environments");
@@ -73949,13 +74057,13 @@ function registerDepsCommand(program3) {
73949
74057
  console.error(source_default.red(`Bundled skills pool dir not found at ${skillsRoot} \u2014 run \`switchroom update\` to install it.`));
73950
74058
  process.exit(1);
73951
74059
  }
73952
- const skillDir = join57(skillsRoot, skill);
74060
+ const skillDir = join58(skillsRoot, skill);
73953
74061
  if (!existsSync57(skillDir)) {
73954
74062
  console.error(source_default.red(`Unknown skill: ${skill} (no dir at ${skillDir})`));
73955
74063
  process.exit(1);
73956
74064
  }
73957
- const requirementsPath = join57(skillDir, "requirements.txt");
73958
- const packageJsonPath = join57(skillDir, "package.json");
74065
+ const requirementsPath = join58(skillDir, "requirements.txt");
74066
+ const packageJsonPath = join58(skillDir, "package.json");
73959
74067
  const wantPython = opts.python ?? (!opts.python && !opts.node && existsSync57(requirementsPath));
73960
74068
  const wantNode = opts.node ?? (!opts.python && !opts.node && existsSync57(packageJsonPath));
73961
74069
  let did = 0;
@@ -74018,7 +74126,7 @@ function registerDepsCommand(program3) {
74018
74126
  init_helpers();
74019
74127
  init_loader();
74020
74128
  import { existsSync as existsSync58 } from "node:fs";
74021
- import { resolve as resolve36, sep as sep3 } from "node:path";
74129
+ import { resolve as resolve37, sep as sep3 } from "node:path";
74022
74130
  import { spawnSync as spawnSync9 } from "node:child_process";
74023
74131
 
74024
74132
  // src/agents/workspace.ts
@@ -74724,8 +74832,8 @@ function registerWorkspaceCommand(program3) {
74724
74832
  const dir = resolveAgentWorkspaceDirOrExit(program3, agentName);
74725
74833
  if (!dir)
74726
74834
  return;
74727
- const resolvedWorkspace = resolve36(dir);
74728
- const target = resolve36(resolvedWorkspace, file ?? "AGENTS.md");
74835
+ const resolvedWorkspace = resolve37(dir);
74836
+ const target = resolve37(resolvedWorkspace, file ?? "AGENTS.md");
74729
74837
  if (!isInsideWorkspace(resolvedWorkspace, target)) {
74730
74838
  process.stderr.write(`workspace edit: refusing path traversal outside workspace dir (${target})
74731
74839
  `);
@@ -74793,7 +74901,7 @@ function registerWorkspaceCommand(program3) {
74793
74901
  const dir = resolveAgentWorkspaceDirOrExit(program3, agentName);
74794
74902
  if (!dir)
74795
74903
  return;
74796
- const gitDir = resolve36(dir, ".git");
74904
+ const gitDir = resolve37(dir, ".git");
74797
74905
  if (!existsSync58(gitDir)) {
74798
74906
  process.stdout.write(`Workspace is not a git repository. Re-run \`switchroom agent create ${agentName}\` ` + `or manually \`git init\` in ${dir} to enable versioning.
74799
74907
  `);
@@ -74847,7 +74955,7 @@ function registerWorkspaceCommand(program3) {
74847
74955
  const dir = resolveAgentWorkspaceDirOrExit(program3, agentName);
74848
74956
  if (!dir)
74849
74957
  return;
74850
- const gitDir = resolve36(dir, ".git");
74958
+ const gitDir = resolve37(dir, ".git");
74851
74959
  if (!existsSync58(gitDir)) {
74852
74960
  process.stdout.write(`Workspace is not a git repository.
74853
74961
  `);
@@ -74871,7 +74979,7 @@ function resolveAgentWorkspaceDirOrExit(program3, agentName) {
74871
74979
  return;
74872
74980
  }
74873
74981
  const agentsDir = resolveAgentsDir(config);
74874
- const agentDir = resolve36(agentsDir, agentName);
74982
+ const agentDir = resolve37(agentsDir, agentName);
74875
74983
  const dir = resolveAgentWorkspaceDir(agentDir);
74876
74984
  if (!existsSync58(dir)) {
74877
74985
  process.stderr.write(`workspace: ${dir} does not exist yet. Run \`switchroom setup\` or \`switchroom agent scaffold ${agentName}\` to seed it.
@@ -74910,7 +75018,7 @@ init_helpers();
74910
75018
  init_loader();
74911
75019
  init_merge();
74912
75020
  import { copyFileSync as copyFileSync10, existsSync as existsSync59, readFileSync as readFileSync52, writeFileSync as writeFileSync29 } from "node:fs";
74913
- import { join as join58, resolve as resolve37 } from "node:path";
75021
+ import { join as join59, resolve as resolve38 } from "node:path";
74914
75022
  init_schema();
74915
75023
  function resolveSoulTargetOrExit(program3, agentName) {
74916
75024
  const config = getConfig(program3);
@@ -74923,7 +75031,7 @@ function resolveSoulTargetOrExit(program3, agentName) {
74923
75031
  const profileName = merged.extends ?? DEFAULT_PROFILE;
74924
75032
  const profilePath = getProfilePath(profileName);
74925
75033
  const agentsDir = resolveAgentsDir(config);
74926
- const agentDir = resolve37(agentsDir, agentName);
75034
+ const agentDir = resolve38(agentsDir, agentName);
74927
75035
  const workspaceDir = resolveAgentWorkspaceDir(agentDir);
74928
75036
  if (!existsSync59(workspaceDir)) {
74929
75037
  console.error(`soul: ${workspaceDir} does not exist yet. Run \`switchroom setup\` ` + `or \`switchroom agent scaffold ${agentName}\` to seed it.`);
@@ -74934,7 +75042,7 @@ function resolveSoulTargetOrExit(program3, agentName) {
74934
75042
  profileName,
74935
75043
  profilePath,
74936
75044
  workspaceDir,
74937
- soulPath: join58(workspaceDir, "SOUL.md"),
75045
+ soulPath: join59(workspaceDir, "SOUL.md"),
74938
75046
  soul: merged.soul
74939
75047
  };
74940
75048
  }
@@ -75001,7 +75109,7 @@ function registerSoulCommand(program3) {
75001
75109
  init_helpers();
75002
75110
  init_loader();
75003
75111
  import { existsSync as existsSync60, readFileSync as readFileSync53, readdirSync as readdirSync21, statSync as statSync26 } from "node:fs";
75004
- import { resolve as resolve38, join as join59 } from "node:path";
75112
+ import { resolve as resolve39, join as join60 } from "node:path";
75005
75113
  import { createHash as createHash13 } from "node:crypto";
75006
75114
  init_merge();
75007
75115
  init_hindsight();
@@ -75015,7 +75123,7 @@ function sha256(content) {
75015
75123
  return createHash13("sha256").update(content).digest("hex").slice(0, 16);
75016
75124
  }
75017
75125
  function findLatestTranscriptJsonl(claudeConfigDir) {
75018
- const projectsDir = join59(claudeConfigDir, "projects");
75126
+ const projectsDir = join60(claudeConfigDir, "projects");
75019
75127
  if (!existsSync60(projectsDir))
75020
75128
  return;
75021
75129
  try {
@@ -75024,8 +75132,8 @@ function findLatestTranscriptJsonl(claudeConfigDir) {
75024
75132
  for (const entry of entries) {
75025
75133
  if (!entry.isDirectory())
75026
75134
  continue;
75027
- const projectPath = join59(projectsDir, entry.name);
75028
- const transcriptPath = join59(projectPath, "transcript.jsonl");
75135
+ const projectPath = join60(projectsDir, entry.name);
75136
+ const transcriptPath = join60(projectPath, "transcript.jsonl");
75029
75137
  if (!existsSync60(transcriptPath))
75030
75138
  continue;
75031
75139
  const stat3 = statSync26(transcriptPath);
@@ -75088,17 +75196,17 @@ function registerDebugCommand(program3) {
75088
75196
  process.exit(1);
75089
75197
  }
75090
75198
  const agentsDir = resolveAgentsDir(config);
75091
- const agentDir = resolve38(agentsDir, agentName);
75199
+ const agentDir = resolve39(agentsDir, agentName);
75092
75200
  if (!existsSync60(agentDir)) {
75093
75201
  console.error(`Agent directory not found: ${agentDir}`);
75094
75202
  process.exit(1);
75095
75203
  }
75096
75204
  const workspaceDir = resolveAgentWorkspaceDir(agentDir);
75097
- const claudeConfigDir = join59(agentDir, ".claude");
75098
- const claudeMdPath = join59(agentDir, "CLAUDE.md");
75099
- const soulMdPath = join59(agentDir, "SOUL.md");
75100
- const workspaceSoulMdPath = join59(workspaceDir, "SOUL.md");
75101
- const handoffPath = join59(agentDir, ".handoff.md");
75205
+ const claudeConfigDir = join60(agentDir, ".claude");
75206
+ const claudeMdPath = join60(agentDir, "CLAUDE.md");
75207
+ const soulMdPath = join60(agentDir, "SOUL.md");
75208
+ const workspaceSoulMdPath = join60(workspaceDir, "SOUL.md");
75209
+ const handoffPath = join60(agentDir, ".handoff.md");
75102
75210
  const lastN = parseInt(opts.last, 10);
75103
75211
  if (isNaN(lastN) || lastN < 1) {
75104
75212
  console.error("--last must be a positive integer");
@@ -75248,7 +75356,7 @@ init_source();
75248
75356
  // src/worktree/claim.ts
75249
75357
  import { execFileSync as execFileSync17 } from "node:child_process";
75250
75358
  import { closeSync as closeSync12, mkdirSync as mkdirSync33, openSync as openSync12, existsSync as existsSync62, unlinkSync as unlinkSync13 } from "node:fs";
75251
- import { join as join61, resolve as resolve40 } from "node:path";
75359
+ import { join as join62, resolve as resolve41 } from "node:path";
75252
75360
  import { homedir as homedir36 } from "node:os";
75253
75361
  import { randomBytes as randomBytes13 } from "node:crypto";
75254
75362
 
@@ -75262,13 +75370,13 @@ import {
75262
75370
  existsSync as existsSync61,
75263
75371
  renameSync as renameSync12
75264
75372
  } from "node:fs";
75265
- import { join as join60, resolve as resolve39 } from "node:path";
75373
+ import { join as join61, resolve as resolve40 } from "node:path";
75266
75374
  import { homedir as homedir35 } from "node:os";
75267
75375
  function registryDir() {
75268
- return resolve39(process.env.SWITCHROOM_WORKTREE_DIR ?? join60(homedir35(), ".switchroom", "worktrees"));
75376
+ return resolve40(process.env.SWITCHROOM_WORKTREE_DIR ?? join61(homedir35(), ".switchroom", "worktrees"));
75269
75377
  }
75270
75378
  function recordPath(id) {
75271
- return join60(registryDir(), `${id}.json`);
75379
+ return join61(registryDir(), `${id}.json`);
75272
75380
  }
75273
75381
  function ensureDir2() {
75274
75382
  mkdirSync32(registryDir(), { recursive: true });
@@ -75319,7 +75427,7 @@ function acquireRepoLock(repoPath) {
75319
75427
  const lockDir = registryDir();
75320
75428
  mkdirSync33(lockDir, { recursive: true });
75321
75429
  const lockName = repoPath.replace(/[^A-Za-z0-9]/g, "_");
75322
- const lockPath = join61(lockDir, `.lock-${lockName}`);
75430
+ const lockPath = join62(lockDir, `.lock-${lockName}`);
75323
75431
  const deadline = Date.now() + 5000;
75324
75432
  let fd = null;
75325
75433
  while (fd === null) {
@@ -75346,7 +75454,7 @@ function acquireRepoLock(repoPath) {
75346
75454
  }
75347
75455
  var DEFAULT_CONCURRENCY = 5;
75348
75456
  function worktreesBaseDir() {
75349
- return resolve40(process.env.SWITCHROOM_WORKTREE_BASE ?? join61(homedir36(), ".switchroom", "worktree-checkouts"));
75457
+ return resolve41(process.env.SWITCHROOM_WORKTREE_BASE ?? join62(homedir36(), ".switchroom", "worktree-checkouts"));
75350
75458
  }
75351
75459
  function shortId() {
75352
75460
  return randomBytes13(4).toString("hex");
@@ -75368,7 +75476,7 @@ function resolveRepoPath(repo, codeRepos) {
75368
75476
  }
75369
75477
  function expandHome(p) {
75370
75478
  if (p.startsWith("~/"))
75371
- return join61(homedir36(), p.slice(2));
75479
+ return join62(homedir36(), p.slice(2));
75372
75480
  return p;
75373
75481
  }
75374
75482
  async function claimWorktree(input, codeRepos) {
@@ -75396,7 +75504,7 @@ async function claimWorktree(input, codeRepos) {
75396
75504
  branch = `task/${taskSuffix}-${id}`;
75397
75505
  const baseDir = worktreesBaseDir();
75398
75506
  mkdirSync33(baseDir, { recursive: true });
75399
- worktreePath = join61(baseDir, `${id}-${taskSuffix}`);
75507
+ worktreePath = join62(baseDir, `${id}-${taskSuffix}`);
75400
75508
  const now = new Date().toISOString();
75401
75509
  const record2 = {
75402
75510
  id,
@@ -75651,7 +75759,7 @@ import {
75651
75759
  rmSync as rmSync15,
75652
75760
  writeFileSync as writeFileSync31
75653
75761
  } from "node:fs";
75654
- import { join as join62 } from "node:path";
75762
+ import { join as join63 } from "node:path";
75655
75763
  function encodeCredentialsFilename(email) {
75656
75764
  const SAFE = new Set([
75657
75765
  ..."ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
@@ -75841,16 +75949,16 @@ function resolveCredentialsDir(env2) {
75841
75949
  if (explicit && explicit.length > 0)
75842
75950
  return explicit;
75843
75951
  const stateBase = env2.SWITCHROOM_CONTAINER === "1" ? "/state/agent" : env2.HOME ?? ".";
75844
- return join62(stateBase, "google-workspace-mcp", "credentials");
75952
+ return join63(stateBase, "google-workspace-mcp", "credentials");
75845
75953
  }
75846
75954
  function writeSeedFile(dir, email, seed) {
75847
75955
  mkdirSync34(dir, { recursive: true, mode: 448 });
75848
75956
  chmodSync9(dir, 448);
75849
75957
  for (const name of readdirSync23(dir)) {
75850
- rmSync15(join62(dir, name), { force: true, recursive: true });
75958
+ rmSync15(join63(dir, name), { force: true, recursive: true });
75851
75959
  }
75852
75960
  const filename = encodeCredentialsFilename(email);
75853
- const filePath = join62(dir, filename);
75961
+ const filePath = join63(dir, filename);
75854
75962
  writeFileSync31(filePath, JSON.stringify(seed), { mode: 384 });
75855
75963
  chmodSync9(filePath, 384);
75856
75964
  return filePath;
@@ -76010,7 +76118,7 @@ function registerDriveMcpLauncherCommand(program3) {
76010
76118
  init_scaffold_integration();
76011
76119
  import { spawn as spawn6 } from "node:child_process";
76012
76120
  import { writeFileSync as writeFileSync32, mkdirSync as mkdirSync35 } from "node:fs";
76013
- import { dirname as dirname17, join as join63 } from "node:path";
76121
+ import { dirname as dirname17, join as join64 } from "node:path";
76014
76122
  var SOFTERIA_TOKEN_ENV = "MS365_MCP_OAUTH_TOKEN";
76015
76123
  var DEFAULT_REFRESH_LEAD_MS = 5 * 60 * 1000;
76016
76124
  var MAX_REFRESH_INTERVAL_MS = 60 * 60 * 1000;
@@ -76042,7 +76150,7 @@ function writeRefreshHeartbeat(agentName, data) {
76042
76150
  function heartbeatPath(agentName) {
76043
76151
  const override = process.env.SWITCHROOM_M365_HEARTBEAT_DIR;
76044
76152
  if (override) {
76045
- return join63(override, `m365-launcher-${agentName}.heartbeat.json`);
76153
+ return join64(override, `m365-launcher-${agentName}.heartbeat.json`);
76046
76154
  }
76047
76155
  return "/state/agent/m365-launcher.heartbeat.json";
76048
76156
  }
@@ -76066,20 +76174,20 @@ function wireStdio(child) {
76066
76174
  async function killChild(child, gracefulMs = 3000) {
76067
76175
  if (child.exitCode !== null || child.signalCode !== null)
76068
76176
  return;
76069
- return new Promise((resolve41) => {
76177
+ return new Promise((resolve42) => {
76070
76178
  let killTimer = null;
76071
76179
  const onExit = () => {
76072
76180
  if (killTimer) {
76073
76181
  clearTimeout(killTimer);
76074
76182
  killTimer = null;
76075
76183
  }
76076
- resolve41();
76184
+ resolve42();
76077
76185
  };
76078
76186
  child.once("exit", onExit);
76079
76187
  try {
76080
76188
  child.kill("SIGTERM");
76081
76189
  } catch {
76082
- resolve41();
76190
+ resolve42();
76083
76191
  return;
76084
76192
  }
76085
76193
  killTimer = setTimeout(() => {
@@ -76193,8 +76301,8 @@ async function runMs365McpLauncher(opts, rt) {
76193
76301
  };
76194
76302
  process.on("SIGINT", onSignal);
76195
76303
  process.on("SIGTERM", onSignal);
76196
- return new Promise((resolve41) => {
76197
- resolveLauncher = resolve41;
76304
+ return new Promise((resolve42) => {
76305
+ resolveLauncher = resolve42;
76198
76306
  });
76199
76307
  }
76200
76308
  function registerM365McpLauncherCommand(program3) {
@@ -76296,23 +76404,23 @@ async function runNotionMcpLauncher(opts, runtime) {
76296
76404
  };
76297
76405
  process.on("SIGTERM", () => forward("SIGTERM"));
76298
76406
  process.on("SIGINT", () => forward("SIGINT"));
76299
- const exitCode = await new Promise((resolve41) => {
76407
+ const exitCode = await new Promise((resolve42) => {
76300
76408
  child.once("exit", (code, signal) => {
76301
76409
  clearTimer(heartbeatHandle);
76302
76410
  if (typeof code === "number") {
76303
- resolve41(code);
76411
+ resolve42(code);
76304
76412
  } else if (signal) {
76305
76413
  const sigCode = { SIGTERM: 15, SIGINT: 2, SIGKILL: 9 }[signal] ?? 1;
76306
- resolve41(128 + sigCode);
76414
+ resolve42(128 + sigCode);
76307
76415
  } else {
76308
- resolve41(1);
76416
+ resolve42(1);
76309
76417
  }
76310
76418
  });
76311
76419
  child.once("error", (err) => {
76312
76420
  clearTimer(heartbeatHandle);
76313
76421
  process.stderr.write(`notion-mcp-launcher: child spawn error: ${err.message}
76314
76422
  `);
76315
- resolve41(1);
76423
+ resolve42(1);
76316
76424
  });
76317
76425
  });
76318
76426
  return exitCode;
@@ -76961,7 +77069,7 @@ agents:
76961
77069
 
76962
77070
  // src/cli/apply.ts
76963
77071
  init_resolver();
76964
- import { dirname as dirname21, join as join67, resolve as resolve42 } from "node:path";
77072
+ import { dirname as dirname21, join as join68, resolve as resolve43 } from "node:path";
76965
77073
  import { homedir as homedir38 } from "node:os";
76966
77074
  import { execFileSync as execFileSync20 } from "node:child_process";
76967
77075
  init_vault();
@@ -76970,7 +77078,7 @@ init_loader();
76970
77078
 
76971
77079
  // src/cli/update-prompt-hook.ts
76972
77080
  import { existsSync as existsSync66, readFileSync as readFileSync55, writeFileSync as writeFileSync34, chmodSync as chmodSync10, mkdirSync as mkdirSync37 } from "node:fs";
76973
- import { join as join64 } from "node:path";
77081
+ import { join as join65 } from "node:path";
76974
77082
  var HOOK_FILENAME = "update-card-on-prompt.sh";
76975
77083
  function updatePromptHookScript() {
76976
77084
  return `#!/bin/bash
@@ -77036,9 +77144,9 @@ exit 0
77036
77144
  `;
77037
77145
  }
77038
77146
  function installUpdatePromptHook(agentDir) {
77039
- const hooksDir = join64(agentDir, ".claude", "hooks");
77147
+ const hooksDir = join65(agentDir, ".claude", "hooks");
77040
77148
  mkdirSync37(hooksDir, { recursive: true });
77041
- const scriptPath = join64(hooksDir, HOOK_FILENAME);
77149
+ const scriptPath = join65(hooksDir, HOOK_FILENAME);
77042
77150
  const desired = updatePromptHookScript();
77043
77151
  let installed = false;
77044
77152
  const existing = existsSync66(scriptPath) ? readFileSync55(scriptPath, "utf-8") : "";
@@ -77051,7 +77159,7 @@ function installUpdatePromptHook(agentDir) {
77051
77159
  chmodSync10(scriptPath, 493);
77052
77160
  } catch {}
77053
77161
  }
77054
- const settingsPath = join64(agentDir, ".claude", "settings.json");
77162
+ const settingsPath = join65(agentDir, ".claude", "settings.json");
77055
77163
  if (!existsSync66(settingsPath)) {
77056
77164
  return { scriptPath, settingsPath, installed };
77057
77165
  }
@@ -77177,7 +77285,7 @@ import {
77177
77285
  realpathSync as realpathSync6,
77178
77286
  statSync as statSync27
77179
77287
  } from "node:fs";
77180
- import { join as join66 } from "node:path";
77288
+ import { join as join67 } from "node:path";
77181
77289
  function resolveOperatorUid() {
77182
77290
  const sudoUid = process.env.SUDO_UID;
77183
77291
  if (sudoUid !== undefined) {
@@ -77193,14 +77301,14 @@ function resolveOperatorUid() {
77193
77301
  return;
77194
77302
  }
77195
77303
  function operatorOwnedPaths(home2) {
77196
- const root = join66(home2, ".switchroom");
77304
+ const root = join67(home2, ".switchroom");
77197
77305
  return [
77198
- join66(root, "vault"),
77199
- join66(root, "vault-auto-unlock"),
77200
- join66(root, "vault-audit.log"),
77201
- join66(root, "host-control-audit.log"),
77202
- join66(root, "accounts"),
77203
- join66(root, "compose")
77306
+ join67(root, "vault"),
77307
+ join67(root, "vault-auto-unlock"),
77308
+ join67(root, "vault-audit.log"),
77309
+ join67(root, "host-control-audit.log"),
77310
+ join67(root, "accounts"),
77311
+ join67(root, "compose")
77204
77312
  ];
77205
77313
  }
77206
77314
  function restoreOperatorOwnership(home2, operatorUid, deps = {}) {
@@ -77249,7 +77357,7 @@ function restoreOperatorOwnership(home2, operatorUid, deps = {}) {
77249
77357
  } catch {}
77250
77358
  if (isDir(target)) {
77251
77359
  for (const entry of readdir2(target)) {
77252
- visit(join66(target, entry));
77360
+ visit(join67(target, entry));
77253
77361
  }
77254
77362
  }
77255
77363
  };
@@ -77263,14 +77371,14 @@ var EMBEDDED_EXAMPLES = {
77263
77371
  switchroom: switchroom_default,
77264
77372
  minimal: minimal_default
77265
77373
  };
77266
- var DEFAULT_COMPOSE_PATH2 = join67(homedir38(), ".switchroom", "compose", "docker-compose.yml");
77374
+ var DEFAULT_COMPOSE_PATH2 = join68(homedir38(), ".switchroom", "compose", "docker-compose.yml");
77267
77375
  var COMPOSE_PROJECT2 = "switchroom";
77268
77376
  function resolveVaultBindMountDir(homeDir, ctx) {
77269
77377
  const isCustomPath = ctx.migrationKind === "custom-path-skipped";
77270
77378
  if (isCustomPath && ctx.customVaultPath) {
77271
77379
  return dirname21(ctx.customVaultPath);
77272
77380
  }
77273
- return join67(homeDir, ".switchroom", "vault");
77381
+ return join68(homeDir, ".switchroom", "vault");
77274
77382
  }
77275
77383
  function inspectVaultBindMountDir(vaultDir) {
77276
77384
  if (!existsSync69(vaultDir))
@@ -77301,42 +77409,42 @@ function hasVaultRefs(value) {
77301
77409
  async function ensureHostMountSources(config) {
77302
77410
  const home2 = homedir38();
77303
77411
  const dirs = [
77304
- join67(home2, ".switchroom", "approvals"),
77305
- join67(home2, ".switchroom", "scheduler"),
77306
- join67(home2, ".switchroom", "logs"),
77307
- join67(home2, ".switchroom", "compose"),
77308
- join67(home2, ".switchroom", "broker-operator")
77412
+ join68(home2, ".switchroom", "approvals"),
77413
+ join68(home2, ".switchroom", "scheduler"),
77414
+ join68(home2, ".switchroom", "logs"),
77415
+ join68(home2, ".switchroom", "compose"),
77416
+ join68(home2, ".switchroom", "broker-operator")
77309
77417
  ];
77310
77418
  for (const name of Object.keys(config.agents)) {
77311
- dirs.push(join67(home2, ".switchroom", "agents", name));
77312
- dirs.push(join67(home2, ".switchroom", "logs", name));
77313
- dirs.push(join67(home2, ".claude", "projects", name));
77314
- dirs.push(join67(home2, ".switchroom", "audit", name));
77315
- if (existsSync69(join67(home2, ".switchroom-config"))) {
77316
- dirs.push(join67(home2, ".switchroom-config", "agents", name, "personal-skills"));
77419
+ dirs.push(join68(home2, ".switchroom", "agents", name));
77420
+ dirs.push(join68(home2, ".switchroom", "logs", name));
77421
+ dirs.push(join68(home2, ".claude", "projects", name));
77422
+ dirs.push(join68(home2, ".switchroom", "audit", name));
77423
+ if (existsSync69(join68(home2, ".switchroom-config"))) {
77424
+ dirs.push(join68(home2, ".switchroom-config", "agents", name, "personal-skills"));
77317
77425
  }
77318
77426
  }
77319
77427
  for (const dir of dirs) {
77320
77428
  await mkdir(dir, { recursive: true });
77321
77429
  }
77322
- const autoUnlockPath = join67(home2, ".switchroom", "vault-auto-unlock");
77430
+ const autoUnlockPath = join68(home2, ".switchroom", "vault-auto-unlock");
77323
77431
  if (!existsSync69(autoUnlockPath)) {
77324
77432
  writeFileSync35(autoUnlockPath, "", { mode: 384 });
77325
77433
  }
77326
- const auditLogPath = join67(home2, ".switchroom", "vault-audit.log");
77434
+ const auditLogPath = join68(home2, ".switchroom", "vault-audit.log");
77327
77435
  if (!existsSync69(auditLogPath)) {
77328
77436
  writeFileSync35(auditLogPath, "", { mode: 420 });
77329
77437
  }
77330
- const grantsDbPath = join67(home2, ".switchroom", "vault-grants.db");
77438
+ const grantsDbPath = join68(home2, ".switchroom", "vault-grants.db");
77331
77439
  if (!existsSync69(grantsDbPath)) {
77332
77440
  writeFileSync35(grantsDbPath, "", { mode: 384 });
77333
77441
  }
77334
- const hostdAuditLogPath = join67(home2, ".switchroom", "host-control-audit.log");
77442
+ const hostdAuditLogPath = join68(home2, ".switchroom", "host-control-audit.log");
77335
77443
  if (!existsSync69(hostdAuditLogPath)) {
77336
77444
  writeFileSync35(hostdAuditLogPath, "", { mode: 420 });
77337
77445
  }
77338
77446
  for (const name of Object.keys(config.agents)) {
77339
- const tokenPath = join67(home2, ".switchroom", "agents", name, ".vault-token");
77447
+ const tokenPath = join68(home2, ".switchroom", "agents", name, ".vault-token");
77340
77448
  if (!existsSync69(tokenPath)) {
77341
77449
  writeFileSync35(tokenPath, "", { mode: 384 });
77342
77450
  }
@@ -77345,15 +77453,15 @@ async function ensureHostMountSources(config) {
77345
77453
  chownSync4(tokenPath, uid, uid);
77346
77454
  } catch {}
77347
77455
  }
77348
- const fleetDir = join67(home2, ".switchroom", "fleet");
77456
+ const fleetDir = join68(home2, ".switchroom", "fleet");
77349
77457
  await mkdir(fleetDir, { recursive: true });
77350
- const invariantsPath = join67(fleetDir, "switchroom-invariants.md");
77458
+ const invariantsPath = join68(fleetDir, "switchroom-invariants.md");
77351
77459
  const invariantsCanonical = renderFleetInvariants();
77352
77460
  const invariantsCurrent = existsSync69(invariantsPath) ? readFileSync56(invariantsPath, "utf-8") : null;
77353
77461
  if (invariantsCurrent !== invariantsCanonical) {
77354
77462
  writeFileSync35(invariantsPath, invariantsCanonical, { mode: 420 });
77355
77463
  }
77356
- const fleetClaudePath = join67(fleetDir, "CLAUDE.md");
77464
+ const fleetClaudePath = join68(fleetDir, "CLAUDE.md");
77357
77465
  if (!existsSync69(fleetClaudePath)) {
77358
77466
  writeFileSync35(fleetClaudePath, [
77359
77467
  "# Switchroom fleet defaults",
@@ -77438,8 +77546,8 @@ function detectAndReportLegacyGdriveSlots(vaultPath) {
77438
77546
  }
77439
77547
  function writeInstallTypeCache(homeDir = homedir38()) {
77440
77548
  const ctx = detectInstallType();
77441
- const dir = join67(homeDir, ".switchroom");
77442
- const out = join67(dir, "install-type.json");
77549
+ const dir = join68(homeDir, ".switchroom");
77550
+ const out = join68(dir, "install-type.json");
77443
77551
  const tmp = `${out}.tmp`;
77444
77552
  mkdirSync38(dir, { recursive: true });
77445
77553
  const payload = {
@@ -77488,14 +77596,14 @@ Applying switchroom config...
77488
77596
  writeOut(source_default.green(` + ${name}`) + source_default.gray(` (${agentConfig.extends ?? "default"}) \u2014 ${detail}
77489
77597
  `));
77490
77598
  try {
77491
- installUpdatePromptHook(join67(agentsDir, name));
77599
+ installUpdatePromptHook(join68(agentsDir, name));
77492
77600
  } catch (hookErr) {
77493
77601
  writeOut(source_default.gray(` (update-prompt hook install failed for ${name}: ${hookErr.message})
77494
77602
  `));
77495
77603
  }
77496
77604
  try {
77497
77605
  const uid = allocateAgentUid(name);
77498
- alignAgentUid(name, join67(agentsDir, name), uid, {
77606
+ alignAgentUid(name, join68(agentsDir, name), uid, {
77499
77607
  confirm: !options.nonInteractive,
77500
77608
  writeOut
77501
77609
  });
@@ -77532,7 +77640,7 @@ Applying switchroom config...
77532
77640
  for (const name of agentNames) {
77533
77641
  try {
77534
77642
  const uid = allocateAgentUid(name);
77535
- alignAgentUid(name, join67(agentsDir, name), uid, {
77643
+ alignAgentUid(name, join68(agentsDir, name), uid, {
77536
77644
  confirm: !options.nonInteractive,
77537
77645
  writeOut
77538
77646
  });
@@ -77684,7 +77792,7 @@ function copyExampleConfig2(name) {
77684
77792
  if (!/^[a-z0-9_-]+$/.test(name)) {
77685
77793
  throw new Error(`Invalid example name: ${name} (must match /^[a-z0-9_-]+$/)`);
77686
77794
  }
77687
- const dest = resolve42(process.cwd(), "switchroom.yaml");
77795
+ const dest = resolve43(process.cwd(), "switchroom.yaml");
77688
77796
  if (existsSync69(dest)) {
77689
77797
  console.error(source_default.yellow("switchroom.yaml already exists \u2014 skipping example copy"));
77690
77798
  return;
@@ -77695,7 +77803,7 @@ function copyExampleConfig2(name) {
77695
77803
  console.log(source_default.green(`Copied ${name}.yaml -> switchroom.yaml`));
77696
77804
  return;
77697
77805
  }
77698
- const exampleFile = resolve42(import.meta.dirname, `../../examples/${name}.yaml`);
77806
+ const exampleFile = resolve43(import.meta.dirname, `../../examples/${name}.yaml`);
77699
77807
  if (!existsSync69(exampleFile)) {
77700
77808
  throw new Error(`Example config not found: ${name}.yaml (available: ${Object.keys(EMBEDDED_EXAMPLES).join(", ")})`);
77701
77809
  }
@@ -77707,7 +77815,7 @@ function findUnwritableAgentDirs(config, opts) {
77707
77815
  const targets = opts.only ? [opts.only] : Object.keys(config.agents ?? {});
77708
77816
  const unwritable = [];
77709
77817
  for (const name of targets) {
77710
- const startSh = join67(agentsDir, name, "start.sh");
77818
+ const startSh = join68(agentsDir, name, "start.sh");
77711
77819
  if (!existsSync69(startSh))
77712
77820
  continue;
77713
77821
  try {
@@ -77887,7 +77995,7 @@ function runRedactStdin() {
77887
77995
 
77888
77996
  // src/cli/status-ask.ts
77889
77997
  import { readFileSync as readFileSync57, existsSync as existsSync70, readdirSync as readdirSync26 } from "node:fs";
77890
- import { join as join68 } from "node:path";
77998
+ import { join as join69 } from "node:path";
77891
77999
  import { homedir as homedir39 } from "node:os";
77892
78000
 
77893
78001
  // src/status-ask/report.ts
@@ -78223,7 +78331,7 @@ function resolveSources(explicitPath) {
78223
78331
  const config = loadConfig();
78224
78332
  agentsDir = resolveAgentsDir(config);
78225
78333
  } catch {
78226
- agentsDir = join68(homedir39(), ".switchroom", "agents");
78334
+ agentsDir = join69(homedir39(), ".switchroom", "agents");
78227
78335
  }
78228
78336
  if (!existsSync70(agentsDir))
78229
78337
  return [];
@@ -78235,7 +78343,7 @@ function resolveSources(explicitPath) {
78235
78343
  return [];
78236
78344
  }
78237
78345
  for (const name of entries) {
78238
- const path8 = join68(agentsDir, name, "runtime-metrics.jsonl");
78346
+ const path8 = join69(agentsDir, name, "runtime-metrics.jsonl");
78239
78347
  if (existsSync70(path8)) {
78240
78348
  sources.push({ path: path8, agent: name });
78241
78349
  }
@@ -78257,7 +78365,7 @@ function inferAgentFromPath(p) {
78257
78365
 
78258
78366
  // src/cli/agent-config.ts
78259
78367
  init_helpers();
78260
- import { join as join69 } from "node:path";
78368
+ import { join as join70 } from "node:path";
78261
78369
  import { homedir as homedir40 } from "node:os";
78262
78370
  import {
78263
78371
  existsSync as existsSync71,
@@ -78265,9 +78373,9 @@ import {
78265
78373
  appendFileSync as appendFileSync4,
78266
78374
  readFileSync as readFileSync58
78267
78375
  } from "node:fs";
78268
- var AUDIT_ROOT = join69(homedir40(), ".switchroom", "audit");
78376
+ var AUDIT_ROOT = join70(homedir40(), ".switchroom", "audit");
78269
78377
  function auditPathFor(agent) {
78270
- return join69(AUDIT_ROOT, agent, "agent-config.jsonl");
78378
+ return join70(AUDIT_ROOT, agent, "agent-config.jsonl");
78271
78379
  }
78272
78380
  function appendAudit(agent, cmd, args, exit, opts = {}) {
78273
78381
  const row = {
@@ -78525,21 +78633,21 @@ import {
78525
78633
  unlinkSync as unlinkSync14,
78526
78634
  writeSync as writeSync8
78527
78635
  } from "node:fs";
78528
- import { join as join70, resolve as resolve43 } from "node:path";
78636
+ import { join as join71, resolve as resolve44 } from "node:path";
78529
78637
  var STAGING_SUBDIR = ".staging";
78530
78638
  function overlayPathsFor(agent, opts = {}) {
78531
- const base = opts.root ? resolve43(opts.root, agent) : resolve43(resolveDualPath(`~/.switchroom/agents/${agent}`));
78532
- const scheduleDir = join70(base, "schedule.d");
78533
- const scheduleStagingDir = join70(scheduleDir, STAGING_SUBDIR);
78534
- const skillsDir = join70(base, "skills.d");
78535
- const skillsStagingDir = join70(skillsDir, STAGING_SUBDIR);
78639
+ const base = opts.root ? resolve44(opts.root, agent) : resolve44(resolveDualPath(`~/.switchroom/agents/${agent}`));
78640
+ const scheduleDir = join71(base, "schedule.d");
78641
+ const scheduleStagingDir = join71(scheduleDir, STAGING_SUBDIR);
78642
+ const skillsDir = join71(base, "skills.d");
78643
+ const skillsStagingDir = join71(skillsDir, STAGING_SUBDIR);
78536
78644
  return {
78537
78645
  agentRoot: base,
78538
78646
  scheduleDir,
78539
78647
  scheduleStagingDir,
78540
78648
  skillsDir,
78541
78649
  skillsStagingDir,
78542
- lockPath: join70(base, ".lock"),
78650
+ lockPath: join71(base, ".lock"),
78543
78651
  stagingDir: scheduleStagingDir
78544
78652
  };
78545
78653
  }
@@ -78593,8 +78701,8 @@ function writeOverlayEntry(agent, slug, yamlText, opts = {}) {
78593
78701
  const paths = overlayPathsFor(agent, opts);
78594
78702
  return withAgentLock(paths, () => {
78595
78703
  ensureDirs(paths);
78596
- const stagingPath = join70(paths.scheduleStagingDir, `${slug}.yaml`);
78597
- const finalPath = join70(paths.scheduleDir, `${slug}.yaml`);
78704
+ const stagingPath = join71(paths.scheduleStagingDir, `${slug}.yaml`);
78705
+ const finalPath = join71(paths.scheduleDir, `${slug}.yaml`);
78598
78706
  const fd = openSync13(stagingPath, "w", 384);
78599
78707
  try {
78600
78708
  writeSync8(fd, yamlText);
@@ -78610,8 +78718,8 @@ function writeSkillsOverlayEntry(agent, slug, yamlText, opts = {}) {
78610
78718
  const paths = overlayPathsFor(agent, opts);
78611
78719
  return withAgentLock(paths, () => {
78612
78720
  ensureSkillsDirs(paths);
78613
- const stagingPath = join70(paths.skillsStagingDir, `${slug}.yaml`);
78614
- const finalPath = join70(paths.skillsDir, `${slug}.yaml`);
78721
+ const stagingPath = join71(paths.skillsStagingDir, `${slug}.yaml`);
78722
+ const finalPath = join71(paths.skillsDir, `${slug}.yaml`);
78615
78723
  const fd = openSync13(stagingPath, "w", 384);
78616
78724
  try {
78617
78725
  writeSync8(fd, yamlText);
@@ -78626,7 +78734,7 @@ function writeSkillsOverlayEntry(agent, slug, yamlText, opts = {}) {
78626
78734
  function deleteSkillsOverlayEntry(agent, slug, opts = {}) {
78627
78735
  const paths = overlayPathsFor(agent, opts);
78628
78736
  return withAgentLock(paths, () => {
78629
- const finalPath = join70(paths.skillsDir, `${slug}.yaml`);
78737
+ const finalPath = join71(paths.skillsDir, `${slug}.yaml`);
78630
78738
  if (!existsSync72(finalPath))
78631
78739
  return false;
78632
78740
  unlinkSync14(finalPath);
@@ -78641,7 +78749,7 @@ function listSkillsOverlayEntries(agent, opts = {}) {
78641
78749
  for (const name of readdirSync27(paths.skillsDir)) {
78642
78750
  if (!/\.ya?ml$/i.test(name))
78643
78751
  continue;
78644
- const full = join70(paths.skillsDir, name);
78752
+ const full = join71(paths.skillsDir, name);
78645
78753
  try {
78646
78754
  const raw = readFileSync59(full, "utf-8");
78647
78755
  const slug = name.replace(/\.ya?ml$/i, "");
@@ -78653,7 +78761,7 @@ function listSkillsOverlayEntries(agent, opts = {}) {
78653
78761
  function deleteOverlayEntry(agent, slug, opts = {}) {
78654
78762
  const paths = overlayPathsFor(agent, opts);
78655
78763
  return withAgentLock(paths, () => {
78656
- const finalPath = join70(paths.scheduleDir, `${slug}.yaml`);
78764
+ const finalPath = join71(paths.scheduleDir, `${slug}.yaml`);
78657
78765
  if (!existsSync72(finalPath))
78658
78766
  return false;
78659
78767
  unlinkSync14(finalPath);
@@ -78668,7 +78776,7 @@ function listOverlayEntries(agent, opts = {}) {
78668
78776
  for (const name of readdirSync27(paths.scheduleDir)) {
78669
78777
  if (!/\.ya?ml$/i.test(name))
78670
78778
  continue;
78671
- const full = join70(paths.scheduleDir, name);
78779
+ const full = join71(paths.scheduleDir, name);
78672
78780
  try {
78673
78781
  const raw = readFileSync59(full, "utf-8");
78674
78782
  const slug = name.replace(/\.ya?ml$/i, "");
@@ -78824,12 +78932,12 @@ import {
78824
78932
  writeFileSync as writeFileSync36,
78825
78933
  writeSync as writeSync9
78826
78934
  } from "node:fs";
78827
- import { join as join71 } from "node:path";
78935
+ import { join as join72 } from "node:path";
78828
78936
  import { randomBytes as randomBytes14 } from "node:crypto";
78829
78937
  var STAGE_ID_PREFIX = "cap_";
78830
78938
  function pendingDir(agent, opts = {}) {
78831
78939
  const paths = overlayPathsFor(agent, opts);
78832
- return join71(paths.scheduleDir, ".pending");
78940
+ return join72(paths.scheduleDir, ".pending");
78833
78941
  }
78834
78942
  function ensurePendingDir(agent, opts = {}) {
78835
78943
  const dir = pendingDir(agent, opts);
@@ -78842,8 +78950,8 @@ function newStageId() {
78842
78950
  function stagePendingScheduleEntry(opts) {
78843
78951
  const dir = ensurePendingDir(opts.agent, { root: opts.root });
78844
78952
  const stageId = opts.stageId ?? newStageId();
78845
- const yamlPath = join71(dir, `${stageId}.yaml`);
78846
- const metaPath = join71(dir, `${stageId}.meta.json`);
78953
+ const yamlPath = join72(dir, `${stageId}.yaml`);
78954
+ const metaPath = join72(dir, `${stageId}.meta.json`);
78847
78955
  const meta = {
78848
78956
  v: 1,
78849
78957
  stage_id: stageId,
@@ -78877,8 +78985,8 @@ function listPendingScheduleEntries(agent, opts = {}) {
78877
78985
  if (!name.endsWith(".meta.json"))
78878
78986
  continue;
78879
78987
  const stageId = name.slice(0, -".meta.json".length);
78880
- const metaPath = join71(dir, name);
78881
- const yamlPath = join71(dir, `${stageId}.yaml`);
78988
+ const metaPath = join72(dir, name);
78989
+ const yamlPath = join72(dir, `${stageId}.yaml`);
78882
78990
  if (!existsSync73(yamlPath))
78883
78991
  continue;
78884
78992
  try {
@@ -78897,7 +79005,7 @@ function commitPendingScheduleEntry(opts) {
78897
79005
  return { committed: false, reason: "not_found" };
78898
79006
  const slug = match.meta.entry.name ?? match.stageId;
78899
79007
  const paths = overlayPathsFor(opts.agent, { root: opts.root });
78900
- const finalPath = join71(paths.scheduleDir, `${slug}.yaml`);
79008
+ const finalPath = join72(paths.scheduleDir, `${slug}.yaml`);
78901
79009
  if (existsSync73(finalPath)) {
78902
79010
  return { committed: false, reason: "slug_collision" };
78903
79011
  }
@@ -79403,7 +79511,7 @@ var import_yaml16 = __toESM(require_dist(), 1);
79403
79511
  import { existsSync as existsSync75 } from "node:fs";
79404
79512
  init_reconcile_default_skills();
79405
79513
  var import_yaml17 = __toESM(require_dist(), 1);
79406
- import { join as join72 } from "node:path";
79514
+ import { join as join73 } from "node:path";
79407
79515
  var MAX_SKILLS_PER_AGENT = 20;
79408
79516
  var V1_ALLOWED_SOURCE_PREFIX = "bundled:";
79409
79517
  function exitCodeFor2(code) {
@@ -79478,7 +79586,7 @@ function skillInstall(opts) {
79478
79586
  return err("E_SKILL_QUOTA_EXCEEDED", `agent ${agent} already has ${used} overlay-installed skills (cap ${MAX_SKILLS_PER_AGENT})`);
79479
79587
  }
79480
79588
  const poolDir = opts.bundledSkillsPoolDir ?? getBundledSkillsPoolDir();
79481
- const skillPath = join72(poolDir, skillName);
79589
+ const skillPath = join73(poolDir, skillName);
79482
79590
  if (!existsSync75(skillPath)) {
79483
79591
  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.`);
79484
79592
  }
@@ -79657,7 +79765,7 @@ import {
79657
79765
  writeFileSync as writeFileSync37
79658
79766
  } from "node:fs";
79659
79767
  import { tmpdir as tmpdir4, homedir as homedir41 } from "node:os";
79660
- import { dirname as dirname22, join as join73, relative as relative2, resolve as resolve44 } from "node:path";
79768
+ import { dirname as dirname22, join as join74, relative as relative2, resolve as resolve45 } from "node:path";
79661
79769
  import { spawnSync as spawnSync10 } from "node:child_process";
79662
79770
 
79663
79771
  // src/cli/skill-common.ts
@@ -79851,11 +79959,11 @@ function scanForClaudeP2(content) {
79851
79959
  function resolveSkillsPoolDir2(override) {
79852
79960
  const raw = override ?? "~/.switchroom/skills";
79853
79961
  if (raw.startsWith("~/")) {
79854
- return join73(homedir41(), raw.slice(2));
79962
+ return join74(homedir41(), raw.slice(2));
79855
79963
  }
79856
79964
  if (raw === "~")
79857
79965
  return homedir41();
79858
- return resolve44(raw);
79966
+ return resolve45(raw);
79859
79967
  }
79860
79968
  function readStdinSync() {
79861
79969
  const chunks = [];
@@ -79890,7 +79998,7 @@ function loadFromDir(dir) {
79890
79998
  const walk2 = (sub) => {
79891
79999
  const entries = readdirSync29(sub, { withFileTypes: true });
79892
80000
  for (const ent of entries) {
79893
- const full = join73(sub, ent.name);
80001
+ const full = join74(sub, ent.name);
79894
80002
  const rel = relative2(abs, full);
79895
80003
  if (ent.isSymbolicLink()) {
79896
80004
  fail2(`refusing to read symlink inside --from dir: ${rel}`);
@@ -79925,7 +80033,7 @@ function loadFromTarball(tarPath) {
79925
80033
  fail2(`tarball contains disallowed path: ${JSON.stringify(entry)} \u2014 ` + `refusing to extract before any file is written`);
79926
80034
  }
79927
80035
  }
79928
- const staging = mkdtempSync5(join73(tmpdir4(), "skill-apply-extract-"));
80036
+ const staging = mkdtempSync5(join74(tmpdir4(), "skill-apply-extract-"));
79929
80037
  try {
79930
80038
  const flags = isGz ? ["-xzf"] : ["-xf"];
79931
80039
  const r = spawnSync10("tar", [
@@ -80011,8 +80119,8 @@ function validatePayload(name, files) {
80011
80119
  errors2.push(`${path8} fails \`bash -n\` syntax check: ${(r.stderr ?? "").trim()}`);
80012
80120
  }
80013
80121
  } else if (PY_SCRIPT_RE2.test(path8)) {
80014
- const tmp = mkdtempSync5(join73(tmpdir4(), "skill-apply-py-"));
80015
- const tmpPy = join73(tmp, "check.py");
80122
+ const tmp = mkdtempSync5(join74(tmpdir4(), "skill-apply-py-"));
80123
+ const tmpPy = join74(tmp, "check.py");
80016
80124
  try {
80017
80125
  writeFileSync37(tmpPy, content);
80018
80126
  const r = spawnSync10("python3", ["-m", "py_compile", tmpPy], {
@@ -80035,7 +80143,7 @@ function diffSummary(currentDir, files) {
80035
80143
  if (existsSync76(currentDir)) {
80036
80144
  const walk2 = (sub) => {
80037
80145
  for (const ent of readdirSync29(sub, { withFileTypes: true })) {
80038
- const full = join73(sub, ent.name);
80146
+ const full = join74(sub, ent.name);
80039
80147
  const rel = relative2(currentDir, full);
80040
80148
  if (ent.isDirectory()) {
80041
80149
  walk2(full);
@@ -80071,7 +80179,7 @@ function writePayload(poolDir, name, files) {
80071
80179
  if (!existsSync76(poolDir)) {
80072
80180
  mkdirSync42(poolDir, { recursive: true, mode: 493 });
80073
80181
  }
80074
- const target = join73(poolDir, name);
80182
+ const target = join74(poolDir, name);
80075
80183
  let targetIsSymlink = false;
80076
80184
  try {
80077
80185
  const st = lstatSync8(target);
@@ -80082,11 +80190,11 @@ function writePayload(poolDir, name, files) {
80082
80190
  if (targetIsSymlink) {
80083
80191
  fail2(`refusing to overwrite symlink at ${target}; investigate manually`);
80084
80192
  }
80085
- const staging = mkdtempSync5(join73(poolDir, `.skill-apply-stage-${name}-`));
80193
+ const staging = mkdtempSync5(join74(poolDir, `.skill-apply-stage-${name}-`));
80086
80194
  let oldRename = null;
80087
80195
  try {
80088
80196
  for (const [path8, content] of Object.entries(files)) {
80089
- const full = join73(staging, path8);
80197
+ const full = join74(staging, path8);
80090
80198
  mkdirSync42(dirname22(full), { recursive: true, mode: 493 });
80091
80199
  const fd = openSync15(full, "wx");
80092
80200
  try {
@@ -80139,7 +80247,7 @@ function registerSkillCommand(program3) {
80139
80247
  if (opts.from === undefined) {
80140
80248
  files = loadFromStdin();
80141
80249
  } else {
80142
- const fromPath = resolve44(opts.from);
80250
+ const fromPath = resolve45(opts.from);
80143
80251
  if (!existsSync76(fromPath)) {
80144
80252
  fail2(`--from path does not exist: ${opts.from}`);
80145
80253
  }
@@ -80164,7 +80272,7 @@ function registerSkillCommand(program3) {
80164
80272
  }
80165
80273
  const config = loadConfig();
80166
80274
  const poolDir = resolveSkillsPoolDir2(config.switchroom?.skills_dir);
80167
- const currentDir = join73(poolDir, name);
80275
+ const currentDir = join74(poolDir, name);
80168
80276
  console.log(source_default.bold(`Skill: ${name}`) + source_default.gray(` (${Object.keys(files).length} files, ${sumBytes(files)} bytes)`));
80169
80277
  console.log(source_default.bold("Diff vs current pool content:"));
80170
80278
  console.log(diffSummary(currentDir, files));
@@ -80208,7 +80316,7 @@ import {
80208
80316
  utimesSync,
80209
80317
  writeFileSync as writeFileSync38
80210
80318
  } from "node:fs";
80211
- import { dirname as dirname23, join as join74, relative as relative3, resolve as resolve45 } from "node:path";
80319
+ import { dirname as dirname23, join as join75, relative as relative3, resolve as resolve46 } from "node:path";
80212
80320
  import { homedir as homedir42, tmpdir as tmpdir5 } from "node:os";
80213
80321
  import { spawnSync as spawnSync11 } from "node:child_process";
80214
80322
  init_helpers();
@@ -80219,10 +80327,10 @@ var TRASH_TTL_MS = 24 * 60 * 60 * 1000;
80219
80327
  var PERSONAL_SKILLS_SUBPATH = "personal-skills";
80220
80328
  function resolveConfigSkillsDir(agent) {
80221
80329
  const override = process.env.SWITCHROOM_CONFIG_DIR;
80222
- const candidate = override ? resolve45(override) : join74(homedir42(), ".switchroom-config");
80330
+ const candidate = override ? resolve46(override) : join75(homedir42(), ".switchroom-config");
80223
80331
  if (!existsSync77(candidate))
80224
80332
  return null;
80225
- return join74(candidate, "agents", agent, PERSONAL_SKILLS_SUBPATH);
80333
+ return join75(candidate, "agents", agent, PERSONAL_SKILLS_SUBPATH);
80226
80334
  }
80227
80335
  var MIRROR_PRIOR_TTL_MS = 24 * 60 * 60 * 1000;
80228
80336
  function sweepMirrorPriors(configSkillsRoot) {
@@ -80240,7 +80348,7 @@ function sweepMirrorPriors(configSkillsRoot) {
80240
80348
  if (now - ts < MIRROR_PRIOR_TTL_MS)
80241
80349
  continue;
80242
80350
  try {
80243
- rmSync17(join74(configSkillsRoot, ent), { recursive: true, force: true });
80351
+ rmSync17(join75(configSkillsRoot, ent), { recursive: true, force: true });
80244
80352
  } catch {}
80245
80353
  }
80246
80354
  } catch {}
@@ -80249,7 +80357,7 @@ function mirrorToConfigRepo(agent, name, liveSkillDir) {
80249
80357
  const configSkillsRoot = resolveConfigSkillsDir(agent);
80250
80358
  if (!configSkillsRoot)
80251
80359
  return;
80252
- const dest = join74(configSkillsRoot, name);
80360
+ const dest = join75(configSkillsRoot, name);
80253
80361
  try {
80254
80362
  if (liveSkillDir !== null) {
80255
80363
  try {
@@ -80264,19 +80372,19 @@ function mirrorToConfigRepo(agent, name, liveSkillDir) {
80264
80372
  if (liveSkillDir === null) {
80265
80373
  sweepMirrorPriors(configSkillsRoot);
80266
80374
  if (existsSync77(dest)) {
80267
- const trash = join74(configSkillsRoot, `.${name}-trash-${Date.now()}`);
80375
+ const trash = join75(configSkillsRoot, `.${name}-trash-${Date.now()}`);
80268
80376
  renameSync17(dest, trash);
80269
80377
  }
80270
80378
  return;
80271
80379
  }
80272
80380
  mkdirSync43(configSkillsRoot, { recursive: true, mode: 493 });
80273
80381
  sweepMirrorPriors(configSkillsRoot);
80274
- const staging = mkdtempSync6(join74(configSkillsRoot, `.${name}-staging-`));
80382
+ const staging = mkdtempSync6(join75(configSkillsRoot, `.${name}-staging-`));
80275
80383
  const walk2 = (src, dst) => {
80276
80384
  mkdirSync43(dst, { recursive: true, mode: 493 });
80277
80385
  for (const ent of readdirSync30(src, { withFileTypes: true })) {
80278
- const s = join74(src, ent.name);
80279
- const d = join74(dst, ent.name);
80386
+ const s = join75(src, ent.name);
80387
+ const d = join75(dst, ent.name);
80280
80388
  if (ent.isSymbolicLink())
80281
80389
  continue;
80282
80390
  if (ent.isDirectory())
@@ -80288,7 +80396,7 @@ function mirrorToConfigRepo(agent, name, liveSkillDir) {
80288
80396
  };
80289
80397
  walk2(liveSkillDir, staging);
80290
80398
  if (existsSync77(dest)) {
80291
- const prior = join74(configSkillsRoot, `.${name}-prior-${Date.now()}`);
80399
+ const prior = join75(configSkillsRoot, `.${name}-prior-${Date.now()}`);
80292
80400
  renameSync17(dest, prior);
80293
80401
  }
80294
80402
  renameSync17(staging, dest);
@@ -80314,14 +80422,14 @@ function resolveAgent(opts) {
80314
80422
  }
80315
80423
  function resolveAgentsRoot(opts) {
80316
80424
  if (opts.root)
80317
- return resolve45(opts.root);
80318
- return join74(homedir42(), ".switchroom", "agents");
80425
+ return resolve46(opts.root);
80426
+ return join75(homedir42(), ".switchroom", "agents");
80319
80427
  }
80320
80428
  function personalSkillDir(agentsRoot, agent, name) {
80321
- return join74(agentsRoot, agent, ".claude", "skills", PERSONAL_PREFIX + name);
80429
+ return join75(agentsRoot, agent, ".claude", "skills", PERSONAL_PREFIX + name);
80322
80430
  }
80323
80431
  function trashDir(agentsRoot, agent) {
80324
- return join74(agentsRoot, agent, ".claude", TRASH_DIRNAME);
80432
+ return join75(agentsRoot, agent, ".claude", TRASH_DIRNAME);
80325
80433
  }
80326
80434
  function readStdinSync2() {
80327
80435
  const chunks = [];
@@ -80344,14 +80452,14 @@ function readStdinSync2() {
80344
80452
  return Buffer.concat(chunks).toString("utf-8");
80345
80453
  }
80346
80454
  function loadFromDir2(dir) {
80347
- const abs = resolve45(dir);
80455
+ const abs = resolve46(dir);
80348
80456
  if (!statSync30(abs).isDirectory()) {
80349
80457
  fail3(`--from path is not a directory: ${dir}`);
80350
80458
  }
80351
80459
  const files = {};
80352
80460
  const walk2 = (sub) => {
80353
80461
  for (const ent of readdirSync30(sub, { withFileTypes: true })) {
80354
- const full = join74(sub, ent.name);
80462
+ const full = join75(sub, ent.name);
80355
80463
  if (ent.isSymbolicLink()) {
80356
80464
  fail3(`refusing to read symlink in --from dir: ${relative3(abs, full)}`);
80357
80465
  }
@@ -80404,8 +80512,8 @@ function behavioralValidate(files) {
80404
80512
  errors2.push(`${path8} fails \`bash -n\`: ${(r.stderr ?? "").trim()}`);
80405
80513
  }
80406
80514
  } else if (PY_SCRIPT_RE.test(path8)) {
80407
- const tmp = mkdtempSync6(join74(tmpdir5(), "skill-personal-py-"));
80408
- const tmpPy = join74(tmp, "check.py");
80515
+ const tmp = mkdtempSync6(join75(tmpdir5(), "skill-personal-py-"));
80516
+ const tmpPy = join75(tmp, "check.py");
80409
80517
  try {
80410
80518
  writeFileSync38(tmpPy, content);
80411
80519
  const r = spawnSync11("python3", ["-m", "py_compile", tmpPy], {
@@ -80429,7 +80537,7 @@ function sweepTrash(agentsRoot, agent) {
80429
80537
  for (const ent of readdirSync30(trash, { withFileTypes: true })) {
80430
80538
  if (!ent.isDirectory())
80431
80539
  continue;
80432
- const entPath = join74(trash, ent.name);
80540
+ const entPath = join75(trash, ent.name);
80433
80541
  try {
80434
80542
  const st = statSync30(entPath);
80435
80543
  if (now - st.mtimeMs > TRASH_TTL_MS) {
@@ -80450,11 +80558,11 @@ function writePersonalSkill(targetDir, files) {
80450
80558
  fail3(`refusing to overwrite symlink at ${targetDir}; investigate manually`);
80451
80559
  }
80452
80560
  mkdirSync43(dirname23(targetDir), { recursive: true, mode: 493 });
80453
- const staging = mkdtempSync6(join74(dirname23(targetDir), `.skill-personal-stage-`));
80561
+ const staging = mkdtempSync6(join75(dirname23(targetDir), `.skill-personal-stage-`));
80454
80562
  let oldRename = null;
80455
80563
  try {
80456
80564
  for (const [path8, content] of Object.entries(files)) {
80457
- const full = join74(staging, path8);
80565
+ const full = join75(staging, path8);
80458
80566
  mkdirSync43(dirname23(full), { recursive: true, mode: 493 });
80459
80567
  const fd = openSync16(full, "wx");
80460
80568
  try {
@@ -80538,7 +80646,7 @@ function loadFiles(opts) {
80538
80646
  if (opts.from === undefined) {
80539
80647
  return loadFromStdin2();
80540
80648
  }
80541
- const p = resolve45(opts.from);
80649
+ const p = resolve46(opts.from);
80542
80650
  if (!existsSync77(p)) {
80543
80651
  fail3(`--from path does not exist: ${opts.from}`);
80544
80652
  }
@@ -80587,10 +80695,10 @@ function editPersonalAction(name, opts) {
80587
80695
  }
80588
80696
  var CLONE_SOURCE_RE = /^(shared|bundled):([a-z0-9][a-z0-9_-]{0,62})$/;
80589
80697
  function defaultSharedRoot() {
80590
- return join74(homedir42(), ".switchroom", "skills");
80698
+ return join75(homedir42(), ".switchroom", "skills");
80591
80699
  }
80592
80700
  function defaultBundledRoot() {
80593
- return join74(homedir42(), ".switchroom", "skills", "_bundled");
80701
+ return join75(homedir42(), ".switchroom", "skills", "_bundled");
80594
80702
  }
80595
80703
  function resolveCloneSource(source, opts) {
80596
80704
  const m = CLONE_SOURCE_RE.exec(source);
@@ -80600,7 +80708,7 @@ function resolveCloneSource(source, opts) {
80600
80708
  const tier = m[1];
80601
80709
  const slug = m[2];
80602
80710
  const root = tier === "bundled" ? opts.bundledRoot ?? defaultBundledRoot() : opts.sharedRoot ?? defaultSharedRoot();
80603
- const dir = join74(root, slug);
80711
+ const dir = join75(root, slug);
80604
80712
  if (!existsSync77(dir)) {
80605
80713
  fail3(`clone source ${JSON.stringify(source)} not found at ${dir}; ` + `check \`switchroom skill search --tier ${tier}\``, 1);
80606
80714
  }
@@ -80616,7 +80724,7 @@ function readSourceFiles(dir) {
80616
80724
  const skipped = [];
80617
80725
  const walk2 = (sub) => {
80618
80726
  for (const ent of readdirSync30(sub, { withFileTypes: true })) {
80619
- const full = join74(sub, ent.name);
80727
+ const full = join75(sub, ent.name);
80620
80728
  if (ent.isSymbolicLink()) {
80621
80729
  continue;
80622
80730
  }
@@ -80727,7 +80835,7 @@ function removePersonalAction(name, opts) {
80727
80835
  const trashRoot = trashDir(agentsRoot, agent);
80728
80836
  mkdirSync43(trashRoot, { recursive: true, mode: 493 });
80729
80837
  const ts = Date.now();
80730
- const trashTarget = join74(trashRoot, `${name}-${ts}`);
80838
+ const trashTarget = join75(trashRoot, `${name}-${ts}`);
80731
80839
  renameSync17(target, trashTarget);
80732
80840
  const now = new Date(ts);
80733
80841
  utimesSync(trashTarget, now, now);
@@ -80746,7 +80854,7 @@ function listPersonalAction(opts) {
80746
80854
  const agent = resolveAgent(opts);
80747
80855
  const agentsRoot = resolveAgentsRoot(opts);
80748
80856
  sweepTrash(agentsRoot, agent);
80749
- const skillsDir = join74(agentsRoot, agent, ".claude", "skills");
80857
+ const skillsDir = join75(agentsRoot, agent, ".claude", "skills");
80750
80858
  const personal = [];
80751
80859
  if (existsSync77(skillsDir)) {
80752
80860
  for (const ent of readdirSync30(skillsDir, { withFileTypes: true })) {
@@ -80755,7 +80863,7 @@ function listPersonalAction(opts) {
80755
80863
  if (!ent.name.startsWith(PERSONAL_PREFIX))
80756
80864
  continue;
80757
80865
  const skillName = ent.name.slice(PERSONAL_PREFIX.length);
80758
- const skillPath = join74(skillsDir, ent.name);
80866
+ const skillPath = join75(skillsDir, ent.name);
80759
80867
  let fileCount = 0;
80760
80868
  let totalBytes = 0;
80761
80869
  const walk2 = (sub) => {
@@ -80763,10 +80871,10 @@ function listPersonalAction(opts) {
80763
80871
  if (e.isFile()) {
80764
80872
  fileCount += 1;
80765
80873
  try {
80766
- totalBytes += statSync30(join74(sub, e.name)).size;
80874
+ totalBytes += statSync30(join75(sub, e.name)).size;
80767
80875
  } catch {}
80768
80876
  } else if (e.isDirectory()) {
80769
- walk2(join74(sub, e.name));
80877
+ walk2(join75(sub, e.name));
80770
80878
  }
80771
80879
  }
80772
80880
  };
@@ -80807,21 +80915,21 @@ init_helpers();
80807
80915
  var import_yaml19 = __toESM(require_dist(), 1);
80808
80916
  import { existsSync as existsSync78, readdirSync as readdirSync31, readFileSync as readFileSync64, statSync as statSync31 } from "node:fs";
80809
80917
  import { homedir as homedir43 } from "node:os";
80810
- import { join as join75, resolve as resolve46 } from "node:path";
80918
+ import { join as join76, resolve as resolve47 } from "node:path";
80811
80919
  var PERSONAL_PREFIX2 = "personal-";
80812
80920
  var BUNDLED_SUBDIR = "_bundled";
80813
80921
  var AGENT_NAME_RE3 = /^[a-z][a-z0-9_-]{0,62}$/;
80814
80922
  function defaultAgentsRoot() {
80815
- return resolve46(homedir43(), ".switchroom/agents");
80923
+ return resolve47(homedir43(), ".switchroom/agents");
80816
80924
  }
80817
80925
  function defaultSharedRoot2() {
80818
- return resolve46(homedir43(), ".switchroom/skills");
80926
+ return resolve47(homedir43(), ".switchroom/skills");
80819
80927
  }
80820
80928
  function defaultBundledRoot2() {
80821
- return resolve46(homedir43(), ".switchroom/skills/_bundled");
80929
+ return resolve47(homedir43(), ".switchroom/skills/_bundled");
80822
80930
  }
80823
80931
  function readSkillFrontmatter(skillDir) {
80824
- const mdPath = join75(skillDir, "SKILL.md");
80932
+ const mdPath = join76(skillDir, "SKILL.md");
80825
80933
  if (!existsSync78(mdPath))
80826
80934
  return null;
80827
80935
  let content;
@@ -80854,7 +80962,7 @@ function readSkillFrontmatter(skillDir) {
80854
80962
  return { fm: parsed };
80855
80963
  }
80856
80964
  function statSkillMd(skillDir) {
80857
- const mdPath = join75(skillDir, "SKILL.md");
80965
+ const mdPath = join76(skillDir, "SKILL.md");
80858
80966
  try {
80859
80967
  const st = statSync31(mdPath);
80860
80968
  return { size: st.size, mtime: st.mtime.toISOString() };
@@ -80865,7 +80973,7 @@ function statSkillMd(skillDir) {
80865
80973
  function listPersonalSkills(agent, agentsRoot = defaultAgentsRoot()) {
80866
80974
  if (!AGENT_NAME_RE3.test(agent))
80867
80975
  return [];
80868
- const skillsDir = join75(agentsRoot, agent, ".claude/skills");
80976
+ const skillsDir = join76(agentsRoot, agent, ".claude/skills");
80869
80977
  if (!existsSync78(skillsDir))
80870
80978
  return [];
80871
80979
  const out = [];
@@ -80878,7 +80986,7 @@ function listPersonalSkills(agent, agentsRoot = defaultAgentsRoot()) {
80878
80986
  for (const ent of entries) {
80879
80987
  if (!ent.startsWith(PERSONAL_PREFIX2))
80880
80988
  continue;
80881
- const dirPath = join75(skillsDir, ent);
80989
+ const dirPath = join76(skillsDir, ent);
80882
80990
  try {
80883
80991
  if (!statSync31(dirPath).isDirectory())
80884
80992
  continue;
@@ -80918,7 +81026,7 @@ function listSharedSkills(sharedRoot = defaultSharedRoot2()) {
80918
81026
  continue;
80919
81027
  if (ent.startsWith("."))
80920
81028
  continue;
80921
- const dirPath = join75(sharedRoot, ent);
81029
+ const dirPath = join76(sharedRoot, ent);
80922
81030
  try {
80923
81031
  if (!statSync31(dirPath).isDirectory())
80924
81032
  continue;
@@ -80954,7 +81062,7 @@ function listBundledSkills(bundledRoot = defaultBundledRoot2()) {
80954
81062
  for (const ent of entries) {
80955
81063
  if (ent.startsWith("."))
80956
81064
  continue;
80957
- const dirPath = join75(bundledRoot, ent);
81065
+ const dirPath = join76(bundledRoot, ent);
80958
81066
  try {
80959
81067
  if (!statSync31(dirPath).isDirectory())
80960
81068
  continue;
@@ -81100,7 +81208,7 @@ init_source();
81100
81208
  init_helpers();
81101
81209
  import { existsSync as existsSync80, mkdirSync as mkdirSync44, readdirSync as readdirSync32, readFileSync as readFileSync66, writeFileSync as writeFileSync39, statSync as statSync32, copyFileSync as copyFileSync12 } from "node:fs";
81102
81210
  import { homedir as homedir44 } from "node:os";
81103
- import { join as join76 } from "node:path";
81211
+ import { join as join77 } from "node:path";
81104
81212
  import { spawnSync as spawnSync13 } from "node:child_process";
81105
81213
  init_audit_reader();
81106
81214
  var DEFAULT_IMAGE_TAG = "latest";
@@ -81191,10 +81299,10 @@ networks:
81191
81299
  `;
81192
81300
  }
81193
81301
  function hostdDir() {
81194
- return join76(homedir44(), ".switchroom", "hostd");
81302
+ return join77(homedir44(), ".switchroom", "hostd");
81195
81303
  }
81196
81304
  function hostdComposePath() {
81197
- return join76(hostdDir(), "docker-compose.yml");
81305
+ return join77(hostdDir(), "docker-compose.yml");
81198
81306
  }
81199
81307
  function backupExistingCompose() {
81200
81308
  const p = hostdComposePath();
@@ -81302,7 +81410,7 @@ function doStatus() {
81302
81410
  for (const name of readdirSync32(dir)) {
81303
81411
  if (name === "docker-compose.yml" || name.startsWith("docker-compose.yml."))
81304
81412
  continue;
81305
- const sockPath = join76(dir, name, "sock");
81413
+ const sockPath = join77(dir, name, "sock");
81306
81414
  if (existsSync80(sockPath)) {
81307
81415
  const st = statSync32(sockPath);
81308
81416
  if ((st.mode & 61440) === 49152) {