switchroom 0.15.38 → 0.15.39

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -31571,6 +31571,13 @@ var init_doctor_notion = __esm(() => {
31571
31571
  });
31572
31572
 
31573
31573
  // src/cli/doctor-mcp-secrets.ts
31574
+ function entryScopeDenies(agent, allow, deny) {
31575
+ if (deny.includes(agent))
31576
+ return true;
31577
+ if (allow.length > 0 && !allow.includes(agent))
31578
+ return true;
31579
+ return false;
31580
+ }
31574
31581
  function computeMcpSecretRequirements(config) {
31575
31582
  const cfg = config;
31576
31583
  const reqs = [];
@@ -31650,20 +31657,19 @@ async function runMcpSecretChecks(config, deps = {}) {
31650
31657
  });
31651
31658
  continue;
31652
31659
  }
31653
- if (!acl.allow.includes(r.agent)) {
31654
- const updated = [...new Set([...acl.allow, r.agent])].sort().join(",");
31660
+ if (entryScopeDenies(r.agent, acl.allow, acl.deny)) {
31655
31661
  results.push({
31656
31662
  name,
31657
31663
  status: "fail",
31658
- detail: `agent '${r.agent}' loads MCP '${r.server}' but is NOT on the vault ACL for '${key}' \u2014 the broker will deny it at runtime`,
31659
- fix: `switchroom vault set ${key} --allow ${updated} (vault set overwrites the scope \u2014 re-state the full list including '${r.agent}').`
31664
+ detail: `agent '${r.agent}' loads MCP '${r.server}' but the vault entry scope for '${key}' denies it \u2014 the broker will deny at runtime`,
31665
+ fix: `switchroom vault set ${key} --allow ${[...new Set([...acl.allow, r.agent])].sort().join(",")} (vault set overwrites the scope \u2014 re-state the full list including '${r.agent}'; and drop it from --deny if present).`
31660
31666
  });
31661
31667
  continue;
31662
31668
  }
31663
31669
  results.push({
31664
31670
  name,
31665
31671
  status: "ok",
31666
- detail: `MCP '${r.server}' \u2192 '${key}' present + ACL-allowed`
31672
+ detail: `MCP '${r.server}' \u2192 '${key}' present + scope-allowed`
31667
31673
  });
31668
31674
  }
31669
31675
  }
@@ -34014,7 +34020,11 @@ function registerDoctorCommand(program3) {
34014
34020
  const { getViaBrokerStructured: getViaBrokerStructured2 } = await Promise.resolve().then(() => (init_client(), exports_client));
34015
34021
  const result = await getViaBrokerStructured2(key);
34016
34022
  if (result.kind === "ok") {
34017
- return { kind: "ok", allow: result.entry.scope?.allow ?? [] };
34023
+ return {
34024
+ kind: "ok",
34025
+ allow: result.entry.scope?.allow ?? [],
34026
+ deny: result.entry.scope?.deny ?? []
34027
+ };
34018
34028
  }
34019
34029
  if (result.kind === "not_found")
34020
34030
  return { kind: "not_found" };
@@ -50692,8 +50702,8 @@ var {
50692
50702
  } = import__.default;
50693
50703
 
50694
50704
  // src/build-info.ts
50695
- var VERSION = "0.15.38";
50696
- var COMMIT_SHA = "d28a331f";
50705
+ var VERSION = "0.15.39";
50706
+ var COMMIT_SHA = "69e5a2e8";
50697
50707
 
50698
50708
  // src/cli/agent.ts
50699
50709
  init_source();
@@ -68599,6 +68609,8 @@ var HINDSIGHT_DEFAULT_MEM_LIMIT = "4g";
68599
68609
  var HINDSIGHT_DEFAULT_MEM_RESERVATION = "2g";
68600
68610
  var HINDSIGHT_DEFAULT_PIDS_LIMIT = 1000;
68601
68611
  var HINDSIGHT_DEFAULT_SHM_SIZE = "2g";
68612
+ var HINDSIGHT_HEALTHCHECK_PY = 'import urllib.request,sys; sys.exit(0 if urllib.request.urlopen("http://localhost:8888/health",timeout=4).getcode()==200 else 1)';
68613
+ var HINDSIGHT_HEALTHCHECK_CMD = `python3 -c '${HINDSIGHT_HEALTHCHECK_PY}'`;
68602
68614
  function isPortFree(port) {
68603
68615
  return new Promise((resolve28) => {
68604
68616
  const server = createServer4();
@@ -68690,6 +68702,16 @@ function startHindsight(ports) {
68690
68702
  `--memory-reservation=${HINDSIGHT_DEFAULT_MEM_RESERVATION}`,
68691
68703
  `--pids-limit=${HINDSIGHT_DEFAULT_PIDS_LIMIT}`,
68692
68704
  `--shm-size=${HINDSIGHT_DEFAULT_SHM_SIZE}`,
68705
+ "--health-cmd",
68706
+ HINDSIGHT_HEALTHCHECK_CMD,
68707
+ "--health-interval",
68708
+ "30s",
68709
+ "--health-timeout",
68710
+ "5s",
68711
+ "--health-retries",
68712
+ "3",
68713
+ "--health-start-period",
68714
+ "60s",
68693
68715
  "-p",
68694
68716
  `127.0.0.1:${apiPort}:8888`,
68695
68717
  "-p",
@@ -68697,6 +68719,8 @@ function startHindsight(ports) {
68697
68719
  "-v",
68698
68720
  "switchroom-hindsight-data:/home/hindsight/.pg0",
68699
68721
  "-v",
68722
+ "switchroom-hindsight-backups:/backups",
68723
+ "-v",
68700
68724
  `${HINDSIGHT_BROKER_SOCK_VOLUME}:/run/switchroom/auth-broker`,
68701
68725
  "--tmpfs",
68702
68726
  `/run/claude-creds:rw,mode=0700,uid=${HINDSIGHT_DEFAULT_UID},gid=${HINDSIGHT_DEFAULT_UID}`,
@@ -68744,8 +68768,15 @@ function generateHindsightComposeSnippet() {
68744
68768
  ` mem_reservation: ${HINDSIGHT_DEFAULT_MEM_RESERVATION}`,
68745
68769
  ` pids_limit: ${HINDSIGHT_DEFAULT_PIDS_LIMIT}`,
68746
68770
  ` shm_size: ${HINDSIGHT_DEFAULT_SHM_SIZE}`,
68771
+ " healthcheck:",
68772
+ ` test: ${JSON.stringify(["CMD", "python3", "-c", HINDSIGHT_HEALTHCHECK_PY])}`,
68773
+ " interval: 30s",
68774
+ " timeout: 5s",
68775
+ " retries: 3",
68776
+ " start_period: 60s",
68747
68777
  " volumes:",
68748
68778
  " - switchroom-hindsight-data:/home/hindsight/.pg0",
68779
+ " - switchroom-hindsight-backups:/backups",
68749
68780
  ` - ${HINDSIGHT_BROKER_SOCK_VOLUME}:/run/switchroom/auth-broker`,
68750
68781
  " tmpfs:",
68751
68782
  ` - /run/claude-creds:rw,mode=0700,uid=${HINDSIGHT_DEFAULT_UID},gid=${HINDSIGHT_DEFAULT_UID}`,
@@ -68753,6 +68784,7 @@ function generateHindsightComposeSnippet() {
68753
68784
  "",
68754
68785
  "volumes:",
68755
68786
  " switchroom-hindsight-data:",
68787
+ " switchroom-hindsight-backups:",
68756
68788
  ` ${HINDSIGHT_BROKER_SOCK_VOLUME}:`,
68757
68789
  " external: true",
68758
68790
  " # Bound by the switchroom-auth-broker singleton in the main",
@@ -83273,14 +83305,14 @@ async function computeAgentConnectionIssues(config, agentName, vaultAclReader) {
83273
83305
  });
83274
83306
  continue;
83275
83307
  }
83276
- if (!acl.allow.includes(agentName)) {
83308
+ if (entryScopeDenies(agentName, acl.allow, acl.deny)) {
83277
83309
  const updated = [...new Set([...acl.allow, agentName])].sort().join(",");
83278
83310
  issues.push({
83279
83311
  server: r.server,
83280
83312
  key,
83281
83313
  kind: "acl",
83282
- detail: `MCP '${r.server}' not on the vault ACL for '${key}' \u2014 broker will deny at runtime`,
83283
- fix: `switchroom vault set ${key} --allow ${updated} (re-state the full list)`
83314
+ detail: `MCP '${r.server}' \u2014 vault entry scope for '${key}' denies this agent \u2014 broker will deny at runtime`,
83315
+ fix: `switchroom vault set ${key} --allow ${updated} (re-state the full list; drop from --deny if present)`
83284
83316
  });
83285
83317
  }
83286
83318
  }
@@ -83710,7 +83742,11 @@ Applying switchroom config...
83710
83742
  const { getViaBrokerStructured: getViaBrokerStructured2 } = await Promise.resolve().then(() => (init_client(), exports_client));
83711
83743
  const result = await getViaBrokerStructured2(key);
83712
83744
  if (result.kind === "ok") {
83713
- return { kind: "ok", allow: result.entry.scope?.allow ?? [] };
83745
+ return {
83746
+ kind: "ok",
83747
+ allow: result.entry.scope?.allow ?? [],
83748
+ deny: result.entry.scope?.deny ?? []
83749
+ };
83714
83750
  }
83715
83751
  if (result.kind === "not_found")
83716
83752
  return { kind: "not_found" };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "switchroom",
3
- "version": "0.15.38",
3
+ "version": "0.15.39",
4
4
  "description": "Run Claude Code 24/7 on your Claude Pro/Max subscription over Telegram. Open-source alternative to OpenClaw and NanoClaw — no API keys.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -28,6 +28,8 @@ You are operating in the **{{topicName}}** {{#if topicEmoji}}{{topicEmoji}} {{/i
28
28
  - Prefer `trash` over `rm` when available (recoverable beats gone forever).
29
29
  - Safe to do freely: read files, explore, organize, search the web, check calendars, work within this workspace.
30
30
  - Ask first: sending emails, tweets, public posts, anything that leaves the machine, anything you're uncertain about.
31
+ - **Batch foreseeable approvals; don't drip surprises.** When you can already see that several actions will each need the user's approval, tell them up front which approvals are coming and why. Request independent ones together so they can decide once; for dependent ones (one's input comes from another), say what you're doing first and what approval comes next — a permission card should never arrive out of the blue.
32
+ - **A timed-out approval isn't a denial.** If a request came back denied only because the user was away (a timeout, not an explicit "no"), don't silently abandon it. When they're back, remind them it's still pending and re-offer it if they still want it.
31
33
 
32
34
  ## Execution Bias
33
35
 
@@ -54519,11 +54519,11 @@ function readTurnActiveMarkerAgeMs(stateDir, now) {
54519
54519
  }
54520
54520
 
54521
54521
  // ../src/build-info.ts
54522
- var VERSION = "0.15.38";
54523
- var COMMIT_SHA = "d28a331f";
54524
- var COMMIT_DATE = "2026-06-18T11:43:40+10:00";
54522
+ var VERSION = "0.15.39";
54523
+ var COMMIT_SHA = "69e5a2e8";
54524
+ var COMMIT_DATE = "2026-06-18T12:27:21+10:00";
54525
54525
  var LATEST_PR = null;
54526
- var COMMITS_AHEAD_OF_TAG = 13;
54526
+ var COMMITS_AHEAD_OF_TAG = 4;
54527
54527
 
54528
54528
  // gateway/boot-version.ts
54529
54529
  function formatRelativeAgo(iso) {